blog_id ); // add backend requirements, triggering the settings file to be created self::update_backend(); // restore current blog from before new site restore_current_blog(); } /** * add or update backend requirements * * @return $new_option_value new or current database option value */ public static function update_backend() { // delete user(s) meta key from deleted publishing action (1.5.0) delete_metadata( 'user', 0, '_clear_post_cache_on_update', '', true ); // maybe rename old database option (1.5.0) $old_option_value = get_option( 'a2opt-cache' ); if ( $old_option_value !== false ) { delete_option( 'a2opt-cache' ); add_option( 'a2opt-cache', $old_option_value ); } // get defined settings, fall back to empty array if not found $old_option_value = get_option( 'a2opt-cache', [] ); // update default system settings $old_option_value = wp_parse_args( self::get_default_settings( 'system' ), $old_option_value ); // merge defined settings into default settings $new_option_value = wp_parse_args( $old_option_value, self::get_default_settings() ); // add or update database option update_option( 'a2opt-cache', $new_option_value ); // create settings file if action has not been registered for hook yet, like when in activation hook if ( has_action( 'update_option_a2opt_cache', [ __CLASS__, 'on_update_backend' ] ) === false ) { A2_Optimized_Cache_Disk::create_settings_file( $new_option_value ); } return $new_option_value; } /** * add or update database option hook * * @param mixed $option old database option value or name of the option to add * @param mixed $new_option_value new database option value */ public static function on_update_backend($option, $new_option_value) { A2_Optimized_Cache_Disk::create_settings_file( $new_option_value ); } /** * uninstall on deleted site in multisite network * * @param WP_Site $old_site old site instance */ public static function uninstall_later($old_site) { $delete_cache_size_transient = false; // clean system files A2_Optimized_Cache_Disk::clean(); // clear site cache of deleted site self::clear_site_cache_by_blog_id( (int) $old_site->blog_id, $delete_cache_size_transient ); } /** * uninstall backend requirements * */ private static function uninstall_backend() { // delete database option delete_option( 'a2opt-cache' ); } /** * enter each site * * @param boolean $network whether or not each site in network * @param string $callback callback function * @param array $callback_params callback function parameters * @return array $callback_return returned value(s) from callback function */ private static function each_site($network, $callback, $callback_params = []) { $callback_return = []; if ( $network ) { $blog_ids = self::get_blog_ids(); // switch to each site in network foreach ( $blog_ids as $blog_id ) { switch_to_blog( $blog_id ); $callback_return[ $blog_id ] = call_user_func_array( $callback, $callback_params ); restore_current_blog(); } } else { $callback_return[] = (int) call_user_func_array( $callback, $callback_params ); } return $callback_return; } /** * plugin activation and deactivation hooks * */ public static function on_plugin_activation_deactivation() { // if setting enabled clear site cache on any plugin activation or deactivation if ( A2_Optimized_Cache_Engine::$settings['clear_site_cache_on_changed_plugin'] ) { self::clear_site_cache(); } } /** * get settings from database * * @return array $settings current settings from database */ public static function get_settings() { // get database option value $settings = get_option( 'a2opt-cache' ); // if database option does not exist or settings are outdated if ( $settings === false || isset( $settings['version'] ) && $settings['version'] !== A2OPT_VERSION ) { $settings = self::update_backend(); } return $settings; } /** * get blog IDs * * @return array $blog_ids blog IDs */ private static function get_blog_ids() { $blog_ids = [ 1 ]; if ( is_multisite() ) { global $wpdb; $blog_ids = array_map( 'absint', $wpdb->get_col( "SELECT blog_id FROM $wpdb->blogs" ) ); } return $blog_ids; } /** * get blog path * * @return string $blog_path blog path from site address URL, empty otherwise */ public static function get_blog_path() { $site_url_path = parse_url( home_url(), PHP_URL_PATH ); $site_url_path = rtrim( $site_url_path, '/' ); $site_url_path_pieces = explode( '/', $site_url_path ); // get last piece in case installation is in a subdirectory $blog_path = ( ! empty( end( $site_url_path_pieces ) ) ) ? '/' . end( $site_url_path_pieces ) . '/' : ''; return $blog_path; } /** * get blog paths * * @return array $blog_paths blog paths */ public static function get_blog_paths() { $blog_paths = [ '/' ]; if ( is_multisite() ) { global $wpdb; $blog_paths = $wpdb->get_col( "SELECT path FROM $wpdb->blogs" ); } return $blog_paths; } /** * get permalink structure * * @return string permalink structure */ private static function get_permalink_structure() { // get permalink structure $permalink_structure = get_option( 'permalink_structure' ); // permalink structure is custom and has a trailing slash if ( $permalink_structure && preg_match( '/\/$/', $permalink_structure ) ) { return 'has_trailing_slash'; } // permalink structure is custom and does not have a trailing slash if ( $permalink_structure && ! preg_match( '/\/$/', $permalink_structure ) ) { return 'no_trailing_slash'; } // permalink structure is not custom if ( empty( $permalink_structure ) ) { return 'plain'; } } /** * get cache size * * @return integer $cache_size cache size in bytes */ public static function get_cache_size() { $cache_size = get_transient( self::get_cache_size_transient_name() ); if ( ! $cache_size ) { $cache_size = A2_Optimized_Cache_Disk::cache_size(); set_transient( self::get_cache_size_transient_name(), $cache_size, MINUTE_IN_SECONDS * 15 ); } return $cache_size; } /** * get the cache size transient name * * @return string $transient_name transient name */ private static function get_cache_size_transient_name() { $transient_name = 'a2opt_cache_cache_size'; return $transient_name; } /** * get the cache cleared transient name used for the clear notice * * @return string $transient_name transient name */ private static function get_cache_cleared_transient_name() { $transient_name = 'a2opt_cache_cache_cleared_' . get_current_user_id(); return $transient_name; } /** * get default settings * * @param string $settings_type default `system` settings * @return array $system_default_settings|$default_settings only default system settings or all default settings */ private static function get_default_settings($settings_type = null) { $system_default_settings = [ 'version' => (string) A2OPT_VERSION, 'permalink_structure' => (string) self::get_permalink_structure(), ]; if ( $settings_type === 'system' ) { return $system_default_settings; } $user_default_settings = [ 'cache_expires' => 0, 'cache_expiry_time' => 0, 'clear_site_cache_on_saved_post' => 1, 'clear_site_cache_on_saved_comment' => 1, 'clear_site_cache_on_changed_plugin' => 1, 'compress_cache' => 0, 'convert_image_urls_to_webp' => 0, 'excluded_post_ids' => '', 'excluded_page_paths' => '', 'excluded_query_strings' => '', 'excluded_cookies' => '', 'minify_html' => 1, 'minify_inline_css_js' => 0, ]; // merge default settings $default_settings = wp_parse_args( $user_default_settings, $system_default_settings ); return $default_settings; } /** * add admin bar items * * @param object menu properties */ public static function add_admin_bar_items($wp_admin_bar) { // check user role if ( ! self::user_can_clear_cache() ) { return; } // set clear cache button title $title = ( is_multisite() && is_network_admin() ) ? esc_html__( 'Clear Network Cache', 'a2-optimized-wp' ) : esc_html__( 'Clear Site Cache', 'a2-optimized-wp' ); // add "Clear Network Cache" or "Clear Site Cache" button in admin bar $wp_admin_bar->add_menu( [ 'id' => 'a2opt_cache_clear_cache', 'href' => wp_nonce_url( add_query_arg( [ '_cache' => 'a2-optimized-wp', '_action' => 'clear', ] ), 'a2opt_cache_clear_cache_nonce' ), 'parent' => 'top-secondary', 'title' => '' . $title . '', 'meta' => [ 'title' => $title ], ] ); // add "Clear Page Cache" button in admin bar if ( ! is_admin() ) { $wp_admin_bar->add_menu( [ 'id' => 'a2opt_cache_clear_page_cache', 'href' => wp_nonce_url( add_query_arg( [ '_cache' => 'a2-optimized-wp', '_action' => 'clearurl', ] ), 'a2opt_cache_clear_cache_nonce' ), 'parent' => 'top-secondary', 'title' => '' . esc_html__( 'Clear Page Cache', 'a2-optimized-wp' ) . '', 'meta' => [ 'title' => esc_html__( 'Clear Page Cache', 'a2-optimized-wp' ) ], ] ); } } /** * check if user can clear cache * * @return boolean true if user can clear cache, false otherwise */ private static function user_can_clear_cache() { if ( apply_filters( 'a2opt_cache_user_can_clear_cache', current_user_can( 'manage_options' ) ) ) { return true; } return false; } /** * process clear cache request * */ public static function process_clear_cache_request() { // check if clear cache request if ( empty( $_GET['_cache'] ) || empty( $_GET['_action'] ) || $_GET['_cache'] !== 'a2-optimized-wp' || ( $_GET['_action'] !== 'clear' && $_GET['_action'] !== 'clearurl' ) ) { return; } // validate nonce if ( empty( $_GET['_wpnonce'] ) || ! wp_verify_nonce( $_GET['_wpnonce'], 'a2opt_cache_clear_cache_nonce' ) ) { return; } // check user role if ( ! self::user_can_clear_cache() ) { return; } // clear page cache if ( $_GET['_action'] === 'clearurl' ) { // set clear URL without query string $clear_url = parse_url( home_url(), PHP_URL_SCHEME ) . '://' . parse_url( home_url(), PHP_URL_HOST ) . preg_replace( '/\?.*/', '', $_SERVER['REQUEST_URI'] ); self::clear_page_cache_by_url( $clear_url ); // clear site(s) cache } elseif ( $_GET['_action'] === 'clear' ) { self::each_site( ( is_multisite() && is_network_admin() ), 'self::clear_site_cache' ); } // redirect to same page wp_safe_redirect( wp_get_referer() ); // set transient for clear notice if ( is_admin() ) { set_transient( self::get_cache_cleared_transient_name(), 1 ); } // clear cache request completed exit; } /** * admin notice after cache has been cleared * */ public static function cache_cleared_notice() { // check user role if ( ! self::user_can_clear_cache() ) { return; } if ( get_transient( self::get_cache_cleared_transient_name() ) ) { echo sprintf( '

