admin_url( 'admin-ajax.php' ), 'hostname' => get_option('rabbitloader_field_domain') ]); }); //we need to listen for a few things to invalidate cache #reading settings changed (permalink, post per page) #post+page+comment+tag+category added, deleted, updated #theme+plugin activated deactivated add_action( 'save_post', function($post_ID, $post, $update){ RabbitLoader_21_Admin::onPostChange($post_ID, self::PURGE_POST_CHANGE); }, 10, 3 ); add_action( 'wp_insert_post', function($post_ID, $post, $update){ RabbitLoader_21_Admin::onPostChange($post_ID, self::PURGE_POST_CHANGE); }, 10, 3 ); add_action( 'draft_to_publish', function($post){ if(!empty($post)){ RabbitLoader_21_Admin::onPostChange($post->ID, self::PURGE_POST_CHANGE); } }, 10, 1 ); add_action( 'pending_to_publish', function($post){ if(!empty($post)){ RabbitLoader_21_Admin::onPostChange($post->ID, self::PURGE_POST_CHANGE); } }, 10, 1); add_action( 'transition_post_status', function($new_status, $old_status, $post){ //No need to purge if the post was not public before and its not even now if('publish' !== $old_status && 'publish' !== $new_status){ return; } RabbitLoader_21_Admin::onPostChange($post->ID, self::PURGE_POST_CHANGE); }, 10, 3); add_action( 'transition_comment_status', function($new_status, $old_status, $comment){ RabbitLoader_21_Admin::onPostChange($comment->comment_post_ID, self::PURGE_POST_CHANGE); }, 10, 3); add_action( 'comment_post', function($comment_ID, $comment_approved, $commentdata){ if($comment_approved==1){ $comment = get_comment( $comment_ID ); RabbitLoader_21_Admin::onPostChange($comment->comment_post_ID, self::PURGE_POST_CHANGE); } }, 10, 3); add_action( 'switch_theme', function(){ RabbitLoader_21_Admin::onPostChange('all', self::PURGE_THEME_CHANGE); }, 10, 0); // add_action( 'upgrader_process_complete', function(){ // RabbitLoader_21_Admin::onPostChange('all', self::PURGE_PLUG_CHANGE); // }, 10, 0); // add_action( 'activated_plugin', function(){ // RabbitLoader_21_Admin::onPostChange('all', self::PURGE_PLUG_CHANGE); // }, 10, 0); // add_action( 'deactivated_plugin', function(){ // RabbitLoader_21_Admin::onPostChange('all', self::PURGE_PLUG_CHANGE); // }, 10, 0); add_action( 'woocommerce_updated_product_stock', function($product_id){ RabbitLoader_21_Admin::onPostChange($product_id, self::PURGE_POST_CHANGE); }, 10, 1); add_action( 'woocommerce_updated_product_price', function($product_id){ RabbitLoader_21_Admin::onPostChange($product_id, self::PURGE_POST_CHANGE); }, 10, 1); add_action( 'woocommerce_rest_insert_product', function($post, $request, $creating) { RabbitLoader_21_Admin::onPostChange($post->ID, self::PURGE_POST_CHANGE); }, 10, 3); add_action( 'woocommerce_rest_insert_product_object', function($product, $request, $creating) { RabbitLoader_21_Admin::onPostChange($product->id, self::PURGE_POST_CHANGE); }, 10, 3); add_action( 'woocommerce_product_object_updated_props', function($product, $updated) { RabbitLoader_21_Admin::onPostChange($product->get_id(), self::PURGE_POST_CHANGE); }, 0, 2); add_action( 'wp_ajax_rabbitloader_ajax_purge', function(){ $response = [ 'result'=>false ]; if(!empty($_POST['post_id'])){ $post_id = RabbitLoader_21_Util_Core::get_param('post_id', true); RabbitLoader_21_Admin::onPostChange($post_id, self::PURGE_MANUAL_USER); $response = [ 'result'=>true ]; }else{ RabbitLoader_21_Admin::onPostChange('all', self::PURGE_MANUAL_USER); $response = [ 'result'=>true ]; } RabbitLoader_21_Core::sendJsonResponse($response); }); add_action( 'wp_ajax_rabbitloader_mode_change', function(){ $response = [ 'result'=>true ]; $private_mode = !empty($_POST['private_mode']); RabbitLoader_21_Core::getWpUserOption($user_options); $user_options['private_mode_val'] = $private_mode; $user_options['private_mode_ts'] = date('c'); RabbitLoader_21_Core::updateUserOption($user_options); RabbitLoader_21_Core::sendJsonResponse($response); }); add_action( 'wp_ajax_rabbitloader_ajax_cron', function(){self::deferred_exe();}); add_action( 'rl_site_connected', function(){self::rl_site_connected();}); add_action( 'plugins_loaded', 'RabbitLoader_AD_AD::on_plugins_loaded'); //listeners for taxonomy changes } public static function init(){ } public static function leftMenuOption(){ self::get_warnings($notification_count, false); add_menu_page( 'RabbitLoader', $notification_count ? sprintf('RabbitLoader %d', $notification_count) : 'RabbitLoader', 'manage_options', 'rabbitloader', 'RabbitLoader_21_Tab_Init::echoPluginPage', dirname(plugin_dir_url(__FILE__)) . '/images/icon_16.png', //'', 20 ); $page = RabbitLoader_21_Util_Core::get_param('page'); if($page=='rabbitloader'){ add_action( 'admin_head', 'admin_styles', 10, 1); function admin_styles($a) { echo ' '; } } } protected static function isPluginActivated(){ return !empty(RabbitLoader_21_Core::getWpOptVal('api_token')); } private static function load_purged_urls(){ RabbitLoader_21_Core::get_log_file('purge_urls_fl', $purge_urls_fl); if(file_exists($purge_urls_fl)){ $purge_queue = json_decode(file_get_contents($purge_urls_fl), true); } if(empty($purge_queue)){ $purge_queue = []; } return $purge_queue; } public static function onPostChange($post_id, $purge_source){ if(self::$purge_queue===null){ self::$purge_queue = self::load_purged_urls(); } if($post_id=='all'){ self::$purge_queue['all'] = true; }else{ //invalidate cache for individual post try{ if(wp_is_post_autosave($post_id) || wp_is_post_revision($post_id)){ //no need to purge cache for these posts as they are never displayed on website return; } }catch(\Throwable $e){ RabbitLoader_21_Core::on_exception($e); } if(empty(self::$purge_queue['post_ids'])){ self::$purge_queue['post_ids'] = []; } self::$purge_queue['post_ids'][$post_id] = true; $post_ancestors = get_post_ancestors($post_id); foreach ($post_ancestors as $parent_id) { self::$purge_queue['post_ids'][$parent_id] = true; } } self::$purge_queue['purge_source'] = $purge_source; } private static function execute_purge() { $purge_queue = self::load_purged_urls(); $purge_urls_json = '{}'; RabbitLoader_21_Core::get_log_file('purge_urls_fl', $purge_urls_fl); RabbitLoader_21_Util_Core::fpc($purge_urls_fl, $purge_urls_json, WP_DEBUG); RabbitLoader_21_Core::getWpUserOption($user_options); $purge_source = empty($purge_queue['purge_source'])?'':$purge_queue['purge_source']; $clean_cache = strcmp($purge_source, self::PURGE_MANUAL_USER)===0 || !empty($user_options['purge_on_change']); if(!empty($purge_queue['all'])){ if($clean_cache){ RabbitLoader_21_Core::purge_all($purge_count, $purge_source, $tp_purge_count); } try{ RabbitLoader_21_Core::push_recent_posts($queued_offset, $queued_count, $published_count); }catch(\Throwable $e){ RabbitLoader_21_Core::on_exception($e); } }else if(!empty($purge_queue['post_ids'])){ $urls_to_purge = []; RabbitLoader_21_Core::get_common_cache_urls($urls_to_purge); foreach($purge_queue['post_ids'] as $post_ID=>$val){ $post_obj = get_post(intval($post_ID)); if(!$post_obj){ continue; } $post_canonical_url = wp_get_canonical_url($post_ID); $urls_to_purge[] = $post_canonical_url; RabbitLoader_21_Admin::get_all_taxonomies($post_ID, $post_obj->post_type, $tax_ids, $urls_to_purge); if($clean_cache){ RabbitLoader_21_TP::purge_post_id($post_ID, $tp_purge_count); } } $cache_missed_log = ''; $urls_to_purge = array_filter($urls_to_purge); foreach($urls_to_purge as $url){ if($clean_cache){ RabbitLoader_21_Core::purge_url_cache_local($url, $local_purge_count, $tp_purge_count); RabbitLoader_21_Core::purge_url_cache_local(rawurldecode($url), $local_purge_count, $tp_purge_count); } $cache_missed_log .= "\n".$url; } if(!empty($cache_missed_log)){ RabbitLoader_21_Util_Core::fac('cache_missed', $cache_missed_log, WP_DEBUG); } RabbitLoader_21_Core::callPostApi('purge/request', ['purge_source'=>$purge_source, 'urls'=>array_slice($urls_to_purge,0, 100)], $apiError, $apiMessage); do_action('rl_purge_request_complete', $urls_to_purge, $apiError); } } public static function shutdown() { if(!empty(self::$purge_queue)){ $purge_urls_json = json_encode(self::$purge_queue); RabbitLoader_21_Core::get_log_file('purge_urls_fl', $purge_urls_fl); RabbitLoader_21_Util_Core::fpc($purge_urls_fl, $purge_urls_json, WP_DEBUG); } } private static function get_all_taxonomies($post_ID, $post_type, &$tax_ids, &$tax_urls) { $tax_ids = array(); $taxonomies = get_object_taxonomies($post_type); foreach ($taxonomies as $taxonomy) { $taxonomy_data = get_taxonomy($taxonomy); if ($taxonomy_data instanceof WP_Taxonomy && $taxonomy_data->public===false) { continue; } $terms = get_the_terms( $post_ID, $taxonomy ); if (empty($terms) || is_wp_error($terms)) { continue; }else{ foreach ($terms as $term) { if(!empty($term)){ $tax_ids[] = $term->term_taxonomy_id; $tax_url = get_term_link($term); if(!is_wp_error($tax_url) && !empty($tax_url)){ $tax_urls[] = $tax_url; } } } } } $other_urls_to_merge = []; try{ $other_urls_to_merge[] = get_author_posts_url(get_post_field('post_author', $post_ID)); $other_urls_to_merge[] = get_author_feed_link(get_post_field('post_author', $post_ID)); $other_urls_to_merge[] = get_post_type_archive_link($post_type); $other_urls_to_merge[] = get_post_type_archive_feed_link($post_type); $other_urls_to_merge[] = get_permalink($post_ID); $other_urls_to_merge[] = get_post_comments_feed_link($post_ID); }catch(Throwable $e){ RabbitLoader_21_Core::on_exception($e); } if(!empty($other_urls_to_merge)){ foreach($other_urls_to_merge as $other_url){ if(!empty($other_url) && !is_wp_error($other_url)){ $tax_urls[] = $other_url; } } } } public static function admin_notices(){ try{ $page = RabbitLoader_21_Util_Core::get_param('page'); if(self::$admin_notice_shown || ($page=='rabbitloader')){ return; } self::$admin_notice_shown = true; $plug_url = admin_url("admin.php?page=rabbitloader"); if(!self::isPluginActivated()){ echo '

