'https://help.one.com/hc/en-us/articles/5927991871761-What-is-WP-Rocket-',
'da' => 'https://help.one.com/hc/da/articles/5927991871761-Hvad-er-WP-Rocket-',
'de' => 'https://help.one.com/hc/de/articles/5927991871761-Was-ist-WP-Rocket-',
'es' => 'https://help.one.com/hc/es/articles/5927991871761--Qu%C3%A9-es-WP-Rocket-',
'fr' => 'https://help.one.com/hc/fr/articles/5927991871761-Que-est-ce-que-WP-Rocket-',
'fi' => 'https://help.one.com/hc/fi/articles/5927991871761-Mik%C3%A4-on-WP-Rocket-',
'it' => 'https://help.one.com/hc/it/articles/5927991871761-Cos-%C3%A8-WP-Rocket-',
'nl' => 'https://help.one.com/hc/nl/articles/5927991871761-Wat-is-WP-Rocket-',
'no' => 'https://help.one.com/hc/no/articles/5927991871761-Hva-er-WP-Rocket-',
'pt' => 'https://help.one.com/hc/pt/articles/5927991871761-O-que-%C3%A9-o-WP-Rocket-',
'sv' => 'https://help.one.com/hc/sv/articles/5927991871761-Vad-%C3%A4r-WP-Rocket-',
);
// Initiatize actions
public function init() {
add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_scripts' ) );
add_action( 'wp_ajax_on_reload_plugin_activate', array( $this, 'on_reload_plugin_activate_check' ) );
add_action( 'wp_ajax_activate_onclick_wp_plugin', array( $this, 'onclick_plugin_activate' ) );
add_action( 'wp_ajax_check_addon_purchase_status', array( $this, 'check_addon_purchase_status' ) );
add_action( 'wp_ajax_check_addon_purchase_status_onload', array( $this, 'on_reload_addon_status_check' ) );
add_action( 'activate_wp-rocket/wp-rocket.php', array( $this, 'wp_rocket_activation_action' ) );
}
// Load scripts on relevant page(s) only
public function enqueue_scripts( $hook_suffix ) {
if ( $hook_suffix !== 'one-com_page_onecom-wp-rocket') {
return;
}
wp_enqueue_style( 'oc_wpr_style', ONECOM_WP_URL . 'modules/wp-rocket/assets/css/wp-rocket.css', array(), ONECOM_WP_VERSION );
// Load JS on both pages
wp_enqueue_script( 'oc_wpr_script', ONECOM_WP_URL . 'modules/wp-rocket/assets/js/wp-rocket.js', array( 'jquery' ), ONECOM_WP_VERSION, true );
}
/**
* WP Rocket activation hooks
*/
public function wp_rocket_activation_action(): void {
/**
* Call to the features endpoint for restoring transient value
* Why? So that wp-rocket page and its plugin entry shows latest state in plugins list after activation immediately
*/
oc_set_premi_flag( true );
}
// WP-Rocket translated guide link with en fallback
public function wp_rocket_translated_guide() {
$locale = explode( '_', get_locale() )[0];
if ( ! array_key_exists( $locale, $this->guide_links ) ) {
$locale = 'en';
}
return $this->guide_links[ $locale ];
}
/**
* Plugin activates on the button click
* @return void
*/
public function onclick_plugin_activate() {
$addon_slug = $_POST['addon_slug'];
$transient_key = "{$addon_slug}_activation_button_clicked_at";
set_site_transient( $transient_key, current_time( 'timestamp' ), self::EXPIRATION_TIME_IN_MINUTES * MINUTE_IN_SECONDS );
$this->activate_wp_plugin( $addon_slug );
}
/**
* Addon status check on the button click
* @return void
*/
public function check_addon_purchase_status() {
$addon_slug = $_POST['addon_slug'];
$transient_key = "{$addon_slug}_select_button_clicked_at";
set_site_transient( $transient_key, current_time( 'timestamp' ), self::EXPIRATION_TIME_IN_MINUTES * MINUTE_IN_SECONDS );
$this->addon_status_check( $addon_slug );
}
/**
* Check plugin activation on reload
* @return void
*/
public function on_reload_addon_status_check() {
$addon_slug = $_POST['addon_slug'];
$this->addon_status_check( $addon_slug );
}
/**
* Check plugin activation on reload
* @return void
*/
public function on_reload_plugin_activate_check() {
$addon_slug = $_POST['addon_slug'];
$this->activate_wp_plugin( $addon_slug );
}
public function check_addon_purchase_response($getAddonStatus){
if (is_array($getAddonStatus) && array_key_exists('success', $getAddonStatus) && $getAddonStatus['success']) {
if (array_key_exists('data', $getAddonStatus) && array_key_exists('source', $getAddonStatus['data']) && $getAddonStatus['data']['source'] === 'PURCHASED' && array_key_exists('product', $getAddonStatus['data']) && $getAddonStatus['data']['product'] === 'WP_ROCKET') {
return true;
} else {
return false;
}
} else {
error_log("Error fetching addon status from features endpoint: " . (is_array($getAddonStatus) && array_key_exists('error', $getAddonStatus) ? $getAddonStatus['error'] : 'Unknown error'));
return false;
}
}
/**
* onclick and reload check
* Addon purchase status
*/
public function addon_status_check($addon_slug) {
$start_time_key = "{$addon_slug}_purchase_button_start_at";
$btn_transient_key = "{$addon_slug}_select_button_clicked_at";
$timeout_limit = self::EXPIRATION_TIME_IN_MINUTES * MINUTE_IN_SECONDS;
$current_time = current_time('timestamp');
$plugin_slug = self::WR_SLUG;
// Ensure the activation button was clicked
if ( ! get_site_transient($btn_transient_key) ) {
wp_send_json(['status' => 'normal_reload']);
}
// Common success response
$send_success = function() use ($addon_slug) {
error_log("Addon purchased successfully from WP-admin: {$addon_slug}");
$this->clear_addon_status_queue($addon_slug);
//set status for activation plugin
$this->set_transient_for_addon_activation($addon_slug);
//addon purchased, now set transient for activation plugin
wp_send_json([
'status' => 'addon_purchased'
]);
};
// If the plugin is already active, respond immediately
if (is_plugin_active($plugin_slug)) {
error_log("Plugin already active: {$plugin_slug}, skipping purchase check");
wp_send_json([
'status' => 'already_plugin_active'
]);
}
$start_time = get_site_transient($start_time_key);
// Case 1: First time select click attempt
if (!$start_time) {
set_site_transient($start_time_key, $current_time, $timeout_limit);
wp_send_json(['status' => 'added_in_queue']);
}
//get addon purchase status, force refresh feature endpoint
//call feature endpoint to get latest addon status
$getAddonStatus = $this->wp_rocket_addon_info(true);
$addon_purchased = $this->check_addon_purchase_response($getAddonStatus);
if ($addon_purchased) {
$send_success();
}
$elapsed_time = $current_time - (int) $start_time;
$time_left = $timeout_limit - $elapsed_time;
// Case 2: Stop polling early if less than 30 seconds left
if ($time_left <= 30) {
if ($addon_purchased) {
$send_success();
}
error_log("Polling stopped early (time left: {$time_left}s) for {$addon_slug}");
$this->clear_addon_status_queue($addon_slug);
wp_send_json(['status' => 'expired_queue']);
}
// Case 3: Queue expired after timeout
if ($elapsed_time >= $timeout_limit) {
if ($addon_purchased) {
$send_success();
}
error_log("Addon not purchased and timed out: {$plugin_slug}");
$this->clear_addon_status_queue($addon_slug);
wp_send_json(['status' => 'expired_queue']);
}
// Case 3: Queue still in progress
error_log("Addon purchase in progress: {$plugin_slug}");
wp_send_json(['status' => 'already_in_queue']);
}
/**
* onclick and reload check
* Activate a plugin
*/
public function activate_wp_plugin($addon_slug) {
$start_time_key = "{$addon_slug}_activation_start_at";
$btn_transient_key = "{$addon_slug}_activation_button_clicked_at";
$plugin_slug = self::WR_SLUG;
$admin_url = admin_url('options-general.php?page=wprocket');
$plugin_btn_text = __('Go to WP Rocket plugin', 'onecom-wp');
$timeout_limit = self::EXPIRATION_TIME_IN_MINUTES * MINUTE_IN_SECONDS;
$current_time = current_time('timestamp');
// Ensure the activation button was clicked
if ( ! get_site_transient($btn_transient_key) ) {
wp_send_json(['status' => 'normal_reload']);
}
// Common success response
$send_success = function() use ($addon_slug, $plugin_slug, $admin_url, $plugin_btn_text) {
error_log("Plugin activated successfully from WP-admin: {$plugin_slug}");
$this->clear_activation_queue($addon_slug);
wp_send_json([
'status' => 'activated',
'url' => $admin_url,
'btn_text' => $plugin_btn_text,
]);
};
// If the plugin is already active, respond immediately
if (is_plugin_active($plugin_slug)) {
$send_success();
}
$start_time = get_site_transient($start_time_key);
// Case 1: First time activation attempt
if (!$start_time) {
set_site_transient($start_time_key, $current_time, $timeout_limit);
if ($this->is_wp_rocket_installed()) {
$result = activate_plugin($plugin_slug);
if (is_wp_error($result)) {
error_log("Plugin activation failed from WP-admin: {$plugin_slug}");
$this->clear_activation_queue($addon_slug);
wp_send_json_error([
'status' => 'activation_failed',
'message' => $result->get_error_message(),
]);
}
$send_success();
}
// If not active, trigger provisioner
if (!is_plugin_active($plugin_slug)) {
$status = $this->call_wp_api_provisioner($addon_slug);
error_log('PP status: ' . $status);
wp_send_json(['status' => $status]);
}
}
// Case 2: Existing queue, check timeout
if (($current_time - (int) $start_time) >= $timeout_limit) {
if (is_plugin_active($plugin_slug)) {
$send_success();
}
error_log("Plugin not activated and timed out: {$plugin_slug}");
$this->clear_activation_queue($addon_slug);
wp_send_json(['status' => 'expired_queue']);
}
// Case 3: Queue still in progress
error_log("Plugin activation in progress: {$plugin_slug}");
wp_send_json(['status' => 'already_in_queue']);
}
public function set_transient_for_addon_activation($addon_slug) {
$activation_start_at = "{$addon_slug}_activation_start_at";
$activation_button_clicked_at = "{$addon_slug}_activation_button_clicked_at";
$pp_activation_start_at = "$addon_slug-pp-activation-start-at";
$timeout_limit = self::EXPIRATION_TIME_IN_MINUTES * MINUTE_IN_SECONDS;
$current_time = current_time('timestamp');
set_site_transient( $activation_start_at, $current_time, $timeout_limit );
set_site_transient( $activation_button_clicked_at, $current_time, $timeout_limit
);
set_site_transient( $pp_activation_start_at, $current_time, $timeout_limit );
}
public function clear_activation_queue($addon_slug) {
delete_site_transient( "{$addon_slug}_activation_start_at" );
delete_site_transient( "{$addon_slug}_activation_button_clicked_at" );
delete_site_transient( "$addon_slug-pp-activation-start-at" );
//clear cache
if ( function_exists( 'wp_cache_flush' ) ) {
wp_cache_flush();
}
}
public function clear_addon_status_queue($addon_slug) {
delete_site_transient( "{$addon_slug}_purchase_button_start_at" );
delete_site_transient( "{$addon_slug}_select_button_clicked_at" );
//clear cache
if ( function_exists( 'wp_cache_flush' ) ) {
wp_cache_flush();
}
}
/**
* Function to include WP-Rocket admin page template
*/
public static function wp_rocket_page() {
require_once plugin_dir_path( __DIR__ ) . '/templates/wp-rocket-admin-page.php';
}
// Fetch wp rocket addon info via feature endpoint
public function wp_rocket_addon_info( $force = false, $domain = '' ) {
// check transient
$wp_rocket_addon_info = get_site_transient( 'onecom_wp_rocket_addon_info' );
if ( ! empty( $wp_rocket_addon_info ) && false === $force ) {
return $wp_rocket_addon_info;
}
if ( ! $domain ) {
$domain = isset( $_SERVER['ONECOM_DOMAIN_NAME'] ) ? $_SERVER['ONECOM_DOMAIN_NAME'] : false;
}
if ( ! $domain ) {
return array(
'data' => null,
'error' => 'Empty domain',
'success' => false,
);
}
$totp = oc_generate_totp();
// headers and api url based on cluster domain or not
if ( is_cluster_domain() ) {
//create header for cluster model
$curl_url = self::WR_ADDON_CLUSTER_API;
$http_header = array(
'Cache-Control: no-cache',
'X-Onecom-Client-Domain: ' . $domain,
'X-TOTP: ' . $totp,
'cache-control: no-cache',
);
$http_header[] = 'X-ONECOM-CLUSTER-ID: ' . OC_CLUSTER_ID;
$http_header[] = 'X-ONECOM-WEBCONFIG-NAME: ' . $_SERVER['HTTP_X_GROUPONE_WEBCONFIG_NAME'];
} else {
//prepare headers for domain model
$curl_url = self::WR_ADDON_API;
$http_header = array(
'Cache-Control: no-cache',
'X-Onecom-Client-Domain: ' . $domain, //need to use from wp-config if available otherwise use domain parse
'X-TOTP: ' . $totp,
'cache-control: no-cache',
);
}
$curl = curl_init();
curl_setopt_array(
$curl,
array(
CURLOPT_URL => $curl_url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_HTTPHEADER => $http_header
)
);
$response = curl_exec( $curl );
$response = json_decode( $response, true );
$err = curl_error( $curl );
curl_close( $curl );
if ( $err ) {
return array(
'data' => null,
'error' => __( 'Some error occurred, please reload the page and try again.', 'validator' ),
'success' => false,
);
} else {
// save transient for next calls, & return latest response
set_site_transient( 'onecom_wp_rocket_addon_info', $response, 12 * HOUR_IN_SECONDS );
return $response;
}
}
public function get_marketplace_prices(array $addons = array(), $force = false){
$countryCode = $this->get_cu_country_code();
$addons_param = rawurlencode(implode(', ', $addons));
// check transient
$wp_marketplace_price = get_site_transient( 'onecom_marketplace_prices' );
if ( ! empty( $wp_marketplace_price ) && false === $force ) {
error_log('Using transient marketplace prices');
return $wp_marketplace_price;
}
$curl_url = self::WR_MARKETPLACE_PRICES_API . '?addons=' . $addons_param . '&countryCode=' . rawurlencode($countryCode);
$domain = isset( $_SERVER['ONECOM_DOMAIN_NAME'] ) ? $_SERVER['ONECOM_DOMAIN_NAME'] : false;
$totp = function_exists('oc_generate_totp') ? oc_generate_totp() : '';
// Build headers similar to wp_rocket_addon_info
$http_header = array(
'Cache-Control: no-cache',
);
if($domain){
$http_header[] = 'X-Onecom-Client-Domain: ' . $domain;
}
if($totp){
$http_header[] = 'X-TOTP: ' . $totp;
}
if ( function_exists('is_cluster_domain') && is_cluster_domain() ) {
if(defined('OC_CLUSTER_ID')){
$http_header[] = 'X-ONECOM-CLUSTER-ID: ' . OC_CLUSTER_ID;
}
if(isset($_SERVER['HTTP_X_GROUPONE_WEBCONFIG_NAME'])){
$http_header[] = 'X-ONECOM-WEBCONFIG-NAME: ' . $_SERVER['HTTP_X_GROUPONE_WEBCONFIG_NAME'];
}
}
$curl = curl_init();
curl_setopt_array(
$curl,
array(
CURLOPT_URL => $curl_url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_HTTPHEADER => $http_header
)
);
$response = curl_exec( $curl );
$err = curl_error( $curl );
curl_close( $curl );
// Handle curl error
if ( $err ) {
return array(
'data' => null,
'error' => __( 'Some error occurred, please reload the page and try again.', 'validator' ),
'success' => false,
);
}
$response_arr = json_decode($response, true);
if(!is_array($response_arr)){
return array(
'data' => null,
'error' => __( 'Invalid response from marketplace prices API.', 'onecom-wp' ),
'success' => false,
);
}
//set transient for next calls and return the latest response
set_site_transient( 'onecom_marketplace_prices', $response_arr, 12 * HOUR_IN_SECONDS );
return $response_arr;
}
public function get_wpr_price(array $addons = array('WP_ROCKET')){
// Fetch prices from marketplace API for the requested addons and aggregate all valid ones.
$api_resp = $this->get_marketplace_prices($addons);
if (is_array($api_resp) && isset($api_resp['success']) && $api_resp['success'] && isset($api_resp['data']['prices']) && is_array($api_resp['data']['prices'])) {
// Build an index of prices by addon for an easier lookup
$prices_by_addon = array();
foreach ($api_resp['data']['prices'] as $price_entry) {
if (!isset($price_entry['addon'])) {
continue;
}
$prices_by_addon[$price_entry['addon']] = $price_entry;
}
$result = array('success' => true);
$found_any = false;
// Respect the order of requested addons. Collect all valid ones.
foreach ($addons as $addon_name) {
if (!isset($prices_by_addon[$addon_name])) {
continue;
}
$price_entry = $prices_by_addon[$addon_name];
// Only include if a result is a valid array
if (isset($price_entry['result']) && is_array($price_entry['result'])) {
$r = $price_entry['result'];
$result[$addon_name] = $r;
$found_any = true;
}
}
if ($found_any) {
return $result;
}
}
// If we reach here, no valid pricing available for requested addons; return error with success false as per requirement.
return array(
'success' => false,
'error' => __( 'Requested addon price not available at the moment. Please try again later.', 'onecom-wp' ),
);
}
public function get_cu_country_code(){
$default = 'US';
$status = $this->wp_rocket_addon_info();
$country_code = $default;
if(is_array($status) &&
isset($status['data']) &&
is_array($status['data']) &&
!empty($status['data']['country'])) {
$country_code = $status['data']['country'];
}
error_log("Country code use for addon price: $country_code");
return $country_code;
}
public function call_wp_api_provisioner($addon_slug)
{
if (empty($addon_slug)) {
return;
}
//skip provisioner call if addon not subscribed
if(!$this->is_wp_rocket_addon_purchased()){
error_log('addon_not_subscribed, skipping WP API Provisioner call: ' . $addon_slug);
return 'addon_not_subscribed';
}
error_log("Request plugin activation from wp-admin: $addon_slug");
//Just add the below key in onboarding also for sync
$pp_start_at = "$addon_slug-pp-activation-start-at";
$start_time = get_site_transient( $pp_start_at );
if($start_time){
error_log("The provisioning request has already been sent; skipping the re-request: " . $addon_slug);
return 'already_in_queue';
}
error_log("Calling WP API Provisioner for plugin:" . $addon_slug);
if (is_cluster_domain()) {
$url = MIDDLEWARE_URL . '/plugin-provisioner/cluster';
} else {
$url = onecom_query_check(MIDDLEWARE_URL . '/plugin-provisioner');
}
add_filter('http_request_args', 'oc_add_http_headers', 10, 2);
wp_remote_post(
$url,
array(
'body' => json_encode(array(
'subdomain' => OCPushStats::get_subdomain(),
'domain' => OCPushStats::get_domain(),
'addon_slug' => $addon_slug
))
)
);
remove_filter('http_request_args', 'oc_add_http_headers');
// Push installed plugins with activation status
( class_exists( 'OCPUSHSTATS' ) ? \OCPushStats::push_stats_event_themes_and_plugins( 'plugin_install', 'blog', 'plugin_selector', "wpapi_provisoner" ) : '' );
return 'added_to_queue';
}
/**
* Check if wp_rocket plugin addon purchased
*/
public function is_wp_rocket_addon_purchased(): bool {
$this->wp_rocket_addon_info = $this->wp_rocket_addon_info();
return (
is_array( $this->wp_rocket_addon_info ) &&
array_key_exists( 'success', $this->wp_rocket_addon_info ) &&
$this->wp_rocket_addon_info['success'] &&
array_key_exists( 'data', $this->wp_rocket_addon_info ) &&
array_key_exists( 'source', $this->wp_rocket_addon_info['data'] ) &&
$this->wp_rocket_addon_info['data']['source'] === 'PURCHASED' &&
array_key_exists( 'product', $this->wp_rocket_addon_info['data'] ) &&
$this->wp_rocket_addon_info['data']['product'] === 'WP_ROCKET'
);
}
// Check if WP Rocket is provisioned/installed via one.com
public function is_oc_wp_rocket_flag_exists() {
return get_site_option( 'oc-wp-rocket-activation' );
}
// Check if WP Rocket plugin is active
public function is_wp_rocket_active(): bool {
return is_plugin_active( self::WR_SLUG );
}
// Check if WP Rocket is installed
public function is_wp_rocket_installed(): bool {
wp_clean_plugins_cache();
$plugins = get_plugins();
return array_key_exists( self::WR_SLUG, $plugins );
}
// WP-Rocket plugin json for entry in one.com plugins
public function wp_rocket_plugin_info(): array {
$plugins = onecom_fetch_plugins();
return array(
'id' => count( $plugins ) + 1,
'name' => 'WP Rocket',
'slug' => 'wp-rocket',
'description' => __( 'Speed up your site, improve loading times, and boost your search rankings with one of the most popular performance optimisation plugins.' ),
'new' => '1656829808',
'thumbnail' => self::WR_ICON,
'thumbnail_name' => 'thumbnail.svg',
'redirect' => 'options-general.php?page=wprocket',
'type' => 'external',
);
}
/**
* Section 3: Pricing + Features
* @return void
*/
public function wp_rocket_pricing_table() {
$wpr_features = [
__('Page and browser caching', 'onecom-wp'),
__('GZIP compression', 'onecom-wp'),
__('Cross-Origin support for web fonts', 'onecom-wp'),
__('Detection and support of various third-party plugins, themes', 'onecom-wp'),
__('Combination of inline and 3rd party scripts', 'onecom-wp'),
__('WooCommerce Refresh Cart Fragments Cache', 'onecom-wp'),
__('Optimise Google Fonts files', 'onecom-wp'),
__('Optimise database and emojis', 'onecom-wp'),
];
//The default params will be WP_ROCKET
$wpr_price = $this->get_wpr_price();
$addon_key = 'WP_ROCKET';
$has_price = (is_array($wpr_price) && isset($wpr_price['success']) && $wpr_price['success'] && isset($wpr_price[$addon_key]) && is_array($wpr_price[$addon_key]));
$priceInclVat = $has_price ? $wpr_price[$addon_key]['fullPriceInclVat'] : '';
$currencySymbol = $has_price ? $wpr_price[$addon_key]['currency'] : '';
?>