%s

', ( is_multisite() && is_network_admin() ) ? esc_html__( 'Network cache cleared.', 'a2-optimized-wp' ) : esc_html__( 'Site cache cleared.', 'a2-optimized-wp' ) ); delete_transient( self::get_cache_cleared_transient_name() ); } } /** * save post hook * * @param integer $post_id post ID */ public static function on_save_post($post_id) { // if any published post type is created or updated if ( get_post_status( $post_id ) === 'publish' ) { self::clear_cache_on_post_save( $post_id ); } } /** * post updated hook * * @param integer $post_id post ID * @param WP_Post $post_after post instance following the update * @param WP_Post $post_before post instance before the update */ public static function on_post_updated($post_id, $post_after, $post_before) { // if setting disabled and any published post type author changes if ( $post_before->post_author !== $post_after->post_author ) { if ( ! A2_Optimized_Cache_Engine::$settings['clear_site_cache_on_saved_post'] ) { // clear before the update author archives self::clear_author_archives_cache_by_user_id( $post_before->post_author ); } } } /** * trash post hook * * @param integer $post_id post ID */ public static function on_trash_post($post_id) { // if any published post type is trashed if ( get_post_status( $post_id ) === 'publish' ) { $trashed = true; self::clear_cache_on_post_save( $post_id, $trashed ); } } /** * transition post status hook * * @param string $new_status new post status * @param string $old_status old post status * @param WP_Post $post post instance */ public static function on_transition_post_status($new_status, $old_status, $post) { // if any published post type status has changed if ( $old_status === 'publish' && in_array( $new_status, [ 'future', 'draft', 'pending', 'private' ] ) ) { self::clear_cache_on_post_save( $post->ID ); } } /** * comment post hook * * @param integer $comment_id comment ID * @param integer|string $comment_approved comment approval status */ public static function on_comment_post($comment_id, $comment_approved) { // if new approved comment is posted if ( $comment_approved === 1 ) { // if setting enabled clear site cache if ( A2_Optimized_Cache_Engine::$settings['clear_site_cache_on_saved_comment'] ) { self::clear_site_cache(); // clear page cache otherwise } else { self::clear_page_cache_by_post_id( get_comment( $comment_id )->comment_post_ID ); } } } /** * edit comment hook * * @param integer $comment_id comment ID * @param array $comment_data comment data */ public static function on_edit_comment($comment_id, $comment_data) { $comment_approved = (int) $comment_data['comment_approved']; // if approved comment is edited if ( $comment_approved === 1 ) { // if setting enabled clear site cache if ( A2_Optimized_Cache_Engine::$settings['clear_site_cache_on_saved_comment'] ) { self::clear_site_cache(); // clear page cache otherwise } else { self::clear_page_cache_by_post_id( get_comment( $comment_id )->comment_post_ID ); } } } /** * transition comment status hook * * @param integer|string $new_status new comment status * @param integer|string $old_status old comment status * @param WP_Comment $comment comment instance */ public static function on_transition_comment_status($new_status, $old_status, $comment) { // if comment status has changed from or to approved if ( $old_status === 'approved' || $new_status === 'approved' ) { // if setting enabled clear site cache if ( A2_Optimized_Cache_Engine::$settings['clear_site_cache_on_saved_comment'] ) { self::clear_site_cache(); // clear page cache otherwise } else { self::clear_page_cache_by_post_id( $comment->comment_post_ID ); } } } /** * WooCommerce stock hooks * * @param integer|WC_Product $product product ID or product instance */ public static function on_woocommerce_stock_update($product) { // get product ID if ( is_int( $product ) ) { $product_id = $product; } else { $product_id = $product->get_id(); } self::clear_cache_on_post_save( $product_id ); } /** * clear complete cache * */ public static function clear_complete_cache() { // clear site(s) cache self::each_site( is_multisite(), 'self::clear_site_cache' ); // delete cache size transient(s) self::each_site( is_multisite(), 'delete_transient', [ self::get_cache_size_transient_name() ] ); } /** * clear site cache * */ public static function clear_site_cache() { self::clear_site_cache_by_blog_id( get_current_blog_id() ); } /** * clear cached pages that might have changed from any new or updated post * * @param WP_Post $post post instance */ public static function clear_associated_cache($post) { // clear post type archives self::clear_post_type_archives_cache( $post->post_type ); // clear taxonomies archives self::clear_taxonomies_archives_cache_by_post_id( $post->ID ); if ( $post->post_type === 'post' ) { // clear author archives self::clear_author_archives_cache_by_user_id( $post->post_author ); // clear date archives self::clear_date_archives_cache_by_post_id( $post->ID ); } } /** * clear post type archives page cache * * @param string $post_type post type */ public static function clear_post_type_archives_cache($post_type) { // get post type archives URL $post_type_archives_url = get_post_type_archive_link( $post_type ); if ( ! empty( $post_type_archives_url ) ) { // clear post type archives page and its pagination page(s) cache self::clear_page_cache_by_url( $post_type_archives_url, 'pagination' ); } } /** * clear taxonomies archives pages cache by post ID * * @param integer $post_id post ID */ public static function clear_taxonomies_archives_cache_by_post_id($post_id) { // get taxonomies $taxonomies = get_taxonomies(); foreach ( $taxonomies as $taxonomy ) { if ( wp_count_terms( $taxonomy ) > 0 ) { // get terms attached to post $term_ids = wp_get_post_terms( $post_id, $taxonomy, [ 'fields' => 'ids' ] ); foreach ( $term_ids as $term_id ) { $term_archives_url = get_term_link( (int) $term_id, $taxonomy ); // validate URL and ensure it does not have a query string if ( filter_var( $term_archives_url, FILTER_VALIDATE_URL ) && ! filter_var( $term_archives_url, FILTER_VALIDATE_URL, FILTER_FLAG_QUERY_REQUIRED ) ) { // clear taxonomy archives page and its pagination page(s) cache self::clear_page_cache_by_url( $term_archives_url, 'pagination' ); } } } } } /** * clear author archives page cache by user ID * * @param integer $user_id user ID of the author */ public static function clear_author_archives_cache_by_user_id($user_id) { // get author archives URL $author_username = get_the_author_meta( 'user_login', $user_id ); $author_base = $GLOBALS['wp_rewrite']->author_base; $author_archives_url = home_url( '/' ) . $author_base . '/' . $author_username; // clear author archives page and its pagination page(s) cache self::clear_page_cache_by_url( $author_archives_url, 'pagination' ); } /** * clear date archives pages cache * * @param integer $post_id post ID */ public static function clear_date_archives_cache_by_post_id($post_id) { // get post dates $post_date_day = get_the_date( 'd', $post_id ); $post_date_month = get_the_date( 'm', $post_id ); $post_date_year = get_the_date( 'Y', $post_id ); // get post dates archives URLs $date_archives_day_url = get_day_link( $post_date_year, $post_date_month, $post_date_day ); $date_archives_month_url = get_month_link( $post_date_year, $post_date_month ); $date_archives_year_url = get_year_link( $post_date_year ); // clear date archives pages and their pagination pages cache self::clear_page_cache_by_url( $date_archives_day_url, 'pagination' ); self::clear_page_cache_by_url( $date_archives_month_url, 'pagination' ); self::clear_page_cache_by_url( $date_archives_year_url, 'pagination' ); } /** * clear page cache by post ID * * @param integer|string $post_id post ID * @param string $clear_type clear the `pagination` cache or all `subpages` cache instead of only the `page` cache */ public static function clear_page_cache_by_post_id($post_id, $clear_type = 'page') { // validate integer if ( ! is_int( $post_id ) ) { // if string try to convert to integer $post_id = (int) $post_id; // conversion failed if ( ! $post_id ) { return; } } // clear page cache self::clear_page_cache_by_url( get_permalink( $post_id ), $clear_type ); } /** * clear page cache by URL * * @param string $clear_url full URL to potentially cached page * @param string $clear_type clear the `pagination` cache or all `subpages` cache instead of only the `page` cache */ public static function clear_page_cache_by_url($clear_url, $clear_type = 'page') { A2_Optimized_Cache_Disk::clear_cache( $clear_url, $clear_type ); } /** * clear site cache by blog ID * * @param integer|string $blog_id blog ID * @param boolean $delete_cache_size_transient whether or not the cache size transient should be deleted */ public static function clear_site_cache_by_blog_id($blog_id, $delete_cache_size_transient = true) { // validate integer if ( ! is_int( $blog_id ) ) { // if string try to convert to integer $blog_id = (int) $blog_id; // conversion failed if ( ! $blog_id ) { return; } } // check if blog ID exists if ( ! in_array( $blog_id, self::get_blog_ids() ) ) { return; } // ensure site cache being cleared is current blog if ( is_multisite() ) { switch_to_blog( $blog_id ); } // disable page cache cleared hook self::$fire_page_cache_cleared_hook = false; // get site URL $site_url = home_url(); // get site objects $site_objects = A2_Optimized_Cache_Disk::get_site_objects( $site_url ); // clear all first level pages and subpages cache foreach ( $site_objects as $site_object ) { self::clear_page_cache_by_url( trailingslashit( $site_url ) . $site_object, 'subpages' ); } // clear home page cache self::clear_page_cache_by_url( $site_url ); // delete cache size transient if ( $delete_cache_size_transient ) { delete_transient( self::get_cache_size_transient_name() ); } // restore current blog from before site cache being cleared if ( is_multisite() ) { restore_current_blog(); } } /** * clear cache when any post type is created or updated * * @param integer $post_id post ID * @param boolean $trashed whether this is an existing post being trashed */ public static function clear_cache_on_post_save($post_id, $trashed = false) { // get post data $post = get_post( $post_id ); // if setting enabled clear site cache if ( A2_Optimized_Cache_Engine::$settings['clear_site_cache_on_saved_post'] ) { self::clear_site_cache(); // clear page and/or associated cache otherwise } else { // if updated or trashed clear page cache if ( strtotime( $post->post_modified_gmt ) > strtotime( $post->post_date_gmt ) || $trashed ) { self::clear_page_cache_by_post_id( $post_id ); } // clear associated cache self::clear_associated_cache( $post ); } } /** * check plugin requirements * */ public static function requirements_check() { //confirm // check user role if ( ! current_user_can( 'manage_options' ) ) { return; } // check advanced-cache.php drop-in exists if ( ! file_exists( WP_CONTENT_DIR . '/advanced-cache.php' ) && !is_plugin_active('litespeed-cache/litespeed-cache.php') && get_option('a2_cache_enabled') == 1) { echo sprintf( '

