config = WP_Optimize()->get_page_cache()->config->get(); add_action('woocommerce_init', array($this, 'maybe_set_tax_country_cookie'), 40); add_action('wpo_page_cache_settings_after', array($this, 'add_woocommerce_template_to_cache_settings'), 20, 1); add_filter('wpo_cache_update_config', array($this, 'add_default_values_to_cache_config'), 20); add_filter('wpo_cache_cookies', array($this, 'add_cache_cookies'), 20, 2); add_filter('wpo_cache_query_variables', array($this, 'add_cache_query_variables'), 20, 2); add_filter('display_post_states', array($this, 'add_post_state'), 30, 2); add_action('add_meta_boxes', array($this, 'add_cache_control_metabox')); add_action('admin_enqueue_scripts', array($this, 'enqueue_scripts_styles')); add_action('wpo_premium_scripts_styles', array($this, 'wpo_page_only_scripts'), 20, 3); add_action('wpo_after_cache_exception_urls', array($this, 'output_excluded_posts')); add_action('wpo_after_cache_exception_urls_fieldgroup', array($this, 'output_always_purge_posts')); add_action('save_post', array($this, 'always_purge_post_on_update'), 10, 1); add_action('add_attachment', array($this, 'always_purge_post_on_update'), 10, 1); add_action('edit_attachment', array($this, 'always_purge_post_on_update'), 10, 1); add_action('delete_attachment', array($this, 'always_purge_post_on_update'), 10, 1); // Cloudflare initialisation. include_once(WPO_PLUGIN_MAIN_PATH.'cache/class-wp-optimize-cloudflare-api.php'); include_once(WPO_PLUGIN_MAIN_PATH.'cache/class-wp-optimize-cloudflare.php'); new WP_Optimize_Cloudflare($this->config); // Add action for disable caching for selected posts. add_action('wp', array($this, 'disable_posts_caching')); // Add user per role cache option add_action('wpo_after_cache_settings', array($this, 'output_user_per_role_cache_option'), 9); // Add user specific cache option add_action('wpo_after_cache_settings', array($this, 'output_user_specific_cache_option'), 10); WPO_Cache_Preloader_Premium::get_instance(); WPO_Cache_Purge_Premium::get_instance(); } /** * Default options values. */ public function get_defaults($defaults) { $defaults['enable_per_role_cache'] = false; $defaults['enable_user_specific_cache'] = false; return $defaults; } /** * Disable caching for posts those have _wpo_disable_caching meta field. */ public function disable_posts_caching() { global $post; if (!defined('DONOTCACHEPAGE') && $post && get_post_meta($post->ID, '_wpo_disable_caching') && (is_page() || is_single())) { define('DONOTCACHEPAGE', true); } } /** * Output excluded posts list. */ public function output_excluded_posts() { $wpo_cache_excluded_posts = $this->get_excluded_posts(); WP_Optimize()->include_template('cache/page-cache-excluded-posts.php', false, array( 'wpo_cache_excluded_posts' => $wpo_cache_excluded_posts, )); } /** * Output always purge posts section. */ public function output_always_purge_posts() { $always_purge_post_type = isset($this->config['always_purge_post_type']) ? $this->config['always_purge_post_type'] : array(); $always_purge_post_id = isset($this->config['always_purge_post_id']) ? $this->config['always_purge_post_id'] : array(); $post_types = $this->get_post_types(); $always_purge_post_type_str = array(); foreach ($always_purge_post_type as $i => $post_type) { $post_types_arr = explode(',', $post_type); $post_types_str = ''; foreach ($post_types_arr as $single_pt) { $single_pt = trim($single_pt); $post_types_str .= ('' != $post_types_str) ? ', ' : ''; $post_types_str .= isset($post_types[$single_pt]) ? $post_types[$single_pt] : $single_pt; } $always_purge_post_type_str[$i] = $post_types_str; } WP_Optimize()->include_template('cache/page-cache-always-purge-posts.php', false, array( 'always_purge_post_type' => $always_purge_post_type, 'always_purge_post_type_str' => $always_purge_post_type_str, 'always_purge_post_id' => $always_purge_post_id, 'post_types' => $post_types, )); } /** * Get list name => label with available public post types. */ private function get_post_types() { $result = array(); $post_types = get_post_types(array('public' => true), 'objects'); foreach ($post_types as $post_type_obj) { $result[$post_type_obj->name] = $post_type_obj->labels->singular_name; } return $result; } /** * Get array with "always purge this page" settings. * * @return array */ public function get_always_purge_config() { $always_purge_post_type = isset($this->config['always_purge_post_type']) ? $this->config['always_purge_post_type'] : array(); $always_purge_post_id = isset($this->config['always_purge_post_id']) ? $this->config['always_purge_post_id'] : array(); $result = array(); foreach ($always_purge_post_type as $i => $post_type) { $result[] = array( 'post_id' => $always_purge_post_id[$i], 'post_type' => $post_type, ); } return $result; } /** * Get always purge settings for selected post. * * @param int $post_id * * @return array */ public function get_always_purge_post_config($post_id) { $always_purge_config = $this->get_always_purge_config(); $post_type = array(); foreach ($always_purge_config as $item) { if ($post_id != $item['post_id']) continue; $post_type = array_merge($post_type, explode(',', $item['post_type'])); } return $post_type; } /** * Handle post update and purge pages configured in "always purge this page" settings. */ public function always_purge_post_on_update($post_id) { $post_type = get_post_type($post_id); $post_type_object = get_post_type_object($post_type); if ((defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) || 'revision' === $post_type || !$post_type_object->public) { return; } $always_purge_config = $this->get_always_purge_config(); foreach ($always_purge_config as $item) { $post_types = explode(',', $item['post_type']); if (in_array($post_type, $post_types)) { WPO_Page_Cache::delete_single_post_cache($item['post_id']); } } } /** * Enqueue scripts and styles for premium cache features. */ public function enqueue_scripts_styles() { $current_screen = get_current_screen(); if (null === $current_screen) return; $enqueue_version = WP_Optimize()->get_enqueue_version(); $min_or_not = WP_Optimize()->get_min_or_not_string(); $min_or_not_internal = WP_Optimize()->get_min_or_not_internal_string(); // Only enqueue If the screen is the post edit page if ('post' == $current_screen->base) { if (!wp_script_is('select2')) { wp_enqueue_script('select2', WPO_PLUGIN_URL . 'js/select2/select2' . $min_or_not . '.js', array('jquery'), $enqueue_version); } if (!wp_style_is('select2')) { wp_enqueue_style('select2', WPO_PLUGIN_URL . 'css/select2/select2' . $min_or_not . '.css', array(), $enqueue_version); } wp_enqueue_script('wp-optimize-cache-premium-admin', WPO_PLUGIN_URL . 'js/wpo-cache-premium-edit-post' . $min_or_not_internal . '.js', array('wp-optimize-send-command', 'select2'), $enqueue_version); } if ('edit' === $current_screen->base) { wp_enqueue_script('wp-optimize-cache-premium-admin-preload-purge', WPO_PLUGIN_URL . 'js/wpo-cache-premium-preload-purge' . $min_or_not_internal . '.js', array('jquery', 'block-ui-js', 'wp-optimize-send-command'), $enqueue_version); wp_localize_script('wp-optimize-cache-premium-admin-preload-purge', 'wp_optimize_admin', array( 'purge' => __('Purge cache', 'wp-optimize'), 'preload' => __('Preload cache', 'wp-optimize'), )); } } /** * Adds scripts to WP-Optimize's dashboard only * * @param string $min_or_not_internal - The .min-version-number suffix to use on internal assets * @param string $min_or_not - The .min suffix to use on third party assets * @param string $enqueue_version - The enqueued version * @return void */ public function wpo_page_only_scripts($min_or_not_internal, $min_or_not, $enqueue_version) { wp_enqueue_script('wp-optimize-cache-premium', WPO_PLUGIN_URL . 'js/wpo-cache-premium' . $min_or_not_internal . '.js', array('wp-optimize-send-command'), $enqueue_version); } /** * Add default values to use in cache extensions - filters the WPO config when updating it * * @param array $config - The original config array * @return array */ public function add_default_values_to_cache_config($config) { if (!isset($config['default_values'])) { $config['default_values'] = array(); } // Add WooCommerce's default currency if (function_exists('get_woocommerce_currency')) { /** * Filters wether or not to add WooCommerce default currency to the cache config. */ if (apply_filters('wpo_add_woocommerce_default_currency_to_cache_config', true)) { // Save the default WC currency in our config. // Note: We use get_option('woocommerce_currency') as get_woocommerce_currency() is overridden by the currency selector plugin. $config['default_values']['woocommerce_currency'] = get_option('woocommerce_currency'); } } // Set default woocommerce values if (defined('WC_ABSPATH') && function_exists('WC')) { $config['default_values']['WC_ABSPATH'] = wp_normalize_path(WC_ABSPATH); // If cache per country is enabled if (isset($config['enable_cache_per_country']) && $config['enable_cache_per_country']) { $wc_get_base_location = wc_get_base_location(); $config['default_values']['wc_default_country'] = $wc_get_base_location['country']; // Get Geolite database path if (version_compare(WC()->version, '3.9.0', '>=')) { $integrations = WC()->integrations; if (is_callable(array($integrations, 'get_integration'))) { $integration = $integrations->get_integration('maxmind_geolocation'); if (is_callable(array($integration, 'get_database_service'))) { $database = $integration->get_database_service()->get_database_path(); } } } elseif (is_callable(array('WC_Geolocation', 'get_local_database_path'))) { $database = WC_Geolocation::get_local_database_path(); } // We need the database, WooCommerce 3.4+ and PHP 5.4+ to use Geolite2 $config['default_values']['wc_geolocate'] = isset($database) && file_exists($database) && version_compare(WC()->version, '3.4.0', '>=') && version_compare(PHP_VERSION, '5.4.0', '>='); if (isset($database) && file_exists($database)) { $config['default_values']['wc_geolocate_database'] = wp_normalize_path($database); } } } return $config; } /** * Filter COOKIE variable names used for building cache file name. * * @param array $cookies - The array of cookies * @param array $config - The cache configuration * * @return array */ public function add_cache_cookies($cookies, $config) { // Aelia currency switcher if (class_exists('WC_Aelia_CurrencySwitcher')) { $aelia_cookies = array( 'aelia_cs_selected_currency', 'aelia_customer_country', 'aelia_customer_state', 'aelia_tax_exempt', ); $cookies = array_merge($cookies, $aelia_cookies); } if (isset($config['enable_cache_per_country']) && $config['enable_cache_per_country']) { $cookies[] = 'woocommerce_tax_country'; } return array_merge($cookies, $this->get_curcy_cookies()); } /** * Filter GET query variable names used for building cache file name. * * @param array $variables - The array of query variables * @param array $config - The cache configuration * * @return array */ public function add_cache_query_variables($variables, $config) { // WPML multi currency plugin. if (defined('WCML_VERSION')) { $variables[] = 'wcmlc'; } // check if active WPML plugin. if (defined('ICL_SITEPRESS_VERSION')) { $variables[] = 'lang'; } // Aelia Currency switcher if (class_exists('WC_Aelia_CurrencySwitcher')) { $variables[] = 'aelia_cs_currency'; } // WooCommerce geolocation - Selecting 'geolocation_ajax' in WC will add v=location-key to every request. if ('geolocation_ajax' === get_option('woocommerce_default_customer_address') && isset($config['enable_cache_per_country']) && $config['enable_cache_per_country']) { $variables[] = 'v'; } if (class_exists('WOOMULTI_CURRENCY_F')) { $variables[] = 'wmc-currency'; } return $variables; } /** * Include the extra template * * @param array $wpo_cache_options - The main page cache options * @return void */ public function add_woocommerce_template_to_cache_settings($wpo_cache_options) { // Load this if WooCommerce is loaded if (!apply_filters('wpo_add_woocommerce_template_to_cache_settings', function_exists('WC'))) return; WP_Optimize()->include_template('cache/page-cache-woocommerce.php', false, array('wpo_cache_options' => $wpo_cache_options)); } /** * Maybe sets a cookie with the user's tax country * * @return void */ public function maybe_set_tax_country_cookie() { if ((defined('DOING_CRON') && DOING_CRON) || (is_admin() && (!defined('DOING_AJAX') || !DOING_AJAX)) || (defined('XMLRPC_REQUEST') && XMLRPC_REQUEST) ) return; if (!isset($this->config['enable_cache_per_country']) || !$this->config['enable_cache_per_country']) return; // Override current value when a known $_REQUEST changes it in WC if (isset($_POST['billing_country'])) { // Value from WooCommerce form setcookie('woocommerce_tax_country', $_POST['billing_country'], (time() + 30 * 86400), '/'); $_COOKIE['woocommerce_tax_country'] = $_POST['billing_country']; return; } elseif (isset($_REQUEST['wc_country_preselect'])) { // Value from VAT compliance form setcookie('woocommerce_tax_country', $_REQUEST['wc_country_preselect'], (time() + 30 * 86400), '/'); $_COOKIE['woocommerce_tax_country'] = $_REQUEST['wc_country_preselect']; return; } $country = isset(WC()->customer) ? WC()->customer->get_billing_country() : ''; if (!$country) return; // By default, set the country to WC()->customer->get_billing_country(), and override it if it was set to something else. if (!isset($_COOKIE['woocommerce_tax_country'])) { // $country if cookie was empty setcookie('woocommerce_tax_country', $country, (time() + 30 * 86400), '/'); $_COOKIE['woocommerce_tax_country'] = $country; } elseif ($_COOKIE['woocommerce_tax_country'] != $country) { // Use $country if cookie was different than $country. setcookie('woocommerce_tax_country', $country, (time() + 30 * 86400), '/'); $_COOKIE['woocommerce_tax_country'] = $country; } } /** * Show the cache status in a "post state" in the Posts list table. * * @param array $post_states * @param object $post * @return array */ public function add_post_state($post_states, $post) { $do_not_cache = get_post_meta($post->ID, '_wpo_disable_caching', true); if ($do_not_cache) $post_states['wpo-do-not-cache-state'] = __('Excluded from caching', 'wp-optimize'); return $post_states; } /** * Add metaboxes for disable cache functionality on single post screen. */ public function add_cache_control_metabox() { add_meta_box('wpo-cache-metabox', ''.__('Page caching', 'wp-optimize').'', array($this, 'render_cache_control_metabox'), get_post_types(array('public' => true)), 'side'); } /** * Output metabox for disable cache functionality. * * @param WP_Post $post - post object that the current editing page is for */ public function render_cache_control_metabox($post) { $post_id = $post->ID; $meta_key = '_wpo_disable_caching'; $disable_caching = get_post_meta($post_id, $meta_key, true); $post_type_obj = get_post_type_object(get_post_type($post_id)); $extract = array( 'disable_caching' => $disable_caching, 'post_id' => $post_id, 'post_type' => strtolower($post_type_obj->labels->singular_name), 'post_types' => $this->get_post_types(), 'always_purge_post_type' => $this->get_always_purge_post_config($post_id), ); WP_Optimize()->include_template('cache/admin-metabox-cache-control.php', false, $extract); } /** * Get list of excluded posts from cache. * * @return array */ public function get_excluded_posts() { global $wpdb; $excluded_posts = $wpdb->get_results("SELECT p.ID, p.post_title, p.post_type FROM {$wpdb->postmeta} pm JOIN {$wpdb->posts} p ON pm.post_id = p.ID WHERE pm.meta_key = '_wpo_disable_caching' AND p.post_status = 'publish' ORDER BY p.post_title;", ARRAY_A); return $excluded_posts; } /** * Output user specific cache option. */ public function output_user_specific_cache_option() { global $is_nginx; $extract = array( 'wpo_cache_options' => $this->config, 'is_nginx' => $is_nginx, 'path_to_cache' => defined('WPO_CACHE_DIR') ? str_replace(ABSPATH, '/', WPO_CACHE_DIR) : '/path/to/cache', ); WP_Optimize()->include_template('cache/page-cache-user-specific-cache.php', false, $extract); } /** * Output cache per role option. */ public function output_user_per_role_cache_option() { if (!function_exists('get_editable_roles')) { include_once ABSPATH . 'wp-admin/includes/user.php'; } $user_roles = array(); $wp_roles = get_editable_roles(); foreach ($wp_roles as $role => $info) { $user_roles[] = array( 'role' => $role, 'label' => translate_user_role($info['name']), ); } $extract = array( 'user_roles' => $user_roles, 'wpo_cache_options' => $this->config, ); WP_Optimize()->include_template('cache/page-cache-per-role-cache.php', false, $extract); } /** * Curcy cookies */ private function get_curcy_cookies() { $cookies = array(); if (!class_exists('WOOMULTI_CURRENCY_F') || !class_exists('WOOMULTI_CURRENCY_F_Data')) return $cookies; if (!is_callable(array('WOOMULTI_CURRENCY_F_Data', 'get_ins'))) { error_log('WP-Optimize: Cache - WOOMULTI_CURRENCY_F_Data::get_ins() method not found'); return $cookies; } else { $curcy_settings = WOOMULTI_CURRENCY_F_Data::get_ins(); if (!is_callable(array($curcy_settings, 'get_params'))) { error_log('WP-Optimize: Cache - WOOMULTI_CURRENCY_F_Data::get_params() method not found'); return $cookies; } else { if ($curcy_settings->get_params('use_session')) return $cookies; $cookies[] = 'wmc_current_currency'; $cookies[] = 'wmc_current_currency_old'; if (!is_callable(array($curcy_settings, 'get_auto_detect'))) { error_log('WP-Optimize: Cache - WOOMULTI_CURRENCY_F_Data::get_auto_detect() method not found'); return $cookies; } else { $auto_detect = $curcy_settings->get_auto_detect(); if (1 === $auto_detect || 2 === $auto_detect) { $cookies[] = 'wmc_ip_info'; if (!is_callable(array($curcy_settings, 'get_geo_api'))) { error_log('WP-Optimize: Cache - WOOMULTI_CURRENCY_F_Data::get_geo_api() method not found'); return $cookies; } else { if (2 !== $curcy_settings->get_geo_api()) { $cookies[] = 'wmc_ip_add'; } } } } } } return $cookies; } } endif;