'; printf(RabbitLoader_21_Util_WP::__('RabbitLoader is disconnected. Your pages are not optimized. Click here to connect'), $plug_url); echo '

'; }else{ self::get_warnings($notification_count, false); if($notification_count>0){ echo '

'; printf(RabbitLoader_21_Util_WP::_n( 'RabbitLoader has %d warning which is affecting your website\'s optimizations. check details', 'RabbitLoader has %d warnings which may affect your website\'s optimizations. check details', $notification_count), $notification_count, $plug_url); echo '

'; } } }catch(Throwable $e){ RabbitLoader_21_Core::on_exception($e); } } protected static function get_warnings(&$count, $print){ if(self::$rabbitloader_cache_warnings === false){ self::$rabbitloader_cache_warnings = []; $otherConflictPluginMessages = RabbitLoader_21_Conflicts::getMessages(); foreach ($otherConflictPluginMessages as $plugMessage) { self::$rabbitloader_cache_warnings[] = $plugMessage; } $adv_cache_msg = RabbitLoader_21_Util_WP::__("The file /wp-content/advanced-cache.php is not writable. Please make sure that the PHP script has write access to the /wp-content/ directory and refresh this page to make RabbitLoader work efficiently."); if(!defined('RABBITLOADER_AC_ACTIVE') || (RABBITLOADER_PLUG_VERSION!=RABBITLOADER_AC_PLUG_VERSION)){ $aac_code = self::activate_advanced_cache(); if($aac_code==4){ self::$rabbitloader_cache_warnings[] = $adv_cache_msg; } } $cache_warning = RabbitLoader_21_Util_WP::__("The file /wp-config.php is not writable. Please make sure the file is writable or set WP_CACHE value to true to make RabbitLoader work efficiently."); if ((!defined("WP_CACHE") || !WP_CACHE)) { if (!self::update_wp_config_const('WP_CACHE', 'true')) { self::$rabbitloader_cache_warnings[] = $cache_warning; $cache_warning = ''; } } if (!self::create_cache_folder()) { self::$rabbitloader_cache_warnings[] = RabbitLoader_21_Util_WP::__("The folder /wp-content/ is not writable. Please make sure that the PHP script has write access to the /wp-content/ directory and refresh this page. This is required to store the cached content."); } RabbitLoader_21_Core::getWpOption($rl_wp_options); if(!empty($rl_wp_options['rl_hb_messages'])){ foreach($rl_wp_options['rl_hb_messages'] as $message){ if(!empty($message['fd'])){ self::$rabbitloader_cache_warnings[] = RabbitLoader_21_Util_WP::__($message['fd']); } } } if(!empty($rl_wp_options['rl_latest_plugin_v'])){ if(version_compare(RABBITLOADER_PLUG_VERSION, $rl_wp_options['rl_latest_plugin_v'])==-1){ self::$rabbitloader_cache_warnings[] = RabbitLoader_21_Util_WP::__("You are using an outdated version of RabbitLoader plugin. Please update it for a better experience."); } } } $count = count(self::$rabbitloader_cache_warnings); if($print){ foreach(self::$rabbitloader_cache_warnings as $message){ // echo ''; echo '