%s

', sprintf( // translators: 1. A2 Optimized 2. advanced-cache.php 3. wp-content/plugins/a2-optimized-wp 4. wp-content esc_html__( '%1$s requires the %2$s drop-in. Please disable and then re-enable the "Page Caching" setting in A2 Optimized to automatically copy this file or manually copy it from the %3$s directory to the %4$s directory.', 'a2-optimized-wp' ), 'A2 Optimized', 'advanced-cache.php', 'wp-content/plugins/a2-optimized-wp', 'wp-content' ) ); } // check advanced-cache.php drop-in is ours if (file_exists( WP_CONTENT_DIR . '/advanced-cache.php' ) && !is_plugin_active('litespeed-cache/litespeed-cache.php') && get_option('a2_cache_enabled') == 1) { $existing_hash = md5(WP_CONTENT_DIR . '/advanced-cache.php'); $plugin_hash = md5(A2OPT_DIR . '/advanced-cache.php'); if($plugin_hash != $existing_hash){ @unlink( WP_CONTENT_DIR . '/advanced-cache.php' ); A2_Optimized_Cache_Disk::setup(); } } // check permalink structure if ( A2_Optimized_Cache_Engine::$settings['permalink_structure'] === 'plain' && current_user_can( 'manage_options' ) ) { echo sprintf( '

