oc_vc_path = __DIR__;
$this->oc_vc_uri = plugins_url( '', __FILE__ );
$this->vc_path = dirname( $this->oc_vc_path );
$this->onecom_vcache_dir_url = plugin_dir_url( __FILE__ );
$this->logger = new Onecom_Logger();
$this->blog_url = get_option( 'home' );
$this->purge_id = $this->oc_json_get_option( 'onecom_vcache_info', 'vcache_purge_id' );
if ( is_multisite() ) {
$this->cdn_url = rtrim( 'https://usercontent.one/wp/' . str_replace( array( self::HTTPS, self::HTTP ), '', network_site_url() ), '/' );
} else {
$this->cdn_url = 'https://usercontent.one/wp/' . str_replace( array( self::HTTPS, self::HTTP ), '', $this->blog_url );
}
$this->clusterAdjustments();
/**
* This commented becuase performance cache is available to all now.
* and Enable disable settings works with activation/deactivation hooks, no need to do it on each page load
* @todo - to be deleted after a while if all works well
*/
add_action( 'admin_init', array( $this, 'runAdminSettings' ), 1 );
add_action( 'admin_menu', array( $this, 'remove_parent_page' ), 100 );
add_action( 'admin_menu', array( $this, 'add_menu_item' ) );
add_action( 'admin_init', array( $this, 'options_page_fields' ) );
add_action( 'plugins_loaded', array( $this, 'filter_purge_settings' ), 1 );
add_action( 'admin_head', array( $this, 'vcaching_reset_dev_mode' ), 10 );
add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_resources' ) );
add_action( 'admin_head', array( $this, 'onecom_vcache_icon_css' ) );
add_action( 'wp_ajax_oc_set_vc_state', array( $this, 'oc_set_vc_state_cb' ) );
// add_action( 'wp_ajax_oc_set_vc_ttl', array( $this, 'oc_set_vc_ttl_cb' ) );
// add_action( 'wp_ajax_oc_set_cdn_state', array( $this, 'oc_cdn_state_cb' ) );
// add_action( 'wp_ajax_oc_set_dev_mode', array( $this, 'oc_set_dev_mode_cb' ) );
// add_action( 'wp_ajax_oc_exclude_cdn_mode', array( $this, 'oc_exclude_cdn_mode_cb' ) );
// add_action( 'wp_ajax_oc_update_cdn_data', array( $this, 'oc_update_cdn_data_cb' ) );
add_action( 'wp_ajax_oc_activate_wp_rocket', array( $this, 'oc_activate_wp_rocket' ) );
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( 'template_redirect', array( $this, 'oc_cdn_rewrites' ) );
add_action( 'upgrader_process_complete', array( $this, 'oc_upgrade_housekeeping' ), 10, 2 );
add_action( 'plugins_loaded', array( $this, 'oc_update_headers_htaccess' ) );
add_action( 'switch_theme', array( $this, 'purge_theme_cache' ) );
add_action( 'onecom_purge_cdn', array( $this, 'oc_purge_cdn_cache' ) );
add_action( 'wp_ajax_oc_handle_cdn_settings', array( $this, 'oc_handle_cdn_settings_cb' ) );
// remove purge requests from Oclick demo importer
add_filter( 'vcaching_events', array( $this, 'vcaching_events_cb' ) );
//intercept the list of urls, replace multiple urls with a single generic url
add_filter( 'vcaching_purge_urls', array( $this, 'vcaching_purge_urls_cb' ) );
add_action( 'wp_ajax_purge_cache', array( $this,'handle_purge_cache_request' ));
register_activation_hook( $this->vc_path . DIRECTORY_SEPARATOR . 'vcaching.php', array( $this, 'onActivatePlugin' ) );
register_deactivation_hook( $this->vc_path . DIRECTORY_SEPARATOR . 'vcaching.php', array( $this, 'onDeactivatePlugin' ) );
$exclude_cache = new OnecomExcludeCache();
}
/**
* Function to run admin settings
*
*/
public function runAdminSettings() {
if ( 'false' !== $this->state ) {
return;
}
// Following removes admin bar purge link, so commented
// add_action( 'admin_bar_menu', array( $this, 'remove_toolbar_node' ), 999 );
add_filter( 'post_row_actions', array( $this, 'remove_post_row_actions' ), 10, 2 );
add_filter( 'page_row_actions', array( $this, 'remove_page_row_actions' ), 10, 2 );
}
/**
* Function will execute after plugin activated
*
**/
public function onActivatePlugin() {
// Enable/Disable Cache/CDN on activation based on eligibility
$cdn_enabled = update_site_option( self::OPTIONCDN, 'true', 'no' );
self::setDefaultSettings();
}
/**
* Function will execute after plugin deactivated
*
*/
public function onDeactivatePlugin() {
$on_deactivate = true;
self::disableDefaultSettings( $on_deactivate );
self::purgeAll();
}
/**
* Function to make some checks to ensure best usage
**/
private function runChecklist() {
$this->oc_upgrade_housekeeping( 'activate' );
// If not exist, then return
if ( ! in_array( 'vcaching/vcaching.php', (array) get_site_option( 'active_plugins' ), true ) ) {
return true;
}
$this->logger->wp_api_sendlog( 'already_exists', self::PLUGINNAME, self::PLUGINNAME . 'DefaultWP Caching plugin already exists.', self::PLUGINVERSION );
add_action( 'admin_notices', array( $this, 'duplicateWarning' ) );
return false;
}
/**
* Function to disable vcache promo/notice
*
*/
private function disablePromoNotice() {
$local_promo = get_site_option( 'onecom_local_promo' );
if ( isset( $local_promo['xpromo'] ) && '18-jul-2018' === $local_promo['xpromo'] ) {
$local_promo['show'] = false;
update_site_option( 'onecom_local_promo', $local_promo, 'no' );
}
}
/*
* Show Admin notice
*/
public function duplicateWarning() {
$screen = get_current_screen();
$warn_screens = array(
'toplevel_page_onecom-vcache-plugin',
'one-com_page_onecom-vcache-plugin',
'plugins',
'options-general',
'dashboard',
);
if ( ! in_array( $screen->id, $warn_screens, true ) ) {
return;
}
$class = 'notice notice-warning is-dismissible';
$dect_link = add_query_arg(
array(
'disable-old-varnish' => 1,
'_wpnonce' => wp_create_nonce( 'disable-old-varnish' ),
)
);
$dect_link = wp_nonce_url( $dect_link, 'plugin-deactivation' );
$message = __( 'To get the best out of One.com Performance Cache, kindly deactivate the existing "Varnish Caching" plugin. ', 'vcaching' );
$message .= sprintf( "%s ", ( $dect_link ), __( 'Deactivate' ) );
printf( '
', esc_attr( $class ), $message );
}
/* Function to convert boolean to string
*
*
*/
private function booleanCast( $value ) {
if ( ! is_string( $value ) ) {
$value = ( 1 === $value || true === $value ) ? 'true' : 'false';
}
if ( '1' === $value ) {
$value = 'true';
}
if ( '0' === $value ) {
$value = 'false';
}
return $value;
}
/**
* Function to set default settings for one.com
*
**/
private function setDefaultSettings() {
// Enable by default
$enable = $this->booleanCast( self::DEFAULTENABLE );
$enabled = update_site_option( self::DEFAULTPREFIX . 'enable', $enable, 'no' );
$check = get_site_option( self::DEFAULTPREFIX . 'enable', $enable );
if ( ! ( 'true' === $check || true === $check || 1 === $check ) ) {
return;
}
// Update the cookie name
if (! get_site_option(self::DEFAULTPREFIX . 'cookie')) {
$name = bin2hex(random_bytes(16)); // changed from sha1(md5(uniqid())) to fix SAST
update_site_option(self::DEFAULTPREFIX . 'cookie', $name, 'no');
}
// Set default TTL
$ttl = self::DEFAULTTTL;
$ttl_unit = self::DEFAULTTTLUNIT;
if ( ! get_site_option( self::DEFAULTPREFIX . 'ttl' ) && ! is_bool( get_site_option( self::DEFAULTPREFIX . 'ttl' ) ) && get_site_option( self::DEFAULTPREFIX . 'ttl' ) !== 0 ) {
update_site_option( self::DEFAULTPREFIX . 'ttl', $ttl, 'no' );
update_site_option( self::DEFAULTPREFIX . 'ttl_unit', $ttl_unit, 'no' );
} elseif ( ! get_site_option( self::DEFAULTPREFIX . 'ttl' ) && is_bool( get_site_option( self::DEFAULTPREFIX . 'ttl' ) ) ) {
update_site_option( self::DEFAULTPREFIX . 'ttl', $ttl, 'no' );
update_site_option( self::DEFAULTPREFIX . 'ttl_unit', $ttl_unit, 'no' );
}
if ( ! get_site_option( self::DEFAULTPREFIX . 'homepage_ttl' ) && ! is_bool( get_site_option( self::DEFAULTPREFIX . 'homepage_ttl' ) ) && get_site_option( self::DEFAULTPREFIX . 'homepage_ttl' ) !== 0 ) {
update_site_option( self::DEFAULTPREFIX . 'homepage_ttl', $ttl, 'no' );
update_site_option( self::DEFAULTPREFIX . 'ttl_unit', $ttl_unit, 'no' );
} elseif ( ! get_site_option( self::DEFAULTPREFIX . 'homepage_ttl' ) && is_bool( get_site_option( self::DEFAULTPREFIX . 'homepage_ttl' ) ) ) {
update_site_option( self::DEFAULTPREFIX . 'homepage_ttl', $ttl, 'no' );
update_site_option( self::DEFAULTPREFIX . 'ttl_unit', $ttl_unit, 'no' );
}
// Set default varnish IP
$ip = getHostByName( getHostName() );
update_site_option( self::DEFAULTPREFIX . 'ips', $ip, 'no' );
if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
update_site_option( self::DEFAULTPREFIX . 'debug', true, 'no' );
}
// Deactivate the old varnish caching plugin on user's consent.
if ( isset( $_REQUEST['disable-old-varnish'] ) && 1 === $_REQUEST['disable-old-varnish'] ) {
deactivate_plugins( '/vcaching/vcaching.php' );
self::runAdminSettings();
add_action( 'admin_bar_menu', array( $this, 'remove_toolbar_node' ), 999 );
}
// Check and notify if varnish plugin already active.
if ( in_array( 'vcaching/vcaching.php', (array) get_site_option( 'active_plugins' ), true ) ) {
add_action( 'admin_notices', array( $this, 'duplicateWarning' ) );
}
}
/**
* Function to disable varnish plugin
**/
private function disableDefaultSettings( $on_deactivate = false ) {
self::purgeAll();
delete_option( self::DEFAULTPREFIX . 'ttl' );
delete_option( self::DEFAULTPREFIX . 'homepage_ttl' );
delete_option( self::DEFAULTPREFIX . 'ttl_unit' );
delete_option( 'onecom_vcache_info' );
}
/**
* Remove current menu item
*
*/
public function remove_parent_page() {
remove_menu_page( 'vcaching-plugin' );
}
/**
* Add menu item
*
*/
public function add_menu_item() {
if ( parent::check_if_purgeable() ) {
global $onecom_generic_menu_position;
$position = ( function_exists( 'onecom_get_free_menu_position' ) && ! empty( $onecom_generic_menu_position ) ) ? onecom_get_free_menu_position( $onecom_generic_menu_position ) : null;
add_menu_page( __( 'Performance Cache', 'vcaching' ), __( 'Performance Cache ', 'vcaching' ), 'manage_options', self::PLUGINNAME . '-plugin', array( $this, 'settings_page' ), 'dashicons-dashboard', $position );
}
}
/**
* Function to show settings page
*
*/
public static function cache_settings_page() {
require_once plugin_dir_path( __FILE__ ) . '/templates/cache-settings.php';
}
public static function cdn_settings_page() {
require_once plugin_dir_path( __FILE__ ) . '/templates/cdn-settings.php';
}
public static function wp_rocket_page() {
require_once plugin_dir_path( __FILE__ ) . '/templates/wp-rocket.php';
}
/**
* Function to customize options fields
*
*/
public function options_page_fields() {
add_settings_section( self::DEFAULTPREFIX . 'oc_options', null, null, self::DEFAULTPREFIX . 'oc_options' );
add_settings_field( self::DEFAULTPREFIX . 'ttl', __( 'Cache TTL', 'vcaching' ) . '' . __( 'The time that website data is stored in the Varnish cache. After the TTL expires the data will be updated, 0 means no caching.', 'vcaching' ) . ' ', array( $this, self::DEFAULTPREFIX . 'ttl_callback' ), self::DEFAULTPREFIX . 'oc_options', self::DEFAULTPREFIX . 'oc_options' );
if ( isset( $_POST['option_page'] ) && self::DEFAULTPREFIX . 'oc_options' === $_POST['option_page'] ) {
register_setting( self::DEFAULTPREFIX . 'oc_options', self::DEFAULTPREFIX . 'enable' );
register_setting( self::DEFAULTPREFIX . 'oc_options', self::DEFAULTPREFIX . 'ttl' );
$ttl = $_POST[ self::DEFAULTPREFIX . 'ttl' ];
$is_update = update_site_option( self::DEFAULTPREFIX . 'homepage_ttl', $ttl, 'no' ); //overriding homepage TTL
}
self::disablePromoNotice();
}
/**
* Function enqueue resources
*
*/
public function enqueue_resources( $hook ) {
$pages = array(
'toplevel_page_onecom-vcache-plugin',
'one-com_page_onecom-vcache-plugin',
'_page_onecom-vcache-plugin',
'one-com_page_onecom-cdn',
'_page_onecom-wp-rocket',
'one-com_page_onecom-wp-rocket'
);
if ( ! in_array( $hook, $pages, true ) ) {
return;
}
if ( SCRIPT_DEBUG || SCRIPT_DEBUG === 'true' ) {
$folder = '';
$extenstion = '';
} else {
$folder = 'min-';
$extenstion = '.min';
}
wp_register_style(
self::PLUGINNAME,
$this->oc_vc_uri . '/assets/' . $folder . 'css/style' . $extenstion . '.css',
null,
self::PLUGINVERSION,
'all'
);
wp_enqueue_style(
'onecss',
$this->oc_vc_uri . '/assets/min-css/one.min.css',
null,
self::PLUGINVERSION,
'all'
);
wp_register_script(
self::PLUGINNAME,
$this->oc_vc_uri . '/assets/' . $folder . 'js/scripts' . $extenstion . '.js',
array( 'jquery' ),
self::PLUGINVERSION,
'all'
);
wp_enqueue_style( self::PLUGINNAME );
wp_enqueue_script( self::PLUGINNAME );
if( 'toplevel_page_onecom-vcache-plugin' === $hook || 'one-com_page_onecom-vcache-plugin' === $hook) {
wp_enqueue_script(
'cache-admin-form',
plugins_url('/assets/js/blocks/oc-cache-settings.js', __FILE__),
['wp-element'],
self::PLUGINVERSION,
true
);
}
if( 'one-com_page_onecom-cdn' === $hook ) {
wp_enqueue_script(
'cdn-admin-form' ,
plugins_url( '/assets/js/blocks/oc-cdn-settings.js' , __FILE__ ) ,
[ 'wp-element' ] ,
self::PLUGINVERSION ,
true
);
}
$varnish_caching_ttl = get_site_option( 'varnish_caching_ttl' );
$varnish_caching_ttl_unit = get_site_option( 'varnish_caching_ttl_unit' );
$varnish_caching = get_site_option( 'varnish_caching_enable' );
if ( 'minutes' === $varnish_caching_ttl_unit ) {
$vc_ttl_as_unit = $varnish_caching_ttl / 60;
} elseif ( 'hours' === $varnish_caching_ttl_unit ) {
$vc_ttl_as_unit = $varnish_caching_ttl / 3600;
} elseif ( 'days' === $varnish_caching_ttl_unit ) {
$vc_ttl_as_unit = $varnish_caching_ttl / 86400;
} else {
$vc_ttl_as_unit = $varnish_caching_ttl;
}
wp_localize_script('cache-admin-form', 'vcacheSettings', [
'ajax_url' => admin_url('admin-ajax.php'),
'nonce' => wp_create_nonce('vcaching'),
'vc_ttl' => $vc_ttl_as_unit,
'vc_ttl_unit' => $varnish_caching_ttl_unit,
'vc_status' => $varnish_caching,
'cache_ttl' => __( 'Cache TTL' , 'vcaching' ),
'frequency_ttl' => __( 'Frequency' , 'vcaching' ),
'clearCacheMessage' => array(
'success' => __('Your cache was cleared.', 'vcaching'),
'failure' => __('Couldn’t clear your cache. Please try again and contact our support if the issue persists.', 'vcaching'),
),
'settingsSaveMessage' => array(
'success' => __('Your changes were saved.', 'vcaching'),
'failure' => __('Couldn’t save your changes. Please try again and contact our support if the issue persists.', 'vcaching'),
),
'ttlValidationMsg' => __('TTL value must be at least 1 second.','vcaching'),
'frequency_options' => [
'seconds' => __('Seconds', 'vcaching'),
'minutes' => __('Minutes', 'vcaching'),
'hours' => __('Hours', 'vcaching'),
'days' => __('Days', 'vcaching'),
],
'LblActive' => __('Active', 'vcaching'),
'LblInactive' => __('Inactive', 'vcaching'),
'TooltipMessage' => __('The time your website data will be stored in the Varnish cache. Our default value is 30 days. When the TTL expires, the cached content will be refreshed.', 'vcaching'),
'Ttlplaceholder' =>__('Enter Cache TTL','vcaching'),
'ClearCache' =>__('Clear Cache now','vcaching'),
'clearingCache' =>__('Clearing cache','vcaching'),
'labelSave' => __('Save', 'vcaching'),
'labelSaving' => __('Saving', 'vcaching'),
'imageDIR' => $this->onecom_vcache_dir_url,
]);
$cdn_enabled = get_site_option( 'oc_cdn_enabled' );
$dev_mode_duration = parent::oc_json_get_option( 'onecom_vcache_info', 'dev_mode_duration' );
$oc_dev_mode_status = parent::oc_json_get_option( 'onecom_vcache_info', 'oc_dev_mode_enabled' );
$oc_exclude_cdn_data = parent::oc_json_get_option( 'onecom_vcache_info', 'oc_exclude_cdn_data' );
$oc_exclude_cdn_status = parent::oc_json_get_option( 'onecom_vcache_info', 'oc_exclude_cdn_enabled' );
wp_localize_script('cdn-admin-form', 'CdnSettings', [
'ajax_url' => admin_url('admin-ajax.php'),
'nonce' => wp_create_nonce('vcaching'),
'clearCacheMessage' => array(
'success' => __('Your CDN cache was cleared.', 'vcaching'),
'failure' => __('Couldn’t clear your CDN cache. Please try again and contact our support if the issue persists.', 'vcaching'),
),
'settingsSaveMessage' => array(
'success' => __('Your changes were saved.', 'vcaching'),
'failure' => __('Couldn’t save your changes. Please try again and contact our support if the issue persists.', 'vcaching'),
),
'CdnStatus' => $cdn_enabled,
'devModeDuration' => $dev_mode_duration,
'devModeStatus' => $oc_dev_mode_status,
'excludeCdnData' => $oc_exclude_cdn_data,
'excludeCdnStatus' => $oc_exclude_cdn_status,
'lblActive' => __('Active', 'vcaching'),
'lblInactive' => __('Inactive', 'vcaching'),
'excludeTitle' => __('Exclude items from CDN' , 'vcaching'),
'excludeDescription' => __('Enter file names (myfile.jpg), file extensions (.jpg) or paths (wp-content/uploads/2025/file.jpg) that shouldn’t be delivered through CDN. Enter one item per line.' , 'vcaching'),
'excludeValidationMsg' => __('Enter what you want to exclude.' , 'vcaching'),
'excludeCdnMsg' => __('Enter one item per line' , 'vcaching'),
'CdnTitle' => __('CDN settings' , 'vcaching'),
'clearCache' => __('Clear CDN cache' , 'vcaching'),
'clearingCache' => __('Clearing CDN cache' , 'vcaching'),
'excludeValidationMsg' => __('Enter what you want to exclude.' , 'vcaching'),
'devModeTitle' => __('Activate development mode', 'vcaching'),
'devModeDescription' => __('Specify when development mode should get deactivated again (hours). Note that CDN is inactive for logged-in users while development mode is active.', 'vcaching'),
'mwpDisabledHeading' => __('This is a Managed WP feature', 'vcaching'),
'mwpDisabledMessage' => __('Upgrade now to get access to development mode and exclude CDN feature.', 'vcaching'),
'isMWP' => $this->oc_premium(),
'labelSave' => __('Save', 'vcaching'),
'labelSaving' => __('Saving', 'vcaching'),
'labelExclude' => __('Items to exclude', 'vcaching'),
'upgradeBtn' => __('Upgrade now', 'vcaching'),
'imageDIR' => $this->onecom_vcache_dir_url,
]);
}
/* Function to enqueue style tag in admin head
* */
public function onecom_vcache_icon_css() {
echo "";
return;
}
/* Function to show inline promo on premium cdn switches */
public function mwp_promo($cuJourneyEvent = '') {
ob_start(); ?>
$_SERVER['SERVER_NAME'],
'X-VC-Purge-Method' => $purgemethod,
'X-VC-Purge-Host' => $_SERVER['SERVER_NAME'],
);
$response = wp_remote_request(
$purgeme,
array(
'method' => 'PURGE',
'headers' => $headers,
'sslverify' => false,
)
);
if ( $response instanceof WP_Error ) {
error_log( 'Cannot purge: ' . $purgeme );
}
}
/**
* Function to change purge settings
*
*/
public function filter_purge_settings() {
add_filter( 'ocvc_purge_notices', array( $this, 'ocvc_purge_notices_callback' ), 10, 2 );
add_filter( 'ocvc_purge_url', array( $this, 'ocvc_purge_url_callback' ), 1, 3 );
add_filter( 'ocvc_purge_headers', array( $this, 'ocvc_purge_headers_callback' ), 1, 2 );
add_filter( 'ocvc_permalink_notice', array( $this, 'ocvc_permalink_notice_callback' ) );
add_filter( 'vcaching_purge_urls', array( $this, 'vcaching_purge_urls_callback' ), 10, 2 );
add_action( 'admin_notices', array( $this, 'oc_vc_notice' ) );
add_action( 'network_admin_notices', array( $this, 'oc_vc_notice' ) );
}
/**
* Function to filter the purge request response
*
* @param object $response //request response object
* @param string $url // url trying to purge
*/
public function ocvc_purge_notices_callback( $response, $url ) {
$response = wp_remote_retrieve_body( $response );
$find = array(
/* translators: %s is the URL of the resource being purged */
'404 Key not found' => sprintf( __( 'It seems that %s is already purged. There is no resource in the cache to purge.', 'vcaching' ), $url ),
/* translators: %s is the URL of the resource that was purged */
'Error 200 Purged' => sprintf( __( '%s is purged successfully.', 'vcaching' ), $url ),
);
foreach ( $find as $key => $message ) {
if ( strpos( $response, $key ) !== false ) {
array_push( $this->messages, $message );
}
}
}
/**
* Function to add notice
*
*/
public function oc_vc_notice() {
if ( empty( $this->messages ) && empty( $_SESSION['ocvcaching_purge_note'] ) ) {
return;
}
?>
messages ) ) {
foreach ( $this->messages as $key => $message ) {
if ( $key > 0 ) {
break;
}
?>
$message ) {
if ( $key > 0 ) {
break;
}
?>
Permalinks Options Page to configure them.', 'vcaching' );
return '';
}
/**
* Function to to remove menu item from admin menu bar
*
*/
public function remove_toolbar_node( $wp_admin_bar ) {
// replace 'updraft_admin_node' with your node id
$wp_admin_bar->remove_node( 'purge-all-varnish-cache' );
}
/**
* Function to to remove purge cache from post
*
*/
public function remove_post_row_actions( $actions, $post ) {
if ( isset( $actions['vcaching_purge_post'] ) ) {
unset( $actions['vcaching_purge_post'] );
}
return $actions;
}
/**
* Function to to remove purge cache from page
*
*/
public function remove_page_row_actions( $actions, $post ) {
if ( isset( $actions['vcaching_purge_page'] ) ) {
unset( $actions['vcaching_purge_page'] );
}
return $actions;
}
/**
* Function to set purge single post/page URL
*
* @param array $array_urls // array of urls
* @param number $post_id //POST ID
*/
public function vcaching_purge_urls_callback( $array_urls, $post_id ) {
$url = get_permalink( $post_id );
array_unshift( $array_urls, $url );
return $array_urls;
}
/**
* Function vcaching_events_cb
* Callback function for vcaching_events WP filter
* This function checks if the registered events are to be returned, judging from request payload.
* e.g. the events are nulled for request actions like "heartbeat" and "ocdi_import_demo_data"
* @param $events, an array of events on which caching is hooked.
* @return array
*/
public function vcaching_events_cb( $events ) {
$no_post_action = ! isset( $_REQUEST['action'] );
$action_not_watched = isset( $_REQUEST['action'] ) && ( 'ocdi_import_demo_data' === $_REQUEST['action'] || 'heartbeat' === $_REQUEST['action'] );
if ( $no_post_action || $action_not_watched ) {
return array();
} else {
return $events;
}
}
/**
* Function vcaching_purge_urls_cb
* Callback function for vcaching_purge_urls WP filters
* This function removes all the urls that are to be purged and returns single url that purges entire cache.
* @param $urls, an array of urls that were originally to be purged.
* @return array
*/
public function vcaching_purge_urls_cb( $urls ) {
$site_url = trailingslashit( get_site_url() );
$purge_url = $site_url . '.*';
$urls = array( $purge_url );
return $urls;
}
/**
* Function vcaching_reset_dev_mode
* This function deletes/reset development mode data on admin init
* ** if development mode expire time passed
*/
public function vcaching_reset_dev_mode() {
$cdn_dev_enabled = $this->oc_json_get_option( 'onecom_vcache_info', 'oc_dev_mode_enabled' );
$dev_expire_time = $this->oc_json_get_option( 'onecom_vcache_info', 'dev_expire_time' );
if ( 'true' === $cdn_dev_enabled && 'false' !== $dev_expire_time && $dev_expire_time < time() ) {
// if development mode exists and expired, reset it
$this->oc_json_delete_option( 'onecom_vcache_info', 'oc_dev_mode_enabled' );
$this->oc_json_delete_option( 'onecom_vcache_info', 'dev_expire_time' );
$this->oc_json_delete_option( 'onecom_vcache_info', 'dev_mode_duration' );
return true;
} else {
return false;
}
}
/**
* Function oc_set_vc_state_cb()
* Enable/disable vcaching. Used as AJAX callback
* @since v0.1.24
* @param null
* @return null
*/
public function oc_set_vc_state_cb() {
if ( ! isset( $_POST['oc_csrf'] ) && ! wp_verify_nonce( 'one_vcache_nonce' ) ) {
return false;
}
$state = intval( $_POST['vc_state'] ) === 0 ? 'false' : 'true';
// check eligibility if Performance Cache is being enabled. If it is being disabled, allow to continue
if ( 'true' === $state ) {
$event_action = 'enable';
$res = $this->oc_check_pc_activation( $state );
if ( 'success' !== $res['status'] ) {
wp_send_json( $res );
return false;
}
} else {
$event_action = 'disable';
}
if ( get_site_option( self::DEFAULTPREFIX . 'enable' ) === $state ) {
$result_status = true;
} else {
$result_status = update_site_option( self::DEFAULTPREFIX . 'enable', $state, 'no' );
}
$result_ttl = $this->oc_set_vc_ttl_cb( false );
$response = array();
if ( $result_ttl && $result_status ) {
$response = array(
'status' => 'success',
'message' => __( 'Performance cache settings updated' ),
);
( class_exists( 'OCPushStats' ) ? \OCPushStats::push_stats_performance_cache( "$event_action", 'setting', 'cache', 'performance_cache' ) : '' );
} else {
$response = array(
'status' => 'error',
'message' => __( 'Something went wrong!' ),
);
}
wp_send_json( $response );
}
public function oc_set_vc_ttl_cb( $echo_oc ) {
if ( wp_doing_ajax() && ! isset( $_POST['oc_csrf'] ) && ! wp_verify_nonce( 'one_vcache_nonce' ) ) {
return false;
}
if ( '' === $echo_oc ) {
$echo_oc = true;
}
$ttl_value = intval( trim( $_POST['vc_ttl'] ) );
$ttl = 0 === $ttl_value ? 2592000 : $ttl_value;
$ttl_unit = trim( $_POST['vc_ttl_unit'] );
$ttl_unit = empty( $ttl_unit ) ? 'days' : $ttl_unit;
// Convert into seconds except default value
if ( 2592000 !== $ttl && 'minutes' === $ttl_unit ) {
$ttl = $ttl * 60;
} elseif ( 2592000 !== $ttl && 'hours' === $ttl_unit ) {
$ttl = $ttl * 3600;
} elseif ( 2592000 !== $ttl && 'days' === $ttl_unit ) {
$ttl = $ttl * 86400;
}
if ( ( get_site_option( 'varnish_caching_ttl' ) === (string)$ttl ) && ( get_site_option( 'varnish_caching_homepage_ttl' ) === (string)$ttl ) && ( get_site_option( 'varnish_caching_ttl_unit' ) === (string)$ttl_unit ) ) {
$result = true;
} else {
$result = update_site_option( 'varnish_caching_ttl', $ttl, 'no' );
update_site_option( 'varnish_caching_homepage_ttl', $ttl, 'no' );
update_site_option( 'varnish_caching_ttl_unit', $ttl_unit, 'no' );
( class_exists( 'OCPushStats' ) ? \OCPushStats::push_stats_performance_cache( 'update', 'setting', 'ttl', 'performance_cache' ) : '' );
}
$response = array();
if ( $result ) {
$response = array(
'status' => 'success',
'message' => __( 'TTL updated' ),
);
} else {
$response = array(
'status' => 'error',
'message' => __( 'Something went wrong!' ),
);
}
if ( $echo_oc ) {
wp_send_json( $response );
} else {
return $result;
}
}
/**
* Activate a plugin
*/
public function oc_activate_wp_rocket() {
$activation_status = is_null( activate_plugin( self::WP_ROCKET_PATH ) );
wp_send_json( array( 'status' => $activation_status ) );
}
/**
* 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->oc_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', 'vcaching');
$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();
}
}
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 oc_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.', 'vcaching' ),
'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.', 'vcaching' ),
);
}
public function get_cu_country_code(){
$default = 'US';
$status = $this->oc_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';
}
/**
* Section 3: Pricing + Features
* @return void
*/
public function wp_rocket_pricing_table() {
$wpr_features = [
__('Page and browser caching', 'vcaching'),
__('GZIP compression', 'vcaching'),
__('Cross-Origin support for web fonts', 'vcaching'),
__('Detection and support of various third-party plugins, themes', 'vcaching'),
__('Combination of inline and 3rd party scripts', 'vcaching'),
__('WooCommerce Refresh Cart Fragments Cache', 'vcaching'),
__('Optimise Google Fonts files', 'vcaching'),
__('Optimise database and emojis', 'vcaching'),
];
//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'] : '';
?>
$domain";
echo sprintf(
__("You have a WP Rocket subscription for %s, but you still need to activate it for this installation. Activate the plugin to boost your site's performance.", 'vcaching'), $value);
?>
oc_json_get_option( 'onecom_vcache_info', 'oc_dev_mode_enabled' );
$dev_expire_time = $this->oc_json_get_option( 'onecom_vcache_info', 'dev_expire_time' );
// If development mode is not expired, skip CDN rewrite
if ( 'true' === $cdn_dev_enabled && $dev_expire_time > time() && current_user_can( 'administrator' ) ) {
return null;
} elseif ( 'true' === $cdn_dev_enabled && 'false' !== $dev_expire_time && $dev_expire_time < time() ) {
// if development mode exists but expired, reset it
$this->oc_json_delete_option( 'onecom_vcache_info', 'oc_dev_mode_enabled' );
$this->oc_json_delete_option( 'onecom_vcache_info', 'dev_expire_time' );
$this->oc_json_delete_option( 'onecom_vcache_info', 'dev_mode_duration' );
}
ob_start( array( $this, 'rewrite' ) );
}
/**
* Function rewrite
* Rewrite assets url, replace native ones with the CDN version if the url meets rewrite conditions.
* @since v0.1.24
* @param array $html, the html source of the page, provided by ob_start
* @return string modified html source
*/
public function rewrite( $html ) {
$url = get_option( 'home' );
if ( is_multisite() ) {
$protocols = array( self::HTTPS, self::HTTP );
} else {
$protocols = array( self::HTTPS, self::HTTP, '/' );
}
$domain_name = str_replace( $protocols, '', $url );
$directories = 'wp-content';
if ( is_multisite() ) {
$pattern = "#(?:https://{$domain_name}/{$directories})(\S*\.[0-9a-z]+)\b#m";
} else {
$pattern = "/(?:https:\/\/$domain_name\/$directories)(\S*\.[0-9a-z]+)\b/m";
}
//Take backup of script schema if class name found in script tag.
$result = $this->backupScriptSchemas($html, ['rank-math-schema-pro' ,'rank-math-schema', 'yoast-schema-graph']);
$updated_html = preg_replace_callback( $pattern, array( $this, 'rewrite_asset_url' ), $result['html'] );
//Rollback of script schema if class name found in script tag.
return $this->restoreScriptSchemas($updated_html, $result['backups']);
}
/**
* Extracts