'; RabbitLoader_21_Util_WP::_e('Warning'); echo ': '; _e($message, RABBITLOADER_TEXT_DOMAIN); echo '

'; } } } private static function create_cache_folder(){ $dirs = [ RABBITLOADER_CACHE_DIR, RabbitLoader_21_Util_WP::get_cache_dir('short'), RabbitLoader_21_Util_WP::get_cache_dir('long') ]; $dirs_exists = 0; try{ foreach($dirs as $dir){ if (!file_exists($dir)){ if(@mkdir($dir, 0755, true)){ ++$dirs_exists; } }else{ ++$dirs_exists; } } if(count($dirs)!=$dirs_exists){ return false; } //add htaccess file for security $htaccess_loc = RABBITLOADER_CACHE_DIR.DIRECTORY_SEPARATOR.".htaccess"; if (!file_exists($htaccess_loc)) { $htaccess_content = "deny from all"; RabbitLoader_21_Util_Core::fpc($htaccess_loc, $htaccess_content, WP_DEBUG); } return file_exists($htaccess_loc); }catch(Throwable $e){ RabbitLoader_21_Core::on_exception($e); } } public static function activate_advanced_cache(){ try{ if (!empty(RabbitLoader_21_Conflicts::getMessages())){ return 1; } if(!self::create_cache_folder()){ return 2; } $adv_cache_sample = RABBITLOADER_PLUG_DIR . "advanced-cache.php"; $file_updated = false; if (file_exists($adv_cache_sample)) { $adv_cache_contents = file_get_contents($adv_cache_sample); $adv_cache_contents = str_replace("%%RABBITLOADER_AC_ABSPATH%%", ABSPATH, $adv_cache_contents); $adv_cache_contents = str_replace("%%RABBITLOADER_AC_PLUG_DIR%%", RABBITLOADER_PLUG_DIR, $adv_cache_contents); $adv_cache_contents = str_replace("%%RABBITLOADER_AC_LOGGED_IN_COOKIE%%", LOGGED_IN_COOKIE, $adv_cache_contents); $adv_cache_contents = str_replace("%%RABBITLOADER_AC_CACHE_DIR%%", RABBITLOADER_CACHE_DIR, $adv_cache_contents); $adv_cache_contents = str_replace("%%RABBITLOADER_AC_PLUG_VERSION%%", RABBITLOADER_PLUG_VERSION, $adv_cache_contents); $adv_cache_contents = str_replace("%%RABBITLOADER_AC_PLUG_ENV%%", RABBITLOADER_PLUG_ENV, $adv_cache_contents); $advanced_cache_file = WP_CONTENT_DIR . DIRECTORY_SEPARATOR.'advanced-cache.php'; $file_updated = RabbitLoader_21_Util_Core::fpc($advanced_cache_file, $adv_cache_contents, WP_DEBUG); } if($file_updated){ self::update_wp_config_const('WP_CACHE', 'true'); return 3; }else{ return 4; } }catch(Throwable $e){ RabbitLoader_21_Core::on_exception($e); } } private static function update_wp_config_const($const_name, $const_val){ $wp_config_path = RabbitLoader_21_Util_WP::get_wp_config(); //check if config file is writable if ( empty($wp_config_path) || !is_writable($wp_config_path)) { //echo 'rl_not_writable__'; return; } $lines = file( $wp_config_path ); $last_line = count($lines) - 1; $new_file = array(); $const_added = false; foreach ( $lines as $current_line=>$line_content ) { //check if constant is already defined if ( preg_match( "/define\(\s*'{$const_name}'/i", $line_content ) ) { $const_added = true; $new_file[] = "define( '{$const_name}', {$const_val} ); //RabbitLoader\n"; continue; //dont't break here, its a complete file rewrite } $thatsAllLine = (preg_match( "/\/\* That's all, stop editing!.*/i", $line_content )); //constants should be before this line. $isLast = ($thatsAllLine && !defined($const_name)) || ($last_line==$current_line); // If we reach the end and no define - add it. if (empty($const_added) && $isLast) { $new_file[] = "define( '{$const_name}', {$const_val} ); //RabbitLoader\n"; } $new_file[] = $line_content; } $file_contents = implode("", $new_file); return RabbitLoader_21_Util_Core::fpc($wp_config_path, $file_contents, WP_DEBUG); } public static function plugin_deactivate(){ try{ self::update_wp_config_const('WP_CACHE', 'false'); $advanced_cache_file = WP_CONTENT_DIR . DIRECTORY_SEPARATOR.'advanced-cache.php'; if (file_exists($advanced_cache_file)) { //during uninstall RABBITLOADER_AC_ACTIVE will not be there $adv_cache_contents = ""; $file_updated = RabbitLoader_21_Util_Core::fpc($advanced_cache_file, $adv_cache_contents, WP_DEBUG); } }catch(Throwable $e){ RabbitLoader_21_Core::on_exception($e); } } public static function plugin_uninstall(){ self::plugin_deactivate(); $post_data['uninstall'] = 1; $http = RabbitLoader_21_Core::callPOSTAPI('domain/heartbeat', $post_data, $apiError, $apiMessage); RabbitLoader_21_Core::cleanAllCachedFiles('long'); $ourOptions = array('rabbitloader_field_apikey', 'rabbitloader_field_apisecret', 'rabbitloader_field_domain','rl_optimizer_engine_version', 'rabbit_loader_wp_options', 'rabbit_loader_user_options', 'rabbitloader_cdn_prefix'); foreach ($ourOptions as $optionName) { delete_option($optionName); } } public static function postSubmitButton(){ wp_enqueue_script('rabbitloader-editor', RABBITLOADER_PLUG_URL . 'admin/js/editor.js', ['wp-edit-post', 'wp-plugins', 'wp-i18n', 'wp-element'], RABBITLOADER_PLUG_VERSION); } private static function rl_site_connected(){ try{ RabbitLoader_21_Core::push_recent_posts($queued_offset, $queued_count, $published_count); RabbitLoader_21_TP::purge_all($tp_purge_count); }catch(\Throwable $e){ RabbitLoader_21_Core::on_exception($e); } } public static function settings_link($links){ $url_settings = esc_url( add_query_arg( 'page', 'rabbitloader', get_admin_url() . 'admin.php' )); $link = "" . __( 'Settings' ) . ''; array_push($links, $link); $url_kb = esc_url('https://rabbitloader.com/kb/'); $link = "" . __( 'Knowledge Base' ) . ''; array_push($links, $link); return $links; } private static function deferred_exe(){ try{ self::execute_purge(); RabbitLoader_21_Core::clean_orphaned_cached_files(RabbitLoader_21_Util_Core::isDev()?5:50); }catch(\Throwable $e){ RabbitLoader_21_Core::on_exception($e); } } } ?>