%s

', sprintf( // translators: 1. A2 Optimized 2. Permalink Settings esc_html__( '%1$s requires a custom permalink structure. Please enable a custom structure in the %2$s.', 'a2-optimized-wp' ), 'A2 Optimized', sprintf( '%s', admin_url( 'options-permalink.php' ), esc_html__( 'Permalink Settings', 'a2-optimized-wp' ) ) ) ); } // check file permissions if ( file_exists( dirname( A2_Optimized_Cache_Disk::$cache_dir ) ) && ! is_writable( dirname( A2_Optimized_Cache_Disk::$cache_dir ) ) ) { echo sprintf( '

%s

', sprintf( // translators: 1. A2 Optimized 2. 755 3. wp-content/cache 4. file permissions esc_html__( '%1$s requires write permissions %2$s in the %3$s directory. Please change the %4$s.', 'a2-optimized-wp' ), 'A2 Optimized', '755', 'wp-content/cache', sprintf( '%s', 'https://wordpress.org/support/article/changing-file-permissions/', esc_html__( 'file permissions', 'a2-optimized-wp' ) ) ) ); } // check Autoptimize HTML optimization if ( defined( 'AUTOPTIMIZE_PLUGIN_DIR' ) && A2_Optimized_Cache_Engine::$settings['minify_html'] && get_option( 'autoptimize_html', '' ) !== '' ) { echo sprintf( '

%s

', sprintf( // translators: 1. Autoptimize 2. A2 Optimized Settings esc_html__( '%1$s HTML optimization is enabled. Please disable HTML minification in the %2$s.', 'a2-optimized-wp' ), 'Autoptimize', sprintf( '%s', admin_url( 'admin.php?page=a2-optimized-wp' ), esc_html__( 'A2 Optimized Settings', 'a2-optimized-wp' ) ) ) ); } } /** * register textdomain * */ public static function register_textdomain() { // load translated strings load_plugin_textdomain( 'a2-optimized-wp', false, 'a2-optimized-wp/lang' ); } /** * register settings * */ public static function register_settings() { register_setting( 'a2opt-cache', 'a2opt-cache', [ __CLASS__, 'validate_settings' ] ); register_setting( 'a2opt-cache', 'a2_optimized_objectcache_type' ); register_setting( 'a2opt-cache', 'a2_optimized_memcached_server', [ __CLASS__, 'validate_object_cache' ]); register_setting( 'a2opt-cache', 'a2_optimized_redis_server', [ __CLASS__, 'validate_object_cache' ]); } /** * validate regex * * @param string $regex string containing regex * @return string $validated_regex string containing regex or empty string if input is invalid */ public static function validate_regex($regex) { if ( ! empty( $regex ) ) { if ( ! preg_match( '/^\/.*\/$/', $regex ) ) { $regex = '/' . $regex . '/'; } if ( @preg_match( $regex, null ) === false ) { return ''; } $validated_regex = sanitize_text_field( $regex ); return $validated_regex; } return ''; } /** * validate settings * * @param array $settings user defined settings * @return array $validated_settings validated settings */ public static function validate_settings($settings) { // validate array if ( ! is_array( $settings ) ) { return; } $validated_settings = [ 'cache_expires' => (int) ( ! empty( $settings['cache_expires'] ) ), 'cache_expiry_time' => (int) @$settings['cache_expiry_time'], 'clear_site_cache_on_saved_post' => (int) ( ! empty( $settings['clear_site_cache_on_saved_post'] ) ), 'clear_site_cache_on_saved_comment' => (int) ( ! empty( $settings['clear_site_cache_on_saved_comment'] ) ), 'clear_site_cache_on_changed_plugin' => (int) ( ! empty( $settings['clear_site_cache_on_changed_plugin'] ) ), 'compress_cache' => (int) ( ! empty( $settings['compress_cache'] ) ), 'convert_image_urls_to_webp' => (int) ( ! empty( $settings['convert_image_urls_to_webp'] ) ), 'excluded_post_ids' => (string) sanitize_text_field( @$settings['excluded_post_ids'] ), 'excluded_page_paths' => (string) self::validate_regex( @$settings['excluded_page_paths'] ), 'excluded_query_strings' => (string) self::validate_regex( @$settings['excluded_query_strings'] ), 'excluded_cookies' => (string) self::validate_regex( @$settings['excluded_cookies'] ), 'minify_html' => (int) ( ! empty( $settings['minify_html'] ) ), 'minify_inline_css_js' => (int) ( ! empty( $settings['minify_inline_css_js'] ) ), ]; // add default system settings $validated_settings = wp_parse_args( $validated_settings, self::get_default_settings( 'system' ) ); // check if site cache should be cleared if ( ! empty( $settings['clear_site_cache_on_saved_settings'] ) ) { self::clear_site_cache(); set_transient( self::get_cache_cleared_transient_name(), 1 ); } // check if database optimizations should be executed if ( ! empty( $settings['apply_db_optimizations_on_saved_settings'] ) ) { $a2_db_optimizations = new A2_Optimized_DBOptimizations; $a2_db_optimizations->execute_optimizations(); } return $validated_settings; } /** * validate memcached settings * * @param string $settings user defined settings * @return string $validated_settings validated settings */ public static function validate_object_cache($server_address) { if (!$server_address || strtolower($server_address) === 'false') { return; } $object_cache_type = ''; if (get_option('a2_optimized_objectcache_type')) { $object_cache_type = get_option('a2_optimized_objectcache_type'); } $address_valid = false; switch ($object_cache_type) { case 'memcached': if (class_exists('Memcached')) { $memcached = new Memcached; if ( 'unix://' == substr( $server_address, 0, 7 ) ) { $node = str_replace('unix://', '', $server_address); $port = 0; } else { list( $node, $port ) = explode( ':', $server_address ); if ( ! $port ) { $port = ini_get( 'memcache.default_port' ); } $port = intval( $port ); if ( ! $port ) { $port = 11211; } } $instances[] = [ $node, $port, 1 ]; $memcached->addServers($instances); $memcached_available = $memcached->getStats(); if ($memcached_available) { update_option('litespeed.conf.object-kind', 0); update_option('litespeed.conf.object-host', $server_address); update_option('litespeed.conf.object-port', 0); delete_option('a2_optimized_memcached_invalid'); $address_valid = true; } else { update_option('a2_optimized_memcached_invalid', 'Unable to connect to Memcached Server'); } } else { update_option('a2_optimized_memcached_invalid', 'Missing Memcached extension'); } break; case 'redis': if (class_exists('Redis') && file_exists($server_address)) { $conn = new Redis() ; $conn->connect( $server_address, 0 ) ; $conn->select( 0 ); // default db $redis_available = $conn->ping(); if ($redis_available) { update_option('litespeed.conf.object-kind', 1); update_option('litespeed.conf.object-host', $server_address); update_option('litespeed.conf.object-port', 0); delete_option('a2_optimized_memcached_invalid'); $address_valid = true; } else { update_option('a2_optimized_memcached_invalid', 'Unable to connect to Redis Server'); } } else { update_option('a2_optimized_memcached_invalid', 'Missing Redis extension or invalid socket path'); } break; } if($address_valid){ return $server_address; } else { return false; } } }