+
+
+
+
+
+
diff --git a/wp-content/plugins/w3-total-cache/ObjectCache_Plugin.php b/wp-content/plugins/w3-total-cache/ObjectCache_Plugin.php
new file mode 100644
index 0000000000..dd0139ce56
--- /dev/null
+++ b/wp-content/plugins/w3-total-cache/ObjectCache_Plugin.php
@@ -0,0 +1,344 @@
+_config = Dispatcher::config();
+ }
+
+ /**
+ * Runs plugin
+ */
+ function run() {
+ add_filter( 'cron_schedules', array(
+ $this,
+ 'cron_schedules'
+ ) );
+
+ add_filter( 'w3tc_footer_comment', array(
+ $this,
+ 'w3tc_footer_comment'
+ ) );
+
+ if ( $this->_config->get_string( 'objectcache.engine' ) == 'file' ) {
+ add_action( 'w3_objectcache_cleanup', array(
+ $this,
+ 'cleanup'
+ ) );
+ }
+
+ if ( $this->_do_flush() ) {
+ add_action( 'clean_post_cache', array(
+ $this,
+ 'on_post_change'
+ ), 0, 2 );
+ }
+
+ if ( $this->_do_flush() ) {
+ add_action( 'comment_post', array(
+ $this,
+ 'on_comment_change'
+ ), 0 );
+
+ add_action( 'edit_comment', array(
+ $this,
+ 'on_comment_change'
+ ), 0 );
+
+ add_action( 'delete_comment', array(
+ $this,
+ 'on_comment_change'
+ ), 0 );
+
+ add_action( 'wp_set_comment_status', array(
+ $this,
+ 'on_comment_status'
+ ), 0, 2 );
+
+ add_action( 'trackback_post', array(
+ $this,
+ 'on_comment_change'
+ ), 0 );
+
+ add_action( 'pingback_post', array(
+ $this,
+ 'on_comment_change'
+ ), 0 );
+ }
+
+ add_action( 'switch_theme', array(
+ $this,
+ 'on_change'
+ ), 0 );
+
+ if ( $this->_do_flush() ) {
+ add_action( 'updated_option', array(
+ $this,
+ 'on_change_option'
+ ), 0, 1 );
+ add_action( 'added_option', array(
+ $this,
+ 'on_change_option'
+ ), 0, 1 );
+
+ add_action( 'delete_option', array(
+ $this,
+ 'on_change_option'
+ ), 0, 1 );
+ }
+
+ add_action( 'edit_user_profile_update', array(
+ $this,
+ 'on_change_profile'
+ ), 0 );
+
+ add_filter( 'w3tc_admin_bar_menu',
+ array( $this, 'w3tc_admin_bar_menu' ) );
+
+ // usage statistics handling
+ add_action( 'w3tc_usage_statistics_of_request', array(
+ $this, 'w3tc_usage_statistics_of_request' ), 10, 1 );
+ add_filter( 'w3tc_usage_statistics_metrics', array(
+ $this, 'w3tc_usage_statistics_metrics' ) );
+ add_filter( 'w3tc_usage_statistics_sources', array(
+ $this, 'w3tc_usage_statistics_sources' ) );
+
+
+ if ( Util_Environment::is_wpmu() ) {
+ add_action( 'delete_blog', array(
+ $this,
+ 'on_change'
+ ), 0 );
+
+ add_action( 'switch_blog', array(
+ $this,
+ 'switch_blog'
+ ), 0, 2 );
+ }
+ }
+
+ /**
+ * Does disk cache cleanup
+ *
+ * @return void
+ */
+ function cleanup() {
+ $w3_cache_file_cleaner = new Cache_File_Cleaner( array(
+ 'cache_dir' => Util_Environment::cache_blog_dir( 'object' ),
+ 'clean_timelimit' => $this->_config->get_integer( 'timelimit.cache_gc' )
+ ) );
+
+ $w3_cache_file_cleaner->clean();
+ }
+
+ /**
+ * Cron schedules filter
+ *
+ * @param array $schedules
+ * @return array
+ */
+ function cron_schedules( $schedules ) {
+ $gc = $this->_config->get_integer( 'objectcache.file.gc' );
+
+ return array_merge( $schedules, array(
+ 'w3_objectcache_cleanup' => array(
+ 'interval' => $gc,
+ 'display' => sprintf( '[W3TC] Object Cache file GC (every %d seconds)', $gc )
+ )
+ ) );
+ }
+
+ /**
+ * Change action
+ */
+ function on_change() {
+ static $flushed = false;
+
+ if ( !$flushed ) {
+ $flush = Dispatcher::component( 'CacheFlush' );
+ $flush->objectcache_flush();
+ $flushed = true;
+ }
+ }
+
+ /**
+ * Change post action
+ */
+ function on_post_change( $post_id = 0, $post = null ) {
+ static $flushed = false;
+
+ if ( !$flushed ) {
+ if ( is_null( $post ) )
+ $post = $post_id;
+
+ if ( $post_id> 0 && !Util_Environment::is_flushable_post(
+ $post, 'objectcache', $this->_config ) ) {
+ return;
+ }
+
+ $flush = Dispatcher::component( 'CacheFlush' );
+ $flush->objectcache_flush();
+ $flushed = true;
+ }
+ }
+
+ /**
+ * Change action
+ */
+ function on_change_option( $option ) {
+ static $flushed = false;
+/*
+ if ( !$flushed ) {
+ if ( $option != 'cron' ) {
+ $flush = Dispatcher::component( 'CacheFlush' );
+ $flush->objectcache_flush();
+ $flushed = true;
+ }
+ }*/
+ }
+
+ /**
+ * Flush cache when user profile is updated
+ *
+ * @param int $user_id
+ */
+ function on_change_profile( $user_id ) {
+ static $flushed = false;
+
+ if ( !$flushed ) {
+ if ( Util_Environment::is_wpmu() ) {
+ $blogs = get_blogs_of_user( $user_id, true );
+ if ( $blogs ) {
+ global $w3_multisite_blogs;
+ $w3_multisite_blogs = $blogs;
+ }
+ }
+
+ $flush = Dispatcher::component( 'CacheFlush' );
+ $flush->objectcache_flush();
+
+ $flushed = true;
+ }
+ }
+
+ /**
+ * Switch blog action
+ */
+ function switch_blog( $blog_id, $previous_blog_id ) {
+ $o = Dispatcher::component( 'ObjectCache_WpObjectCache_Regular' );
+ $o->switch_blog( $blog_id );
+ }
+
+
+ /**
+ * Comment change action
+ *
+ * @param integer $comment_id
+ */
+ function on_comment_change( $comment_id ) {
+ $post_id = 0;
+
+ if ( $comment_id ) {
+ $comment = get_comment( $comment_id, ARRAY_A );
+ $post_id = ( !empty( $comment['comment_post_ID'] ) ?
+ (int) $comment['comment_post_ID'] : 0 );
+ }
+
+ $this->on_post_change( $post_id );
+ }
+
+ /**
+ * Comment status action
+ *
+ * @param integer $comment_id
+ * @param string $status
+ */
+ function on_comment_status( $comment_id, $status ) {
+ if ( $status === 'approve' || $status === '1' ) {
+ $this->on_comment_change( $comment_id );
+ }
+ }
+
+ public function w3tc_admin_bar_menu( $menu_items ) {
+ $menu_items['20410.objectcache'] = array(
+ 'id' => 'w3tc_flush_objectcache',
+ 'parent' => 'w3tc_flush',
+ 'title' => __( 'Object Cache', 'w3-total-cache' ),
+ 'href' => wp_nonce_url( admin_url(
+ 'admin.php?page=w3tc_dashboard&w3tc_flush_objectcache' ), 'w3tc' )
+ );
+
+ return $menu_items;
+ }
+
+ public function w3tc_footer_comment( $strings ) {
+ $o = Dispatcher::component( 'ObjectCache_WpObjectCache_Regular' );
+ $strings = $o->w3tc_footer_comment( $strings );
+
+ return $strings;
+ }
+
+ public function w3tc_usage_statistics_of_request( $storage ) {
+ $o = Dispatcher::component( 'ObjectCache_WpObjectCache_Regular' );
+ $o->w3tc_usage_statistics_of_request( $storage );
+ }
+
+ public function w3tc_usage_statistics_metrics( $metrics ) {
+ $metrics = array_merge( $metrics, array(
+ 'objectcache_get_total',
+ 'objectcache_get_hits',
+ 'objectcache_sets',
+ 'objectcache_flushes',
+ 'objectcache_time_ms'
+ ) );
+
+ return $metrics;
+ }
+
+ public function w3tc_usage_statistics_sources($sources) {
+ $c = Dispatcher::config();
+ if ( $c->get_string( 'objectcache.engine' ) == 'apc' ) {
+ $sources['apc_servers']['objectcache'] = array(
+ 'name' => __( 'Object Cache', 'w3-total-cache' )
+ );
+ } elseif ( $c->get_string( 'objectcache.engine' ) == 'memcached' ) {
+ $sources['memcached_servers']['objectcache'] = array(
+ 'servers' => $c->get_array( 'objectcache.memcached.servers' ),
+ 'username' => $c->get_string( 'objectcache.memcached.username' ),
+ 'password' => $c->get_string( 'objectcache.memcached.password' ),
+ 'binary_protocol' => $c->get_boolean( 'objectcache.memcached.binary_protocol' ),
+ 'name' => __( 'Object Cache', 'w3-total-cache' )
+ );
+ } elseif ( $c->get_string( 'objectcache.engine' ) == 'redis' ) {
+ $sources['redis_servers']['objectcache'] = array(
+ 'servers' => $c->get_array( 'objectcache.redis.servers' ),
+ 'username' => $c->get_boolean( 'objectcache.redis.username' ),
+ 'dbid' => $c->get_integer( 'objectcache.redis.dbid' ),
+ 'password' => $c->get_string( 'objectcache.redis.password' ),
+ 'name' => __( 'Object Cache', 'w3-total-cache' )
+ );
+ }
+
+ return $sources;
+ }
+
+ /**
+ *
+ *
+ * @return bool
+ */
+ private function _do_flush() {
+ //TODO: Requires admin flush until OC can make changes in Admin backend
+ return $this->_config->get_boolean( 'cluster.messagebus.enabled' )
+ || $this->_config->get_boolean( 'objectcache.purge.all' )
+ || defined( 'WP_ADMIN' );
+ }
+}
diff --git a/wp-content/plugins/w3-total-cache/ObjectCache_Plugin_Admin.php b/wp-content/plugins/w3-total-cache/ObjectCache_Plugin_Admin.php
new file mode 100644
index 0000000000..b3d02c02f0
--- /dev/null
+++ b/wp-content/plugins/w3-total-cache/ObjectCache_Plugin_Admin.php
@@ -0,0 +1,92 @@
+get_boolean( 'objectcache.enabled' ) ) {
+ add_filter( 'w3tc_errors', array( $this, 'w3tc_errors' ) );
+ add_filter( 'w3tc_notes', array( $this, 'w3tc_notes' ) );
+ add_filter( 'w3tc_usage_statistics_summary_from_history', array(
+ $this, 'w3tc_usage_statistics_summary_from_history' ), 10, 2 );
+ }
+ }
+
+
+
+ public function w3tc_errors( $errors ) {
+ $c = Dispatcher::config();
+
+ if ( $c->get_string( 'objectcache.engine' ) == 'memcached' ) {
+ $memcached_servers = $c->get_array(
+ 'objectcache.memcached.servers' );
+
+ if ( !Util_Installed::is_memcache_available( $memcached_servers ) ) {
+ if ( !isset( $errors['memcache_not_responding.details'] ) )
+ $errors['memcache_not_responding.details'] = array();
+
+ $errors['memcache_not_responding.details'][] = sprintf(
+ __( 'Object Cache: %s.', 'w3-total-cache' ),
+ implode( ', ', $memcached_servers ) );
+ }
+ }
+
+ return $errors;
+ }
+
+
+
+ public function w3tc_notes( $notes ) {
+ $c = Dispatcher::config();
+ $state = Dispatcher::config_state();
+ $state_note = Dispatcher::config_state_note();
+
+ /**
+ * Show notification when object cache needs to be emptied
+ */
+ if ( $state_note->get( 'objectcache.show_note.flush_needed' ) &&
+ !is_network_admin() /* flushed dont work under network admin */ &&
+ !$c->is_preview() ) {
+ $notes['objectcache_flush_needed'] = sprintf(
+ __( 'The setting change(s) made either invalidate the cached data or modify the behavior of the site. %s now to provide a consistent user experience.',
+ 'w3-total-cache' ),
+ Util_Ui::button_link(
+ __( 'Empty the object cache', 'w3-total-cache' ),
+ Util_Ui::url( array( 'w3tc_flush_objectcache' => 'y' ) ) ) );
+ }
+
+ return $notes;
+ }
+
+
+
+ public function w3tc_usage_statistics_summary_from_history( $summary, $history ) {
+ // counters
+ $get_total = Util_UsageStatistics::sum( $history, 'objectcache_get_total' );
+ $get_hits = Util_UsageStatistics::sum( $history, 'objectcache_get_hits' );
+ $sets = Util_UsageStatistics::sum( $history, 'objectcache_sets' );
+
+ $c = Dispatcher::config();
+ $e = $c->get_string( 'objectcache.engine' );
+
+ $summary['objectcache'] = array(
+ 'get_total' => Util_UsageStatistics::integer( $get_total ),
+ 'get_hits' => Util_UsageStatistics::integer( $get_hits ),
+ 'sets' => Util_UsageStatistics::integer( $sets ),
+ 'flushes' => Util_UsageStatistics::integer(
+ Util_UsageStatistics::sum( $history, 'objectcache_flushes' ) ),
+ 'time_ms' => Util_UsageStatistics::integer(
+ Util_UsageStatistics::sum( $history, 'objectcache_time_ms' ) ),
+ 'calls_per_second' => Util_UsageStatistics::value_per_period_seconds(
+ $get_total + $sets, $summary ),
+ 'hit_rate' => Util_UsageStatistics::percent(
+ $get_hits, $get_total ),
+ 'engine_name' => Cache::engine_name( $e )
+ );
+
+ return $summary;
+ }
+}
diff --git a/wp-content/plugins/w3-total-cache/ObjectCache_WpObjectCache.php b/wp-content/plugins/w3-total-cache/ObjectCache_WpObjectCache.php
new file mode 100644
index 0000000000..d0566c42a8
--- /dev/null
+++ b/wp-content/plugins/w3-total-cache/ObjectCache_WpObjectCache.php
@@ -0,0 +1,193 @@
+_config = Dispatcher::config();
+ $this->_default_cache = Dispatcher::component(
+ 'ObjectCache_WpObjectCache_Regular' );
+ $this->_caches[] = $this->_default_cache;
+ }
+
+ /**
+ * Registers cache object so that its used for specific groups of
+ * object cache instead of default cache
+ */
+ public function register_cache( $cache, $use_for_object_groups ) {
+ $this->_caches[] = $cache;
+ foreach ( $use_for_object_groups as $group )
+ $this->_cache_by_group[$group] = $cache;
+ }
+
+ /**
+ * Get from the cache
+ *
+ * @param string $id
+ * @param string $group
+ * @return mixed
+ */
+ function get( $id, $group = 'default', $force = false, &$found = null ) {
+ $cache = $this->_get_engine( $group );
+ return $cache->get( $id, $group, $force, $found );
+ }
+
+ /**
+ * Set to the cache
+ *
+ * @param string $id
+ * @param mixed $data
+ * @param string $group
+ * @param integer $expire
+ * @return boolean
+ */
+ function set( $id, $data, $group = 'default', $expire = 0 ) {
+ $cache = $this->_get_engine( $group );
+ return $cache->set( $id, $data, $group, $expire );
+ }
+
+ /**
+ * Delete from the cache
+ *
+ * @param string $id
+ * @param string $group
+ * @param bool $force
+ * @return boolean
+ */
+ function delete( $id, $group = 'default', $force = false ) {
+ $cache = $this->_get_engine( $group );
+ return $cache->delete( $id, $group, $force );
+ }
+
+ /**
+ * Add to the cache
+ *
+ * @param string $id
+ * @param mixed $data
+ * @param string $group
+ * @param integer $expire
+ * @return boolean
+ */
+ function add( $id, $data, $group = 'default', $expire = 0 ) {
+ $cache = $this->_get_engine( $group );
+ return $cache->add( $id, $data, $group, $expire );
+ }
+
+ /**
+ * Replace in the cache
+ *
+ * @param string $id
+ * @param mixed $data
+ * @param string $group
+ * @param integer $expire
+ * @return boolean
+ */
+ function replace( $id, $data, $group = 'default', $expire = 0 ) {
+ $cache = $this->_get_engine( $group );
+ return $cache->replace( $id, $data, $group, $expire );
+ }
+
+ /**
+ * Reset keys
+ *
+ * @return boolean
+ */
+ function reset() {
+ $result = true;
+ foreach ( $this->_caches as $engine )
+ $result = $result && $engine->reset();
+ return $result;
+ }
+
+ /**
+ * Flush cache
+ *
+ * @return boolean
+ */
+ function flush() {
+ $result = true;
+ foreach ( $this->_caches as $engine )
+ $result = $result && $engine->flush();
+ return $result;
+ }
+
+ /**
+ * Add global groups
+ *
+ * @param array $groups
+ * @return void
+ */
+ function add_global_groups( $groups ) {
+ if ( !is_array( $groups ) )
+ $groups = array( $groups );
+
+ foreach ( $groups as $group ) {
+ $cache = $this->_get_engine( $group );
+ $cache->add_global_groups( array( $group ) );
+ }
+ }
+
+ /**
+ * Add non-persistent groups
+ *
+ * @param array $groups
+ * @return void
+ */
+ function add_nonpersistent_groups( $groups ) {
+ if ( !is_array( $groups ) )
+ $groups = array( $groups );
+
+ foreach ( $groups as $group ) {
+ $cache = $this->_get_engine( $group );
+ $cache->add_nonpersistent_groups( array( $group ) );
+ }
+ }
+
+ /**
+ * Return engine based on which group the OC value belongs to.
+ *
+ * @param string $group
+ * @return mixed
+ */
+ private function _get_engine( $group = '' ) {
+ if ( isset( $this->_cache_by_group[$group] ) )
+ return $this->_cache_by_group[$group];
+
+ return $this->_default_cache;
+ }
+
+ /**
+ * Decrement numeric cache item's value
+ *
+ * @param int|string $id The cache key to increment
+ * @param int $offset The amount by which to decrement the item's value. Default is 1.
+ * @param string $group The group the key is in.
+ * @return bool|int False on failure, the item's new value on success.
+ */
+ function decr( $id, $offset = 1, $group = 'default' ) {
+ $cache = $this->_get_engine( $group );
+ return $cache->decr( $id, $offset, $group );
+ }
+
+ /**
+ * Increment numeric cache item's value
+ *
+ * @param int|string $id The cache key to increment
+ * @param int $offset The amount by which to increment the item's value. Default is 1.
+ * @param string $group The group the key is in.
+ * @return false|int False on failure, the item's new value on success.
+ */
+ function incr( $id, $offset = 1, $group = 'default' ) {
+ $cache = $this->_get_engine( $group );
+ return $cache->incr( $id, $offset, $group );
+ }
+
+ function switch_to_blog( $blog_id ) {
+ foreach ( $this->_caches as $cache )
+ $cache->switch_blog( $blog_id );
+ }
+}
diff --git a/wp-content/plugins/w3-total-cache/ObjectCache_WpObjectCache_Regular.php b/wp-content/plugins/w3-total-cache/ObjectCache_WpObjectCache_Regular.php
new file mode 100644
index 0000000000..fb6544cac5
--- /dev/null
+++ b/wp-content/plugins/w3-total-cache/ObjectCache_WpObjectCache_Regular.php
@@ -0,0 +1,922 @@
+_config = Dispatcher::config();
+ $this->_lifetime = $this->_config->get_integer( 'objectcache.lifetime' );
+ $this->_debug = $this->_config->get_boolean( 'objectcache.debug' );
+ $this->_caching = $this->_can_cache();
+ $this->global_groups = $this->_config->get_array( 'objectcache.groups.global' );
+ $this->nonpersistent_groups = $this->_config->get_array(
+ 'objectcache.groups.nonpersistent' );
+ $this->stats_enabled = $this->_config->get_boolean( 'stats.enabled' );
+
+ $this->_blog_id = Util_Environment::blog_id();
+ }
+
+ /**
+ * Get from the cache
+ *
+ * @param string $id
+ * @param string $group
+ * @return mixed
+ */
+ function get( $id, $group = 'default', $force = false, &$found = null ) {
+ if ( $this->_debug || $this->stats_enabled ) {
+ $time_start = Util_Debug::microtime();
+ }
+
+ if ( empty( $group ) ) {
+ $group = 'default';
+ }
+
+ $key = $this->_get_cache_key( $id, $group );
+ $in_incall_cache = isset( $this->cache[$key] );
+ $fallback_used = false;
+
+ $cache_total_inc = 0;
+ $cache_hits_inc = 0;
+
+ if ( $in_incall_cache && !$force ) {
+ $found = true;
+ $value = $this->cache[$key];
+ } elseif ( $this->_caching &&
+ !in_array( $group, $this->nonpersistent_groups ) &&
+ $this->_check_can_cache_runtime( $group ) ) {
+ $cache = $this->_get_cache( null, $group );
+ $v = $cache->get( $key );
+
+ /* for debugging
+ $a = $cache->_get_with_old_raw( $key );
+ $path = $cache->get_full_path( $key);
+ $returned = 'x ' . $path . ' ' .
+ (is_readable( $path ) ? ' readable ' : ' not-readable ') .
+ json_encode($a);
+ */
+
+ $cache_total_inc = 1;
+
+ if ( is_array( $v ) && isset( $v['content'] ) ) {
+ $found = true;
+ $value = $v['content'];
+ $cache_hits_inc = 1;
+ } else {
+ $found = false;
+ $value = false;
+ }
+ } else {
+ $found = false;
+ $value = false;
+ }
+
+ if ( $value === null ) {
+ $value = false;
+ }
+
+ if ( is_object( $value ) ) {
+ $value = clone $value;
+ }
+
+ if ( !$found &&
+ $this->_is_transient_group( $group ) &&
+ $this->_config->get_boolean( 'objectcache.fallback_transients' ) ) {
+ $fallback_used = true;
+ $value = $this->_transient_fallback_get( $id, $group );
+ $found = ( $value !== false );
+ }
+
+ if ( $found ) {
+ if ( !$in_incall_cache ) {
+ $this->cache[$key] = $value;
+ }
+ }
+
+ /**
+ * Add debug info
+ */
+ if ( !$in_incall_cache ) {
+ $this->cache_total += $cache_total_inc;
+ $this->cache_hits += $cache_hits_inc;
+
+ if ( $this->_debug || $this->stats_enabled ) {
+ $time = Util_Debug::microtime() - $time_start;
+ $this->time_total += $time;
+
+ if ( $this->_debug ) {
+ if ( $fallback_used ) {
+ if ( !$found ) {
+ $returned = 'not in db';
+ } else {
+ $returned = 'from db fallback';
+ }
+ } else {
+ if ( !$found ) {
+ if ( $cache_total_inc <= 0 ) {
+ $returned = 'not tried cache';
+ } else {
+ $returned = 'not in cache';
+ }
+ } else {
+ $returned = 'from persistent cache';
+ }
+ }
+
+ $this->log_call( array(
+ date( 'r' ),
+ 'get',
+ $group,
+ $id,
+ $returned,
+ ( $value ? strlen( serialize( $value ) ) : 0 ),
+ (int)($time * 1000000)
+ ) );
+ }
+ }
+ }
+
+ return $value;
+ }
+
+ /**
+ * Set to the cache
+ *
+ * @param string $id
+ * @param mixed $data
+ * @param string $group
+ * @param integer $expire
+ * @return boolean
+ */
+ function set( $id, $data, $group = 'default', $expire = 0 ) {
+ if ( $this->_debug || $this->stats_enabled ) {
+ $time_start = Util_Debug::microtime();
+ }
+
+ if ( empty( $group ) ) {
+ $group = 'default';
+ }
+
+ $key = $this->_get_cache_key( $id, $group );
+
+ if ( is_object( $data ) ) {
+ $data = clone $data;
+ }
+
+ $this->cache[$key] = $data;
+ $return = true;
+ $ext_return = NULL;
+ $cache_sets_inc = 0;
+
+ if ( $this->_caching &&
+ !in_array( $group, $this->nonpersistent_groups ) &&
+ $this->_check_can_cache_runtime( $group ) ) {
+ $cache = $this->_get_cache( null, $group );
+
+ if ( $id == 'alloptions' && $group == 'options' ) {
+ // alloptions are deserialized on the start when some classes are not loaded yet
+ // so postpone it until requested
+ foreach ( $data as $k => $v ) {
+ if ( is_object( $v ) ) {
+ $data[$k] = serialize( $v );
+ }
+ }
+ }
+
+ $v = array( 'content' => $data );
+ $cache_sets_inc = 1;
+ $ext_return = $cache->set( $key, $v,
+ ( $expire ? $expire : $this->_lifetime ) );
+ $return = $ext_return;
+ }
+
+ if ( $this->_is_transient_group( $group ) &&
+ $this->_config->get_boolean( 'objectcache.fallback_transients' ) ) {
+ $this->_transient_fallback_set( $id, $data, $group, $expire );
+ }
+
+ if ( $this->_debug || $this->stats_enabled ) {
+ $time = Util_Debug::microtime() - $time_start;
+
+ $this->cache_sets += $cache_sets_inc;
+ $this->time_total += $time;
+
+ if ( $this->_debug ) {
+ if ( is_null( $ext_return ) ) {
+ $reason = 'not set ' . $this->cache_reject_reason;
+ } else if ( $ext_return ) {
+ $reason = 'put in cache';
+ } else {
+ $reason = 'failed';
+ }
+
+ $this->log_call( array(
+ date( 'r' ),
+ 'set',
+ $group,
+ $id,
+ $reason,
+ ( $data ? strlen( serialize( $data ) ) : 0 ),
+ (int)($time * 1000000)
+ ) );
+ }
+ }
+
+ return $return;
+ }
+
+ /**
+ * Delete from the cache
+ *
+ * @param string $id
+ * @param string $group
+ * @param bool $force
+ * @return boolean
+ */
+ function delete( $id, $group = 'default', $force = false ) {
+ if ( !$force && $this->get( $id, $group ) === false ) {
+ return false;
+ }
+
+ $key = $this->_get_cache_key( $id, $group );
+ $return = true;
+ unset( $this->cache[$key] );
+
+ if ( $this->_caching && !in_array( $group, $this->nonpersistent_groups ) ) {
+ $cache = $this->_get_cache( null, $group );
+ $return = $cache->delete( $key );
+ }
+
+ if ( $this->_is_transient_group( $group ) &&
+ $this->_config->get_boolean( 'objectcache.fallback_transients' ) ) {
+ $this->_transient_fallback_delete( $id, $group );
+ }
+
+ if ( $this->_debug ) {
+ $this->log_call( array(
+ date( 'r' ),
+ 'delete',
+ $group,
+ $id,
+ ( $return ? 'deleted' : 'discarded' ),
+ 0,
+ 0
+ ) );
+ }
+
+ return $return;
+ }
+
+ /**
+ * Add to the cache
+ *
+ * @param string $id
+ * @param mixed $data
+ * @param string $group
+ * @param integer $expire
+ * @return boolean
+ */
+ function add( $id, $data, $group = 'default', $expire = 0 ) {
+ if ( $this->get( $id, $group ) !== false ) {
+ return false;
+ }
+
+ return $this->set( $id, $data, $group, $expire );
+ }
+
+ /**
+ * Replace in the cache
+ *
+ * @param string $id
+ * @param mixed $data
+ * @param string $group
+ * @param integer $expire
+ * @return boolean
+ */
+ function replace( $id, $data, $group = 'default', $expire = 0 ) {
+ if ( $this->get( $id, $group ) === false ) {
+ return false;
+ }
+
+ return $this->set( $id, $data, $group, $expire );
+ }
+
+ /**
+ * Reset keys
+ *
+ * @return boolean
+ */
+ function reset() {
+ $this->cache = array();
+
+ return true;
+ }
+
+ /**
+ * Flush cache
+ *
+ * @return boolean
+ */
+ function flush( $reason = '' ) {
+ if ( $this->_debug || $this->stats_enabled ) {
+ $time_start = Util_Debug::microtime();
+ }
+ if ( $this->_config->get_boolean( 'objectcache.debug_purge' ) ) {
+ Util_Debug::log_purge( 'objectcache', 'flush', $reason );
+ }
+
+ $this->cache = array();
+
+ global $w3_multisite_blogs;
+ if ( isset( $w3_multisite_blogs ) ) {
+ foreach ( $w3_multisite_blogs as $blog ) {
+ $cache = $this->_get_cache( $blog->userblog_id );
+ $cache->flush();
+ }
+ } else {
+ $cache = $this->_get_cache( 0 );
+ $cache->flush();
+
+ $cache = $this->_get_cache();
+ $cache->flush();
+ }
+
+ if ( $this->_debug || $this->stats_enabled ) {
+ $time = Util_Debug::microtime() - $time_start;
+
+ $this->cache_flushes++;
+ $this->time_total += $time;
+
+ if ( $this->_debug ) {
+ $this->log_call( array(
+ date( 'r' ),
+ 'flush',
+ '',
+ '',
+ $reason,
+ 0,
+ (int)($time * 1000000)
+ ) );
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Add global groups
+ *
+ * @param array $groups
+ * @return void
+ */
+ function add_global_groups( $groups ) {
+ if ( !is_array( $groups ) ) {
+ $groups = (array) $groups;
+ }
+
+ $this->global_groups = array_merge( $this->global_groups, $groups );
+ $this->global_groups = array_unique( $this->global_groups );
+ }
+
+ /**
+ * Add non-persistent groups
+ *
+ * @param array $groups
+ * @return void
+ */
+ function add_nonpersistent_groups( $groups ) {
+ if ( !is_array( $groups ) ) {
+ $groups = (array) $groups;
+ }
+
+ $this->nonpersistent_groups = array_merge( $this->nonpersistent_groups, $groups );
+ $this->nonpersistent_groups = array_unique( $this->nonpersistent_groups );
+ }
+
+ /**
+ * Increment numeric cache item's value
+ *
+ * @param int|string $key The cache key to increment
+ * @param int $offset The amount by which to increment the item's value. Default is 1.
+ * @param string $group The group the key is in.
+ * @return bool|int False on failure, the item's new value on success.
+ */
+ function incr( $key, $offset = 1, $group = 'default' ) {
+ $value = $this->get( $key, $group );
+ if ( $value === false )
+ return false;
+
+ if ( !is_numeric( $value ) )
+ $value = 0;
+
+ $offset = (int) $offset;
+ $value += $offset;
+
+ if ( $value < 0 )
+ $value = 0;
+ $this->replace( $key, $value, $group );
+ return $value;
+ }
+
+ /**
+ * Decrement numeric cache item's value
+ *
+ * @param int|string $key The cache key to increment
+ * @param int $offset The amount by which to decrement the item's value. Default is 1.
+ * @param string $group The group the key is in.
+ * @return bool|int False on failure, the item's new value on success.
+ */
+ function decr( $key, $offset = 1, $group = 'default' ) {
+ $value = $this->get( $key, $group );
+ if ( $value === false )
+ return false;
+
+ if ( !is_numeric( $value ) )
+ $value = 0;
+
+ $offset = (int) $offset;
+ $value -= $offset;
+
+ if ( $value < 0 )
+ $value = 0;
+ $this->replace( $key, $value, $group );
+ return $value;
+ }
+
+ private function _transient_fallback_get( $transient, $group ) {
+ if ( $group == 'transient' ) {
+ $transient_option = '_transient_' . $transient;
+ if ( function_exists( 'wp_installing') && ! wp_installing() ) {
+ // If option is not in alloptions, it is not autoloaded and thus has a timeout
+ $alloptions = wp_load_alloptions();
+ if ( !isset( $alloptions[$transient_option] ) ) {
+ $transient_timeout = '_transient_timeout_' . $transient;
+ $timeout = get_option( $transient_timeout );
+ if ( false !== $timeout && $timeout < time() ) {
+ delete_option( $transient_option );
+ delete_option( $transient_timeout );
+ $value = false;
+ }
+ }
+ }
+
+ if ( ! isset( $value ) )
+ $value = get_option( $transient_option );
+ } elseif ( $group == 'site-transient' ) {
+ // Core transients that do not have a timeout. Listed here so querying timeouts can be avoided.
+ $no_timeout = array('update_core', 'update_plugins', 'update_themes');
+ $transient_option = '_site_transient_' . $transient;
+ if ( ! in_array( $transient, $no_timeout ) ) {
+ $transient_timeout = '_site_transient_timeout_' . $transient;
+ $timeout = get_site_option( $transient_timeout );
+ if ( false !== $timeout && $timeout < time() ) {
+ delete_site_option( $transient_option );
+ delete_site_option( $transient_timeout );
+ $value = false;
+ }
+ }
+
+ if ( ! isset( $value ) )
+ $value = get_site_option( $transient_option );
+ } else {
+ $value = false;
+ }
+
+ return $value;
+ }
+
+ private function _transient_fallback_delete( $transient, $group ) {
+ if ( $group == 'transient' ) {
+ $option_timeout = '_transient_timeout_' . $transient;
+ $option = '_transient_' . $transient;
+ $result = delete_option( $option );
+ if ( $result )
+ delete_option( $option_timeout );
+ } elseif ( $group == 'site-transient' ) {
+ $option_timeout = '_site_transient_timeout_' . $transient;
+ $option = '_site_transient_' . $transient;
+ $result = delete_site_option( $option );
+ if ( $result )
+ delete_site_option( $option_timeout );
+ }
+ }
+
+ private function _transient_fallback_set( $transient, $value, $group, $expiration ) {
+ if ( $group == 'transient' ) {
+ $transient_timeout = '_transient_timeout_' . $transient;
+ $transient_option = '_transient_' . $transient;
+ if ( false === get_option( $transient_option ) ) {
+ $autoload = 'yes';
+ if ( $expiration ) {
+ $autoload = 'no';
+ add_option( $transient_timeout, time() + $expiration, '', 'no' );
+ }
+ $result = add_option( $transient_option, $value, '', $autoload );
+ } else {
+ // If expiration is requested, but the transient has no timeout option,
+ // delete, then re-create transient rather than update.
+ $update = true;
+ if ( $expiration ) {
+ if ( false === get_option( $transient_timeout ) ) {
+ delete_option( $transient_option );
+ add_option( $transient_timeout, time() + $expiration, '', 'no' );
+ $result = add_option( $transient_option, $value, '', 'no' );
+ $update = false;
+ } else {
+ update_option( $transient_timeout, time() + $expiration );
+ }
+ }
+ if ( $update ) {
+ $result = update_option( $transient_option, $value );
+ }
+ }
+ } elseif ( $group == 'site-transient' ) {
+ $transient_timeout = '_site_transient_timeout_' . $transient;
+ $option = '_site_transient_' . $transient;
+ if ( false === get_site_option( $option ) ) {
+ if ( $expiration )
+ add_site_option( $transient_timeout, time() + $expiration );
+ $result = add_site_option( $option, $value );
+ } else {
+ if ( $expiration )
+ update_site_option( $transient_timeout, time() + $expiration );
+ $result = update_site_option( $option, $value );
+ }
+ }
+ }
+
+ /**
+ * Switches context to another blog
+ *
+ * @param integer $blog_id
+ */
+ function switch_blog( $blog_id ) {
+ $this->reset();
+ $this->_blog_id = $blog_id;
+ }
+
+ /**
+ * Returns cache key
+ *
+ * @param string $id
+ * @param string $group
+ * @return string
+ */
+ function _get_cache_key( $id, $group = 'default' ) {
+ if ( !$group ) {
+ $group = 'default';
+ }
+
+ $blog_id = $this->_blog_id;
+ if ( in_array( $group, $this->global_groups ) )
+ $blog_id = 0;
+
+ return $blog_id . $group . $id;
+ }
+
+ public function get_usage_statistics_cache_config() {
+ $engine = $this->_config->get_string( 'objectcache.engine' );
+
+ switch ( $engine ) {
+ case 'memcached':
+ $engineConfig = array(
+ 'servers' => $this->_config->get_array( 'objectcache.memcached.servers' ),
+ 'persistent' => $this->_config->get_boolean( 'objectcache.memcached.persistent' ),
+ 'aws_autodiscovery' => $this->_config->get_boolean( 'objectcache.memcached.aws_autodiscovery' ),
+ 'username' => $this->_config->get_string( 'objectcache.memcached.username' ),
+ 'password' => $this->_config->get_string( 'objectcache.memcached.password' ),
+ 'binary_protocol' => $this->_config->get_boolean( 'objectcache.memcached.binary_protocol' )
+ );
+ break;
+
+ case 'redis':
+ $engineConfig = array(
+ 'servers' => $this->_config->get_array( 'objectcache.redis.servers' ),
+ 'persistent' => $this->_config->get_boolean( 'objectcache.redis.persistent' ),
+ 'dbid' => $this->_config->get_integer( 'objectcache.redis.dbid' ),
+ 'password' => $this->_config->get_string( 'objectcache.redis.password' )
+ );
+ break;
+
+ default:
+ $engineConfig = array();
+ }
+
+ $engineConfig['engine'] = $engine;
+ return $engineConfig;
+ }
+
+ /**
+ * Returns cache object
+ *
+ * @param int|null $blog_id
+ * @param string $group
+ * @return W3_Cache_Base
+ */
+ function _get_cache( $blog_id = null, $group = '' ) {
+ static $cache = array();
+
+ if ( is_null( $blog_id ) && !in_array( $group, $this->global_groups ) )
+ $blog_id = $this->_blog_id;
+ elseif ( is_null( $blog_id ) )
+ $blog_id = 0;
+
+ if ( !isset( $cache[$blog_id] ) ) {
+ $engine = $this->_config->get_string( 'objectcache.engine' );
+
+ switch ( $engine ) {
+ case 'memcached':
+ $engineConfig = array(
+ 'servers' => $this->_config->get_array( 'objectcache.memcached.servers' ),
+ 'persistent' => $this->_config->get_boolean(
+ 'objectcache.memcached.persistent' ),
+ 'aws_autodiscovery' => $this->_config->get_boolean( 'objectcache.memcached.aws_autodiscovery' ),
+ 'username' => $this->_config->get_string( 'objectcache.memcached.username' ),
+ 'password' => $this->_config->get_string( 'objectcache.memcached.password' ),
+ 'binary_protocol' => $this->_config->get_boolean( 'objectcache.memcached.binary_protocol' )
+ );
+ break;
+
+ case 'redis':
+ $engineConfig = array(
+ 'servers' => $this->_config->get_array( 'objectcache.redis.servers' ),
+ 'persistent' => $this->_config->get_boolean(
+ 'objectcache.redis.persistent' ),
+ 'dbid' => $this->_config->get_integer( 'objectcache.redis.dbid' ),
+ 'password' => $this->_config->get_string( 'objectcache.redis.password' )
+ );
+ break;
+
+ case 'file':
+ $engineConfig = array(
+ 'section' => 'object',
+ 'locking' => $this->_config->get_boolean( 'objectcache.file.locking' ),
+ 'flush_timelimit' => $this->_config->get_integer( 'timelimit.cache_flush' )
+ );
+ break;
+
+ default:
+ $engineConfig = array();
+ }
+ $engineConfig['blog_id'] = $blog_id;
+ $engineConfig['module'] = 'object';
+ $engineConfig['host'] = Util_Environment::host();
+ $engineConfig['instance_id'] = Util_Environment::instance_id();
+
+ $cache[$blog_id] = Cache::instance( $engine, $engineConfig );
+ }
+
+ return $cache[$blog_id];
+ }
+
+ /**
+ * Check if caching allowed on init
+ *
+ * @return boolean
+ */
+ function _can_cache() {
+ /**
+ * Don't cache in console mode
+ */
+ if ( PHP_SAPI === 'cli' ) {
+ $this->cache_reject_reason = 'Console mode';
+
+ return false;
+ }
+
+ /**
+ * Skip if disabled
+ */
+ if ( !$this->_config->get_boolean( 'objectcache.enabled' ) ) {
+ $this->cache_reject_reason = 'objectcache.disabled';
+
+ return false;
+ }
+
+ /**
+ * Check for DONOTCACHEOBJECT constant
+ */
+ if ( defined( 'DONOTCACHEOBJECT' ) && DONOTCACHEOBJECT ) {
+ $this->cache_reject_reason = 'DONOTCACHEOBJECT';
+
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Returns if we can cache, that condition can change in runtime
+ *
+ * @param unknown $group
+ * @return boolean
+ */
+ function _check_can_cache_runtime( $group ) {
+ //Need to be handled in wp admin as well as frontend
+ if ( $this->_is_transient_group( $group ) )
+ return true;
+
+ if ( $this->_can_cache_dynamic != null )
+ return $this->_can_cache_dynamic;
+
+ if ( $this->_config->get_boolean( 'objectcache.enabled_for_wp_admin' ) ) {
+ $this->_can_cache_dynamic = true;
+ } else {
+ if ( $this->_caching ) {
+ if ( defined( 'WP_ADMIN' ) &&
+ ( !defined( 'DOING_AJAX' ) || !DOING_AJAX ) ) {
+ $this->_can_cache_dynamic = false;
+ $this->cache_reject_reason = 'WP_ADMIN defined';
+ return $this->_can_cache_dynamic;
+ }
+ }
+ }
+
+ return $this->_caching;
+ }
+
+ private function _is_transient_group( $group ) {
+ return in_array( $group, array( 'transient', 'site-transient' ) ) ;
+ }
+
+ public function w3tc_footer_comment( $strings ) {
+ $reason = $this->get_reject_reason();
+ $append = empty( $reason ) ? '' : sprintf( ' (%1$s)', $reason );
+
+ $strings[] = sprintf(
+ // translators: 1: Cache hits, 2: Cache total cache objects, 3: Engine anme, 4: Reason.
+ __( 'Object Caching %1$d/%2$d objects using %3$s%4$s', 'w3-total-cache' ),
+ $this->cache_hits,
+ $this->cache_total,
+ Cache::engine_name( $this->_config->get_string( 'objectcache.engine' ) ),
+ $append
+ );
+
+ if ( $this->_config->get_boolean( 'objectcache.debug' ) ) {
+ $strings[] = '';
+ $strings[] = 'Object Cache debug info:';
+ $strings[] = sprintf( "%s%s", str_pad( 'Caching: ', 20 ),
+ ( $this->_caching ? 'enabled' : 'disabled' ) );
+
+ $strings[] = sprintf( "%s%d", str_pad( 'Total calls: ', 20 ), $this->cache_total );
+ $strings[] = sprintf( "%s%d", str_pad( 'Cache hits: ', 20 ), $this->cache_hits );
+ $strings[] = sprintf( "%s%.4f", str_pad( 'Total time: ', 20 ), $this->time_total );
+
+ if ( $this->log_filehandle ) {
+ fclose( $this->log_filehandle );
+ $this->log_filehandle = false;
+ }
+ }
+
+ return $strings;
+ }
+
+ public function w3tc_usage_statistics_of_request( $storage ) {
+ $storage->counter_add( 'objectcache_get_total', $this->cache_total );
+ $storage->counter_add( 'objectcache_get_hits', $this->cache_hits );
+ $storage->counter_add( 'objectcache_sets', $this->cache_sets );
+ $storage->counter_add( 'objectcache_flushes', $this->cache_flushes );
+ $storage->counter_add( 'objectcache_time_ms', (int)($this->time_total * 1000) );
+ }
+
+ public function get_reject_reason() {
+ if ( is_null( $this->cache_reject_reason ) )
+ return '';
+ return $this->_get_reject_reason_message( $this->cache_reject_reason );
+ }
+
+ /**
+ *
+ *
+ * @param unknown $key
+ * @return string|void
+ */
+ private function _get_reject_reason_message( $key ) {
+ if ( !function_exists( '__' ) )
+ return $key;
+
+ switch ( $key ) {
+ case 'objectcache.disabled':
+ return __( 'Object caching is disabled', 'w3-total-cache' );
+ case 'DONOTCACHEOBJECT':
+ return __( 'DONOTCACHEOBJECT constant is defined', 'w3-total-cache' );
+ default:
+ return '';
+ }
+ }
+
+
+
+ private function log_call( $line ) {
+ if ( !$this->log_filehandle ) {
+ $filename = Util_Debug::log_filename( 'objectcache-calls' );
+ $this->log_filehandle = fopen( $filename, 'a' );
+ }
+
+ fputcsv ( $this->log_filehandle, $line, "\t" );
+ }
+}
diff --git a/wp-content/plugins/w3-total-cache/PageSpeed_Api.php b/wp-content/plugins/w3-total-cache/PageSpeed_Api.php
new file mode 100644
index 0000000000..e92292c345
--- /dev/null
+++ b/wp-content/plugins/w3-total-cache/PageSpeed_Api.php
@@ -0,0 +1,128 @@
+key = $api_key;
+ $this->key_restrict_referrer = $api_ref;
+ }
+
+
+
+ public function analyze( $url ) {
+ return array(
+ 'mobile' => $this->analyze_strategy( $url, 'mobile' ),
+ 'desktop' => $this->analyze_strategy( $url, 'desktop' ),
+ 'test_url' => Util_Environment::url_format(
+ 'https://developers.google.com/speed/pagespeed/insights/',
+ array( 'url' => $url ) )
+ );
+ }
+
+
+
+ public function analyze_strategy( $url, $strategy ) {
+ $json = $this->_request( array(
+ 'url' => $url,
+ 'category' => 'performance',
+ 'strategy' => $strategy
+ ) );
+
+ if ( !$json ) {
+ return null;
+ }
+
+ $data = array();
+ try {
+ $data = json_decode( $json, true );
+ } catch ( \Exception $e ) {
+ }
+
+ return array(
+ 'score' => $this->v( $data, array( 'lighthouseResult', 'categories', 'performance', 'score' ) ) * 100,
+ 'metrics' => $this->v( $data, array( 'loadingExperience', 'metrics' ) )
+ );
+ }
+
+
+
+ public function get_page_score( $url ) {
+ $json = $this->_request( array(
+ 'url' => $url,
+ 'category' => 'performance',
+ 'strategy' => 'desktop'
+ ) );
+
+ if ( !$json ) {
+ return null;
+ }
+
+ $data = array();
+ try {
+ $data = json_decode( $json, true );
+ } catch ( \Exception $e ) {
+ }
+
+ return $this->v( $data, array( 'lighthouseResult', 'categories', 'performance', 'score' ) );
+ }
+
+
+
+ /**
+ * Make API request
+ *
+ * @param string $url
+ * @return string
+ */
+ function _request( $query ) {
+ $request_url = Util_Environment::url_format( W3TC_PAGESPEED_API_URL,
+ array_merge( $query, array(
+ 'key' => $this->key
+ ) ) );
+
+ $response = Util_Http::get( $request_url, array(
+ 'timeout' => 120,
+ 'headers' => array( 'Referer' => $this->key_restrict_referrer )
+ ) );
+
+ if ( !is_wp_error( $response ) && $response['response']['code'] == 200 ) {
+ return $response['body'];
+ }
+
+ return false;
+ }
+
+
+
+ function v( $data, $elements ) {
+ if ( empty( $elements ) ) {
+ return $data;
+ }
+
+ $key = array_shift( $elements );
+ if ( !isset( $data[$key] ) ) {
+ return null;
+ }
+
+ return $this->v( $data[$key], $elements );
+ }
+}
diff --git a/wp-content/plugins/w3-total-cache/PageSpeed_Plugin_Widget.php b/wp-content/plugins/w3-total-cache/PageSpeed_Plugin_Widget.php
new file mode 100644
index 0000000000..687ae257f9
--- /dev/null
+++ b/wp-content/plugins/w3-total-cache/PageSpeed_Plugin_Widget.php
@@ -0,0 +1,139 @@
+' .
+ ' ' .
+ __( 'Page Speed Report', 'w3-total-cache' ) .
+ ' ',
+ array( $this, 'widget_pagespeed' ),
+ Util_Ui::admin_url( 'admin.php?page=w3tc_general#miscellaneous' ),
+ 'normal' );
+ }
+
+
+
+ /**
+ * PageSpeed widget
+ *
+ * @return void
+ */
+ public function widget_pagespeed() {
+ $config = Dispatcher::config();
+ $key = $config->get_string( 'widget.pagespeed.key' );
+
+ if ( empty( $key ) )
+ include W3TC_DIR . '/PageSpeed_Widget_View_NotConfigured.php';
+ else
+ include W3TC_DIR . '/PageSpeed_Widget_View.php';
+ }
+
+
+
+ public function w3tc_ajax_pagespeed_widgetdata() {
+ $api_response = null;
+ if ( Util_Request::get( 'cache' ) != 'no' ) {
+ $r = get_transient( 'w3tc_pagespeed_widgetdata' );
+ $r = @json_decode( $r, true );
+ if ( is_array( $r ) && isset( $r['time'] ) &&
+ $r['time'] >= time() - 3600 ) {
+ $api_response = $r;
+ }
+ }
+
+ if ( is_null( $api_response ) ) {
+ $config = Dispatcher::config();
+ $key = $config->get_string( 'widget.pagespeed.key' );
+ $ref = $config->get_string( 'widget.pagespeed.key.restrict.referrer' );
+
+ $w3_pagespeed = new PageSpeed_Api( $key, $ref );
+ $api_response = $w3_pagespeed->analyze( get_home_url() );
+
+ if ( !$api_response ) {
+ echo json_encode( array( 'error' => 'API call failed' ) );
+ return;
+ }
+
+ $api_response['time'] = time();
+ set_transient( 'w3tc_pagespeed_widgetdata', json_encode( $api_response ), 3600 );
+ }
+
+ ob_start();
+ include __DIR__ . '/PageSpeed_Widget_View_FromApi.php';
+ $content = ob_get_contents();
+ ob_end_clean();
+
+ echo json_encode( array( '.w3tcps_content' => $content ) );
+ }
+
+
+
+ public function w3tc_monitoring_score( $score ) {
+ if ( empty( $_SERVER['HTTP_REFERER'] ) ) {
+ return 'n/a';
+ }
+
+ $url = $_SERVER['HTTP_REFERER'];
+
+ $config = Dispatcher::config();
+ $key = $config->get_string( 'widget.pagespeed.key' );
+ $ref = $config->get_string( 'widget.pagespeed.key.restrict.referrer' );
+ $w3_pagespeed = new PageSpeed_Api( $key, $ref );
+
+ $r = $w3_pagespeed->get_page_score( $url );
+
+ if ( !is_null( $r ) ) {
+ $score .= (int)((float)$r * 100) . ' / 100';
+ }
+
+ return $score;
+ }
+}
diff --git a/wp-content/plugins/w3-total-cache/PageSpeed_Widget_View.css b/wp-content/plugins/w3-total-cache/PageSpeed_Widget_View.css
new file mode 100644
index 0000000000..c9d4838430
--- /dev/null
+++ b/wp-content/plugins/w3-total-cache/PageSpeed_Widget_View.css
@@ -0,0 +1,60 @@
+.w3tcps_error {
+ position: absolute;
+}
+
+.w3tcps_scores {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
+.w3tcps_scores p {
+ padding: 0 10px;
+}
+
+.w3tcps_scores section {
+ font-size: 30px;
+ font-weight: bold;
+}
+
+.w3tcps_metric {
+ margin-top: 10px;
+ margin-bottom: 5px;
+}
+
+.w3tcps_barline {
+ display: flex;
+ font-size: 14px;
+ margin-bottom: 2px;
+}
+
+.w3tcps_barline div {
+ text-align: left;
+ padding-left: 10px;
+ min-width: 38px;
+ position: relative;
+}
+
+.w3tcps_barfast {
+ background-color: #0cc66b;
+ color: #fff;
+}
+
+.w3tcps_baraverage {
+ background-color: #ffa400;
+ color: #000;
+}
+
+.w3tcps_barslow {
+ background-color: #ff4e42;
+ color: #fff;
+}
+
+.w3tcps_buttons {
+ display: flex;
+ justify-content: center;
+}
+
+.w3tcps_buttons .button {
+ margin: 5px;
+}
diff --git a/wp-content/plugins/w3-total-cache/PageSpeed_Widget_View.js b/wp-content/plugins/w3-total-cache/PageSpeed_Widget_View.js
new file mode 100644
index 0000000000..64e057461a
--- /dev/null
+++ b/wp-content/plugins/w3-total-cache/PageSpeed_Widget_View.js
@@ -0,0 +1,36 @@
+jQuery(document).ready(function($) {
+ function w3tcps_load(nocache) {
+ $('.w3tcps_loading').removeClass('w3tc_hidden');
+ $('.w3tcps_content').addClass('w3tc_hidden');
+ $('.w3tcps_error').addClass('w3tc_none');
+
+ $.getJSON(ajaxurl + '?action=w3tc_ajax&_wpnonce=' + w3tc_nonce +
+ '&w3tc_action=pagespeed_widgetdata' + (nocache ? '&cache=no' : ''),
+ function(data) {
+ $('.w3tcps_loading').addClass('w3tc_hidden');
+
+ if (data.error) {
+ $('.w3tcps_error').removeClass('w3tc_none');
+ return;
+ }
+
+ jQuery('.w3tcps_content').html(data['.w3tcps_content']);
+ $('.w3tcps_content').removeClass('w3tc_hidden');
+ }
+ ).fail(function() {
+ $('.w3tcps_error').removeClass('w3tc_none');
+ $('.w3tcps_content').addClass('w3tc_hidden');
+ $('.w3tcps_loading').addClass('w3tc_hidden');
+ });
+ }
+
+
+
+ jQuery('.w3tcps_content').on('click', '.w3tcps_refresh', function() {
+ w3tcps_load(true);
+ });
+
+
+
+ w3tcps_load();
+});
diff --git a/wp-content/plugins/w3-total-cache/PageSpeed_Widget_View.php b/wp-content/plugins/w3-total-cache/PageSpeed_Widget_View.php
new file mode 100644
index 0000000000..781c9c21e9
--- /dev/null
+++ b/wp-content/plugins/w3-total-cache/PageSpeed_Widget_View.php
@@ -0,0 +1,58 @@
+
+Loading...
+
+ Unable to fetch Page Speed results.
+
+
+
+
+
+
+
+
+
+ V
+
+
+ V
+
+
+ V
+
+
+ V
+
+
+
+
+
+
diff --git a/wp-content/plugins/w3-total-cache/PageSpeed_Widget_View_FromApi.php b/wp-content/plugins/w3-total-cache/PageSpeed_Widget_View_FromApi.php
new file mode 100644
index 0000000000..6cf99d6671
--- /dev/null
+++ b/wp-content/plugins/w3-total-cache/PageSpeed_Widget_View_FromApi.php
@@ -0,0 +1,62 @@
+
+
+ ' . esc_html( $name ) . '';
+ w3tcps_barline( $r['mobile']['metrics'][$metric]);
+ w3tcps_barline( $r['desktop']['metrics'][$metric]);
+}
+
+
+
+?>
+
+
+
+
+
+
+
+
+
diff --git a/wp-content/plugins/w3-total-cache/PageSpeed_Widget_View_NotConfigured.php b/wp-content/plugins/w3-total-cache/PageSpeed_Widget_View_NotConfigured.php
new file mode 100644
index 0000000000..e599e9b466
--- /dev/null
+++ b/wp-content/plugins/w3-total-cache/PageSpeed_Widget_View_NotConfigured.php
@@ -0,0 +1,15 @@
+
+
+ Google Page Speed score is not available.
+
+
+ Please follow the directions
+ found in the Miscellanous settings box on the
+ General Settings tab.
+
diff --git a/wp-content/plugins/w3-total-cache/PgCache_ConfigLabels.php b/wp-content/plugins/w3-total-cache/PgCache_ConfigLabels.php
new file mode 100644
index 0000000000..a564abeeb2
--- /dev/null
+++ b/wp-content/plugins/w3-total-cache/PgCache_ConfigLabels.php
@@ -0,0 +1,60 @@
+ __( 'Page Cache Method:', 'w3-total-cache' ),
+ 'pgcache.enabled' => __( 'Page Cache:', 'w3-total-cache' ),
+ 'pgcache.debug' => __( 'Page Cache', 'w3-total-cache' ),
+ 'pgcache.cache.home' => get_option( 'show_on_front' ) == 'posts' ? __( 'Cache front page', 'w3-total-cache' ): __( 'Cache posts page', 'w3-total-cache' ),
+ 'pgcache.reject.front_page' => __( 'Don\'t cache front page', 'w3-total-cache' ),
+ 'pgcache.cache.feed' => __( 'Cache feeds: site, categories, tags, comments', 'w3-total-cache' ),
+ 'pgcache.cache.ssl' => __( 'Cache SSL (HTTPS) requests', 'w3-total-cache' ),
+ 'pgcache.cache.query' => __( 'Cache URIs with query string variables', 'w3-total-cache' ),
+ 'pgcache.cache.404' => __( 'Cache 404 (not found) pages', 'w3-total-cache' ),
+ 'pgcache.reject.logged' => __( 'Don\'t cache pages for logged in users', 'w3-total-cache' ),
+ 'pgcache.reject.logged_roles' => __( 'Don\'t cache pages for following user roles', 'w3-total-cache' ),
+ 'pgcache.prime.enabled' => __( 'Automatically prime the page cache', 'w3-total-cache' ),
+ 'pgcache.prime.interval' => __( 'Update interval:', 'w3-total-cache' ),
+ 'pgcache.prime.limit' => __( 'Pages per interval:', 'w3-total-cache' ),
+ 'pgcache.prime.sitemap' =>__( 'Sitemap URL:', 'w3-total-cache' ),
+ 'pgcache.prime.post.enabled' => __( 'Preload the post cache upon publish events', 'w3-total-cache' ),
+ 'pgcache.purge.front_page' => __( 'Front page', 'w3-total-cache' ),
+ 'pgcache.purge.home' => get_option( 'show_on_front' ) == 'posts' ? __( 'Front page', 'w3-total-cache' ): __( 'Posts page', 'w3-total-cache' ),
+ 'pgcache.purge.post' => __( 'Post page', 'w3-total-cache' ),
+ 'pgcache.purge.feed.blog' => __( 'Blog feed', 'w3-total-cache' ),
+ 'pgcache.purge.comments' => __( 'Post comments pages', 'w3-total-cache' ),
+ 'pgcache.purge.author' => __( 'Post author pages', 'w3-total-cache' ),
+ 'pgcache.purge.terms' => __( 'Post terms pages', 'w3-total-cache' ),
+ 'pgcache.purge.feed.comments' => __( 'Post comments feed', 'w3-total-cache' ),
+ 'pgcache.purge.feed.author' => __( 'Post author feed', 'w3-total-cache' ),
+ 'pgcache.purge.feed.terms' => __( 'Post terms feeds', 'w3-total-cache' ),
+ 'pgcache.purge.archive.daily' => __( 'Daily archive pages', 'w3-total-cache' ),
+ 'pgcache.purge.archive.monthly' => __( 'Monthly archive pages', 'w3-total-cache' ),
+ 'pgcache.purge.archive.yearly' => __( 'Yearly archive pages', 'w3-total-cache' ),
+ 'pgcache.purge.feed.types' => __( 'Specify the feed types to purge:', 'w3-total-cache' ),
+ 'pgcache.purge.postpages_limit' => __( 'Purge limit:', 'w3-total-cache' ),
+ 'pgcache.purge.pages' => __( 'Additional pages:', 'w3-total-cache' ),
+ 'pgcache.purge.sitemap_regex' => __( 'Purge sitemaps:', 'w3-total-cache' ),
+ 'pgcache.compatibility' => __( 'Enable', 'w3-total-cache' ),
+ 'pgcache.remove_charset' => __( 'Disable UTF-8 blog charset support' , 'w3-total-cache' ),
+ 'pgcache.reject.request_head' => __( ' Disable caching of HEAD HTTP requests', 'w3-total-cache' ),
+ 'pgcache.lifetime' => __( 'Maximum lifetime of cache objects:', 'w3-total-cache' ),
+ 'pgcache.file.gc' => __( 'Garbage collection interval:', 'w3-total-cache' ),
+ 'pgcache.comment_cookie_ttl' => __( 'Comment cookie lifetime:', 'w3-total-cache' ),
+ 'pgcache.accept.qs' => __( 'Accepted query strings:', 'w3-total-cache' ),
+ 'pgcache.reject.ua' => __( 'Rejected user agents:', 'w3-total-cache' ),
+ 'pgcache.reject.cookie' => __( 'Rejected cookies:', 'w3-total-cache' ),
+ 'pgcache.reject.uri' => __( 'Never cache the following pages:', 'w3-total-cache' ),
+ 'pgcache.reject.categories' => __( 'Never cache pages associated with these categories:', 'w3-total-cache' ),
+ 'pgcache.reject.tags' => __( 'Never cache pages that use these tags:', 'w3-total-cache' ),
+ 'pgcache.reject.authors' => __( 'Never cache pages by these authors:', 'w3-total-cache' ),
+ 'pgcache.reject.custom' => __( 'Never cache pages that use these custom fields:', 'w3-total-cache' ),
+ 'pgcache.accept.files' => __( 'Cache exception list:', 'w3-total-cache' ),
+ 'pgcache.accept.uri' => __( 'Non-trailing slash pages:', 'w3-total-cache' ),
+ 'pgcache.cache.headers' => __( 'Specify page headers:', 'w3-total-cache' ),
+ 'pgcache.cache.nginx_handle_xml' => __( 'Handle XML mime type', 'w3-total-cache' ),
+ ) );
+ }
+}
diff --git a/wp-content/plugins/w3-total-cache/PgCache_ContentGrabber.php b/wp-content/plugins/w3-total-cache/PgCache_ContentGrabber.php
new file mode 100644
index 0000000000..4854ba4d01
--- /dev/null
+++ b/wp-content/plugins/w3-total-cache/PgCache_ContentGrabber.php
@@ -0,0 +1,2222 @@
+ 'path' => , 'querystring' => ]
+ private $_request_url_fragments;
+
+ /**
+ * Page key
+ *
+ * @var string
+ */
+ var $_page_key = '';
+ private $_page_key_extension;
+
+ /**
+ * Shutdown buffer
+ *
+ * @var string
+ */
+ var $_shutdown_buffer = '';
+
+ /**
+ * Mobile object
+ *
+ * @var W3_Mobile
+ */
+ var $_mobile = null;
+
+ /**
+ * Referrer object
+ *
+ * @var W3_Referrer
+ */
+ var $_referrer = null;
+
+ /**
+ * Cache reject reason
+ *
+ * @var string
+ */
+ var $cache_reject_reason = '';
+
+ private $process_status = '';
+ private $output_size = 0;
+
+ /**
+ *
+ *
+ * @var bool If cached page should be displayed after init
+ */
+ var $_late_init = false;
+
+ var $_cached_data = null;
+
+ var $_old_exists = false;
+
+ /**
+ * PHP5 Constructor
+ */
+ function __construct() {
+ $this->_config = Dispatcher::config();
+ $this->_debug = $this->_config->get_boolean( 'pgcache.debug' );
+
+ $this->_request_url_fragments = array(
+ 'host' => Util_Environment::host_port()
+ );
+
+ $this->_request_uri = $_SERVER['REQUEST_URI'];
+ $this->_lifetime = $this->_config->get_integer( 'pgcache.lifetime' );
+ $this->_late_init = $this->_config->get_boolean( 'pgcache.late_init' );
+ $this->_late_caching = $this->_config->get_boolean( 'pgcache.late_caching' );
+
+ $engine = $this->_config->get_string( 'pgcache.engine' );
+ $this->_enhanced_mode = ( $engine == 'file_generic' );
+ $this->_nginx_memcached = ( $engine == 'nginx_memcached' );
+
+ if ( $this->_config->get_boolean( 'mobile.enabled' ) ) {
+ $this->_mobile = Dispatcher::component( 'Mobile_UserAgent' );
+ }
+
+ if ( $this->_config->get_boolean( 'referrer.enabled' ) ) {
+ $this->_referrer = Dispatcher::component( 'Mobile_Referrer' );
+ }
+ }
+
+ /**
+ * Do cache logic
+ */
+ function process() {
+ $this->run_extensions_dropin();
+
+ /**
+ * Skip caching for some pages
+ */
+ switch ( true ) {
+ case defined( 'DONOTCACHEPAGE' ):
+ $this->process_status = 'miss_third_party';
+ $this->cache_reject_reason = 'DONOTCACHEPAGE defined';
+ if ( $this->_debug ) {
+ self::log( 'skip processing because of DONOTCACHEPAGE constant' );
+ }
+ return;
+ case defined( 'DOING_AJAX' ):
+ $this->process_status = 'miss_ajax';
+ $this->cache_reject_reason = 'AJAX request';
+ if ( $this->_debug ) {
+ self::log( 'skip processing because of AJAX constant' );
+ }
+ return;
+
+ case defined( 'APP_REQUEST' ):
+ case defined( 'XMLRPC_REQUEST' ):
+ $this->cache_reject_reason = 'API call constant defined';
+ $this->process_status = 'miss_api_call';
+ if ( $this->_debug ) {
+ self::log( 'skip processing because of API call constant' );
+ }
+ return;
+
+ case defined( 'DOING_CRON' ):
+ case defined( 'WP_ADMIN' ):
+ case ( defined( 'SHORTINIT' ) && SHORTINIT ):
+ $this->cache_reject_reason = 'WP_ADMIN defined';
+ $this->process_status = 'miss_wp_admin';
+ if ( $this->_debug ) {
+ self::log( 'skip processing because of generic constant' );
+ }
+ return;
+ }
+
+ /**
+ * Do page cache logic
+ */
+ if ( $this->_debug ) {
+ $this->_time_start = Util_Debug::microtime();
+ }
+
+ // TODO: call modifies object state, rename method at least
+ $this->_caching = $this->_can_read_cache();
+ global $w3_late_init;
+
+ if ( $this->_debug ) {
+ self::log( 'start, can_cache: ' .
+ ( $this->_caching ? 'true' : 'false' ) .
+ ', reject reason: ' . $this->cache_reject_reason );
+ }
+
+ $this->_page_key_extension = $this->_get_key_extension();
+ if ( !$this->_page_key_extension['cache'] ) {
+ $this->_caching = false;
+ $this->cache_reject_reason =
+ $this->_page_key_extension['cache_reject_reason'];
+ }
+
+ if ( $this->_caching && !$this->_late_caching ) {
+ $this->_cached_data = $this->_extract_cached_page( false );
+ if ( $this->_cached_data ) {
+ if ( $this->_late_init ) {
+ $w3_late_init = true;
+ return;
+ } else {
+ $this->process_status = 'hit';
+ $this->process_cached_page_and_exit( $this->_cached_data );
+ // if is passes here - exit is not possible now and
+ // will happen on init
+ return;
+ }
+ } else
+ $this->_late_init = false;
+ } else {
+ $this->_late_init = false;
+ }
+ $w3_late_init = $this->_late_init;
+ /**
+ * Start output buffering
+ */
+ Util_Bus::add_ob_callback( 'pagecache', array( $this, 'ob_callback' ) );
+ }
+
+
+
+ private function run_extensions_dropin() {
+ $c = $this->_config;
+ $extensions = $c->get_array( 'extensions.active' );
+
+ $dropin = $c->get_array( 'extensions.active_dropin' );
+ foreach ( $dropin as $extension => $nothing ) {
+ if ( isset( $extensions[$extension] ) ) {
+ $path = $extensions[$extension];
+ $filename = W3TC_EXTENSION_DIR . '/' .
+ str_replace( '..', '', trim( $path, '/' ) );
+
+ if ( file_exists( $filename ) ) {
+ include_once( $filename );
+ }
+ }
+ }
+ }
+
+
+
+ /**
+ * Extracts page from cache
+ *
+ * @return boolean
+ */
+ function _extract_cached_page( $with_filter ) {
+ $cache = $this->_get_cache( $this->_page_key_extension['group'] );
+
+ $mobile_group = $this->_page_key_extension['useragent'];
+ $referrer_group = $this->_page_key_extension['referrer'];
+ $encryption = $this->_page_key_extension['encryption'];
+ $compression = $this->_page_key_extension['compression'];
+
+ /**
+ * Check if page is cached
+ */
+ if ( !$this->_set_extract_page_key( $this->_page_key_extension, $with_filter ) ) {
+ $data = null;
+ } else {
+ $data = $cache->get_with_old( $this->_page_key, $this->_page_group );
+ list( $data, $this->_old_exists ) = $data;
+ }
+
+ /**
+ * Try to get uncompressed version of cache
+ */
+ if ( $compression && !$data ) {
+ if ( !$this->_set_extract_page_key(
+ array_merge( $this->_page_key_extension,
+ array( 'compression' => '') ), $with_filter ) ) {
+ $data = null;
+ } else {
+ $data = $cache->get_with_old( $this->_page_key, $this->_page_group );
+ list( $data, $this->_old_exists ) = $data;
+ $compression = false;
+ }
+ }
+
+ if ( !$data ) {
+ if ( $this->_debug ) {
+ self::log( 'no cache entry for ' .
+ $this->_request_url_fragments['host'] . $this->_request_uri . ' ' .
+ $this->_page_key );
+ }
+
+ return null;
+ }
+
+ $data['compression'] = $compression;
+
+ return $data;
+ }
+
+
+
+ private function _set_extract_page_key( $page_key_extension, $with_filter ) {
+ // set page group
+ $this->_page_group = $page_key_extension['group'];
+ if ( $with_filter ) {
+ // return empty value if caching should not happen
+ $this->_page_group = apply_filters( 'w3tc_page_extract_group',
+ $page_key_extension['group'],
+ $this->_request_url_fragments['host'] . $this->_request_uri,
+ $page_key_extension );
+ $page_key_extension['group'] = $this->_page_group;
+ }
+
+ // set page key
+ $this->_page_key = $this->_get_page_key( $page_key_extension );
+
+ if ( $with_filter ) {
+ // return empty value if caching should not happen
+ $this->_page_key = apply_filters( 'w3tc_page_extract_key',
+ $this->_page_key,
+ $page_key_extension['useragent'],
+ $page_key_extension['referrer'],
+ $page_key_extension['encryption'],
+ $page_key_extension['compression'],
+ $page_key_extension['content_type'],
+ $this->_request_url_fragments['host'] . $this->_request_uri,
+ $page_key_extension );
+ }
+
+ if ( !empty( $this->_page_key ) )
+ return true;
+
+ $this->caching = false;
+ $this->cache_reject_reason =
+ 'w3tc_page_extract_key filter result forced not to cache';
+
+ return false;
+ }
+
+
+
+ /**
+ * Process extracted cached pages
+ *
+ * @param unknown $data
+ */
+ private function process_cached_page_and_exit( $data ) {
+ /**
+ * Do Bad Behavior check
+ */
+ $this->_bad_behavior();
+
+ $is_404 = isset( $data['404'] ) ? $data['404'] : false;
+ $headers = isset( $data['headers'] ) ? $data['headers'] : array();
+ $content = $data['content'];
+ $has_dynamic = isset( $data['has_dynamic'] ) && $data['has_dynamic'];
+ $etag = md5( $content );
+
+ if ( $has_dynamic ) {
+ // its last modification date is now, and any compression
+ // browser wants cant be used, since its compressed now
+ $time = time();
+ $compression = $this->_page_key_extension['compression'];
+ } else {
+ $time = isset( $data['time'] ) ? $data['time'] : time();
+ $compression = $data['compression'];
+ }
+
+ /**
+ * Send headers
+ */
+ $this->_send_headers( $is_404, $time, $etag, $compression, $headers );
+ if ( isset( $_SERVER['REQUEST_METHOD'] ) && $_SERVER['REQUEST_METHOD'] == 'HEAD' )
+ return;
+
+ // parse dynamic content and compress if it's dynamic page with mfuncs
+ if ( $has_dynamic ) {
+ $content = $this->_parse_dynamic( $content );
+ $content = $this->_compress( $content, $compression );
+ }
+
+ echo $content;
+
+ Dispatcher::usage_statistics_apply_before_init_and_exit( array( $this,
+ 'w3tc_usage_statistics_of_request' ) );
+ }
+
+ /**
+ * Output buffering callback
+ *
+ * @param string $buffer
+ * @return string
+ */
+ function ob_callback( $buffer ) {
+ $this->output_size = strlen( $buffer );
+
+ if ( !$this->_is_cacheable_content_type() ) {
+ if ( $this->_debug )
+ self::log( 'storing cached page - not a cached content' );
+
+ return $buffer;
+ }
+
+ $compression = false;
+ $has_dynamic = $this->_has_dynamic( $buffer );
+ $response_headers = $this->_get_response_headers();
+
+ // TODO: call modifies object state, rename method at least
+ $original_can_cache = $this->_can_write_cache( $buffer, $response_headers );
+ $can_cache = apply_filters( 'w3tc_can_cache', $original_can_cache, $this, $buffer );
+ if ( $can_cache != $original_can_cache ) {
+ $this->cache_reject_reason = 'Third-party plugin has modified caching activity';
+ }
+
+ if ( $this->_debug ) {
+ self::log( 'storing cached page: ' .
+ ( $can_cache ? 'true' : 'false' ) .
+ ' original ' . ( $this->_caching ? ' true' : 'false' ) .
+ ' reason ' . $this->cache_reject_reason );
+ }
+
+ $buffer = str_replace('{w3tc_pagecache_reject_reason}',
+ ( $this->cache_reject_reason != '' ? sprintf( ' (%s)', $this->cache_reject_reason )
+ : '' ),
+ $buffer );
+
+ if ( $can_cache ) {
+ $buffer = $this->_maybe_save_cached_result( $buffer, $response_headers, $has_dynamic );
+ } else {
+ if ( $has_dynamic ) {
+ // send common headers since output will be compressed
+ $compression_header = $this->_page_key_extension['compression'];
+ if ( defined( 'W3TC_PAGECACHE_OUTPUT_COMPRESSION_OFF' ) )
+ $compression_header = false;
+ $headers = $this->_get_common_headers( $compression_header );
+ $this->_headers( $headers );
+ }
+
+ // remove cached entries if its not cached anymore
+ if ( $this->cache_reject_reason ) {
+ if ( $this->_old_exists ) {
+ $cache = $this->_get_cache( $this->_page_key_extension['group'] );
+
+ $compressions_to_store = $this->_get_compressions();
+
+ foreach ( $compressions_to_store as $_compression ) {
+ $_page_key = $this->_get_page_key(
+ array_merge( $this->_page_key_extension,
+ array( 'compression' => $_compression ) ) );
+ $cache->hard_delete( $_page_key );
+ }
+ }
+ }
+ }
+
+ /**
+ * We can't capture output in ob_callback
+ * so we use shutdown function
+ */
+ if ( $has_dynamic ) {
+ $this->_shutdown_buffer = $buffer;
+
+ $buffer = '';
+
+ register_shutdown_function( array(
+ $this,
+ 'shutdown'
+ ) );
+ }
+
+ return $buffer;
+ }
+
+ /**
+ * Shutdown callback
+ *
+ * @return void
+ */
+ public function shutdown() {
+ $compression = $this->_page_key_extension['compression'];
+
+ // Parse dynamic content
+ $buffer = $this->_parse_dynamic( $this->_shutdown_buffer );
+
+ // Compress page according to headers already set
+ echo $this->_compress( $buffer, $compression );
+ }
+
+ /**
+ * Checks if can we do cache logic
+ *
+ * @return boolean
+ */
+ private function _can_read_cache() {
+ /**
+ * Don't cache in console mode
+ */
+ if ( PHP_SAPI === 'cli' ) {
+ $this->cache_reject_reason = 'Console mode';
+
+ return false;
+ }
+
+ /**
+ * Skip if session defined
+ */
+ if ( defined( 'SID' ) && SID != '' ) {
+ $this->cache_reject_reason = 'Session started';
+
+ return false;
+ }
+
+ if ( !$this->_config->get_boolean('pgcache.cache.ssl') && Util_Environment::is_https() ) {
+ $this->cache_reject_reason = 'SSL caching disabled';
+ $this->process_status = 'miss_configuration';
+
+ return false;
+ }
+
+ /**
+ * Skip if posting
+ */
+ if ( isset( $_SERVER['REQUEST_METHOD'] ) && in_array( strtoupper( $_SERVER['REQUEST_METHOD'] ), array( 'DELETE', 'PUT', 'OPTIONS', 'TRACE', 'CONNECT', 'POST' ) ) ) {
+ $this->cache_reject_reason = sprintf( 'Requested method is %s', $_SERVER['REQUEST_METHOD'] );
+
+ return false;
+ }
+
+ /**
+ * Skip if HEAD request
+ */
+ if ( isset( $_SERVER['REQUEST_METHOD'] ) && strtoupper( $_SERVER['REQUEST_METHOD'] ) == 'HEAD' &&
+ ( $this->_enhanced_mode || $this->_config->get_boolean( 'pgcache.reject.request_head' ) ) ) {
+ $this->cache_reject_reason = 'Requested method is HEAD';
+
+ return false;
+ }
+
+ /**
+ * Skip if there is query in the request uri
+ */
+ $this->_preprocess_request_uri();
+
+ if ( !empty( $this->_request_url_fragments['querystring'] ) ) {
+ $should_reject_qs =
+ ( !$this->_config->get_boolean( 'pgcache.cache.query' ) ||
+ $this->_config->get_string( 'pgcache.engine' ) == 'file_generic' );
+
+ if ( $should_reject_qs &&
+ $this->_config->get_string( 'pgcache.rest' ) == 'cache' &&
+ Util_Environment::is_rest_request( $this->_request_uri ) ) {
+ $should_reject_qs = false;
+ }
+
+ if ( $should_reject_qs ) {
+ $this->cache_reject_reason = 'Requested URI contains query';
+ $this->process_status = 'miss_query_string';
+
+ return false;
+ }
+ }
+
+ /**
+ * Check request URI
+ */
+ if ( !$this->_passed_accept_files() && !$this->_passed_reject_uri() ) {
+ $this->cache_reject_reason = 'Requested URI is rejected';
+ $this->process_status = 'miss_configuration';
+
+ return false;
+ }
+
+ /**
+ * Check User Agent
+ */
+ if ( !$this->_check_ua() ) {
+ $this->cache_reject_reason = 'User agent is rejected';
+ if ( isset( $_REQUEST['w3tc_rewrite_test'] ) ) {
+ // special common case - w3tc_rewrite_test check request
+ $this->process_status = 'miss_wp_admin';
+ } else {
+ $this->process_status = 'miss_configuration';
+ }
+
+ return false;
+ }
+
+ /**
+ * Check WordPress cookies
+ */
+ if ( !$this->_check_cookies() ) {
+ $this->cache_reject_reason = 'Cookie is rejected';
+ $this->process_status = 'miss_configuration';
+
+ return false;
+ }
+
+ /**
+ * Skip if user is logged in or user role is logged in
+ */
+ if ( $this->_config->get_boolean( 'pgcache.reject.logged' ) ) {
+ if ( !$this->_check_logged_in() ) {
+ $this->cache_reject_reason = 'User is logged in';
+ $this->process_status = 'miss_logged_in';
+
+ return false;
+ }
+ } else {
+ if ( !$this->_check_logged_in_role_allowed() ) {
+ $this->cache_reject_reason = 'Rejected user role is logged in';
+ $this->process_status = 'miss_logged_in';
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Checks if can we do cache logic
+ *
+ * @param string $buffer
+ * @return boolean
+ */
+ private function _can_write_cache( $buffer, $response_headers ) {
+ /**
+ * Skip if caching is disabled
+ */
+ if ( !$this->_caching ) {
+ return false;
+ }
+
+ /**
+ * Check for DONOTCACHEPAGE constant
+ */
+ if ( defined( 'DONOTCACHEPAGE' ) && DONOTCACHEPAGE ) {
+ $this->cache_reject_reason = 'DONOTCACHEPAGE constant is defined';
+ $this->process_status = 'miss_third_party';
+ return false;
+ }
+
+ if ( $this->_config->get_string( 'pgcache.rest' ) != 'cache' ) {
+ if ( defined( 'REST_REQUEST' ) && REST_REQUEST ) {
+ $this->cache_reject_reason = 'REST request';
+ $this->process_status = 'miss_api_call';
+
+ return false;
+ }
+ }
+
+ /**
+ * Don't cache 404 pages
+ */
+ if ( !$this->_config->get_boolean( 'pgcache.cache.404' ) && function_exists( 'is_404' ) && is_404() ) {
+ $this->cache_reject_reason = 'Page is 404';
+ $this->process_status = 'miss_404';
+
+ return false;
+ }
+
+ /**
+ * Don't cache homepage
+ */
+ if ( !$this->_config->get_boolean( 'pgcache.cache.home' ) && function_exists( 'is_home' ) && is_home() ) {
+ $this->cache_reject_reason = is_front_page() && is_home() ? 'Page is front page' : 'Page is posts page';
+ $this->process_status = 'miss_configuration';
+
+ return false;
+ }
+
+ /**
+ * Don't cache front page
+ */
+ if ( $this->_config->get_boolean( 'pgcache.reject.front_page' ) && function_exists( 'is_front_page' ) && is_front_page() && !is_home() ) {
+ $this->cache_reject_reason = 'Page is front page';
+ $this->process_status = 'miss_configuration';
+
+ return false;
+ }
+
+ /**
+ * Don't cache feed
+ */
+ if ( !$this->_config->get_boolean( 'pgcache.cache.feed' ) && function_exists( 'is_feed' ) && is_feed() ) {
+ $this->cache_reject_reason = 'Page is feed';
+ $this->process_status = 'miss_configuration';
+
+ return false;
+ }
+
+ /**
+ * Check if page contains dynamic tags
+ */
+ if ( $this->_enhanced_mode && $this->_has_dynamic( $buffer ) ) {
+ $this->cache_reject_reason = 'Page contains dynamic tags (mfunc or mclude) can not be cached in enhanced mode';
+ $this->process_status = 'miss_mfunc';
+
+ return false;
+ }
+
+ if ( !$this->_passed_accept_files() ) {
+ if ( is_single() ) {
+ /**
+ * Don't cache pages associated with categories
+ */
+ if ( $this->_passed_reject_categories() ) {
+ $this->cache_reject_reason = 'Page associated with a rejected category';
+ $this->process_status = 'miss_configuration';
+ return false;
+ }
+ /**
+ * Don't cache pages that use tags
+ */
+ if ( $this->_passed_reject_tags() ) {
+ $this->cache_reject_reason = 'Page using a rejected tag';
+ $this->process_status = 'miss_configuration';
+ return false;
+ }
+ }
+ /**
+ * Don't cache pages by these authors
+ */
+ if ( $this->_passed_reject_authors() ) {
+ $this->cache_reject_reason = 'Page written by a rejected author';
+ $this->process_status = 'miss_configuration';
+ return false;
+ }
+ /**
+ * Don't cache pages using custom fields
+ */
+ if ( $this->_passed_reject_custom_fields() ) {
+ $this->cache_reject_reason = 'Page using a rejected custom field';
+ $this->process_status = 'miss_configuration';
+ return false;
+ }
+ }
+
+ if ( !empty( $response_headers['kv']['Content-Encoding'] ) ) {
+ $this->cache_reject_reason = 'Response is compressed';
+ $this->process_status = 'miss_compressed';
+ return false;
+ }
+
+ if ( empty( $buffer ) && empty( $response_headers['kv']['Location'] ) ) {
+ $this->cache_reject_reason = 'Empty response';
+ $this->process_status = 'miss_empty_response';
+ return false;
+ }
+
+ if ( isset( $response_headers['kv']['Location'] ) ) {
+ // dont cache query-string normalization redirects
+ // (e.g. from wp core)
+ // when cache key is normalized, since that cause redirect loop
+
+ if ( $this->_get_page_key( $this->_page_key_extension ) ==
+ $this->_get_page_key( $this->_page_key_extension, $response_headers['kv']['Location'] ) ) {
+ $this->cache_reject_reason = 'Normalization redirect';
+ $this->process_status = 'miss_normalization_redirect';
+ return false;
+ }
+ }
+
+ if ( isset( $_SERVER['REQUEST_METHOD'] ) && $_SERVER['REQUEST_METHOD'] == 'HEAD' ) {
+ $this->cache_reject_reason = 'HEAD request';
+ $this->process_status = 'miss_request_method';
+ return;
+ }
+
+ return true;
+ }
+
+ public function get_cache_stats_size( $timeout_time ) {
+ $cache = $this->_get_cache();
+ if ( method_exists( $cache, 'get_stats_size' ) )
+ return $cache->get_stats_size( $timeout_time );
+
+ return null;
+ }
+
+ public function get_usage_statistics_cache_config() {
+ $engine = $this->_config->get_string( 'pgcache.engine' );
+
+ switch ( $engine ) {
+ case 'memcached':
+ case 'nginx_memcached':
+ $engineConfig = array(
+ 'servers' => $this->_config->get_array( 'pgcache.memcached.servers' ),
+ 'persistent' => $this->_config->get_boolean( 'pgcache.memcached.persistent' ),
+ 'aws_autodiscovery' => $this->_config->get_boolean( 'pgcache.memcached.aws_autodiscovery' ),
+ 'username' => $this->_config->get_string( 'pgcache.memcached.username' ),
+ 'password' => $this->_config->get_string( 'pgcache.memcached.password' ),
+ 'binary_protocol' => $this->_config->get_boolean( 'pgcache.memcached.binary_protocol' )
+ );
+ break;
+
+ case 'redis':
+ $engineConfig = array(
+ 'servers' => $this->_config->get_array( 'pgcache.redis.servers' ),
+ 'persistent' => $this->_config->get_boolean( 'pgcache.redis.persistent' ),
+ 'dbid' => $this->_config->get_integer( 'pgcache.redis.dbid' ),
+ 'password' => $this->_config->get_string( 'pgcache.redis.password' )
+ );
+ break;
+
+ case 'file_generic':
+ $engine = 'file';
+ break;
+
+ default:
+ $engineConfig = array();
+ }
+
+ $engineConfig['engine'] = $engine;
+ return $engineConfig;
+ }
+
+ /**
+ * Returns cache object
+ *
+ * @return W3_Cache_Base
+ */
+ function _get_cache( $group = '*' ) {
+ static $caches = array();
+
+ if ( empty( $group ) ) {
+ $group = '*';
+ }
+
+ if ( empty( $caches[$group] ) ) {
+ $engine = $this->_config->get_string( 'pgcache.engine' );
+
+ switch ( $engine ) {
+ case 'memcached':
+ case 'nginx_memcached':
+ $engineConfig = array(
+ 'servers' => $this->_config->get_array( 'pgcache.memcached.servers' ),
+ 'persistent' => $this->_config->get_boolean( 'pgcache.memcached.persistent' ),
+ 'aws_autodiscovery' => $this->_config->get_boolean( 'pgcache.memcached.aws_autodiscovery' ),
+ 'username' => $this->_config->get_string( 'pgcache.memcached.username' ),
+ 'password' => $this->_config->get_string( 'pgcache.memcached.password' ),
+ 'binary_protocol' => $this->_config->get_boolean( 'pgcache.memcached.binary_protocol' )
+ );
+ break;
+
+ case 'redis':
+ $engineConfig = array(
+ 'servers' => $this->_config->get_array( 'pgcache.redis.servers' ),
+ 'persistent' => $this->_config->get_boolean( 'pgcache.redis.persistent' ),
+ 'dbid' => $this->_config->get_integer( 'pgcache.redis.dbid' ),
+ 'password' => $this->_config->get_string( 'pgcache.redis.password' )
+ );
+ break;
+
+ case 'file':
+ $engineConfig = array(
+ 'section' => 'page',
+ 'flush_parent' => ( Util_Environment::blog_id() == 0 ),
+ 'locking' => $this->_config->get_boolean( 'pgcache.file.locking' ),
+ 'flush_timelimit' => $this->_config->get_integer( 'timelimit.cache_flush' )
+ );
+ break;
+
+ case 'file_generic':
+ if ( $group != '*' ) {
+ $engine = 'file';
+
+ $engineConfig = array(
+ 'section' => 'page',
+ 'cache_dir' =>
+ W3TC_CACHE_PAGE_ENHANCED_DIR .
+ DIRECTORY_SEPARATOR .
+ Util_Environment::host_port(),
+ 'flush_parent' => ( Util_Environment::blog_id() == 0 ),
+ 'locking' => $this->_config->get_boolean( 'pgcache.file.locking' ),
+ 'flush_timelimit' => $this->_config->get_integer( 'timelimit.cache_flush' )
+ );
+ break;
+ }
+
+ if ( Util_Environment::blog_id() == 0 ) {
+ $flush_dir = W3TC_CACHE_PAGE_ENHANCED_DIR;
+ } else {
+ $flush_dir = W3TC_CACHE_PAGE_ENHANCED_DIR .
+ DIRECTORY_SEPARATOR .
+ Util_Environment::host();
+ }
+
+ $engineConfig = array(
+ 'exclude' => array(
+ '.htaccess'
+ ),
+ 'expire' => $this->_lifetime,
+ 'cache_dir' => W3TC_CACHE_PAGE_ENHANCED_DIR,
+ 'locking' => $this->_config->get_boolean( 'pgcache.file.locking' ),
+ 'flush_timelimit' => $this->_config->get_integer( 'timelimit.cache_flush' ),
+ 'flush_dir' => $flush_dir,
+ );
+ break;
+
+ default:
+ $engineConfig = array();
+ }
+
+ $engineConfig['use_expired_data'] = true;
+ $engineConfig['module'] = 'pgcache';
+ $engineConfig['host'] = ''; // host is always put to a key
+ $engineConfig['instance_id'] = Util_Environment::instance_id();
+
+ $caches[$group] = Cache::instance( $engine, $engineConfig );
+ }
+
+ return $caches[$group];
+ }
+
+ /**
+ * Checks request URI
+ *
+ * @return boolean
+ */
+ function _passed_reject_uri() {
+ $auto_reject_uri = array(
+ 'wp-login',
+ 'wp-register'
+ );
+
+ foreach ( $auto_reject_uri as $uri ) {
+ if ( strstr( $this->_request_uri, $uri ) !== false ) {
+ return false;
+ }
+ }
+
+ $reject_uri = $this->_config->get_array( 'pgcache.reject.uri' );
+ $reject_uri = array_map( array( '\W3TC\Util_Environment', 'parse_path' ), $reject_uri );
+
+ foreach ( $reject_uri as $expr ) {
+ $expr = trim( $expr );
+ if ( $expr != '' && preg_match( '~' . $expr . '~i', $this->_request_uri ) ) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Check if in the cache exception list
+ *
+ * @return boolean
+ */
+ function _passed_accept_files() {
+ $accept_uri = $this->_config->get_array( 'pgcache.accept.files' );
+ $accept_uri = array_map( array( '\W3TC\Util_Environment', 'parse_path' ), $accept_uri );
+ foreach ( $accept_uri as &$val ) $val = trim( str_replace( "~", "\~", $val ) );
+ $accept_uri = array_filter( $accept_uri, function( $val ){ return $val != ""; } );
+ if ( !empty( $accept_uri ) && @preg_match( '~' . implode( "|", $accept_uri ) . '~i', $this->_request_uri ) ) {
+ return true;
+ }
+ return false;
+ }
+ /**
+ * Checks page against rejected categories
+ *
+ * @return boolean
+ */
+ function _passed_reject_categories() {
+ $reject_categories = $this->_config->get_array( 'pgcache.reject.categories' );
+ if ( !empty( $reject_categories ) ) {
+ if ( $cats = get_the_category() ) {
+ foreach( $cats as $cat ) {
+ if ( in_array( $cat->slug, $reject_categories ) ) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+ /**
+ * Checks page against rejected tags
+ *
+ * @return boolean
+ */
+ function _passed_reject_tags() {
+ $reject_tags = $this->_config->get_array( 'pgcache.reject.tags' );
+ if ( !empty( $reject_tags ) ) {
+ if ( $tags = get_the_tags() ) {
+ foreach( $tags as $tag ) {
+ if ( in_array( $tag->slug,$reject_tags ) ) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+ /**
+ * Checks page against rejected authors
+ *
+ * @return boolean
+ */
+ function _passed_reject_authors() {
+ $reject_authors = $this->_config->get_array( 'pgcache.reject.authors' );
+ if ( !empty( $reject_authors ) ) {
+ if ( $author = get_the_author_meta( 'user_login' ) ) {
+ if ( in_array( $author, $reject_authors ) ) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+ /**
+ * Checks page against rejected custom fields
+ *
+ * @return boolean
+ */
+ function _passed_reject_custom_fields() {
+ $reject_custom = $this->_config->get_array( 'pgcache.reject.custom' );
+ if ( empty( $reject_custom ) )
+ return false;
+
+ foreach ( $reject_custom as &$val ) {
+ $val = preg_quote( trim( $val ), '~' );
+ }
+ $reject_custom = implode( '|', array_filter( $reject_custom ) );
+ if ( !empty( $reject_custom ) ) {
+ if ( $customs = get_post_custom() ) {
+ foreach ( $customs as $key => $value ) {
+ if ( @preg_match( '~' . $reject_custom . '~i', $key . ( isset( $value[0] ) ? "={$value[0]}" : "" ) ) ) {
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Checks User Agent
+ *
+ * @return boolean
+ */
+ function _check_ua() {
+ $uas = $this->_config->get_array( 'pgcache.reject.ua' );
+
+ $uas = array_merge( $uas, array( W3TC_POWERED_BY ) );
+
+ foreach ( $uas as $ua ) {
+ if ( !empty( $ua ) ) {
+ if ( isset( $_SERVER['HTTP_USER_AGENT'] ) &&
+ stristr( $_SERVER['HTTP_USER_AGENT'], $ua ) !== false )
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Checks WordPress cookies
+ *
+ * @return boolean
+ */
+ function _check_cookies() {
+ foreach ( array_keys( $_COOKIE ) as $cookie_name ) {
+ if ( $cookie_name == 'wordpress_test_cookie' ) {
+ continue;
+ }
+ if ( preg_match( '/^(wp-postpass|comment_author)/', $cookie_name ) ) {
+ return false;
+ }
+ }
+
+ foreach ( $this->_config->get_array( 'pgcache.reject.cookie' ) as $reject_cookie ) {
+ if ( !empty( $reject_cookie ) ) {
+ foreach ( array_keys( $_COOKIE ) as $cookie_name ) {
+ if ( strstr( $cookie_name, $reject_cookie ) !== false ) {
+ return false;
+ }
+ }
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Check if user is logged in
+ *
+ * @return boolean
+ */
+ function _check_logged_in() {
+ foreach ( array_keys( $_COOKIE ) as $cookie_name ) {
+ if ( strpos( $cookie_name, 'wordpress_logged_in' ) === 0 )
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Check if logged in user role is allwed to be cached
+ *
+ * @return boolean
+ */
+ function _check_logged_in_role_allowed() {
+ if ( !$this->_config->get_boolean( 'pgcache.reject.logged_roles' ) )
+ return true;
+ $roles = $this->_config->get_array( 'pgcache.reject.roles' );
+
+ if ( empty( $roles ) )
+ return true;
+
+ foreach ( array_keys( $_COOKIE ) as $cookie_name ) {
+ if ( strpos( $cookie_name, 'w3tc_logged_' ) === 0 ) {
+ foreach ( $roles as $role ) {
+ if ( strstr( $cookie_name, md5( NONCE_KEY . $role ) ) )
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Checks if rules file present and creates it if not
+ */
+ function _check_rules_present() {
+ if ( Util_Environment::is_nginx() )
+ return; // nginx store it in a single file
+
+ $filename = Util_Rule::get_pgcache_rules_cache_path();
+ if ( file_exists( $filename ) )
+ return;
+
+ // we call it as little times as possible
+ // its expensive, but have to restore lost .htaccess file
+ $e = Dispatcher::component( 'PgCache_Environment' );
+ try {
+ $e->fix_on_wpadmin_request( $this->_config, true );
+ } catch ( \Exception $ex ) {
+ }
+ }
+
+ /**
+ * Compress data
+ *
+ * @param string $data
+ * @param string $compression
+ * @return string
+ */
+ function _compress( $data, $compression ) {
+ switch ( $compression ) {
+ case 'gzip':
+ $data = gzencode( $data );
+ break;
+
+ case 'deflate':
+ $data = gzdeflate( $data );
+ break;
+
+ case 'br':
+ $data = brotli_compress( $data );
+ break;
+ }
+
+ return $data;
+ }
+
+ /**
+ * Returns page key extension for current request
+ *
+ * @return string
+ */
+ private function _get_key_extension() {
+ $extension = array(
+ 'useragent' => '',
+ 'referrer' => '',
+ 'cookie' => '',
+ 'encryption' => '',
+ 'compression' => $this->_get_compression(),
+ 'content_type' => '',
+ 'cache' => true,
+ 'cache_reject_reason' => '',
+ 'group' => ''
+ );
+
+ if ( $this->_mobile )
+ $extension['useragent'] = $this->_mobile->get_group();
+ if ( $this->_referrer )
+ $extension['referrer'] = $this->_referrer->get_group();
+ if ( Util_Environment::is_https() )
+ $extension['encryption'] = 'ssl';
+
+ $this->_fill_key_extension_cookie( $extension );
+
+ // fill group
+ $extension['group'] = $this->get_cache_group_by_uri( $this->_request_uri );
+ $extension = w3tc_apply_filters( 'pagecache_key_extension', $extension,
+ $this->_request_url_fragments['host'], $this->_request_uri );
+
+ return $extension;
+ }
+
+ private function _fill_key_extension_cookie( &$extension ) {
+ if ( !$this->_config->get_boolean( 'pgcache.cookiegroups.enabled' ) )
+ return;
+
+ $groups = $this->_config->get_array( 'pgcache.cookiegroups.groups' );
+ foreach ( $groups as $group_name => $g ) {
+ if ( isset( $g['enabled'] ) && $g['enabled'] ) {
+
+ $cookies = array();
+ foreach ($g['cookies'] as $cookie ) {
+ $cookie = trim( $cookie );
+ if ( !empty( $cookie ) ) {
+ $cookie = str_replace( '+', ' ', $cookie );
+ $cookie = Util_Environment::preg_quote( $cookie );
+ if ( strpos( $cookie, '=') === false )
+ $cookie .= '=.*';
+ $cookies[] = $cookie;
+ }
+ }
+
+ if ( count( $cookies ) > 0 ) {
+ $cookies_regexp = '~^(' . implode( '|', $cookies ) . ')$~i';
+
+ foreach ( $_COOKIE as $key => $value ) {
+ if ( @preg_match( $cookies_regexp, $key . '=' . $value ) ) {
+ $extension['cookie'] = $group_name;
+ if ( !$g['cache'] ) {
+ $extension['cache'] = false;
+ $extension['cache_reject_reason'] = 'cookiegroup ' . $group_name;
+ }
+ return;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ protected function get_cache_group_by_uri( $uri ) {
+ // "!$this->_enhanced_mode" in condition above
+ // prevents usage of separate group under disk-enhanced
+ // so that rewrite rules still work.
+ // flushing is handled by workaround in this case
+ if ( !$this->_enhanced_mode ) {
+ $sitemap_regex = $this->_config->get_string(
+ 'pgcache.purge.sitemap_regex' );
+
+ if ( $sitemap_regex && preg_match( '~' . $sitemap_regex . '~',
+ basename( $uri ) ) ) {
+ return 'sitemaps';
+ }
+ }
+
+ if ( $this->_config->get_string( 'pgcache.rest' ) == 'cache' &&
+ Util_Environment::is_rest_request( $uri ) &&
+ Util_Environment::is_w3tc_pro( $this->_config ) ) {
+ return 'rest';
+ }
+
+ return '';
+ }
+
+ /**
+ * Returns current compression
+ *
+ * @return boolean
+ */
+ function _get_compression() {
+ if ( $this->_debug ) // cannt generate/use compressed files during debug mode
+ return '';
+
+ if ( !Util_Environment::is_zlib_enabled() && !$this->_is_buggy_ie() ) {
+ $compressions = $this->_get_compressions();
+
+ foreach ( $compressions as $compression ) {
+ if ( is_string( $compression ) &&
+ isset( $_SERVER['HTTP_ACCEPT_ENCODING'] ) &&
+ stristr( $_SERVER['HTTP_ACCEPT_ENCODING'], $compression ) !== false ) {
+ return $compression;
+ }
+ }
+ }
+
+ return '';
+ }
+
+ /**
+ * Returns array of compressions
+ *
+ * @return array
+ */
+ function _get_compressions() {
+ $compressions = array(
+ false
+ );
+
+ if ( defined( 'W3TC_PAGECACHE_STORE_COMPRESSION_OFF' ) ) {
+ return $compressions;
+ }
+
+ if ( $this->_config->get_boolean( 'browsercache.enabled' ) &&
+ $this->_config->get_boolean( 'browsercache.html.compression' ) &&
+ function_exists( 'gzencode' ) ) {
+ $compressions[] = 'gzip';
+ }
+
+ if ( $this->_config->get_boolean( 'browsercache.enabled' ) &&
+ $this->_config->get_boolean( 'browsercache.html.brotli' ) &&
+ function_exists( 'brotli_compress' ) ) {
+ $compressions[] = 'br';
+ }
+
+ return $compressions;
+ }
+
+ /**
+ * Returns array of response headers
+ *
+ * @return array
+ */
+ function _get_response_headers() {
+ $headers_kv = array();
+ $headers_plain = array();
+
+ if ( function_exists( 'headers_list' ) ) {
+ $headers_list = headers_list();
+ if ( $headers_list ) {
+ foreach ( $headers_list as $header ) {
+ $pos = strpos( $header, ':' );
+ if ( $pos ) {
+ $header_name = trim( substr( $header, 0, $pos ) );
+ $header_value = trim( substr( $header, $pos + 1 ) );
+ } else {
+ $header_name = $header;
+ $header_value = '';
+ }
+ $headers_kv[$header_name] = $header_value;
+ $headers_plain[] = array(
+ 'name' => $header_name,
+ 'value' => $header_value
+ );
+ }
+ }
+ }
+
+ return array(
+ 'kv' => $headers_kv,
+ 'plain' => $headers_plain
+ );
+ }
+
+ /**
+ * Checks for buggy IE6 that doesn't support compression
+ *
+ * @return boolean
+ */
+ function _is_buggy_ie() {
+ if ( isset( $_SERVER['HTTP_USER_AGENT'] ) ) {
+ $ua = $_SERVER['HTTP_USER_AGENT'];
+
+ if ( strpos( $ua, 'Mozilla/4.0 (compatible; MSIE ' ) === 0 && strpos( $ua, 'Opera' ) === false ) {
+ $version = (float) substr( $ua, 30 );
+
+ return $version < 6 || ( $version == 6 && strpos( $ua, 'SV1' ) === false );
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Returns array of data headers
+ *
+ * @return array
+ */
+ function _get_cached_headers( $response_headers ) {
+ $data_headers = array();
+ $cache_headers = array_merge(
+ array( 'Location', 'X-WP-Total', 'X-WP-TotalPages' ),
+ $this->_config->get_array( 'pgcache.cache.headers' )
+ );
+
+ if ( function_exists( 'http_response_code' ) ) { // php5.3 compatibility
+ $data_headers['Status-Code'] = http_response_code();
+ }
+
+ $repeating_headers = array(
+ 'link',
+ 'cookie',
+ 'set-cookie'
+ );
+ $repeating_headers = apply_filters( 'w3tc_repeating_headers',
+ $repeating_headers );
+
+ foreach ( $response_headers as $i ) {
+ $header_name = $i['name'];
+ $header_value = $i['value'];
+
+ foreach ( $cache_headers as $cache_header_name ) {
+ if ( strcasecmp( $header_name, $cache_header_name ) == 0 ) {
+ $header_name_lo = strtolower( $header_name );
+ if ( in_array($header_name_lo, $repeating_headers) ) {
+ // headers may repeat
+ $data_headers[] = array(
+ 'n' => $header_name,
+ 'v' => $header_value
+ );
+ } else {
+ $data_headers[$header_name] = $header_value;
+ }
+ }
+ }
+ }
+
+ return $data_headers;
+ }
+
+ /**
+ * Returns page key
+ *
+ * @return string
+ */
+ function _get_page_key( $page_key_extension, $request_url = '' ) {
+ // key url part
+ if ( empty( $request_url ) ) {
+ $request_url_fragments = $this->_request_url_fragments;
+ } else {
+ $request_url_fragments = array();
+
+ $parts = parse_url( $request_url );
+
+ if ( isset( $parts['host'] ) ) {
+ $request_url_fragments['host'] = $parts['host'] .
+ ( isset( $parts['port'] ) ? ':' . $parts['port'] : '' );
+ } else {
+ $request_url_fragments['host'] = $this->_request_url_fragments['host'];
+ }
+
+ $request_url_fragments['path'] =
+ ( isset( $parts['path'] ) ? $parts['path'] : '' );
+ $request_url_fragments['querystring'] =
+ ( isset( $parts['query'] ) ? '?' . $parts['query'] : '' );
+ $request_url_fragments = $this->_normalize_url_fragments(
+ $request_url_fragments );
+ }
+
+ $key_urlpart =
+ $request_url_fragments['host'] .
+ $request_url_fragments['path'] .
+ $request_url_fragments['querystring'];
+
+ $key_urlpart = $this->_get_page_key_urlpart( $key_urlpart, $page_key_extension );
+
+ // key extension
+ $key_extension = '';
+ $extensions = array( 'useragent', 'referrer', 'cookie', 'encryption' );
+ foreach ( $extensions as $e ) {
+ if ( !empty( $page_key_extension[$e] ) ) {
+ $key_extension .= '_' . $page_key_extension[$e];
+ }
+ }
+ if ( Util_Environment::is_preview_mode() ) {
+ $key_extension .= '_preview';
+ }
+
+ // key postfix
+ $key_postfix = '';
+ if ( $this->_enhanced_mode && empty( $page_key_extension['group'] ) ) {
+ $key_postfix = '.html';
+ if ( $this->_config->get_boolean( 'pgcache.cache.nginx_handle_xml' ) ) {
+ $content_type = isset( $page_key_extension['content_type'] ) ?
+ $page_key_extension['content_type'] : '';
+
+ if ( @preg_match( "~(text/xml|text/xsl|application/xhtml\+xml|application/rdf\+xml|application/rss\+xml|application/atom\+xml|application/xml)~i", $content_type ) ||
+ preg_match( W3TC_FEED_REGEXP, $request_url_fragments['path'] ) ||
+ strpos( $request_url_fragments['path'], ".xsl" ) !== false ) {
+ $key_postfix = '.xml';
+ }
+ }
+ }
+
+ // key compression
+ $key_compression = '';
+ if ( $page_key_extension['compression'] ) {
+ $key_compression = '_' . $page_key_extension['compression'];
+ }
+
+ $key = w3tc_apply_filters( 'pagecache_page_key', array(
+ 'key' => array(
+ $key_urlpart,
+ $key_extension,
+ $key_postfix,
+ $key_compression
+ ),
+ 'page_key_extension' => $page_key_extension,
+ 'url_fragments' => $this->_request_url_fragments
+ ) );
+
+ return implode( '', $key['key'] );
+ }
+
+ private function _get_page_key_urlpart( $key, $page_key_extension ) {
+ // remove fragments
+ $key = preg_replace( '~#.*$~', '', $key );
+
+ // host/uri in different cases means the same page in wp
+ $key = strtolower( $key );
+
+ if ( empty( $page_key_extension['group'] ) ) {
+ if ( $this->_enhanced_mode || $this->_nginx_memcached ) {
+ // URL decode
+ $key = urldecode( $key );
+
+ // replace double slashes
+ $key = preg_replace( '~[/\\\]+~', '/', $key );
+
+ // replace index.php
+ $key = str_replace( '/index.php', '/', $key );
+
+ // remove querystring
+ $key = preg_replace( '~\?.*$~', '', $key );
+
+ // make sure one slash is at the end
+ $key = trim( $key, '/' ) . '/';
+
+ if ( $this->_nginx_memcached ) {
+ return $key;
+ }
+
+ return $key . '_index';
+ }
+ }
+
+ return md5( $key );
+ }
+
+ /**
+ * Returns debug info
+ *
+ * @param boolean $cache
+ * @param string $reason
+ * @param boolean $status
+ * @param double $time
+ * @return string
+ */
+ public function w3tc_footer_comment( $strings ) {
+ $strings[] = sprintf(
+ // translators: 1: Engine name, 2: Reject reason placeholder, 3: Page key extension.
+ __( 'Page Caching using %1$s%2$s%3$s', 'w3-total-cache' ),
+ Cache::engine_name( $this->_config->get_string( 'pgcache.engine' ) ),
+ '{w3tc_pagecache_reject_reason}',
+ isset( $this->_page_key_extension['cookie'] ) ? ' ' . $this->_page_key_extension['cookie'] : ''
+ );
+
+
+ if ( $this->_debug ) {
+ $time_total = Util_Debug::microtime() - $this->_time_start;
+ $engine = $this->_config->get_string( 'pgcache.engine' );
+ $strings[] = '';
+ $strings[] = 'Page cache debug info:';
+ $strings[] = sprintf( "%s%s", str_pad( 'Engine: ', 20 ), Cache::engine_name( $engine ) );
+ $strings[] = sprintf( "%s%s", str_pad( 'Cache key: ', 20 ), $this->_page_key );
+
+ $strings[] = sprintf( "%s%.3fs", str_pad( 'Creation Time: ', 20 ), time() );
+
+ $headers = $this->_get_response_headers();
+
+ if ( count( $headers['plain'] ) ) {
+ $strings[] = "Header info:";
+
+ foreach ( $headers['plain'] as $i ) {
+ $strings[] = sprintf( "%s%s",
+ str_pad( $i['name'] . ': ', 20 ),
+ Util_Content::escape_comment( $i['value'] ) );
+ }
+ }
+
+ $strings[] = '';
+ }
+
+ return $strings;
+ }
+
+ /**
+ * Sends headers
+ *
+ * @param array $headers
+ * @return boolean
+ */
+ function _headers( $headers ) {
+ if ( headers_sent() )
+ return false;
+
+ $repeating = array();
+ // headers are sent as name->value and array(n=>, v=>)
+ // to support repeating headers
+ foreach ( $headers as $name0 => $value0 ) {
+ if ( is_array( $value0 ) && isset( $value0['n'] ) ) {
+ $name = $value0['n'];
+ $value = $value0['v'];
+ } else {
+ $name = $name0;
+ $value = $value0;
+ }
+
+ if ( $name == 'Status' ) {
+ @header( $headers['Status'] );
+ } elseif ( $name == 'Status-Code' ) {
+ if ( function_exists( 'http_response_code' ) ) // php5.3 compatibility)
+ @http_response_code( $headers['Status-Code'] );
+ } elseif ( !empty( $name ) && !empty( $value ) ) {
+ @header( $name . ': ' . $value, !isset( $repeating[$name] ) );
+ $repeating[$name] = true;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Sends headers
+ *
+ * @param boolean $is_404
+ * @param string $etag
+ * @param integer $time
+ * @param string $compression
+ * @param array $custom_headers
+ * @return boolean
+ */
+ function _send_headers( $is_404, $time, $etag, $compression, $custom_headers = array() ) {
+ $exit = false;
+ $headers = ( is_array( $custom_headers ) ? $custom_headers : array() );
+ $curr_time = time();
+
+ $bc_lifetime = $this->_config->get_integer(
+ 'browsercache.html.lifetime' );
+
+ $expires = ( is_null( $time ) ? $curr_time : $time ) + $bc_lifetime;
+ $max_age = ( $expires > $curr_time ? $expires - $curr_time : 0 );
+
+ if ( $is_404 ) {
+ /**
+ * Add 404 header
+ */
+ $headers['Status'] = 'HTTP/1.1 404 Not Found';
+ } elseif ( ( !is_null( $time ) && $this->_check_modified_since( $time ) ) || $this->_check_match( $etag ) ) {
+ /**
+ * Add 304 header
+ */
+ $headers['Status'] = 'HTTP/1.1 304 Not Modified';
+
+ /**
+ * Don't send content if it isn't modified
+ */
+ $exit = true;
+ }
+
+ if ( $this->_config->get_boolean( 'browsercache.enabled' ) ) {
+
+ if ( $this->_config->get_boolean( 'browsercache.html.last_modified' ) ) {
+ $headers['Last-Modified'] = Util_Content::http_date( $time );
+ }
+
+ if ( $this->_config->get_boolean( 'browsercache.html.expires' ) ) {
+ $headers['Expires'] = Util_Content::http_date( $expires );
+ }
+
+ if ( $this->_config->get_boolean( 'browsercache.html.cache.control' ) ) {
+ switch ( $this->_config->get_string( 'browsercache.html.cache.policy' ) ) {
+ case 'cache':
+ $headers['Pragma'] = 'public';
+ $headers['Cache-Control'] = 'public';
+ break;
+
+ case 'cache_public_maxage':
+ $headers['Pragma'] = 'public';
+ $headers['Cache-Control'] = sprintf( 'max-age=%d, public', $max_age );
+ break;
+
+ case 'cache_validation':
+ $headers['Pragma'] = 'public';
+ $headers['Cache-Control'] = 'public, must-revalidate, proxy-revalidate';
+ break;
+
+ case 'cache_noproxy':
+ $headers['Pragma'] = 'public';
+ $headers['Cache-Control'] = 'private, must-revalidate';
+ break;
+
+ case 'cache_maxage':
+ $headers['Pragma'] = 'public';
+ $headers['Cache-Control'] = sprintf( 'max-age=%d, public, must-revalidate, proxy-revalidate', $max_age );
+ break;
+
+ case 'no_cache':
+ $headers['Pragma'] = 'no-cache';
+ $headers['Cache-Control'] = 'max-age=0, private, no-store, no-cache, must-revalidate';
+ break;
+ }
+ }
+
+ if ( $this->_config->get_boolean( 'browsercache.html.etag' ) ) {
+ $headers['ETag'] = '"' . $etag . '"';
+ }
+ }
+
+
+ $headers = array_merge( $headers,
+ $this->_get_common_headers( $compression ) );
+
+ /**
+ * Send headers to client
+ */
+ $result = $this->_headers( $headers );
+
+ if ( $exit )
+ exit();
+
+ return $result;
+ }
+
+ /**
+ * Returns headers to send regardless is page caching is active
+ */
+ function _get_common_headers( $compression ) {
+ $headers = array();
+
+ if ( $this->_config->get_boolean( 'browsercache.enabled' ) ) {
+ if ( $this->_config->get_boolean( 'browsercache.html.w3tc' ) ) {
+ $headers['X-Powered-By'] = Util_Environment::w3tc_header();
+ }
+ }
+
+ $vary = '';
+ //compressed && UAG
+ if ( $compression && $this->_page_key_extension['useragent'] ) {
+ $vary = 'Accept-Encoding,User-Agent,Cookie';
+ $headers['Content-Encoding'] = $compression;
+ //compressed
+ } elseif ( $compression ) {
+ $vary = 'Accept-Encoding';
+ $headers['Content-Encoding'] = $compression;
+ //uncompressed && UAG
+ } elseif ( $this->_page_key_extension['useragent'] ) {
+ $vary = 'User-Agent,Cookie';
+ }
+
+ //Add Cookie to vary if user logged in and not previously set
+ if ( !$this->_check_logged_in() && strpos( $vary, 'Cookie' ) === false ) {
+ if ( $vary )
+ $vary .= ',Cookie';
+ else
+ $vary = 'Cookie';
+ }
+
+ /**
+ * Add vary header
+ */
+ if ( $vary )
+ $headers['Vary'] = $vary;
+
+ /**
+ * Disable caching for preview mode
+ */
+ if ( Util_Environment::is_preview_mode() ) {
+ $headers['Pragma'] = 'private';
+ $headers['Cache-Control'] = 'private';
+ }
+
+ return $headers;
+ }
+
+ /**
+ * Check if content was modified by time
+ *
+ * @param integer $time
+ * @return boolean
+ */
+ function _check_modified_since( $time ) {
+ if ( !empty( $_SERVER['HTTP_IF_MODIFIED_SINCE'] ) ) {
+ $if_modified_since = $_SERVER['HTTP_IF_MODIFIED_SINCE'];
+
+ // IE has tacked on extra data to this header, strip it
+ if ( ( $semicolon = strrpos( $if_modified_since, ';' ) ) !== false ) {
+ $if_modified_since = substr( $if_modified_since, 0, $semicolon );
+ }
+
+ return $time == strtotime( $if_modified_since );
+ }
+
+ return false;
+ }
+
+ /**
+ * Check if content was modified by etag
+ *
+ * @param string $etag
+ * @return boolean
+ */
+ function _check_match( $etag ) {
+ if ( !empty( $_SERVER['HTTP_IF_NONE_MATCH'] ) ) {
+ $if_none_match = $_SERVER['HTTP_IF_NONE_MATCH'] ;
+ $client_etags = explode( ',', $if_none_match );
+
+ foreach ( $client_etags as $client_etag ) {
+ $client_etag = trim( $client_etag );
+
+ if ( $etag == $client_etag ) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Bad Behavior support
+ *
+ * @return void
+ */
+ function _bad_behavior() {
+ $bb_file = $this->_config->get_string( 'pgcache.bad_behavior_path' );
+ if ( $bb_file != '' )
+ require_once $bb_file;
+ }
+
+ /**
+ * Parses dynamic tags
+ */
+ function _parse_dynamic( $buffer ) {
+ if ( !defined( 'W3TC_DYNAMIC_SECURITY' ) )
+ return $buffer;
+
+ $buffer = preg_replace_callback( '~(.*)~Uis', array(
+ $this,
+ '_parse_dynamic_mfunc'
+ ), $buffer );
+
+ $buffer = preg_replace_callback( '~(.*)~Uis', array(
+ $this,
+ '_parse_dynamic_mclude'
+ ), $buffer );
+
+ return $buffer;
+ }
+
+ /**
+ * Parse dynamic mfunc callback
+ *
+ * @param array $matches
+ * @return string
+ */
+ function _parse_dynamic_mfunc( $matches ) {
+ $code1 = trim( $matches[1] );
+ $code2 = trim( $matches[2] );
+ $code = ( $code1 ? $code1 : $code2 );
+
+ if ( $code ) {
+ $code = trim( $code, ';' ) . ';';
+
+ try {
+ ob_start();
+ $result = eval( $code );
+ $output = ob_get_contents();
+ ob_end_clean();
+ } catch ( \Exception $ex ) {
+ $result = false;
+ }
+
+ if ( $result === false ) {
+ $output = sprintf( 'Unable to execute code: %s', htmlspecialchars( $code ) );
+ }
+ } else {
+ $output = htmlspecialchars( 'Invalid mfunc tag syntax. The correct format is: or PHP code.' );
+ }
+
+ return $output;
+ }
+
+ /**
+ * Parse dynamic mclude callback
+ *
+ * @param array $matches
+ * @return string
+ */
+ function _parse_dynamic_mclude( $matches ) {
+ $file1 = trim( $matches[1] );
+ $file2 = trim( $matches[2] );
+
+ $file = ( $file1 ? $file1 : $file2 );
+
+ if ( $file ) {
+ $file = ABSPATH . $file;
+
+ if ( file_exists( $file ) && is_readable( $file ) ) {
+ ob_start();
+ include $file;
+ $output = ob_get_contents();
+ ob_end_clean();
+ } else {
+ $output = sprintf( 'Unable to open file: %s', htmlspecialchars( $file ) );
+ }
+ } else {
+ $output = htmlspecialchars( 'Incorrect mclude tag syntax. The correct format is: or path/to/file.php.' );
+ }
+
+ return $output;
+ }
+
+ /**
+ * Checks if buffer has dynamic tags
+ *
+ * @param string $buffer
+ * @return boolean
+ */
+ function _has_dynamic( $buffer ) {
+ if ( !defined( 'W3TC_DYNAMIC_SECURITY' ) )
+ return false;
+
+ return preg_match( '~(.*)~Uis', $buffer );
+ }
+
+ /**
+ * Check whether requested page has content type that can be cached
+ *
+ * @return bool
+ */
+ private function _is_cacheable_content_type() {
+ $content_type = '';
+ $headers = headers_list();
+ foreach ( $headers as $header ) {
+ $header = strtolower( $header );
+ $m = null;
+ if ( preg_match( '~\s*content-type\s*:([^;]+)~', $header, $m ) ) {
+ $content_type = trim( $m[1] );
+ }
+ }
+
+ $cache_headers = apply_filters( 'w3tc_is_cacheable_content_type',
+ array(
+ '' /* redirects, they have only Location header set */,
+ 'application/json', 'text/html', 'text/xml', 'text/xsl',
+ 'application/xhtml+xml', 'application/rss+xml',
+ 'application/atom+xml', 'application/rdf+xml',
+ 'application/xml'
+ )
+ );
+ return in_array( $content_type, $cache_headers );
+ }
+
+ /**
+ * Fills $_request_url_fragments['path'], $_request_url_fragments['querystring']
+ * with cache-related normalized values
+ */
+ private function _preprocess_request_uri() {
+ $p = explode( '?', $this->_request_uri, 2 );
+
+ $this->_request_url_fragments['path'] = $p[0];
+ $this->_request_url_fragments['querystring'] =
+ ( empty( $p[1] ) ? '' : '?' . $p[1] );
+
+ $this->_request_url_fragments = $this->_normalize_url_fragments(
+ $this->_request_url_fragments );
+ }
+
+
+
+ private function _normalize_url_fragments( $fragments ) {
+ $fragments = w3tc_apply_filters( 'pagecache_normalize_url_fragments',
+ $fragments );
+ $fragments['querystring'] = $this->_normalize_querystring(
+ $fragments['querystring'] );
+
+ return $fragments;
+ }
+
+
+
+ private function _normalize_querystring( $querystring ) {
+ $ignore_qs = $this->_config->get_array( 'pgcache.accept.qs' );
+ $ignore_qs = w3tc_apply_filters( 'pagecache_extract_accept_qs', $ignore_qs );
+ Util_Rule::array_trim( $ignore_qs );
+
+ if ( empty( $ignore_qs ) || empty( $querystring ) ) {
+ return $querystring;
+ }
+
+ $querystring_naked = substr( $querystring, 1 );
+
+ foreach ( $ignore_qs as $qs ) {
+ $m = null;
+ if ( strpos( $qs, '=' ) === false ) {
+ $regexp = Util_Environment::preg_quote( str_replace( '+', ' ', $qs ) );
+ if ( @preg_match( "~^(.*?&|)$regexp(=[^&]*)?(&.*|)$~i", $querystring_naked, $m ) ) {
+ $querystring_naked = $m[1] . $m[3];
+ }
+ } else {
+ $regexp = Util_Environment::preg_quote( str_replace( '+', ' ', $qs ) );
+
+ if ( @preg_match( "~^(.*?&|)$regexp(&.*|)$~i", $querystring_naked, $m ) ) {
+ $querystring_naked = $m[1] . $m[2];
+ }
+ }
+ }
+
+ $querystring_naked = preg_replace( '~[&]+~', '&', $querystring_naked );
+ $querystring_naked = trim( $querystring_naked, '&' );
+
+ return empty( $querystring_naked ) ? '' : '?' . $querystring_naked;
+ }
+
+ /**
+ *
+ */
+ public function delayed_cache_print() {
+ if ( $this->_late_caching && $this->_caching ) {
+ $this->_cached_data = $this->_extract_cached_page( true );
+ if ( $this->_cached_data ) {
+ global $w3_late_caching_succeeded;
+ $w3_late_caching_succeeded = true;
+
+ $this->process_status = 'hit';
+ $this->process_cached_page_and_exit( $this->_cached_data );
+ // if is passes here - exit is not possible now and
+ // will happen on init
+ return;
+ }
+ }
+
+ if ( $this->_late_init && $this->_caching ) {
+ $this->process_status = 'hit';
+ $this->process_cached_page_and_exit( $this->_cached_data );
+ // if is passes here - exit is not possible now and
+ // will happen on init
+ return;
+ }
+ }
+
+ private function _maybe_save_cached_result( $buffer, $response_headers, $has_dynamic ) {
+ $mobile_group = $this->_page_key_extension['useragent'];
+ $referrer_group = $this->_page_key_extension['referrer'];
+ $encryption = $this->_page_key_extension['encryption'];
+ $compression_header = $this->_page_key_extension['compression'];
+ $compressions_to_store = $this->_get_compressions();
+
+ /**
+ * Don't compress here for debug mode or dynamic tags
+ * because we need to modify buffer before send it to client
+ */
+ if ( $this->_debug || $has_dynamic ) {
+ $compressions_to_store = array( false );
+ }
+
+ // right now dont return compressed buffer if we are dynamic,
+ // that will happen on shutdown after processing dynamic stuff
+ $compression_of_returned_content =
+ ( $has_dynamic ? false : $compression_header );
+
+ $headers = $this->_get_cached_headers( $response_headers['plain'] );
+ if ( !empty( $headers['Status-Code'] ) ) {
+ $is_404 = ( $headers['Status-Code'] == 404 );
+ } elseif ( function_exists( 'is_404' ) ) {
+ $is_404 = is_404();
+ } else {
+ $is_404 = false;
+ }
+
+ if ( $this->_enhanced_mode ) {
+ // redirect issued, if we have some old cache entries
+ // they will be turned into fresh files and catch further requests
+ if ( isset( $response_headers['kv']['Location'] ) ) {
+ $cache = $this->_get_cache( $this->_page_key_extension['group'] );
+
+ foreach ( $compressions_to_store as $_compression ) {
+ $_page_key = $this->_get_page_key(
+ array_merge( $this->_page_key_extension,
+ array( 'compression' => $_compression ) ) );
+ $cache->hard_delete( $_page_key );
+ }
+
+ return $buffer;
+ }
+ }
+
+ $content_type = '';
+ if ( $this->_enhanced_mode && !$this->_late_init ) {
+ register_shutdown_function( array(
+ $this,
+ '_check_rules_present'
+ ) );
+
+ if ( isset( $response_headers['kv']['Content-Type'] ) ) {
+ $content_type = $response_headers['kv']['Content-Type'];
+ }
+ }
+
+ $time = time();
+ $cache = $this->_get_cache( $this->_page_key_extension['group'] );
+
+ /**
+ * Store different versions of cache
+ */
+ $buffers = array();
+ $something_was_set = false;
+
+ foreach ( $compressions_to_store as $_compression ) {
+ $this->_set_extract_page_key(
+ array_merge( $this->_page_key_extension,
+ array(
+ 'compression' => $_compression,
+ 'content_type' => $content_type ) ), true );
+ if ( empty( $this->_page_key ) )
+ continue;
+
+ // Compress content
+ $buffers[$_compression] = $this->_compress( $buffer, $_compression );
+
+ // Store cache data
+ $_data = array(
+ '404' => $is_404,
+ 'headers' => $headers,
+ 'time' => $time,
+ 'content' => $buffers[$_compression]
+ );
+ if ( !empty( $_compression ) ) {
+ $_data['c'] = $_compression;
+ }
+ if ( $has_dynamic )
+ $_data['has_dynamic'] = true;
+
+ $_data = apply_filters( 'w3tc_pagecache_set', $_data, $this->_page_key,
+ $this->_page_group );
+
+ if ( !empty( $_data ) ) {
+ $cache->set( $this->_page_key, $_data, $this->_lifetime, $this->_page_group );
+ $something_was_set = true;
+ }
+ }
+
+ if ( $something_was_set ) {
+ $this->process_status = 'miss_fill';
+ } else {
+ $this->process_status = 'miss_third_party';
+ }
+
+ // Change buffer if using compression
+ if ( defined( 'W3TC_PAGECACHE_OUTPUT_COMPRESSION_OFF' ) ) {
+ $compression_header = false;
+ } elseif ( $compression_of_returned_content &&
+ isset( $buffers[$compression_of_returned_content] ) ) {
+ $buffer = $buffers[$compression_of_returned_content];
+ }
+
+ // Calculate content etag
+ $etag = md5( $buffer );
+
+ // Send headers
+ $this->_send_headers( $is_404, $time, $etag, $compression_header,
+ $headers );
+ return $buffer;
+ }
+
+ public function w3tc_usage_statistics_of_request( $storage ) {
+ global $w3tc_start_microtime;
+ $time_ms = 0;
+ if ( !empty( $w3tc_start_microtime ) ) {
+ $time_ms = (int)( ( microtime( true ) - $w3tc_start_microtime ) * 1000 );
+ $storage->counter_add( 'pagecache_requests_time_10ms', (int)( $time_ms / 10 ) );
+ }
+
+ if ( !empty( $this->process_status ) ) {
+ // see registered keys in PgCache_Plugin.w3tc_usage_statistics_metrics
+ $storage->counter_add( 'php_requests_pagecache_' . $this->process_status, 1 );
+
+ if ( $this->_debug ) {
+ self::log( 'finished in ' . $time_ms .
+ ' size ' . $this->output_size .
+ ' with process status ' .
+ $this->process_status .
+ ' reason ' . $this->cache_reject_reason);
+ }
+ }
+ }
+
+
+
+ /**
+ * Log
+ */
+ static protected function log( $msg ) {
+ $data = sprintf( "[%s] [%s] [%s] %s\n", date( 'r' ),
+ $_SERVER['REQUEST_URI'],
+ ( !empty( $_SERVER['HTTP_REFERER'] ) ? $_SERVER['HTTP_REFERER'] : '-' ),
+ $msg );
+ $data = strtr( $data, '<>', '..' );
+
+ $filename = Util_Debug::log_filename( 'pagecache' );
+ return @file_put_contents( $filename, $data, FILE_APPEND );
+ }
+}
diff --git a/wp-content/plugins/w3-total-cache/PgCache_Environment.php b/wp-content/plugins/w3-total-cache/PgCache_Environment.php
new file mode 100644
index 0000000000..52deeea132
--- /dev/null
+++ b/wp-content/plugins/w3-total-cache/PgCache_Environment.php
@@ -0,0 +1,1534 @@
+wp_config_add_directive();
+ } catch ( Util_WpFile_FilesystemOperationException $ex ) {
+ $exs->push( $ex );
+ }
+ }
+
+ $this->fix_folders( $config, $exs );
+
+ if ( $config->get_boolean( 'config.check' ) || $force_all_checks ) {
+ if ( $this->is_rules_required( $config ) ) {
+ $this->rules_core_add( $config, $exs );
+ $this->rules_cache_add( $config, $exs );
+ } else {
+ $this->rules_core_remove( $exs );
+ $this->rules_cache_remove( $exs );
+ }
+ }
+
+ // if no errors so far - check if rewrite actually works
+ if ( count( $exs->exceptions() ) <= 0 ) {
+ try {
+ if ( $config->get_boolean( 'pgcache.enabled' ) &&
+ $config->get_string( 'pgcache.engine' ) == 'file_generic' ) {
+ $this->verify_file_generic_compatibility();
+
+ if ( $config->get_boolean( 'pgcache.debug' ) )
+ $this->verify_file_generic_rewrite_working();
+ }
+ } catch ( \Exception $ex ) {
+ $exs->push( $ex );
+ }
+ }
+
+ if ( count( $exs->exceptions() ) > 0 )
+ throw $exs;
+ }
+
+ /**
+ * Fixes environment once event occurs
+ *
+ * @param Config $config
+ * @param string $event
+ * @param null|Config $old_config
+ * @throws Util_Environment_Exceptions
+ */
+ public function fix_on_event( $config, $event, $old_config = null ) {
+ // Schedules events
+ if ( $config->get_boolean( 'pgcache.enabled' ) &&
+ ( $config->get_string( 'pgcache.engine' ) == 'file' ||
+ $config->get_string( 'pgcache.engine' ) == 'file_generic' ) ) {
+ if ( $old_config != null &&
+ $config->get_integer( 'pgcache.file.gc' ) !=
+ $old_config->get_integer( 'pgcache.file.gc' ) ) {
+ $this->unschedule_gc();
+ }
+
+ if ( !wp_next_scheduled( 'w3_pgcache_cleanup' ) ) {
+ wp_schedule_event( time(),
+ 'w3_pgcache_cleanup', 'w3_pgcache_cleanup' );
+ }
+ } else {
+ $this->unschedule_gc();
+ }
+
+ // Schedule prime event
+ if ( $config->get_boolean( 'pgcache.enabled' ) &&
+ $config->get_boolean( 'pgcache.prime.enabled' ) ) {
+ if ( $old_config != null &&
+ $config->get_integer( 'pgcache.prime.interval' ) !=
+ $old_config->get_integer( 'pgcache.prime.interval' ) ) {
+ $this->unschedule_prime();
+ }
+
+ if ( !wp_next_scheduled( 'w3_pgcache_prime' ) ) {
+ wp_schedule_event( time(),
+ 'w3_pgcache_prime', 'w3_pgcache_prime' );
+ }
+ } else {
+ $this->unschedule_prime();
+ }
+ }
+
+ /**
+ * Fixes environment after plugin deactivation
+ *
+ * @throws Util_Environment_Exceptions
+ */
+ public function fix_after_deactivation() {
+ $exs = new Util_Environment_Exceptions();
+
+ try {
+ $this->wp_config_remove_directive( $exs );
+ } catch ( Util_WpFile_FilesystemOperationException $ex ) {
+ $exs->push( $ex );
+ }
+
+ $this->rules_core_remove( $exs );
+ $this->rules_cache_remove( $exs );
+
+ $this->unschedule_gc();
+ $this->unschedule_prime();
+
+ if ( count( $exs->exceptions() ) > 0 )
+ throw $exs;
+ }
+
+ /**
+ * Are rewrite rules required?.
+ *
+ * @since 0.9.7.3
+ *
+ * @param Config $c Configuration.
+ * @return bool
+ */
+ private function is_rules_required( $c ) {
+ $e = $c->get_string( 'pgcache.engine' );
+
+ return $c->get_boolean( 'pgcache.enabled' ) &&
+ ( 'file_generic' === $e || 'nginx_memcached' === $e );
+ }
+
+ /**
+ * Returns required rules for module
+ *
+ * @param Config $config
+ * @return array
+ */
+ public function get_required_rules( $config ) {
+ if ( !$this->is_rules_required( $config ) ) {
+ return null;
+ }
+
+ $rewrite_rules = array();
+ $pgcache_rules_core_path = Util_Rule::get_pgcache_rules_core_path();
+ $rewrite_rules[] = array(
+ 'filename' => $pgcache_rules_core_path,
+ 'content' => $this->rules_core_generate( $config ),
+ 'priority' => 1000
+ );
+
+ $pgcache_rules_cache_path = Util_Rule::get_pgcache_rules_cache_path();
+ $rewrite_rules[] = array(
+ 'filename' => $pgcache_rules_cache_path,
+ 'content' => $this->rules_cache_generate( $config )
+ );
+
+ return $rewrite_rules;
+ }
+
+
+
+ /**
+ * Fixes folders
+ *
+ * @param Config $config
+ * @param Util_Environment_Exceptions $exs
+ */
+ private function fix_folders( $config, $exs ) {
+ if ( !$config->get_boolean( 'pgcache.enabled' ) )
+ return;
+
+ // folder that we delete if exists and not writeable
+ if ( $config->get_string( 'pgcache.engine' ) == 'file_generic' )
+ $dir = W3TC_CACHE_PAGE_ENHANCED_DIR;
+ else if ( $config->get_string( 'pgcache.engine' ) != 'file' )
+ $dir = W3TC_CACHE_DIR . '/page';
+ else
+ return;
+
+ try{
+ if ( file_exists( $dir ) && !is_writeable( $dir ) )
+ Util_WpFile::delete_folder( $dir, '', $_SERVER['REQUEST_URI'] );
+ } catch ( Util_WpFile_FilesystemRmdirException $ex ) {
+ $exs->push( $ex );
+ }
+ }
+
+ /**
+ * Checks if mode can be used
+ */
+ private function verify_file_generic_compatibility() {
+ $permalink_structure = get_option( 'permalink_structure' );
+
+ if ( $permalink_structure == '' ) {
+ throw new Util_Environment_Exception( 'Disk Enhanced mode ' .
+ 'can\'t work with "Default" permalinks structure' );
+ }
+ }
+
+ /**
+ * Fixes environment for enabled pgcache
+ *
+ * @throws Util_Environment_Exceptions
+ */
+ private function verify_file_generic_rewrite_working() {
+ $url = get_home_url() . '/w3tc_rewrite_test' . rand();
+ if ( !$this->test_rewrite( $url ) ) {
+ $key = sprintf( 'w3tc_rewrite_test_result_%s', substr( md5( $url ), 0, 16 ) );
+ $result = get_transient( $key );
+
+ $home_url = get_home_url();
+
+ $tech_message =
+ ( Util_Environment::is_nginx() ? 'nginx configuration file' : '.htaccess file' ) .
+ ' contains rules to rewrite url ' .
+ $home_url . '/w3tc_rewrite_test into ' .
+ $home_url . '/?w3tc_rewrite_test which, if handled by ' .
+ 'plugin, return "OK" message. ';
+ $tech_message .= 'The plugin made a request to ' .
+ $home_url . '/w3tc_rewrite_test but received: ' .
+ $result . ' ';
+ $tech_message .= 'instead of "OK" response. ';
+
+ $error = 'W3 Total Cache error: ' .
+ 'It appears Page Cache ' .
+ 'URL ' .
+ 'rewriting is not working. ';
+ if ( Util_Environment::is_preview_mode() ) {
+ $error .= ' This could be due to using Preview mode. Click here to manually verify its working. It should say OK. ';
+ }
+
+ if ( Util_Environment::is_nginx() ) {
+ $error .= 'Please verify that all configuration files are ' .
+ 'included in the configuration file ' .
+ '(and that you have reloaded / restarted nginx).';
+ } else {
+ $error .= 'Please verify that the server configuration ' .
+ 'allows .htaccess';
+ }
+
+ $error .= ' Unfortunately disk enhanced page caching will ' .
+ 'not function without custom rewrite rules. ' .
+ 'Please ask your server administrator for assistance. ' .
+ 'Also refer to the install page for the rules for your server.';
+
+ throw new Util_Environment_Exception( $error, $tech_message );
+ }
+ }
+
+ /**
+ * Perform rewrite test
+ *
+ * @param string $url
+ * @return boolean
+ */
+ private function test_rewrite( $url ) {
+ $key = sprintf( 'w3tc_rewrite_test_%s', substr( md5( $url ), 0, 16 ) );
+ $result = get_transient( $key );
+
+ if ( $result === false ) {
+
+ $response = Util_Http::get( $url );
+
+ $result = ( !is_wp_error( $response ) && $response['response']['code'] == 200 && trim( $response['body'] ) == 'OK' );
+
+ if ( $result ) {
+ set_transient( $key, $result, 30 );
+ } else {
+ $key_result = sprintf( 'w3tc_rewrite_test_result_%s', substr( md5( $url ), 0, 16 ) );
+ set_transient( $key_result, is_wp_error( $response )? $response->get_error_message(): implode( ' ', $response['response'] ), 30 );
+ }
+ }
+
+ return $result;
+ }
+
+
+
+ /**
+ * scheduling stuff
+ */
+ private function unschedule_gc() {
+ if ( wp_next_scheduled( 'w3_pgcache_cleanup' ) )
+ wp_clear_scheduled_hook( 'w3_pgcache_cleanup' );
+ }
+
+ private function unschedule_prime() {
+ if ( wp_next_scheduled( 'w3_pgcache_prime' ) )
+ wp_clear_scheduled_hook( 'w3_pgcache_prime' );
+ }
+
+
+
+ /*
+ * wp-config modification
+ */
+
+ /**
+ * Enables WP_CACHE
+ *
+ * @throws Util_WpFile_FilesystemOperationException with S/FTP form if it can't get the required filesystem credentials
+ */
+ private function wp_config_add_directive() {
+ $config_path = Util_Environment::wp_config_path();
+
+ $config_data = @file_get_contents( $config_path );
+ if ( $config_data === false )
+ return;
+
+ $new_config_data = $this->wp_config_remove_from_content( $config_data );
+ $new_config_data = preg_replace(
+ '~<\?(php)?~',
+ "\\0\r\n" . $this->wp_config_addon(),
+ $new_config_data,
+ 1 );
+
+ if ( $new_config_data != $config_data ) {
+ try {
+ Util_WpFile::write_to_file( $config_path, $new_config_data );
+ } catch ( Util_WpFile_FilesystemOperationException $ex ) {
+ throw new Util_WpFile_FilesystemModifyException(
+ $ex->getMessage(), $ex->credentials_form(),
+ 'Edit file ' . $config_path .
+ ' and add next lines:', $config_path,
+ $this->wp_config_addon() );
+ }
+ }
+ // that file was in opcache for sure and it may take time to
+ // start execution of new modified now version
+ $o = Dispatcher::component( 'SystemOpCache_Core' );
+ $o->flush();
+ }
+
+ /**
+ * Disables WP_CACHE
+ *
+ * @throws Util_WpFile_FilesystemOperationException with S/FTP form if it can't get the required filesystem credentials
+ */
+ private function wp_config_remove_directive() {
+ $config_path = Util_Environment::wp_config_path();
+
+ $config_data = @file_get_contents( $config_path );
+ if ( $config_data === false )
+ return;
+
+ $new_config_data = $this->wp_config_remove_from_content( $config_data );
+ if ( $new_config_data != $config_data ) {
+ try {
+ Util_WpFile::write_to_file( $config_path, $new_config_data );
+ } catch ( Util_WpFile_FilesystemOperationException $ex ) {
+ throw new Util_WpFile_FilesystemModifyException(
+ $ex->getMessage(), $ex->credentials_form(),
+ 'Edit file ' . $config_path .
+ ' and remove next lines:',
+ $config_path, $this->wp_config_addon() );
+ }
+ }
+ }
+
+ /**
+ * Returns string Addon required for plugin in wp-config
+ */
+ private function wp_config_addon() {
+ return "/** Enable W3 Total Cache */\r\n" .
+ "define('WP_CACHE', true); // Added by W3 Total Cache\r\n";
+ }
+
+ /**
+ * Disables WP_CACHE
+ *
+ * @param string $config_data wp-config.php content
+ * @return string
+ * @throws Util_WpFile_FilesystemOperationException with S/FTP form if it can't get the required filesystem credentials
+ */
+ private function wp_config_remove_from_content( $config_data ) {
+ $config_data = preg_replace(
+ "~\\/\\*\\* Enable W3 Total Cache \\*\\*?\\/.*?\\/\\/ Added by W3 Total Cache(\r\n)*~s",
+ '', $config_data );
+ $config_data = preg_replace(
+ "~(\\/\\/\\s*)?define\\s*\\(\\s*['\"]?WP_CACHE['\"]?\\s*,.*?\\)\\s*;+\\r?\\n?~is",
+ '', $config_data );
+
+ return $config_data;
+ }
+
+
+
+ /**
+ * rules core modification
+ */
+
+ /**
+ * Writes directives to WP .htaccess / nginx.conf
+ * returns true if modifications has been made
+ */
+ private function rules_core_add( $config, $exs ) {
+ Util_Rule::add_rules( $exs, Util_Rule::get_pgcache_rules_core_path(),
+ $this->rules_core_generate( $config ),
+ W3TC_MARKER_BEGIN_PGCACHE_CORE,
+ W3TC_MARKER_END_PGCACHE_CORE,
+ array(
+ W3TC_MARKER_BEGIN_BROWSERCACHE_NO404WP => 0,
+ W3TC_MARKER_BEGIN_WORDPRESS => 0,
+ W3TC_MARKER_END_MINIFY_CORE =>
+ strlen( W3TC_MARKER_END_MINIFY_CORE ) + 1,
+ W3TC_MARKER_END_BROWSERCACHE_CACHE =>
+ strlen( W3TC_MARKER_END_BROWSERCACHE_CACHE ) + 1,
+ W3TC_MARKER_END_PGCACHE_CACHE =>
+ strlen( W3TC_MARKER_END_PGCACHE_CACHE ) + 1,
+ W3TC_MARKER_END_MINIFY_CACHE =>
+ strlen( W3TC_MARKER_END_MINIFY_CACHE ) + 1
+ ),
+ true
+ );
+ }
+
+ /**
+ * Removes Page Cache core directives
+ *
+ * @param Util_Environment_Exceptions $exs
+ * @throws Util_WpFile_FilesystemOperationException with S/FTP form if it can't get the required filesystem credentials
+ */
+ private function rules_core_remove( $exs ) {
+ Util_Rule::remove_rules( $exs, Util_Rule::get_pgcache_rules_core_path(),
+ W3TC_MARKER_BEGIN_PGCACHE_CORE,
+ W3TC_MARKER_END_PGCACHE_CORE
+ );
+ }
+
+ /**
+ * Generates rules for WP dir
+ *
+ * @param Config $config
+ * @return string
+ */
+ private function rules_core_generate( $config ) {
+ switch ( true ) {
+ case Util_Environment::is_apache():
+ case Util_Environment::is_litespeed():
+ return $this->rules_core_generate_apache( $config );
+
+ case Util_Environment::is_nginx():
+ return $this->rules_core_generate_nginx( $config );
+ }
+
+ return '';
+ }
+
+ /**
+ * Generates rules for WP dir
+ *
+ * @param Config $config
+ * @return string
+ */
+ private function rules_core_generate_apache( $config ) {
+ $rewrite_base = Util_Environment::network_home_url_uri();
+ $cache_dir = Util_Environment::normalize_path( W3TC_CACHE_PAGE_ENHANCED_DIR );
+ $permalink_structure = get_option( 'permalink_structure' );
+
+ $current_user = wp_get_current_user();
+
+ /**
+ * Auto reject cookies
+ */
+ $reject_cookies = array(
+ 'comment_author',
+ 'wp-postpass'
+ );
+
+ $reject_cookies[] = 'w3tc_logged_out';
+
+ /**
+ * Reject cache for logged in users
+ * OR
+ * Reject cache for roles if any
+ */
+ if ( $config->get_boolean( 'pgcache.reject.logged' ) ) {
+ $reject_cookies = array_merge( $reject_cookies, array(
+ 'wordpress_logged_in'
+ ) );
+ } elseif ( $config->get_boolean( 'pgcache.reject.logged_roles' ) ) {
+ $new_cookies = array();
+ foreach ( $config->get_array( 'pgcache.reject.roles' ) as $role ) {
+ $new_cookies[] = 'w3tc_logged_' . md5( NONCE_KEY . $role );
+ }
+ $reject_cookies = array_merge( $reject_cookies, $new_cookies );
+ }
+
+ /**
+ * Custom config
+ */
+ $reject_cookies = array_merge( $reject_cookies, $config->get_array( 'pgcache.reject.cookie' ) );
+ Util_Rule::array_trim( $reject_cookies );
+
+ $reject_user_agents = $config->get_array( 'pgcache.reject.ua' );
+ if ( $config->get_boolean( 'pgcache.compatibility' ) ) {
+ $reject_user_agents = array_merge( array( W3TC_POWERED_BY ), $reject_user_agents );
+ }
+
+ Util_Rule::array_trim( $reject_user_agents );
+
+ /**
+ * Generate directives
+ */
+ $env_W3TC_UA = '';
+ $env_W3TC_REF = '';
+ $env_W3TC_COOKIE = '';
+ $env_W3TC_SSL = '';
+ $env_W3TC_ENC = '';
+
+ $rules = '';
+ $rules .= W3TC_MARKER_BEGIN_PGCACHE_CORE . "\n";
+ $rules .= "\n";
+ $rules .= " RewriteEngine On\n";
+ $rules .= " RewriteBase " . $rewrite_base . "\n";
+
+
+ if ( $config->get_boolean( 'pgcache.debug' ) ) {
+ $rules .= " RewriteRule ^(.*\\/)?w3tc_rewrite_test([0-9]+)/?$ $1?w3tc_rewrite_test=1 [L]\n";
+ }
+
+
+ /**
+ * Set accept query strings
+ */
+ $w3tc_query_strings = apply_filters(
+ 'w3tc_pagecache_rules_apache_accept_qs',
+ $config->get_array( 'pgcache.accept.qs' ) );
+ Util_Rule::array_trim( $w3tc_query_strings );
+
+ if ( !empty( $w3tc_query_strings ) ) {
+ $w3tc_query_strings = str_replace( ' ', '+', $w3tc_query_strings );
+ $w3tc_query_strings = array_map( array( '\W3TC\Util_Environment', 'preg_quote' ), $w3tc_query_strings );
+
+ $rules .= " RewriteRule ^ - [E=W3TC_QUERY_STRING:%{QUERY_STRING}]\n";
+
+ foreach ( $w3tc_query_strings as $query ) {
+ $query_rules = array();
+ if ( strpos( $query, '=' ) === false ) {
+ $query_rules[] = 'RewriteCond %{ENV:W3TC_QUERY_STRING} ^(.*?&|)' .
+ $query . '(=[^&]*)?(&.*|)$ [NC]';
+ $query_rules[] = 'RewriteRule ^ - [E=W3TC_QUERY_STRING:%1%3]';
+ } else {
+ $query_rules[] = 'RewriteCond %{ENV:W3TC_QUERY_STRING} ^(.*?&|)' .
+ $query . '(&.*|)$ [NC]';
+ $query_rules[] = 'RewriteRule ^ - [E=W3TC_QUERY_STRING:%1%2]';
+ }
+
+ $query_rules = apply_filters(
+ 'w3tc_pagecache_rules_apache_accept_qs_rules',
+ $query_rules, $query );
+ $rules .= ' ' . implode( "\n ", $query_rules ) . "\n";
+ }
+
+ $rules .= " RewriteCond %{ENV:W3TC_QUERY_STRING} ^&+$\n";
+ $rules .= " RewriteRule ^ - [E=W3TC_QUERY_STRING]\n";
+ }
+
+ /**
+ * Check for mobile redirect
+ */
+ if ( $config->get_boolean( 'mobile.enabled' ) ) {
+ $mobile_groups = $config->get_array( 'mobile.rgroups' );
+
+ foreach ( $mobile_groups as $mobile_group => $mobile_config ) {
+ $mobile_enabled = ( isset( $mobile_config['enabled'] ) ? (boolean) $mobile_config['enabled'] : false );
+ $mobile_agents = ( isset( $mobile_config['agents'] ) ? (array) $mobile_config['agents'] : '' );
+ $mobile_redirect = ( isset( $mobile_config['redirect'] ) ? $mobile_config['redirect'] : '' );
+
+ if ( $mobile_enabled && count( $mobile_agents ) && $mobile_redirect ) {
+ $rules .= " RewriteCond %{HTTP_USER_AGENT} (" . implode( '|', $mobile_agents ) . ") [NC]\n";
+ $rules .= " RewriteRule .* " . $mobile_redirect . " [R,L]\n";
+ }
+ }
+ }
+
+ /**
+ * Check for referrer redirect
+ */
+ if ( $config->get_boolean( 'referrer.enabled' ) ) {
+ $referrer_groups = $config->get_array( 'referrer.rgroups' );
+
+ foreach ( $referrer_groups as $referrer_group => $referrer_config ) {
+ $referrer_enabled = ( isset( $referrer_config['enabled'] ) ? (boolean) $referrer_config['enabled'] : false );
+ $referrer_referrers = ( isset( $referrer_config['referrers'] ) ? (array) $referrer_config['referrers'] : '' );
+ $referrer_redirect = ( isset( $referrer_config['redirect'] ) ? $referrer_config['redirect'] : '' );
+
+ if ( $referrer_enabled && count( $referrer_referrers ) && $referrer_redirect ) {
+ $rules .= " RewriteCond %{HTTP_COOKIE} w3tc_referrer=.*(" . implode( '|', $referrer_referrers ) . ") [NC]\n";
+ $rules .= " RewriteRule .* " . $referrer_redirect . " [R,L]\n";
+ }
+ }
+ }
+
+ /**
+ * Set mobile groups
+ */
+ if ( $config->get_boolean( 'mobile.enabled' ) ) {
+ $mobile_groups = array_reverse( $config->get_array( 'mobile.rgroups' ) );
+
+ foreach ( $mobile_groups as $mobile_group => $mobile_config ) {
+ $mobile_enabled = ( isset( $mobile_config['enabled'] ) ? (boolean) $mobile_config['enabled'] : false );
+ $mobile_agents = ( isset( $mobile_config['agents'] ) ? (array) $mobile_config['agents'] : '' );
+ $mobile_redirect = ( isset( $mobile_config['redirect'] ) ? $mobile_config['redirect'] : '' );
+
+ if ( $mobile_enabled && count( $mobile_agents ) && !$mobile_redirect ) {
+ $rules .= " RewriteCond %{HTTP_USER_AGENT} (" . implode( '|', $mobile_agents ) . ") [NC]\n";
+ $rules .= " RewriteRule .* - [E=W3TC_UA:_" . $mobile_group . "]\n";
+ $env_W3TC_UA = '%{ENV:W3TC_UA}';
+ }
+ }
+ }
+
+ /**
+ * Set referrer groups
+ */
+ if ( $config->get_boolean( 'referrer.enabled' ) ) {
+ $referrer_groups = array_reverse( $config->get_array( 'referrer.rgroups' ) );
+
+ foreach ( $referrer_groups as $referrer_group => $referrer_config ) {
+ $referrer_enabled = ( isset( $referrer_config['enabled'] ) ? (boolean) $referrer_config['enabled'] : false );
+ $referrer_referrers = ( isset( $referrer_config['referrers'] ) ? (array) $referrer_config['referrers'] : '' );
+ $referrer_redirect = ( isset( $referrer_config['redirect'] ) ? $referrer_config['redirect'] : '' );
+
+ if ( $referrer_enabled && count( $referrer_referrers ) && !$referrer_redirect ) {
+ $rules .= " RewriteCond %{HTTP_COOKIE} w3tc_referrer=.*(" . implode( '|', $referrer_referrers ) . ") [NC]\n";
+ $rules .= " RewriteRule .* - [E=W3TC_REF:_" . $referrer_group . "]\n";
+ $env_W3TC_REF = '%{ENV:W3TC_REF}';
+ }
+ }
+ }
+
+ /**
+ * Set cookie group
+ */
+ if ( $config->get_boolean( 'pgcache.cookiegroups.enabled' ) ) {
+ $cookie_groups = $config->get_array( 'pgcache.cookiegroups.groups' );
+
+ foreach ( $cookie_groups as $group_name => $g ) {
+ if ( isset( $g['enabled'] ) && $g['enabled'] ) {
+ $cookies = array();
+ foreach ($g['cookies'] as $cookie ) {
+ $cookie = trim( $cookie );
+ if ( !empty( $cookie ) ) {
+ $cookie = str_replace( '+', ' ', $cookie );
+ $cookie = Util_Environment::preg_quote( $cookie );
+ if ( strpos( $cookie, '=') === false )
+ $cookie .= '=.*';
+ $cookies[] = $cookie;
+ }
+ }
+
+ if ( count( $cookies ) > 0 ) {
+ $cookies_regexp = '^(.*;\s*)?(' . implode( '|', $cookies ) . ')(\s*;.*)?$';
+ $rules .= " RewriteCond %{HTTP_COOKIE} $cookies_regexp [NC]\n";
+ $rules .= " RewriteRule .* - [E=W3TC_COOKIE:_" . $group_name . "]\n";
+ $env_W3TC_COOKIE = '%{ENV:W3TC_COOKIE}';
+ }
+ }
+ }
+ }
+
+ /**
+ * Set HTTPS
+ */
+ if ( $config->get_boolean( 'pgcache.cache.ssl' ) ) {
+ $rules .= " RewriteCond %{HTTPS} =on\n";
+ $rules .= " RewriteRule .* - [E=W3TC_SSL:_ssl]\n";
+ $rules .= " RewriteCond %{SERVER_PORT} =443\n";
+ $rules .= " RewriteRule .* - [E=W3TC_SSL:_ssl]\n";
+ $rules .= " RewriteCond %{HTTP:X-Forwarded-Proto} =https [NC]\n";
+ $rules .= " RewriteRule .* - [E=W3TC_SSL:_ssl]\n";
+ $env_W3TC_SSL = '%{ENV:W3TC_SSL}';
+ }
+
+ $cache_path = str_replace( Util_Environment::document_root(), '', $cache_dir );
+
+ /**
+ * Set Accept-Encoding
+ */
+ if ( $config->get_boolean( 'browsercache.enabled' ) && $config->get_boolean( 'browsercache.html.brotli' ) ) {
+ $rules .= " RewriteCond %{HTTP:Accept-Encoding} br\n";
+ $rules .= " RewriteRule .* - [E=W3TC_ENC:_br]\n";
+ $env_W3TC_ENC = '%{ENV:W3TC_ENC}';
+ } else if ( $config->get_boolean( 'browsercache.enabled' ) && $config->get_boolean( 'browsercache.html.compression' ) ) {
+ $rules .= " RewriteCond %{HTTP:Accept-Encoding} gzip\n";
+ $rules .= " RewriteRule .* - [E=W3TC_ENC:_gzip]\n";
+ $env_W3TC_ENC = '%{ENV:W3TC_ENC}';
+ }
+ $rules .= " RewriteCond %{HTTP_COOKIE} w3tc_preview [NC]\n";
+ $rules .= " RewriteRule .* - [E=W3TC_PREVIEW:_preview]\n";
+ $env_W3TC_PREVIEW = '%{ENV:W3TC_PREVIEW}';
+
+ $use_cache_rules = '';
+ /**
+ * Don't accept POSTs
+ */
+ $use_cache_rules .= " RewriteCond %{REQUEST_METHOD} !=POST\n";
+
+ /**
+ * Query string should be empty
+ */
+ $use_cache_rules .= empty( $w3tc_query_strings ) ?
+ " RewriteCond %{QUERY_STRING} =\"\"\n" :
+ " RewriteCond %{ENV:W3TC_QUERY_STRING} =\"\"\n";
+
+ /**
+ * Check for rejected cookies
+ */
+ $use_cache_rules .= " RewriteCond %{HTTP_COOKIE} !(" . implode( '|',
+ array_map( array( '\W3TC\Util_Environment', 'preg_quote' ), $reject_cookies ) ) . ") [NC]\n";
+
+ /**
+ * Check for rejected user agents
+ */
+ if ( count( $reject_user_agents ) ) {
+ $use_cache_rules .= " RewriteCond %{HTTP_USER_AGENT} !(" .
+ implode( '|',
+ array_map( array( '\W3TC\Util_Environment', 'preg_quote' ), $reject_user_agents ) ) . ") [NC]\n";
+ }
+
+ /**
+ * Make final rewrites for specific files
+ */
+ $uri_prefix = $cache_path . '/%{HTTP_HOST}/%{REQUEST_URI}/' .
+ '_index' . $env_W3TC_UA . $env_W3TC_REF . $env_W3TC_COOKIE .
+ $env_W3TC_SSL . $env_W3TC_PREVIEW;
+ $uri_prefix = apply_filters( 'w3tc_pagecache_rules_apache_uri_prefix',
+ $uri_prefix );
+
+ $switch = " -" . ( $config->get_boolean( 'pgcache.file.nfs' ) ? 'F' : 'f' );
+
+ $document_root = Util_Rule::apache_docroot_variable();
+
+ // write rule to rewrite to .html/.xml file
+ $exts = array( '.html' );
+ if ($config->get_boolean('pgcache.cache.nginx_handle_xml'))
+ $exts[] = '.xml';
+
+ foreach ( $exts as $ext ) {
+ $rules .= $use_cache_rules;
+
+ if ( $ext == '.html' ) {
+ /**
+ * Check permalink structure trailing slash
+ */
+ if ( substr( $permalink_structure, -1 ) == '/' ) {
+ $rules .= " RewriteCond %{REQUEST_URI} \\/$\n";
+ }
+ }
+
+ $rules .= " RewriteCond \"" . $document_root . $uri_prefix . $ext .
+ $env_W3TC_ENC . "\"" . $switch . "\n";
+ $rules .= " RewriteRule .* \"" . $uri_prefix . $ext .
+ $env_W3TC_ENC . "\" [L]\n";
+ }
+
+ $rules .= "\n";
+
+ $rules .= W3TC_MARKER_END_PGCACHE_CORE . "\n";
+
+ return $rules;
+ }
+
+ /**
+ * Generates rules for WP dir
+ *
+ * @param Config $config
+ * @return string
+ */
+ private function rules_core_generate_nginx( $config ) {
+ $is_network = Util_Environment::is_wpmu();
+
+ $cache_dir = Util_Environment::normalize_path( W3TC_CACHE_PAGE_ENHANCED_DIR );
+ $permalink_structure = get_option( 'permalink_structure' );
+ $pgcache_engine = $config->get_string( 'pgcache.engine' );
+
+ /**
+ * Auto reject cookies
+ */
+ $reject_cookies = array(
+ 'comment_author',
+ 'wp-postpass'
+ );
+
+ if ( $pgcache_engine == 'file_generic' ) {
+ $reject_cookies[] = 'w3tc_logged_out';
+ }
+
+ /**
+ * Reject cache for logged in users
+ * OR
+ * Reject cache for roles if any
+ */
+ if ( $config->get_boolean( 'pgcache.reject.logged' ) ) {
+ $reject_cookies = array_merge( $reject_cookies, array(
+ 'wordpress_logged_in'
+ ) );
+ } elseif ( $config->get_boolean( 'pgcache.reject.logged_roles' ) ) {
+ $new_cookies = array();
+ foreach ( $config->get_array( 'pgcache.reject.roles' ) as $role ) {
+ $new_cookies[] = 'w3tc_logged_' . md5( NONCE_KEY . $role );
+ }
+ $reject_cookies = array_merge( $reject_cookies, $new_cookies );
+ }
+
+ /**
+ * Custom config
+ */
+ $reject_cookies = array_merge( $reject_cookies,
+ $config->get_array( 'pgcache.reject.cookie' ) );
+ Util_Rule::array_trim( $reject_cookies );
+
+ $reject_user_agents = $config->get_array( 'pgcache.reject.ua' );
+ if ( $config->get_boolean( 'pgcache.compatibility' ) ) {
+ $reject_user_agents = array_merge( array( W3TC_POWERED_BY ),
+ $reject_user_agents );
+ }
+ Util_Rule::array_trim( $reject_user_agents );
+
+ /**
+ * Generate rules
+ */
+ $env_w3tc_ua = '';
+ $env_w3tc_ref = '';
+ $env_w3tc_cookie = '';
+ $env_w3tc_ssl = '';
+ $env_w3tc_ext = '';
+ $env_w3tc_enc = '';
+ $env_request_uri = '$request_uri';
+
+ $rules = '';
+ $rules .= W3TC_MARKER_BEGIN_PGCACHE_CORE . "\n";
+ if ( $config->get_boolean( 'pgcache.debug' ) ) {
+ $rules .= "rewrite ^(.*\\/)?w3tc_rewrite_test([0-9]+)/?$ $1?w3tc_rewrite_test=1 last;\n";
+ }
+
+ /**
+ * Set accept query strings
+ */
+ $w3tc_query_strings = apply_filters(
+ 'w3tc_pagecache_rules_nginx_accept_qs',
+ $config->get_array( 'pgcache.accept.qs' ) );
+
+ Util_Rule::array_trim( $w3tc_query_strings );
+
+ if ( !empty( $w3tc_query_strings ) ) {
+ $w3tc_query_strings = str_replace( ' ', '+', $w3tc_query_strings );
+ $w3tc_query_strings = array_map( array( '\W3TC\Util_Environment', 'preg_quote' ), $w3tc_query_strings );
+
+ $rules .= "set \$w3tc_query_string \$query_string;\n";
+
+ foreach ( $w3tc_query_strings as $query ) {
+ $query_rules = array();
+ if ( strpos( $query, '=' ) === false ) {
+ $query_rules[] = 'if ($w3tc_query_string ~* "^(.*?&|)' . $query . '(=[^&]*)?(&.*|)$") {';
+ $query_rules[] = ' set $w3tc_query_string $1$3;';
+ $query_rules[] = '}';
+ } else {
+ $query_rules[] = 'if ($w3tc_query_string ~* "^(.*?&|)' . $query . '(&.*|)$") {';
+ $query_rules[] = ' set $w3tc_query_string $1$2;';
+ $query_rules[] = '}';
+ }
+
+ $query_rules = apply_filters(
+ 'w3tc_pagecache_rules_nginx_accept_qs_rules',
+ $query_rules, $query );
+ $rules .= implode( "\n", $query_rules ) . "\n";
+ }
+
+ $rules .= "if (\$w3tc_query_string ~ ^[?&]+$) {\n";
+ $rules .= " set \$w3tc_query_string \"\";\n";
+ $rules .= "}\n";
+
+ $rules .= "set \$w3tc_request_uri \$request_uri;\n";
+ $rules .= "if (\$w3tc_request_uri ~* \"^([^?]+)\?\") {\n";
+ $rules .= " set \$w3tc_request_uri \$1;\n";
+ $rules .= "}\n";
+ $env_request_uri = '$w3tc_request_uri';
+ }
+
+ /**
+ * Check for mobile redirect
+ */
+ if ( $config->get_boolean( 'mobile.enabled' ) ) {
+ $mobile_groups = $config->get_array( 'mobile.rgroups' );
+
+ foreach ( $mobile_groups as $mobile_group => $mobile_config ) {
+ $mobile_enabled = ( isset( $mobile_config['enabled'] ) ?
+ (boolean) $mobile_config['enabled'] : false );
+ $mobile_agents = ( isset( $mobile_config['agents'] ) ?
+ (array) $mobile_config['agents'] : '' );
+ $mobile_redirect = ( isset( $mobile_config['redirect'] ) ?
+ $mobile_config['redirect'] : '' );
+
+ if ( $mobile_enabled && count( $mobile_agents ) && $mobile_redirect ) {
+ $rules .= "if (\$http_user_agent ~* \"(" . implode( '|',
+ $mobile_agents ) . ")\") {\n";
+ $rules .= " rewrite .* " . $mobile_redirect . " last;\n";
+ $rules .= "}\n";
+ }
+ }
+ }
+
+ /**
+ * Check for referrer redirect
+ */
+ if ( $config->get_boolean( 'referrer.enabled' ) ) {
+ $referrer_groups = $config->get_array( 'referrer.rgroups' );
+
+ foreach ( $referrer_groups as $referrer_group => $referrer_config ) {
+ $referrer_enabled = ( isset( $referrer_config['enabled'] ) ?
+ (boolean) $referrer_config['enabled'] : false );
+ $referrer_referrers = ( isset( $referrer_config['referrers'] ) ?
+ (array) $referrer_config['referrers'] : '' );
+ $referrer_redirect = ( isset( $referrer_config['redirect'] ) ?
+ $referrer_config['redirect'] : '' );
+
+ if ( $referrer_enabled && count( $referrer_referrers ) &&
+ $referrer_redirect ) {
+ $rules .= "if (\$http_cookie ~* \"w3tc_referrer=.*(" .
+ implode( '|', $referrer_referrers ) . ")\") {\n";
+ $rules .= " rewrite .* " . $referrer_redirect . " last;\n";
+ $rules .= "}\n";
+ }
+ }
+ }
+
+ /**
+ * Don't accept POSTs
+ */
+ $rules .= "set \$w3tc_rewrite 1;\n";
+ $rules .= "if (\$request_method = POST) {\n";
+ $rules .= " set \$w3tc_rewrite 0;\n";
+ $rules .= "}\n";
+
+ /**
+ * Query string should be empty
+ */
+ $querystring_variable = ( empty( $w3tc_query_strings ) ?
+ '$query_string' : '$w3tc_query_string' );
+
+ $rules .= "if (" . $querystring_variable . " != \"\") {\n";
+ $rules .= " set \$w3tc_rewrite 0;\n";
+ $rules .= "}\n";
+
+ /**
+ * Check permalink structure trailing slash
+ * and allow WordPress to redirect for non-slash URIs
+ */
+ if ( $pgcache_engine == 'file_generic' ) {
+ if ( substr( $permalink_structure, -1 ) == '/' ) {
+ $rules .= "if ($env_request_uri !~ \\/$) {\n";
+ $rules .= " set \$w3tc_rewrite 0;\n";
+ $rules .= "}\n";
+ }
+ }
+
+ /**
+ * Check for rejected cookies
+ */
+ $rules .= "if (\$http_cookie ~* \"(" . implode( '|',
+ array_map( array( '\W3TC\Util_Environment', 'preg_quote' ), $reject_cookies ) ) . ")\") {\n";
+ $rules .= " set \$w3tc_rewrite 0;\n";
+ $rules .= "}\n";
+
+ /**
+ * Check for rejected user agents
+ */
+ if ( count( $reject_user_agents ) ) {
+ $rules .= "if (\$http_user_agent ~* \"(" . implode( '|',
+ array_map( array( '\W3TC\Util_Environment', 'preg_quote' ), $reject_user_agents ) ) . ")\") {\n";
+ $rules .= " set \$w3tc_rewrite 0;\n";
+ $rules .= "}\n";
+ }
+
+ /**
+ * Check mobile groups
+ */
+ if ( $config->get_boolean( 'mobile.enabled' ) ) {
+ $mobile_groups = array_reverse( $config->get_array( 'mobile.rgroups' ) );
+ $set_ua_var = true;
+
+ foreach ( $mobile_groups as $mobile_group => $mobile_config ) {
+ $mobile_enabled = ( isset( $mobile_config['enabled'] ) ?
+ (boolean) $mobile_config['enabled'] : false );
+ $mobile_agents = ( isset( $mobile_config['agents'] ) ?
+ (array) $mobile_config['agents'] : '' );
+ $mobile_redirect = ( isset( $mobile_config['redirect'] ) ?
+ $mobile_config['redirect'] : '' );
+
+ if ( $mobile_enabled && count( $mobile_agents ) &&
+ !$mobile_redirect ) {
+ if ( $set_ua_var ) {
+ $rules .= "set \$w3tc_ua \"\";\n";
+ $set_ua_var = false;
+ }
+ $rules .= "if (\$http_user_agent ~* \"(" .
+ implode( '|', $mobile_agents ) . ")\") {\n";
+ $rules .= " set \$w3tc_ua _" . $mobile_group . ";\n";
+ $rules .= "}\n";
+
+ $env_w3tc_ua = "\$w3tc_ua";
+ }
+ }
+ }
+
+ /**
+ * Check for preview cookie
+ */
+ $rules .= "set \$w3tc_preview \"\";\n";
+ $rules .= "if (\$http_cookie ~* \"(w3tc_preview)\") {\n";
+ $rules .= " set \$w3tc_preview _preview;\n";
+ $rules .= "}\n";
+ $env_w3tc_preview = "\$w3tc_preview";
+
+ /**
+ * Check referrer groups
+ */
+ if ( $config->get_boolean( 'referrer.enabled' ) ) {
+ $referrer_groups = array_reverse( $config->get_array( 'referrer.rgroups' ) );
+ $set_ref_var = true;
+ foreach ( $referrer_groups as $referrer_group => $referrer_config ) {
+ $referrer_enabled = ( isset( $referrer_config['enabled'] ) ?
+ (boolean) $referrer_config['enabled'] : false );
+ $referrer_referrers = ( isset( $referrer_config['referrers'] ) ?
+ (array) $referrer_config['referrers'] : '' );
+ $referrer_redirect = ( isset( $referrer_config['redirect'] ) ?
+ $referrer_config['redirect'] : '' );
+
+ if ( $referrer_enabled && count( $referrer_referrers ) &&
+ !$referrer_redirect ) {
+ if ( $set_ref_var ) {
+ $rules .= "set \$w3tc_ref \"\";\n";
+ $set_ref_var = false;
+ }
+ $rules .= "if (\$http_cookie ~* \"w3tc_referrer=.*(" .
+ implode( '|', $referrer_referrers ) . ")\") {\n";
+ $rules .= " set \$w3tc_ref _" . $referrer_group . ";\n";
+ $rules .= "}\n";
+
+ $env_w3tc_ref = "\$w3tc_ref";
+ }
+ }
+ }
+
+ /**
+ * Set cookie group
+ */
+ if ( $config->get_boolean( 'pgcache.cookiegroups.enabled' ) ) {
+ $cookie_groups = $config->get_array( 'pgcache.cookiegroups.groups' );
+ $set_cookie_var = true;
+
+ foreach ( $cookie_groups as $group_name => $g ) {
+ if ( isset( $g['enabled'] ) && $g['enabled'] ) {
+ $cookies = array();
+ foreach ($g['cookies'] as $cookie ) {
+ $cookie = trim( $cookie );
+ if ( !empty( $cookie ) ) {
+ $cookie = str_replace( '+', ' ', $cookie );
+ $cookie = Util_Environment::preg_quote( $cookie );
+ if ( strpos( $cookie, '=') === false )
+ $cookie .= '=.*';
+ $cookies[] = $cookie;
+ }
+ }
+
+ if ( count( $cookies ) > 0 ) {
+ $cookies_regexp = '"^(.*;)?(' . implode( '|', $cookies ) . ')(;.*)?$"';
+
+ if ( $set_cookie_var ) {
+ $rules .= "set \$w3tc_cookie \"\";\n";
+ $set_cookie_var = false;
+ }
+ $rules .= "if (\$http_cookie ~* $cookies_regexp) {\n";
+ $rules .= " set \$w3tc_cookie _" . $group_name . ";\n";
+ $rules .= "}\n";
+
+ $env_w3tc_cookie = "\$w3tc_cookie";
+ }
+ }
+ }
+ }
+
+ if ( $config->get_boolean( 'pgcache.cache.ssl' ) ) {
+ $rules .= "set \$w3tc_ssl \"\";\n";
+
+ $rules .= "if (\$scheme = https) {\n";
+ $rules .= " set \$w3tc_ssl _ssl;\n";
+ $rules .= "}\n";
+ $rules .= "if (\$http_x_forwarded_proto = 'https') {\n";
+ $rules .= " set \$w3tc_ssl _ssl;\n";
+ $rules .= "}\n";
+
+ $env_w3tc_ssl = '$w3tc_ssl';
+ }
+
+ if ( $config->get_boolean( 'browsercache.enabled' ) &&
+ $config->get_boolean( 'browsercache.html.brotli' ) ) {
+ $rules .= "set \$w3tc_enc \"\";\n";
+
+ $rules .= "if (\$http_accept_encoding ~ br) {\n";
+ $rules .= " set \$w3tc_enc _br;\n";
+ $rules .= "}\n";
+
+ $env_w3tc_enc = '$w3tc_enc';
+ }
+
+ if ( $config->get_boolean( 'browsercache.enabled' ) &&
+ $config->get_boolean( 'browsercache.html.compression' ) ) {
+ $rules .= "set \$w3tc_enc \"\";\n";
+
+ $rules .= "if (\$http_accept_encoding ~ gzip) {\n";
+ $rules .= " set \$w3tc_enc _gzip;\n";
+ $rules .= "}\n";
+
+ $env_w3tc_enc = '$w3tc_enc';
+ }
+
+ $key_postfix = $env_w3tc_ua . $env_w3tc_ref . $env_w3tc_cookie .
+ $env_w3tc_ssl . $env_w3tc_preview;
+
+ if ( $pgcache_engine == 'file_generic' ) {
+ $rules .= $this->for_file_generic( $config, $cache_dir,
+ $env_request_uri, $key_postfix, $env_w3tc_enc );
+ } elseif ( $pgcache_engine == 'nginx_memcached' ) {
+ $rules .= $this->for_nginx_memcached( $config, $cache_dir,
+ $env_request_uri, $key_postfix, $env_w3tc_enc );
+ }
+
+ $rules .= W3TC_MARKER_END_PGCACHE_CORE . "\n";
+
+ return $rules;
+ }
+
+
+
+ private function for_file_generic( $config, $cache_dir, $env_request_uri,
+ $key_postfix, $env_w3tc_enc ) {
+ $rules = '';
+
+ $cache_path = str_replace( Util_Environment::document_root(), '',
+ $cache_dir );
+ $uri_prefix = "$cache_path/\$http_host/$env_request_uri/_index$key_postfix";
+ $uri_prefix = apply_filters( 'w3tc_pagecache_rules_nginx_uri_prefix',
+ $uri_prefix );
+
+ if ( !$config->get_boolean( 'pgcache.cache.nginx_handle_xml' ) ) {
+ $env_w3tc_ext = '.html';
+
+ $rules .= 'if (!-f "$document_root' . $uri_prefix . '.html' .
+ $env_w3tc_enc . '") {' . "\n";
+ $rules .= ' set $w3tc_rewrite 0;' . "\n";
+ $rules .= "}\n";
+ } else {
+ $env_w3tc_ext = '$w3tc_ext';
+
+ $rules .= 'set $w3tc_ext "";' . "\n";
+ $rules .= 'if (-f "$document_root' . $uri_prefix . '.html' .
+ $env_w3tc_enc . '") {' . "\n";
+ $rules .= ' set $w3tc_ext .html;' . "\n";
+ $rules .= "}\n";
+
+ $rules .= 'if (-f "$document_root' . $uri_prefix . '.xml' .
+ $env_w3tc_enc . '") {' . "\n";
+ $rules .= ' set $w3tc_ext .xml;' . "\n";
+ $rules .= "}\n";
+
+ $rules .= 'if ($w3tc_ext = "") {' . "\n";
+ $rules .= ' set $w3tc_rewrite 0;' . "\n";
+ $rules .= "}\n";
+ }
+
+ $rules .= 'if ($w3tc_rewrite = 1) {' . "\n";
+ $rules .= ' rewrite .* "' . $uri_prefix . $env_w3tc_ext . $env_w3tc_enc .
+ '" last;' . "\n";
+ $rules .= "}\n";
+
+ return $rules;
+ }
+
+
+
+ private function for_nginx_memcached( $config, $cache_dir, $env_request_uri,
+ $key_postfix, $env_w3tc_enc ) {
+ $rules = "set \$request_uri_noslash $env_request_uri;\n";
+ $rules .= "if ($env_request_uri ~ \"(.*?)(/+)$\") {\n";
+ $rules .= ' set $request_uri_noslash $1;' . "\n";
+ $rules .= "}\n";
+
+ $cache_path = str_replace( Util_Environment::document_root(), '',
+ $cache_dir );
+
+ $rules .= 'location ~ ".*(?get_boolean( 'browsercache.enabled' ) &&
+ $config->get_boolean( 'browsercache.html.compression' ) ) {
+ $rules .= ' memcached_gzip_flag 65536;' . "\n";
+ }
+
+ $rules .= ' default_type text/html;' . "\n";
+
+ $memcached_servers = $config->get_array( 'pgcache.memcached.servers' );
+ $memcached_pass = !empty( $memcached_servers ) ? array_values( $memcached_servers )[0] : 'localhost:11211';
+
+ $rules .= ' if ($w3tc_rewrite = 1) {' . "\n";
+ $rules .= ' memcached_pass ' . $memcached_pass . ';' . "\n";
+ $rules .= " }\n";
+ $rules .= ' error_page 404 502 504 = @fallback;' . "\n";
+ $rules .= "}\n";
+
+ $rules .= 'location @fallback {' . "\n";
+ $rules .= ' try_files $uri $uri/ $uri.html /index.php?$args;' . "\n";
+ $rules .= "}\n";
+
+ return $rules;
+ }
+
+
+
+ /*
+ * cache rules
+ */
+
+ /**
+ * Writes directives to file cache .htaccess
+ * Throws exception on error
+ *
+ * @param Config $config
+ * @param Util_Environment_Exceptions $exs
+ */
+ private function rules_cache_add( $config, $exs ) {
+ Util_Rule::add_rules( $exs,
+ Util_Rule::get_pgcache_rules_cache_path(),
+ $this->rules_cache_generate( $config ),
+ W3TC_MARKER_BEGIN_PGCACHE_CACHE,
+ W3TC_MARKER_END_PGCACHE_CACHE,
+ array(
+ W3TC_MARKER_BEGIN_BROWSERCACHE_CACHE => 0,
+ W3TC_MARKER_BEGIN_MINIFY_CORE => 0,
+ W3TC_MARKER_BEGIN_PGCACHE_CORE => 0,
+ W3TC_MARKER_BEGIN_BROWSERCACHE_NO404WP => 0,
+ W3TC_MARKER_BEGIN_WORDPRESS => 0,
+ W3TC_MARKER_END_MINIFY_CACHE => strlen( W3TC_MARKER_END_MINIFY_CACHE ) + 1
+ )
+ );
+ }
+
+ /**
+ * Removes Page Cache cache directives
+ *
+ * @param Util_Environment_Exceptions $exs
+ * @throws Util_WpFile_FilesystemOperationException with S/FTP form if it can't get the required filesystem credentials
+ */
+ private function rules_cache_remove( $exs ) {
+ // apache's cache files are not used when core rules disabled
+ if ( !Util_Environment::is_nginx() )
+ return;
+
+ Util_Rule::remove_rules( $exs,
+ Util_Rule::get_pgcache_rules_cache_path(),
+ W3TC_MARKER_BEGIN_PGCACHE_CACHE,
+ W3TC_MARKER_END_PGCACHE_CACHE );
+ }
+
+ /**
+ * Generates directives for file cache dir
+ *
+ * @param Config $config
+ * @return string
+ */
+ public function rules_cache_generate( $config ) {
+ switch ( true ) {
+ case Util_Environment::is_apache():
+ case Util_Environment::is_litespeed():
+ return $this->rules_cache_generate_apache( $config );
+
+ case Util_Environment::is_nginx():
+ return $this->rules_cache_generate_nginx( $config );
+ }
+
+ return '';
+ }
+
+
+ /**
+ * Generates directives for file cache dir
+ *
+ * @param Config $config
+ * @return string
+ */
+ private function rules_cache_generate_apache( $config ) {
+ $charset = get_option( 'blog_charset' );
+ $pingback_url = get_bloginfo( 'pingback_url' );
+
+ $browsercache = $config->get_boolean( 'browsercache.enabled' );
+ $brotli = ( $browsercache && $config->get_boolean( 'browsercache.html.brotli' ) );
+ $compression = ( $browsercache && $config->get_boolean( 'browsercache.html.compression' ) );
+ $expires = ( $browsercache && $config->get_boolean( 'browsercache.html.expires' ) );
+ $lifetime = ( $browsercache ? $config->get_integer( 'browsercache.html.lifetime' ) : 0 );
+ $cache_control = ( $browsercache && $config->get_boolean( 'browsercache.html.cache.control' ) );
+ $etag = ( $browsercache && $config->get_integer( 'browsercache.html.etag' ) );
+ $w3tc = ( $browsercache && $config->get_integer( 'browsercache.html.w3tc' ) );
+ $compatibility = $config->get_boolean( 'pgcache.compatibility' );
+
+ $rules = '';
+ $rules .= W3TC_MARKER_BEGIN_PGCACHE_CACHE . "\n";
+ if ( $compatibility ) {
+ $rules .= "Options -MultiViews\n";
+
+ // allow to read files by apache if they are blocked at some level above
+ $rules .= "\n";
+
+ if ( version_compare( Util_Environment::get_server_version(), '2.4', '>=' ) ) {
+ $rules .= " Require all granted\n";
+ } else {
+ $rules .= " Order Allow,Deny\n";
+ $rules .= " Allow from all\n";
+ }
+
+ $rules .= "\n";
+
+ if ( !$etag ) {
+ $rules .= "FileETag None\n";
+ }
+ }
+ if ( $config->get_boolean( 'pgcache.file.nfs' ) ) {
+ $rules .= "EnableSendfile Off \n";
+ }
+
+ if ( !$config->get_boolean( 'pgcache.remove_charset' ) ) {
+ $rules .= "AddDefaultCharset " . ( $charset ? $charset : 'utf-8' ) . "\n";
+ }
+
+ if ( $etag ) {
+ $rules .= "FileETag MTime Size\n";
+ }
+
+ if ( $brotli ) {
+ $rules .= "\n";
+ $rules .= " AddType text/html .html_br\n";
+ $rules .= " AddEncoding br .html_br\n";
+ $rules .= " AddType text/xml .xml_br\n";
+ $rules .= " AddEncoding br .xml_br\n";
+ $rules .= "\n";
+ $rules .= "\n";
+ $rules .= " SetEnvIfNoCase Request_URI \\.html_br$ no-brotli\n";
+ $rules .= " SetEnvIfNoCase Request_URI \\.xml_br$ no-brotli\n";
+ $rules .= "\n";
+ }
+
+ if ( $compression ) {
+ $rules .= "\n";
+ $rules .= " AddType text/html .html_gzip\n";
+ $rules .= " AddEncoding gzip .html_gzip\n";
+ $rules .= " AddType text/xml .xml_gzip\n";
+ $rules .= " AddEncoding gzip .xml_gzip\n";
+ $rules .= "\n";
+ $rules .= "\n";
+ $rules .= " SetEnvIfNoCase Request_URI \\.html_gzip$ no-gzip\n";
+ $rules .= " SetEnvIfNoCase Request_URI \\.xml_gzip$ no-gzip\n";
+ $rules .= "\n";
+ }
+
+ if ( $expires ) {
+ $rules .= "\n";
+ $rules .= " ExpiresActive On\n";
+ $rules .= " ExpiresByType text/html M" . $lifetime . "\n";
+ $rules .= "\n";
+ }
+
+ $header_rules = '';
+
+ if ( $compatibility ) {
+ $header_rules .= " Header set X-Pingback \"" . $pingback_url . "\"\n";
+ }
+
+ if ( $w3tc ) {
+ $header_rules .= " Header set X-Powered-By \"" .
+ Util_Environment::w3tc_header() . "\"\n";
+ }
+
+ if ( $expires ) {
+ $header_rules .= " Header set Vary \"Accept-Encoding, Cookie\"\n";
+ }
+
+ $set_last_modified = $config->get_boolean( 'browsercache.html.last_modified' );
+
+ if ( !$set_last_modified && $config->get_boolean( 'browsercache.enabled' ) ) {
+ $header_rules .= " Header unset Last-Modified\n";
+ }
+
+ if ( $cache_control ) {
+ $cache_policy = $config->get_string( 'browsercache.html.cache.policy' );
+
+ switch ( $cache_policy ) {
+ case 'cache':
+ $header_rules .= " Header set Pragma \"public\"\n";
+ $header_rules .= " Header set Cache-Control \"public\"\n";
+ break;
+
+ case 'cache_public_maxage':
+ $header_rules .= " Header set Pragma \"public\"\n";
+
+ if ( $expires ) {
+ $header_rules .= " Header append Cache-Control \"public\"\n";
+ } else {
+ $header_rules .= " Header set Cache-Control \"max-age=" . $lifetime . ", public\"\n";
+ }
+ break;
+
+ case 'cache_validation':
+ $header_rules .= " Header set Pragma \"public\"\n";
+ $header_rules .= " Header set Cache-Control \"public, must-revalidate, proxy-revalidate\"\n";
+ break;
+
+ case 'cache_noproxy':
+ $header_rules .= " Header set Pragma \"public\"\n";
+ $header_rules .= " Header set Cache-Control \"private, must-revalidate\"\n";
+ break;
+
+ case 'cache_maxage':
+ $header_rules .= " Header set Pragma \"public\"\n";
+
+ if ( $expires ) {
+ $header_rules .= " Header append Cache-Control \"public, must-revalidate, proxy-revalidate\"\n";
+ } else {
+ $header_rules .= " Header set Cache-Control \"max-age=" . $lifetime . ", public, must-revalidate, proxy-revalidate\"\n";
+ }
+ break;
+
+ case 'no_cache':
+ $header_rules .= " Header set Pragma \"no-cache\"\n";
+ $header_rules .= " Header set Cache-Control \"max-age=0, private, no-store, no-cache, must-revalidate\"\n";
+ break;
+ }
+ }
+
+ if ( strlen( $header_rules ) > 0 ) {
+ $rules .= "\n";
+ $rules .= $header_rules;
+ $rules .= "\n";
+ }
+
+ $rules .= W3TC_MARKER_END_PGCACHE_CACHE . "\n";
+
+ return $rules;
+ }
+
+ /**
+ * Generates directives for file cache dir
+ *
+ * @param Config $config
+ * @return string
+ */
+ private function rules_cache_generate_nginx( $config ) {
+ if ( $config->get_string( 'pgcache.engine') != 'file_generic' ) {
+ return '';
+ }
+
+ $cache_root = Util_Environment::normalize_path( W3TC_CACHE_PAGE_ENHANCED_DIR );
+ $cache_dir = rtrim( str_replace( Util_Environment::document_root(), '', $cache_root ), '/' );
+
+ if ( Util_Environment::is_wpmu() ) {
+ $cache_dir = preg_replace( '~/w3tc.*?/~', '/w3tc.*?/', $cache_dir, 1 );
+ }
+
+ $browsercache = $config->get_boolean( 'browsercache.enabled' );
+ $brotli = ( $browsercache && $config->get_boolean( 'browsercache.html.brotli' ) );
+ $compression = ( $browsercache && $config->get_boolean( 'browsercache.html.compression' ) );
+
+ $common_rules_a = Dispatcher::nginx_rules_for_browsercache_section(
+ $config, 'html', true );
+ $common_rules = '';
+ if ( !empty( $common_rules_a ) ) {
+ $common_rules = ' ' . implode( "\n ", $common_rules_a ) . "\n";
+ }
+
+ $rules = '';
+ $rules .= W3TC_MARKER_BEGIN_PGCACHE_CACHE . "\n";
+
+ if ( $brotli ) {
+ $maybe_xml = '';
+ if ($config->get_boolean('pgcache.cache.nginx_handle_xml')) {
+ $maybe_xml = "\n" .
+ " text/xml xml_br;\n" .
+ " ";
+ }
+
+ $rules .= "location ~ " . $cache_dir . ".*br$ {\n";
+ $rules .= " brotli off;\n";
+ $rules .= " types {" . $maybe_xml . "}\n";
+ $rules .= " default_type text/html;\n";
+ $rules .= " add_header Content-Encoding br;\n";
+ $rules .= $common_rules;
+ $rules .= "}\n";
+ }
+
+ if ( $compression ) {
+ $maybe_xml = '';
+ if ($config->get_boolean('pgcache.cache.nginx_handle_xml')) {
+ $maybe_xml = "\n" .
+ " text/xml xml_gzip;\n" .
+ " ";
+ }
+
+ $rules .= "location ~ " . $cache_dir . ".*gzip$ {\n";
+ $rules .= " gzip off;\n";
+ $rules .= " types {" . $maybe_xml . "}\n";
+ $rules .= " default_type text/html;\n";
+ $rules .= " add_header Content-Encoding gzip;\n";
+ $rules .= $common_rules;
+ $rules .= "}\n";
+ }
+
+ $rules .= W3TC_MARKER_END_PGCACHE_CACHE . "\n";
+
+ return $rules;
+ }
+}
diff --git a/wp-content/plugins/w3-total-cache/PgCache_Flush.php b/wp-content/plugins/w3-total-cache/PgCache_Flush.php
new file mode 100644
index 0000000000..b1d76ca8f1
--- /dev/null
+++ b/wp-content/plugins/w3-total-cache/PgCache_Flush.php
@@ -0,0 +1,463 @@
+debug_purge = $this->_config->get_boolean( 'pgcache.debug_purge' );
+ }
+
+ /**
+ * Flushes all caches
+ */
+ public function flush() {
+ if ( $this->debug_purge ) {
+ Util_Debug::log_purge( 'pagecache', 'flush_all' );
+ }
+
+ $this->flush_all_operation_requested = true;
+ return true;
+ }
+
+ public function flush_group( $group ) {
+ if ( $this->debug_purge ) {
+ Util_Debug::log_purge( 'pagecache', 'flush_group', $group );
+ }
+
+ $this->queued_groups[$group] = '*';
+ }
+
+ /**
+ * Flushes post cache
+ *
+ * @param integer $post_id
+ */
+ public function flush_post( $post_id = null ) {
+ if ( !$post_id ) {
+ $post_id = Util_Environment::detect_post_id();
+ }
+
+ if ( !$post_id ) {
+ return false;
+ }
+
+ global $wp_rewrite; // required by many Util_PageUrls methods
+ if ( empty( $wp_rewrite ) ) {
+ if ( $this->debug_purge ) {
+ Util_Debug::log_purge( 'pagecache', 'flush_post', array(
+ 'post_id' => $post_id,
+ 'error' => 'Post flush attempt before wp_rewrite initialization. Cant flush cache.'
+ ) );
+ }
+
+ error_log('Post flush attempt before wp_rewrite initialization. Cant flush cache.');
+ return false;
+ }
+
+ // prevent multiple calculation of post urls
+ $queued_post_id_key = Util_Environment::blog_id() . '.' . $post_id;
+ if ( isset( $this->queued_post_ids[$queued_post_id_key] ) ) {
+ return true;
+ }
+ $this->queued_post_ids[$queued_post_id_key] = '*';
+
+ // calculate urls to purge
+ $full_urls = array();
+ $post = get_post( $post_id );
+ $is_cpt = Util_Environment::is_custom_post_type( $post );
+ $terms = array();
+
+ $feeds = $this->_config->get_array( 'pgcache.purge.feed.types' );
+ $limit_post_pages = $this->_config->get_integer( 'pgcache.purge.postpages_limit' );
+
+ if ( $this->_config->get_string( 'pgcache.rest' ) == 'cache' ) {
+ $this->flush_group( 'rest' );
+ }
+
+ if ( $this->_config->get_boolean( 'pgcache.purge.terms' ) ||
+ $this->_config->get_boolean( 'pgcache.purge.feed.terms' ) ) {
+ $taxonomies = get_post_taxonomies( $post_id );
+ $terms = wp_get_post_terms( $post_id, $taxonomies );
+ $terms = $this->_append_parent_terms( $terms, $terms );
+ }
+
+ $front_page = get_option( 'show_on_front' );
+
+ // Home (Frontpage) URL
+ if ( ( $this->_config->get_boolean( 'pgcache.purge.home' ) &&
+ $front_page == 'posts' ) ||
+ $this->_config->get_boolean( 'pgcache.purge.front_page' ) ) {
+ $full_urls = array_merge( $full_urls,
+ Util_PageUrls::get_frontpage_urls( $limit_post_pages ) );
+ }
+
+ // pgcache.purge.home becomes "Posts page" option in settings if home page and blog are set to page(s)
+ // Home (Post page) URL
+ if ( $this->_config->get_boolean( 'pgcache.purge.home' ) &&
+ $front_page != 'posts' &&
+ !$is_cpt ) {
+ $full_urls = array_merge( $full_urls,
+ Util_PageUrls::get_postpage_urls( $limit_post_pages ) );
+ }
+
+ // pgcache.purge.home becomes "Posts page" option in settings if home page and blog are set to page(s)
+ // Custom Post Type Archive URL
+ if ( $this->_config->get_boolean( 'pgcache.purge.home' ) &&
+ $is_cpt ) {
+ $full_urls = array_merge( $full_urls,
+ Util_PageUrls::get_cpt_archive_urls( $post_id, $limit_post_pages ) );
+ }
+
+ // Post URL
+ if ( $this->_config->get_boolean( 'pgcache.purge.post' ) ) {
+ $full_urls = array_merge( $full_urls,
+ Util_PageUrls::get_post_urls( $post_id ) );
+ }
+
+ // Post comments URLs
+ if ( $this->_config->get_boolean( 'pgcache.purge.comments' ) &&
+ function_exists( 'get_comments_pagenum_link' ) ) {
+ $full_urls = array_merge( $full_urls,
+ Util_PageUrls::get_post_comments_urls( $post_id ) );
+ }
+
+ // Post author URLs
+ if ( $this->_config->get_boolean( 'pgcache.purge.author' ) && $post ) {
+ $full_urls = array_merge( $full_urls,
+ Util_PageUrls::get_post_author_urls( $post->post_author,
+ $limit_post_pages ) );
+ }
+
+ // Post terms URLs
+ if ( $this->_config->get_boolean( 'pgcache.purge.terms' ) ) {
+ $full_urls = array_merge( $full_urls,
+ Util_PageUrls::get_post_terms_urls( $terms, $limit_post_pages ) );
+ }
+
+ // Daily archive URLs
+ if ( $this->_config->get_boolean( 'pgcache.purge.archive.daily' ) && $post ) {
+ $full_urls = array_merge( $full_urls,
+ Util_PageUrls::get_daily_archive_urls( $post, $limit_post_pages ) );
+ }
+
+ // Monthly archive URLs
+ if ( $this->_config->get_boolean( 'pgcache.purge.archive.monthly' ) && $post ) {
+ $full_urls = array_merge( $full_urls,
+ Util_PageUrls::get_monthly_archive_urls( $post, $limit_post_pages ) );
+ }
+
+ // Yearly archive URLs
+ if ( $this->_config->get_boolean( 'pgcache.purge.archive.yearly' ) && $post ) {
+ $full_urls = array_merge( $full_urls,
+ Util_PageUrls::get_yearly_archive_urls( $post, $limit_post_pages ) );
+ }
+
+ // Feed URLs for posts
+ if ( $this->_config->get_boolean( 'pgcache.purge.feed.blog' ) &&
+ !$is_cpt ) {
+ $full_urls = array_merge( $full_urls,
+ Util_PageUrls::get_feed_urls( $feeds, null ) );
+ }
+
+ // Feed URLs for posts
+ if ( $this->_config->get_boolean( 'pgcache.purge.feed.blog' ) &&
+ $is_cpt ) {
+ $full_urls = array_merge( $full_urls,
+ Util_PageUrls::get_feed_urls( $feeds, $post->post_type ) );
+ }
+
+ if ( $this->_config->get_boolean( 'pgcache.purge.feed.comments' ) ) {
+ $full_urls = array_merge( $full_urls,
+ Util_PageUrls::get_feed_comments_urls( $post_id, $feeds ) );
+ }
+
+ if ( $this->_config->get_boolean( 'pgcache.purge.feed.author' ) ) {
+ $full_urls = array_merge( $full_urls,
+ Util_PageUrls::get_feed_author_urls( $post->post_author, $feeds ) );
+ }
+
+ if ( $this->_config->get_boolean( 'pgcache.purge.feed.terms' ) ) {
+ $full_urls = array_merge( $full_urls,
+ Util_PageUrls::get_feed_terms_urls( $terms, $feeds ) );
+ }
+
+ // Purge selected pages
+ if ( $this->_config->get_array( 'pgcache.purge.pages' ) ) {
+ $pages = $this->_config->get_array( 'pgcache.purge.pages' );
+ $full_urls = array_merge( $full_urls,
+ Util_PageUrls::get_pages_urls( $pages ) );
+ }
+
+ // add mirror urls
+ $full_urls = Util_PageUrls::complement_with_mirror_urls( $full_urls );
+ $full_urls = apply_filters( 'pgcache_flush_post_queued_urls',
+ $full_urls );
+
+ if ( $this->debug_purge ) {
+ Util_Debug::log_purge( 'pagecache', 'flush_post', $post_id,
+ $full_urls );
+ }
+
+ // Queue flush
+ if ( count( $full_urls ) ) {
+ foreach ( $full_urls as $url )
+ $this->queued_urls[$url] = '*';
+ }
+
+ return true;
+ }
+
+ /**
+ * Flush a single url
+ */
+ public function flush_url( $url ) {
+ $parts = parse_url( $url );
+ $uri = ( isset( $parts['path'] ) ? $parts['path'] : '' ) .
+ ( isset( $parts['query'] ) ? '?' . $parts['query'] : '' );
+ $group = $this->get_cache_group_by_uri( $uri );
+
+ if ( $this->debug_purge ) {
+ Util_Debug::log_purge( 'pagecache', 'flush_url', array(
+ $url, $group ) );
+ }
+
+ $this->queued_urls[$url] = ( empty( $group ) ? '*' : $group );
+ }
+
+ /**
+ * Performs the actual flush at the end of request processing.
+ * Duplicate flushes avoided that way.
+ */
+ public function flush_post_cleanup() {
+ if ( $this->flush_all_operation_requested ) {
+ if ( $this->_config->get_boolean( 'pgcache.debug' ) ) {
+ self::log( 'flush all' );
+ }
+
+ $groups_to_flush = array( '' );
+ if ( $this->_config->get_string( 'pgcache.rest' ) == 'cache' ) {
+ $groups_to_flush[] = 'rest';
+ }
+
+ $groups_to_flush = apply_filters(
+ 'w3tc_pagecache_flush_all_groups', $groups_to_flush );
+
+ foreach ( $groups_to_flush as $group ) {
+ $cache = $this->_get_cache( $group );
+ $cache->flush( $group );
+ }
+
+ $count = 999;
+ $this->flush_all_operation_requested = false;
+ $this->queued_urls = array();
+ } else {
+ $count = 0;
+ if ( count( $this->queued_groups ) > 0 ) {
+ $count += count( $this->queued_urls );
+ foreach ( $this->queued_groups as $group => $flag ) {
+ if ( $this->_config->get_boolean( 'pgcache.debug' ) ) {
+ self::log( 'pgcache flush "' . $group . '" group' );
+ }
+
+ $cache = $this->_get_cache( $group );
+ $cache->flush( $group );
+ }
+ }
+
+ if ( count( $this->queued_urls ) > 0 ) {
+ if ( $this->_config->get_boolean( 'pgcache.debug' ) ) {
+ self::log( 'pgcache flush ' . $count . ' urls' );
+ }
+
+ $mobile_groups = $this->_get_mobile_groups();
+ $referrer_groups = $this->_get_referrer_groups();
+ $cookies = $this->_get_cookies();
+ $encryptions = $this->_get_encryptions();
+ $compressions = $this->_get_compressions();
+
+ $caches = array(
+ '*' => $this->_get_cache()
+ );
+
+ foreach ( $this->queued_urls as $url => $group ) {
+ if ( !isset( $caches[$group] ) ) {
+ $caches[$group] = $this->_get_cache( $group );
+ }
+ $this->_flush_url( $url, $caches[$group], $mobile_groups,
+ $referrer_groups, $cookies, $encryptions, $compressions,
+ $group == '*' ? '' : $group );
+ }
+
+ $count += count( $this->queued_urls );
+
+ // Purge sitemaps if a sitemap option has a regex
+ if ( $this->_config->get_string( 'pgcache.purge.sitemap_regex' ) ) {
+ $cache = $this->_get_cache( 'sitemaps' );
+ $cache->flush( 'sitemaps' );
+ $count++;
+ }
+
+ $this->queued_urls = array();
+ }
+ }
+
+ return $count;
+ }
+
+ /**
+ * Does the actual job - flushing of a single url cache entries
+ */
+ private function _flush_url( $url, $cache, $mobile_groups, $referrer_groups,
+ $cookies, $encryptions, $compressions, $group ) {
+ if ( empty( $url ) ) {
+ return;
+ }
+
+ foreach ( $mobile_groups as $mobile_group ) {
+ foreach ( $referrer_groups as $referrer_group ) {
+ foreach ( $cookies as $cookie ) {
+ foreach ( $encryptions as $encryption ) {
+ foreach ( $compressions as $compression ) {
+ $page_keys = array();
+ $page_keys[] = $this->_get_page_key(
+ array(
+ 'useragent' => $mobile_group,
+ 'referrer' => $referrer_group,
+ 'cookie' => $cookie,
+ 'encryption' => $encryption,
+ 'compression' => $compression,
+ 'group' => $group
+ ),
+ $url );
+
+ $page_keys = apply_filters(
+ 'w3tc_pagecache_flush_url_keys', $page_keys );
+
+ foreach ( $page_keys as $page_key ) {
+ $cache->delete( $page_key, $group );
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Returns array of mobile groups
+ */
+ private function _get_mobile_groups() {
+ $mobile_groups = array( '' );
+
+ if ( $this->_mobile ) {
+ $mobile_groups = array_merge( $mobile_groups, array_keys(
+ $this->_mobile->get_groups() ) );
+ }
+
+ return $mobile_groups;
+ }
+
+ /**
+ * Returns array of referrer groups
+ */
+ private function _get_referrer_groups() {
+ $referrer_groups = array( '' );
+
+ if ( $this->_referrer ) {
+ $referrer_groups = array_merge( $referrer_groups, array_keys(
+ $this->_referrer->get_groups() ) );
+ }
+
+ return $referrer_groups;
+ }
+
+ /**
+ * Returns array of cookies
+ */
+ private function _get_cookies() {
+ $cookies = array( '' );
+
+ if ( $this->_config->get_boolean( 'pgcache.cookiegroups.enabled' ) ) {
+ $cookies = array_merge( $cookies,
+ array_keys( $this->_config->get_array( 'pgcache.cookiegroups.groups' ) ) );
+ }
+
+ return $cookies;
+ }
+
+ /**
+ * Returns array of encryptions
+ */
+ private function _get_encryptions() {
+ $is_https = ( substr( get_home_url(), 0, 5 ) == 'https' );
+
+ $encryptions = array();
+
+ if ( ! $is_https || $this->_config->get_boolean( 'pgcache.cache.ssl' ) )
+ $encryptions[] = '';
+ if ( $is_https || $this->_config->get_boolean( 'pgcache.cache.ssl' ) )
+ $encryptions[] = 'ssl';
+
+ return $encryptions;
+ }
+
+ private function _append_parent_terms( $terms, $terms_to_check_parents ) {
+ $terms_to_check_parents = $terms;
+ $ids = null;
+
+ for ( ;; ) {
+ $parent_ids = array();
+ $taxonomies = array();
+
+ foreach ( $terms_to_check_parents as $term ) {
+ if ( $term->parent ) {
+ $parent_ids[$term->parent] = '*';
+ $taxonomies[$term->taxonomy] = '*';
+ }
+ }
+
+ if ( empty( $parent_ids ) )
+ return $terms;
+
+ if ( is_null( $ids ) ) {
+ // build a map of ids for faster check
+ $ids = array();
+ foreach ( $terms as $term )
+ $ids[$term->term_id] = '*';
+ } else {
+ // append last new items to ids map
+ foreach ( $terms_to_check_parents as $term )
+ $ids[$term->term_id] = '*';
+ }
+
+ // build list to extract
+ $include_ids = array();
+
+ foreach ( $parent_ids as $id => $v ) {
+ if ( !isset( $ids[$id] ) )
+ $include_ids[] = $id;
+ }
+
+ if ( empty( $include_ids ) )
+ return $terms;
+
+ $new_terms = get_terms( array_keys( $taxonomies ),
+ array( 'include' => $include_ids ) );
+
+ $terms = array_merge( $terms, $new_terms );
+ $terms_to_check_parents = $new_terms;
+ }
+ }
+}
diff --git a/wp-content/plugins/w3-total-cache/PgCache_Page.php b/wp-content/plugins/w3-total-cache/PgCache_Page.php
new file mode 100644
index 0000000000..28c7e01c86
--- /dev/null
+++ b/wp-content/plugins/w3-total-cache/PgCache_Page.php
@@ -0,0 +1,47 @@
+feeds;
+
+ $feed_key = array_search( 'feed', $feeds );
+
+ if ( $feed_key !== false ) {
+ unset( $feeds[$feed_key] );
+ }
+
+ $default_feed = get_default_feed();
+ $pgcache_enabled = $this->_config->get_boolean( 'pgcache.enabled' );
+ $permalink_structure = get_option( 'permalink_structure' );
+
+ $varnish_enabled = $this->_config->get_boolean( 'varnish.enabled' );
+ $cdnfsd_enabled = $this->_config->get_boolean( 'cdnfsd.enabled' );
+ include W3TC_INC_DIR . '/options/pgcache.php';
+ }
+}
diff --git a/wp-content/plugins/w3-total-cache/PgCache_Plugin.php b/wp-content/plugins/w3-total-cache/PgCache_Plugin.php
new file mode 100644
index 0000000000..8e400ecb7e
--- /dev/null
+++ b/wp-content/plugins/w3-total-cache/PgCache_Plugin.php
@@ -0,0 +1,397 @@
+_config = Dispatcher::config();
+ }
+
+ /**
+ * Runs plugin
+ */
+ function run() {
+ add_action( 'w3tc_flush_all',
+ array( $this, 'w3tc_flush_posts' ),
+ 1100, 1 );
+ add_action( 'w3tc_flush_group',
+ array( $this, 'w3tc_flush_group' ),
+ 1100, 2 );
+ add_action( 'w3tc_flush_post',
+ array( $this, 'w3tc_flush_post' ),
+ 1100, 1 );
+ add_action( 'w3tc_flushable_posts',
+ '__return_true',
+ 1100 );
+ add_action( 'w3tc_flush_posts',
+ array( $this, 'w3tc_flush_posts' ),
+ 1100 );
+ add_action( 'w3tc_flush_url',
+ array( $this, 'w3tc_flush_url' ),
+ 1100, 1 );
+
+ add_filter( 'w3tc_pagecache_set_header',
+ array( $this, 'w3tc_pagecache_set_header' ), 10, 3 );
+ add_filter( 'w3tc_admin_bar_menu',
+ array( $this, 'w3tc_admin_bar_menu' ) );
+
+ add_filter( 'cron_schedules',
+ array( $this, 'cron_schedules' ) );
+
+ add_action( 'w3tc_config_save',
+ array( $this, 'w3tc_config_save' ),
+ 10, 1 );
+
+ $o = Dispatcher::component( 'PgCache_ContentGrabber' );
+
+ add_filter( 'w3tc_footer_comment',
+ array( $o, 'w3tc_footer_comment' ) );
+
+ add_action( 'w3tc_usage_statistics_of_request',
+ array( $o, 'w3tc_usage_statistics_of_request' ),
+ 10, 1 );
+ add_filter( 'w3tc_usage_statistics_metrics',
+ array( $this, 'w3tc_usage_statistics_metrics' ) );
+ add_filter( 'w3tc_usage_statistics_sources', array(
+ $this, 'w3tc_usage_statistics_sources' ) );
+
+
+ if ( $this->_config->get_string( 'pgcache.engine' ) == 'file' ||
+ $this->_config->get_string( 'pgcache.engine' ) == 'file_generic' ) {
+ add_action( 'w3_pgcache_cleanup',
+ array( $this, 'cleanup' ) );
+ }
+
+ add_action( 'w3_pgcache_prime', array( $this, 'prime' ) );
+
+ Util_AttachToActions::flush_posts_on_actions();
+
+ add_filter( 'comment_cookie_lifetime',
+ array( $this, 'comment_cookie_lifetime' ) );
+
+ if ( $this->_config->get_string( 'pgcache.engine' ) == 'file_generic' ) {
+ add_action( 'wp_logout',
+ array( $this, 'on_logout' ),
+ 0 );
+
+ add_action( 'wp_login',
+ array( $this, 'on_login' ),
+ 0 );
+ }
+
+ if ( $this->_config->get_boolean( 'pgcache.prime.post.enabled', false ) ) {
+ add_action( 'publish_post',
+ array( $this, 'prime_post' ),
+ 30 );
+ }
+
+ if ( ( $this->_config->get_boolean( 'pgcache.late_init' ) ||
+ $this->_config->get_boolean( 'pgcache.late_caching' ) ) &&
+ !is_admin() ) {
+ $o = Dispatcher::component( 'PgCache_ContentGrabber' );
+ add_action( 'init',
+ array( $o, 'delayed_cache_print' ),
+ 99999 );
+ }
+
+ if ( !$this->_config->get_boolean( 'pgcache.mirrors.enabled' ) &&
+ !Util_Environment::is_wpmu_subdomain() ) {
+ add_action( 'init',
+ array( $this, 'redirect_on_foreign_domain' ) );
+ }
+ if ( $this->_config->get_string( 'pgcache.rest' ) == 'disable' ) {
+ // remove XMLRPC edit link
+ remove_action( 'xmlrpc_rsd_apis', 'rest_output_rsd' );
+ // remove wp-json in
+ remove_action( 'wp_head', 'rest_output_link_wp_head', 10 );
+ // remove HTTP Header
+ remove_action( 'template_redirect', 'rest_output_link_header', 11 );
+
+ add_filter( 'rest_authentication_errors',
+ array( $this, 'rest_authentication_errors' ),
+ 100 );
+ }
+ }
+
+
+
+ public function rest_authentication_errors( $result ) {
+ $error_message = __( 'REST API disabled.', 'w3-total-cache' );
+
+ return new \WP_Error( 'rest_disabled', $error_message, array( 'status' => rest_authorization_required_code() ) );
+ }
+
+
+
+ /**
+ * Does disk cache cleanup
+ *
+ * @return void
+ */
+ function cleanup() {
+ $this->_get_admin()->cleanup();
+ }
+
+ /**
+ * Prime cache
+ *
+ * @return void
+ */
+ function prime() {
+ $this->_get_admin()->prime();
+ }
+
+ /**
+ * Instantiates worker on demand
+ */
+ private function _get_admin() {
+ return Dispatcher::component( 'PgCache_Plugin_Admin' );
+ }
+
+ /**
+ * Cron schedules filter
+ *
+ * @param array $schedules
+ * @return array
+ */
+ function cron_schedules( $schedules ) {
+ $c = $this->_config;
+
+ if ( $c->get_boolean( 'pgcache.enabled' ) &&
+ ( $c->get_string( 'pgcache.engine' ) == 'file' ||
+ $c->get_string( 'pgcache.engine' ) == 'file_generic' ) ) {
+ $v = $c->get_integer( 'pgcache.file.gc' );
+ $schedules['w3_pgcache_cleanup'] = array(
+ 'interval' => $v,
+ 'display' => sprintf( '[W3TC] Page Cache file GC (every %d seconds)',
+ $v )
+ );
+ }
+
+ if ( $c->get_boolean( 'pgcache.enabled' ) &&
+ $c->get_boolean( 'pgcache.prime.enabled' ) ) {
+ $v = $c->get_integer( 'pgcache.prime.interval' );
+ $schedules['w3_pgcache_prime'] = array(
+ 'interval' => $v,
+ 'display' => sprintf( '[W3TC] Page Cache prime (every %d seconds)',
+ $v )
+ );
+ }
+
+ return $schedules;
+ }
+
+ public function redirect_on_foreign_domain() {
+ $request_host = Util_Environment::host();
+ // host not known, potentially we are in console mode not http request
+ if ( empty( $request_host ) || defined( 'WP_CLI' ) && WP_CLI )
+ return;
+
+ $home_url = get_home_url();
+ $parsed_url = @parse_url( $home_url );
+
+ if ( isset( $parsed_url['host'] ) &&
+ strtolower( $parsed_url['host'] ) != strtolower( $request_host ) ) {
+ $redirect_url = $parsed_url['scheme'] . '://';
+ if ( !empty( $parsed_url['user'] ) ) {
+ $redirect_url .= $parsed_url['user'];
+ if ( !empty( $parsed_url['pass'] ) )
+ $redirect_url .= ':' . $parsed_url['pass'];
+ }
+ if ( !empty( $parsed_url['host'] ) )
+ $redirect_url .= $parsed_url['host'];
+
+ if ( !empty( $parsed_url['port'] ) && $parsed_url['port'] != 80 ) {
+ $redirect_url .= ':' . (int)$parsed_url['port'];
+ }
+
+ $redirect_url .= $_SERVER['REQUEST_URI'];
+
+ //echo $redirect_url;
+ wp_redirect( $redirect_url, 301 );
+ exit();
+ }
+ }
+
+ function comment_cookie_lifetime( $lifetime ) {
+ $l = $this->_config->get_integer( 'pgcache.comment_cookie_ttl' );
+ if ( $l != -1 )
+ return $l;
+ else
+ return $lifetime;
+ }
+
+ /**
+ * Add cookie on logout to circumvent pagecache due to browser cache resulting in 304s
+ */
+ function on_logout() {
+ setcookie( 'w3tc_logged_out' );
+ }
+
+ /**
+ * Remove logout cookie on logins
+ */
+ function on_login() {
+ if ( isset( $_COOKIE['w3tc_logged_out'] ) )
+ setcookie( 'w3tc_logged_out', '', 1 );
+ }
+
+ /**
+ *
+ *
+ * @param unknown $post_id
+ * @return boolean
+ */
+ function prime_post( $post_id ) {
+ $w3_pgcache = Dispatcher::component( 'CacheFlush' );
+ return $w3_pgcache->prime_post( $post_id );
+ }
+
+ public function w3tc_usage_statistics_metrics( $metrics ) {
+ return array_merge( $metrics, array(
+ 'php_requests_pagecache_hit',
+ 'php_requests_pagecache_miss_404',
+ 'php_requests_pagecache_miss_ajax',
+ 'php_requests_pagecache_miss_api_call',
+ 'php_requests_pagecache_miss_configuration',
+ 'php_requests_pagecache_miss_fill',
+ 'php_requests_pagecache_miss_logged_in',
+ 'php_requests_pagecache_miss_mfunc',
+ 'php_requests_pagecache_miss_query_string',
+ 'php_requests_pagecache_miss_third_party',
+ 'php_requests_pagecache_miss_wp_admin',
+ 'pagecache_requests_time_10ms' ) );
+ }
+
+ public function w3tc_usage_statistics_sources( $sources ) {
+ $c = Dispatcher::config();
+ if ( $c->get_string( 'pgcache.engine' ) == 'apc' ) {
+ $sources['apc_servers']['pgcache'] = array(
+ 'name' => __( 'Page Cache', 'w3-total-cache' )
+ );
+ } elseif ( $c->get_string( 'pgcache.engine' ) == 'memcached' ) {
+ $sources['memcached_servers']['pgcache'] = array(
+ 'servers' => $c->get_array( 'pgcache.memcached.servers' ),
+ 'username' => $c->get_string( 'pgcache.memcached.username' ),
+ 'password' => $c->get_string( 'pgcache.memcached.password' ),
+ 'binary_protocol' => $c->get_boolean( 'pgcache.memcached.binary_protocol' ),
+ 'name' => __( 'Page Cache', 'w3-total-cache' )
+ );
+ } elseif ( $c->get_string( 'pgcache.engine' ) == 'redis' ) {
+ $sources['redis_servers']['pgcache'] = array(
+ 'servers' => $c->get_array( 'pgcache.redis.servers' ),
+ 'dbid' => $c->get_integer( 'pgcache.redis.dbid' ),
+ 'password' => $c->get_string( 'pgcache.redis.password' ),
+ 'name' => __( 'Page Cache', 'w3-total-cache' )
+ );
+ }
+
+ return $sources;
+ }
+
+ public function w3tc_admin_bar_menu( $menu_items ) {
+ $menu_items['20110.pagecache'] = array(
+ 'id' => 'w3tc_flush_pgcache',
+ 'parent' => 'w3tc_flush',
+ 'title' => __( 'Page Cache: All', 'w3-total-cache' ),
+ 'href' => wp_nonce_url( admin_url(
+ 'admin.php?page=w3tc_dashboard&w3tc_flush_pgcache' ),
+ 'w3tc' )
+ );
+
+ if ( Util_Environment::detect_post_id() && ( !defined( 'DOING_AJAX' ) || !DOING_AJAX ) ) {
+ $menu_items['20120.pagecache'] = array(
+ 'id' => 'w3tc_pgcache_flush_post',
+ 'parent' => 'w3tc_flush',
+ 'title' => __( 'Page Cache: Current Page', 'w3-total-cache' ),
+ 'href' => wp_nonce_url( admin_url(
+ 'admin.php?page=w3tc_dashboard&w3tc_flush_post&post_id=' .
+ Util_Environment::detect_post_id() ), 'w3tc' )
+ );
+ }
+
+ return $menu_items;
+ }
+
+ function w3tc_flush_group( $group, $extras = array() ) {
+ if ( isset( $extras['only'] ) && $extras['only'] != 'pagecache' )
+ return;
+
+ $pgcacheflush = Dispatcher::component( 'PgCache_Flush' );
+ $v = $pgcacheflush->flush_group( $group );
+
+ return $v;
+ }
+
+ /**
+ * Flushes all caches
+ *
+ * @return boolean
+ */
+ function w3tc_flush_posts( $extras = array() ) {
+ if ( isset( $extras['only'] ) && $extras['only'] != 'pagecache' )
+ return;
+
+ $pgcacheflush = Dispatcher::component( 'PgCache_Flush' );
+ $v = $pgcacheflush->flush();
+
+ return $v;
+ }
+
+ /**
+ * Flushes post cache
+ *
+ * @param integer $post_id
+ * @return boolean
+ */
+ function w3tc_flush_post( $post_id ) {
+ $pgcacheflush = Dispatcher::component( 'PgCache_Flush' );
+ $v = $pgcacheflush->flush_post( $post_id );
+
+ return $v;
+ }
+
+ /**
+ * Flushes post cache
+ *
+ * @param string $url
+ * @return boolean
+ */
+ function w3tc_flush_url( $url ) {
+ $pgcacheflush = Dispatcher::component( 'PgCache_Flush' );
+ $v = $pgcacheflush->flush_url( $url );
+
+ return $v;
+ }
+
+
+
+ /**
+ * By default headers are not cached by file_generic
+ */
+ public function w3tc_pagecache_set_header( $header, $header_original,
+ $pagecache_engine ) {
+ if ( $pagecache_engine == 'file_generic' ) {
+ return null;
+ }
+
+ return $header;
+ }
+
+
+
+ public function w3tc_config_save( $config ) {
+ // frontend activity
+ if ( $config->get_boolean( 'pgcache.cache.feed' ) ) {
+ $config->set( 'pgcache.cache.nginx_handle_xml', true );
+ }
+ }
+
+}
diff --git a/wp-content/plugins/w3-total-cache/PgCache_Plugin_Admin.php b/wp-content/plugins/w3-total-cache/PgCache_Plugin_Admin.php
new file mode 100644
index 0000000000..415a241bcf
--- /dev/null
+++ b/wp-content/plugins/w3-total-cache/PgCache_Plugin_Admin.php
@@ -0,0 +1,398 @@
+_config = Dispatcher::config();
+ }
+
+ /**
+ * Runs plugin
+ */
+ function run() {
+ add_filter( 'w3tc_save_options', array( $this, 'w3tc_save_options' ) );
+
+ $config_labels = new PgCache_ConfigLabels();
+ add_filter( 'w3tc_config_labels', array( $config_labels, 'config_labels' ) );
+
+ if ( $this->_config->get_boolean( 'pgcache.enabled' ) ) {
+ add_filter( 'w3tc_errors', array( $this, 'w3tc_errors' ) );
+ add_filter( 'w3tc_usage_statistics_summary_from_history', array(
+ $this, 'w3tc_usage_statistics_summary_from_history' ), 10, 2 );
+ }
+
+ add_action( 'admin_print_scripts-performance_page_w3tc_pgcache', array(
+ '\W3TC\PgCache_Page',
+ 'admin_print_scripts_w3tc_pgcache'
+ ) );
+
+ // Cache groups.
+ add_action(
+ 'w3tc_config_ui_save-w3tc_cachegroups',
+ array(
+ '\W3TC\CacheGroups_Plugin_Admin',
+ 'w3tc_config_ui_save_w3tc_cachegroups',
+ ),
+ 10,
+ 1
+ );
+ }
+
+ function cleanup() {
+ // We check to see if we're dealing with a cluster
+ $config = Dispatcher::config();
+ $is_cluster = $config->get_boolean( 'cluster.messagebus.enabled' );
+
+ // If we are, we notify the subscribers. If not, we just cleanup in here
+ if ( $is_cluster ) {
+ $this->cleanup_cluster();
+ } else {
+ $this->cleanup_local();
+ }
+
+ }
+
+ /**
+ * Will trigger notifications to be sent to the cluster to 'order' them to clean their page cache.
+ */
+ function cleanup_cluster() {
+ $sns_client = Dispatcher::component( 'Enterprise_CacheFlush_MakeSnsEvent' );
+ $sns_client->pgcache_cleanup();
+ }
+
+ function cleanup_local() {
+ $engine = $this->_config->get_string( 'pgcache.engine' );
+
+ switch ( $engine ) {
+ case 'file':
+ $w3_cache_file_cleaner = new Cache_File_Cleaner( array(
+ 'cache_dir' => Util_Environment::cache_blog_dir( 'page' ),
+ 'clean_timelimit' => $this->_config->get_integer( 'timelimit.cache_gc' )
+ ) );
+
+ $w3_cache_file_cleaner->clean();
+ break;
+
+ case 'file_generic':
+ if ( Util_Environment::blog_id() == 0 )
+ $flush_dir = W3TC_CACHE_PAGE_ENHANCED_DIR;
+ else
+ $flush_dir = W3TC_CACHE_PAGE_ENHANCED_DIR . '/' . Util_Environment::host();
+
+ $w3_cache_file_cleaner_generic = new Cache_File_Cleaner_Generic( array(
+ 'exclude' => array(
+ '.htaccess'
+ ),
+ 'cache_dir' => $flush_dir,
+ 'expire' => $this->_config->get_integer( 'browsercache.html.lifetime' ),
+ 'clean_timelimit' => $this->_config->get_integer( 'timelimit.cache_gc' )
+ ) );
+
+ $w3_cache_file_cleaner_generic->clean();
+ break;
+ }
+ }
+
+ /**
+ * Prime cache
+ *
+ * @param integer $start
+ * @return void
+ */
+ function prime( $start = null, $limit = null, $log_callback = null ) {
+ if ( is_null( $start ) ) {
+ $start = get_option( 'w3tc_pgcache_prime_offset' );
+ }
+ if ( $start < 0 ) {
+ $start = 0;
+ }
+
+ $interval = $this->_config->get_integer( 'pgcache.prime.interval' );
+ if ( is_null( $limit ) ) {
+ $limit = $this->_config->get_integer( 'pgcache.prime.limit' );
+ }
+ if ( $limit < 1 ) {
+ $limit = 1;
+ }
+
+ $sitemap = $this->_config->get_string( 'pgcache.prime.sitemap' );
+
+ if ( !is_null( $log_callback ) ) {
+ $log_callback( 'Priming from sitemap ' . $sitemap .
+ ' entries ' . ( $start + 1 ) . '..' . ( $start + $limit ) );
+ }
+
+ /**
+ * Parse XML sitemap
+ */
+ $urls = $this->parse_sitemap( $sitemap );
+
+ /**
+ * Queue URLs
+ */
+ $queue = array_slice( $urls, $start, $limit );
+
+ if ( count( $urls ) > ( $start + $limit ) ) {
+ $next_offset = $start + $limit;
+ } else {
+ $next_offset = 0;
+ }
+
+ update_option( 'w3tc_pgcache_prime_offset', $next_offset, false );
+
+ /**
+ * Make HTTP requests and prime cache
+ */
+
+ // use 'WordPress' since by default we use W3TC-powered by
+ // which blocks caching
+ foreach ( $queue as $url ) {
+ Util_Http::get( $url, array( 'user-agent' => 'WordPress' ) );
+
+ if ( !is_null( $log_callback ) ) {
+ $log_callback( 'Priming ' . $url );
+ }
+ }
+ }
+
+ /**
+ * Parses sitemap
+ *
+ * @param string $url
+ * @return array
+ */
+ function parse_sitemap( $url ) {
+ if ( !Util_Environment::is_url( $url ) )
+ $url = home_url( $url );
+
+ $urls = array();
+ $response = Util_Http::get( $url );
+
+ if ( !is_wp_error( $response ) && $response['response']['code'] == 200 ) {
+ $url_matches = null;
+ $sitemap_matches = null;
+
+ if ( preg_match_all( '~(.*?)~is', $response['body'], $sitemap_matches ) ) {
+ $loc_matches = null;
+
+ foreach ( $sitemap_matches[1] as $sitemap_match ) {
+ if ( preg_match( '~(.*?)~is', $sitemap_match, $loc_matches ) ) {
+ $loc = trim( $loc_matches[1] );
+
+ if ( $loc ) {
+ $urls = array_merge( $urls, $this->parse_sitemap( $loc ) );
+ }
+ }
+ }
+ } elseif ( preg_match_all( '~(.*?)~is', $response['body'], $url_matches ) ) {
+ $locs = array();
+ $loc_matches = null;
+ $priority_matches = null;
+
+ foreach ( $url_matches[1] as $url_match ) {
+ $loc = '';
+ $priority = 0.5;
+
+ if ( preg_match( '~(.*?)~is', $url_match, $loc_matches ) ) {
+ $loc = trim( $loc_matches[1] );
+ }
+
+ if ( preg_match( '~(.*?)~is', $url_match, $priority_matches ) ) {
+ $priority = (double) trim( $priority_matches[1] );
+ }
+
+ if ( $loc && $priority ) {
+ $locs[$loc] = $priority;
+ }
+ }
+
+ arsort( $locs );
+
+ $urls = array_keys( $locs );
+ } elseif ( preg_match_all( '~]*>(.*?)~is', $response['body'], $sitemap_matches ) ) {
+
+ // rss feed format
+ if ( preg_match_all( '~]*>(.*?)~is', $response['body'], $url_matches ) ) {
+ foreach ( $url_matches[1] as $url_match ) {
+ $url = trim( $url_match );
+ $cdata_matches = null;
+ if ( preg_match( '~~is', $url, $cdata_matches ) ) {
+ $url = $cdata_matches[1];
+ }
+
+ $urls[] = $url;
+ }
+ }
+ }
+ }
+
+ return $urls;
+ }
+
+ /**
+ * Makes get requests to url specific to a post, its permalink
+ *
+ * @param unknown $post_id
+ * @return boolean returns true on success
+ */
+ public function prime_post( $post_id ) {
+ $post_urls = Util_PageUrls::get_post_urls( $post_id );
+
+ // Make HTTP requests and prime cache
+ foreach ( $post_urls as $url ) {
+ $result = Util_Http::get( $url, array( 'user-agent' => 'WordPress' ) );
+ if ( is_wp_error( $result ) )
+ return false;
+ }
+ return true;
+ }
+
+
+
+ public function w3tc_save_options( $data ) {
+ $new_config = $data['new_config'];
+ $old_config = $data['old_config'];
+
+ if ( ( !$new_config->get_boolean( 'pgcache.cache.home' ) && $old_config->get_boolean( 'pgcache.cache.home' ) ) ||
+ $new_config->get_boolean( 'pgcache.reject.front_page' ) && !$old_config->get_boolean( 'pgcache.reject.front_page' ) ||
+ !$new_config->get_boolean( 'pgcache.cache.feed' ) && $old_config->get_boolean( 'pgcache.cache.feed' ) ||
+ !$new_config->get_boolean( 'pgcache.cache.query' ) && $old_config->get_boolean( 'pgcache.cache.query' ) ||
+ !$new_config->get_boolean( 'pgcache.cache.ssl' ) && $old_config->get_boolean( 'pgcache.cache.ssl' ) ) {
+ $state = Dispatcher::config_state();
+ $state->set( 'common.show_note.flush_posts_needed', true );
+ $state->save();
+ }
+
+ return $data;
+ }
+
+ public function w3tc_errors( $errors ) {
+ $c = Dispatcher::config();
+
+ if ( $c->get_string( 'pgcache.engine' ) == 'memcached' ) {
+ $memcached_servers = $c->get_array( 'pgcache.memcached.servers' );
+
+ if ( !Util_Installed::is_memcache_available( $memcached_servers ) ) {
+ if ( !isset( $errors['memcache_not_responding.details'] ) )
+ $errors['memcache_not_responding.details'] = array();
+
+ $errors['memcache_not_responding.details'][] = sprintf(
+ __( 'Page Cache: %s.', 'w3-total-cache' ),
+ implode( ', ', $memcached_servers ) );
+ }
+ }
+
+ return $errors;
+ }
+
+ public function w3tc_usage_statistics_summary_from_history( $summary, $history ) {
+ // total size
+ $g = Dispatcher::component( 'PgCache_ContentGrabber' );
+ $pagecache = array();
+
+ $e = $this->_config->get_string( 'pgcache.engine' );
+ $pagecache['engine_name'] = Cache::engine_name( $e );
+ $file_generic = ( $e == 'file_generic' );
+
+
+ // build metrics in php block
+ if ( !isset( $summary['php'] ) ) {
+ $summary['php'] = array();
+ }
+
+ Util_UsageStatistics::sum_by_prefix_positive( $summary['php'],
+ $history, 'php_requests_pagecache' );
+
+ // need to return cache size
+ if ( $file_generic ) {
+ list( $v, $should_count ) =
+ Util_UsageStatistics::get_or_init_size_transient(
+ 'w3tc_ustats_pagecache_size', $summary );
+ if ( $should_count ) {
+ $size = $g->get_cache_stats_size( $summary['timeout_time'] );
+ $v['size_used'] = Util_UsageStatistics::bytes_to_size2(
+ $size, 'bytes' );
+ $v['items'] = Util_UsageStatistics::integer2(
+ $size, 'items' );
+
+ set_transient( 'w3tc_ustats_pagecache_size', $v, 55 );
+ }
+
+ if ( isset( $v['size_used'] ) ) {
+ $pagecache['size_used'] = $v['size_used'];
+ $pagecache['items'] = $v['items'];
+ }
+
+ if ( isset( $summary['access_log'] ) ) {
+ $pagecache['requests'] = $summary['access_log']['dynamic_requests_total_v'];
+ $pagecache['requests_hit'] = $pagecache['requests'] - $summary['php']['php_requests_v'];
+ if ($pagecache['requests_hit'] < 0) {
+ $pagecache['requests_hit'] = 0;
+ }
+ }
+ } else {
+ // all request counts data available
+ $pagecache['requests'] = $summary['php']['php_requests_v'];
+ $pagecache['requests_hit'] =
+ isset( $summary['php']['php_requests_pagecache_hit'] ) ?
+ $summary['php']['php_requests_pagecache_hit'] : 0;
+
+ $requests_time_ms = Util_UsageStatistics::sum( $history,
+ 'pagecache_requests_time_10ms' ) * 10;
+ $php_requests = Util_UsageStatistics::sum( $history,
+ 'php_requests' );
+
+ if ( $php_requests > 0 ) {
+ $pagecache['request_time_ms'] = Util_UsageStatistics::integer(
+ $requests_time_ms / $php_requests );
+ }
+ }
+
+ if ( $e == 'memcached' ) {
+ $pagecache['size_percent'] = $summary['memcached']['size_percent'];
+ }
+ if ( isset($pagecache['requests_hit'] ) ) {
+ $pagecache['requests_hit_rate'] = Util_UsageStatistics::percent(
+ $pagecache['requests_hit'], $pagecache['requests'] );
+ }
+
+ if ( !isset( $summary['php']['php_requests_pagecache_hit'] ) ) {
+ $summary['php']['php_requests_pagecache_hit'] = 0;
+ }
+
+ if ( isset( $summary['php']['php_requests_v'] ) ) {
+ $v = $summary['php']['php_requests_v'] -
+ $summary['php']['php_requests_pagecache_hit'];
+ if ( $v < 0 ) {
+ $v = 0;
+ }
+
+ $summary['php']['php_requests_pagecache_miss'] = $v;
+ }
+
+ if ( isset( $pagecache['requests'] ) ) {
+ $pagecache['requests_per_second'] =
+ Util_UsageStatistics::value_per_period_seconds( $pagecache['requests'], $summary );
+ }
+
+
+ $summary['pagecache'] = $pagecache;
+
+ return $summary;
+ }
+}
diff --git a/wp-content/plugins/w3-total-cache/README.md b/wp-content/plugins/w3-total-cache/README.md
new file mode 100644
index 0000000000..ef9987d8c3
--- /dev/null
+++ b/wp-content/plugins/w3-total-cache/README.md
@@ -0,0 +1,14 @@
+Welcome to the W3 Total Cache repository on GitHub. Here you can browse the source, look at open issues and keep track of development.
+
+If you are not a developer, please use the [W3 Total Cache plugin page](https://wordpress.org/plugins/w3-total-cache/) on WordPress.org.
+
+## Support
+This repository is not suitable for support. Please don't use our issue tracker for support requests. Support can take place through the appropriate channels:
+
+* The support form can be found in Performance -> Support page of your wp-admin.
+* [Our community forum on wp.org](https://wordpress.org/support/plugin/w3-total-cache).
+
+Support requests in issues on this repository will be closed on sight.
+
+## Contributing to W3 Total Cache
+If you have a patch or have stumbled upon an issue with W3 Total Cache, you can contribute this back to the code. Please read our [contributor guidelines](https://github.com/W3EDGE/w3-total-cache/wiki/Contributor-Guidelines) for more information how you can do this.
diff --git a/wp-content/plugins/w3-total-cache/Root_AdminActions.php b/wp-content/plugins/w3-total-cache/Root_AdminActions.php
new file mode 100644
index 0000000000..82f2e17d2a
--- /dev/null
+++ b/wp-content/plugins/w3-total-cache/Root_AdminActions.php
@@ -0,0 +1,78 @@
+_get_handler( $action );
+ $handler_class_fullname = '\\W3TC\\' . $handler_class;
+ $handler_object = new $handler_class_fullname;
+
+ $action_details = explode( '~', $action );
+
+ if ( count( $action_details ) > 1 ) {
+ // action is in form "action~parameter"
+ $method = $action_details[0];
+ if ( method_exists( $handler_object, $method ) ) {
+ $handler_object->$method( $action_details[1] );
+ return;
+ }
+ } else {
+ // regular action
+ if ( method_exists( $handler_object, $action ) ) {
+ $handler_object->$action();
+ return;
+ }
+ }
+
+ throw new \Exception( sprintf( __( 'action %s does not exist' ), $action ) );
+ }
+
+ public function exists( $action ) {
+ $handler = $this->_get_handler( $action );
+ return $handler != '';
+ }
+
+ private function _get_handler( $action ) {
+ static $handlers = null;
+ if ( is_null( $handlers ) ) {
+ $handlers = array(
+ 'boldgrid' => 'Generic_WidgetBoldGrid_AdminActions',
+ 'cdn_google_drive' => 'Cdn_GoogleDrive_AdminActions',
+ 'cdn' => 'Cdn_AdminActions',
+ 'config' => 'Generic_AdminActions_Config',
+ 'default' => 'Generic_AdminActions_Default',
+ 'extensions' => 'Extensions_AdminActions',
+ 'flush' => 'Generic_AdminActions_Flush',
+ 'licensing' => 'Licensing_AdminActions',
+ 'support' => 'Support_AdminActions',
+ 'test' => 'Generic_AdminActions_Test',
+ 'ustats' => 'UsageStatistics_AdminActions'
+ );
+ $handlers = apply_filters( 'w3tc_admin_actions', $handlers );
+ }
+
+ if ( $action == 'w3tc_save_options' )
+ return $handlers['default'];
+
+ $candidate_prefix = '';
+ $candidate_class = '';
+
+ foreach ( $handlers as $prefix => $class ) {
+ $v1 = "w3tc_$prefix";
+ $v2 = "w3tc_save_$prefix";
+
+ if ( substr( $action, 0, strlen( $v1 ) ) == $v1 ||
+ substr( $action, 0, strlen( $v2 ) ) == $v2 ) {
+ if ( strlen( $candidate_prefix ) < strlen( $prefix ) ) {
+ $candidate_class = $class;
+ $candidate_prefix = $prefix;
+ }
+ }
+ }
+
+ return $candidate_class;
+ }
+}
diff --git a/wp-content/plugins/w3-total-cache/Root_AdminActivation.php b/wp-content/plugins/w3-total-cache/Root_AdminActivation.php
new file mode 100644
index 0000000000..5945813db3
--- /dev/null
+++ b/wp-content/plugins/w3-total-cache/Root_AdminActivation.php
@@ -0,0 +1,108 @@
+network activate W3 Total Cache when using WordPress Multisite.';
+ die;
+ }
+ }
+
+ try {
+ $e = Dispatcher::component( 'Root_Environment' );
+
+ $config = Dispatcher::config();
+ $e->fix_in_wpadmin( $config, true );
+ $e->fix_on_event( $config, 'activate' );
+
+ // try to save config file if needed, optional thing so exceptions
+ // hidden
+ if ( !ConfigUtil::is_item_exists( 0, false ) ) {
+ try {
+ // create folders
+ $e->fix_in_wpadmin( $config );
+ } catch ( \Exception $ex ) {
+ }
+
+ try {
+ Util_Admin::config_save( Dispatcher::config(), $config );
+ } catch ( \Exception $ex ) {
+ }
+ }
+ } catch ( Util_Environment_Exceptions $e ) {
+ } catch ( \Exception $e ) {
+ Util_Activation::error_on_exception( $e );
+ }
+ }
+
+ /**
+ * Deactivate plugin action
+ *
+ * @return void
+ */
+ static public function deactivate() {
+ try {
+ Util_Activation::enable_maintenance_mode();
+ } catch ( \Exception $ex ) {
+ }
+
+ try {
+ $e = Dispatcher::component( 'Root_Environment' );
+ $e->fix_after_deactivation();
+ } catch ( Util_Environment_Exceptions $exs ) {
+ $r = Util_Activation::parse_environment_exceptions( $exs );
+
+ if ( strlen( $r['required_changes'] ) > 0 ) {
+ $changes_style = 'border: 1px solid black; ' .
+ 'background: white; ' .
+ 'margin: 10px 30px 10px 30px; ' .
+ 'padding: 10px;';
+
+ $error = 'W3 Total Cache Error: ' .
+ 'Files and directories could not be automatically ' .
+ 'removed to complete the deactivation. ' .
+ ' Please execute commands manually: ' .
+ '' .
+ $r['required_changes'] . ' ';
+
+ // this is not shown since wp redirects from that page
+ // not solved now
+ echo '';
+ }
+ }
+
+ try {
+ Util_Activation::disable_maintenance_mode();
+ } catch ( \Exception $ex ) {
+ }
+
+ // Delete cron events.
+ require_once __DIR__ . '/Extension_ImageService_Cron.php';
+ Extension_ImageService_Cron::delete_cron();
+ }
+}
diff --git a/wp-content/plugins/w3-total-cache/Root_AdminMenu.php b/wp-content/plugins/w3-total-cache/Root_AdminMenu.php
new file mode 100644
index 0000000000..4bd929ed15
--- /dev/null
+++ b/wp-content/plugins/w3-total-cache/Root_AdminMenu.php
@@ -0,0 +1,307 @@
+_config = Dispatcher::config();
+ }
+
+ /**
+ * Generate menu array.
+ *
+ * @return array
+ */
+ public function generate_menu_array() {
+ $pages = array(
+ 'w3tc_dashboard' => array(
+ 'page_title' => __( 'Dashboard', 'w3-total-cache' ),
+ 'menu_text' => __( 'Dashboard', 'w3-total-cache' ),
+ 'visible_always' => true,
+ 'order' => 100,
+ ),
+ 'w3tc_feature_showcase' => array(
+ 'page_title' => __( 'Feature Showcase', 'w3-total-cache' ),
+ 'menu_text' => __( 'Feature Showcase', 'w3-total-cache' ),
+ 'visible_always' => false,
+ 'order' => 200,
+ ),
+ 'w3tc_general' => array(
+ 'page_title' => __( 'General Settings', 'w3-total-cache' ),
+ 'menu_text' => __( 'General Settings', 'w3-total-cache' ),
+ 'visible_always' => false,
+ 'order' => 300,
+ ),
+ 'w3tc_pgcache' => array(
+ 'page_title' => __( 'Page Cache', 'w3-total-cache' ),
+ 'menu_text' => __( 'Page Cache', 'w3-total-cache' ),
+ 'visible_always' => false,
+ 'order' => 400,
+ ),
+ 'w3tc_minify' => array(
+ 'page_title' => __( 'Minify', 'w3-total-cache' ),
+ 'menu_text' => __( 'Minify', 'w3-total-cache' ),
+ 'visible_always' => false,
+ 'order' => 500,
+ ),
+ 'w3tc_dbcache' => array(
+ 'page_title' => __( 'Database Cache', 'w3-total-cache' ),
+ 'menu_text' => __( 'Database Cache', 'w3-total-cache' ),
+ 'visible_always' => false,
+ 'order' => 600,
+ ),
+ 'w3tc_objectcache' => array(
+ 'page_title' => __( 'Object Cache', 'w3-total-cache' ),
+ 'menu_text' => __( 'Object Cache', 'w3-total-cache' ),
+ 'visible_always' => false,
+ 'order' => 700,
+ ),
+ 'w3tc_browsercache' => array(
+ 'page_title' => __( 'Browser Cache', 'w3-total-cache' ),
+ 'menu_text' => __( 'Browser Cache', 'w3-total-cache' ),
+ 'visible_always' => false,
+ 'order' => 800,
+ ),
+ 'w3tc_cachegroups' => array(
+ 'page_title' => __( 'Cache Groups', 'w3-total-cache' ),
+ 'menu_text' => __( 'Cache Groups', 'w3-total-cache' ),
+ 'visible_always' => false,
+ 'order' => 900,
+ ),
+ 'w3tc_cdn' => array(
+ 'page_title' => __( 'Content Delivery Network', 'w3-total-cache' ),
+ 'menu_text' => sprintf(
+ 'CDN',
+ __( 'Content Delivery Network', 'w3-total-cache' )
+ ),
+ 'visible_always' => false,
+ 'order' => 1000,
+ ),
+ 'w3tc_faq' => array(
+ 'page_title' => __( 'FAQ', 'w3-total-cache' ),
+ 'menu_text' => __( 'FAQ', 'w3-total-cache' ),
+ 'visible_always' => true,
+ 'order' => 1100,
+ 'redirect_faq' => '*',
+ ),
+ 'w3tc_support' => array(
+ 'page_title' => __( 'Support', 'w3-total-cache' ),
+ 'menu_text' => __( 'Support', 'w3-total-cache' ),
+ 'visible_always' => true,
+ 'order' => 1200,
+ ),
+ 'w3tc_install' => array(
+ 'page_title' => __( 'Install', 'w3-total-cache' ),
+ 'menu_text' => __( 'Install', 'w3-total-cache' ),
+ 'visible_always' => false,
+ 'order' => 1300,
+ ),
+ 'w3tc_setup_guide' => array(
+ 'page_title' => __( 'Setup Guide', 'w3-total-cache' ),
+ 'menu_text' => __( 'Setup Guide', 'w3-total-cache' ),
+ 'visible_always' => false,
+ 'order' => 1400,
+ ),
+ 'w3tc_about' => array(
+ 'page_title' => __( 'About', 'w3-total-cache' ),
+ 'menu_text' => __( 'About', 'w3-total-cache' ),
+ 'visible_always' => true,
+ 'order' => 1500,
+ ),
+ );
+
+ $pages = apply_filters( 'w3tc_admin_menu', $pages, $this->_config );
+
+ return $pages;
+ }
+
+ /**
+ * Generate menu.
+ *
+ * @param string $base_capability Base compatibility.
+ * @return array
+ */
+ public function generate( $base_capability ) {
+ $pages = $this->generate_menu_array();
+
+ uasort(
+ $pages,
+ function( $a, $b ) {
+ return ( $a['order'] - $b['order'] );
+ }
+ );
+
+ add_menu_page(
+ __( 'Performance', 'w3-total-cache' ),
+ __( 'Performance', 'w3-total-cache' ),
+ apply_filters(
+ 'w3tc_capability_menu_w3tc_dashboard',
+ $base_capability
+ ),
+ 'w3tc_dashboard',
+ '',
+ 'none'
+ );
+
+ $submenu_pages = array();
+ $is_master = ( is_network_admin() || ! Util_Environment::is_wpmu() );
+ $remaining_visible = ! $this->_config->get_boolean( 'common.force_master' );
+
+ foreach ( $pages as $slug => $titles ) {
+ if ( $is_master || $titles['visible_always'] || $remaining_visible ) {
+ $hook = add_submenu_page(
+ 'w3tc_dashboard',
+ $titles['page_title'] . ' | W3 Total Cache',
+ $titles['menu_text'],
+ apply_filters(
+ 'w3tc_capability_menu_' . $slug,
+ $base_capability
+ ),
+ $slug,
+ array(
+ $this,
+ 'options',
+ )
+ );
+
+ $submenu_pages[] = $hook;
+ }
+ }
+
+ return $submenu_pages;
+ }
+
+ /**
+ * Options page.
+ */
+ public function options() {
+ $this->_page = Util_Request::get_string( 'page' );
+
+ if ( ! Util_Admin::is_w3tc_admin_page() ) {
+ $this->_page = 'w3tc_dashboard';
+ }
+
+ /*
+ * Hidden pages.
+ */
+ if ( isset( $_REQUEST['w3tc_dbcluster_config'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
+ $options_dbcache = new DbCache_Page();
+ $options_dbcache->dbcluster_config();
+ }
+
+ /**
+ * Show tab.
+ */
+ switch ( $this->_page ) {
+ case 'w3tc_dashboard':
+ $options_dashboard = new Generic_Page_Dashboard();
+ $options_dashboard->options();
+ break;
+
+ case 'w3tc_general':
+ $options_general = new Generic_Page_General();
+ $options_general->options();
+ break;
+
+ case 'w3tc_pgcache':
+ $options_pgcache = new PgCache_Page();
+ $options_pgcache->options();
+ break;
+
+ case 'w3tc_minify':
+ $options_minify = new Minify_Page();
+ $options_minify->options();
+ break;
+
+ case 'w3tc_dbcache':
+ $options_dbcache = new DbCache_Page();
+ $options_dbcache->options();
+ break;
+
+ case 'w3tc_objectcache':
+ $options_objectcache = new ObjectCache_Page();
+ $options_objectcache->options();
+ break;
+
+ case 'w3tc_browsercache':
+ $options_browsercache = new BrowserCache_Page();
+ $options_browsercache->options();
+ break;
+
+ case 'w3tc_cachegroups':
+ $options_cachegroups = new CacheGroups_Plugin_Admin();
+ $options_cachegroups->options();
+ break;
+
+ case 'w3tc_cdn':
+ $options_cdn = new Cdn_Page();
+ $options_cdn->options();
+ break;
+
+ case 'w3tc_stats':
+ $p = new UsageStatistics_Page();
+ $p->render();
+ break;
+
+ case 'w3tc_support':
+ $options_support = new Support_Page();
+ $options_support->options();
+ break;
+
+ case 'w3tc_install':
+ $options_install = new Generic_Page_Install();
+ $options_install->options();
+ break;
+
+ case 'w3tc_setup_guide':
+ $setup_guide = new SetupGuide_Plugin_Admin();
+ $setup_guide->load();
+ break;
+
+ case 'w3tc_feature_showcase':
+ $feature_showcase = new FeatureShowcase_Plugin_Admin();
+ $feature_showcase->load();
+ break;
+
+ case 'w3tc_about':
+ $options_about = new Generic_Page_About();
+ $options_about->options();
+ break;
+ default:
+ // Placeholder to make it the only way to show pages with the time.
+ $view = new Base_Page_Settings();
+ $view->options();
+
+ do_action( 'w3tc_settings_page-' . $this->_page ); // phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores
+
+ $view->render_footer();
+
+ break;
+ }
+ }
+}
diff --git a/wp-content/plugins/w3-total-cache/Root_Environment.php b/wp-content/plugins/w3-total-cache/Root_Environment.php
new file mode 100644
index 0000000000..09c60f4fca
--- /dev/null
+++ b/wp-content/plugins/w3-total-cache/Root_Environment.php
@@ -0,0 +1,202 @@
+get_md5() ) ) {
+ $fix_on_event = true;
+ set_transient( 'w3tc_config_changes', $md5_string, 3600 );
+ }
+ }
+ // call plugin-related handlers
+ foreach ( $this->get_handlers() as $h ) {
+ try {
+ $h->fix_on_wpadmin_request( $config, $force_all_checks );
+ if ( $fix_on_event ) {
+ $this->fix_on_event( $config, 'admin_request' );
+ }
+ } catch ( Util_Environment_Exceptions $ex ) {
+ $exs->push( $ex );
+ }
+ }
+
+ try {
+ do_action( 'w3tc_environment_fix_on_wpadmin_request',
+ $config, $force_all_checks );
+ } catch ( Util_Environment_Exceptions $ex ) {
+ $exs->push( $ex );
+ }
+
+ if ( count( $exs->exceptions() ) > 0 )
+ throw $exs;
+ }
+
+ /**
+ * Fixes environment once event occurs
+ *
+ * @throws Util_Environment_Exceptions
+ */
+ public function fix_on_event( $config, $event, $old_config = null ) {
+ $exs = new Util_Environment_Exceptions();
+
+ // call plugin-related handlers
+ foreach ( $this->get_handlers() as $h ) {
+ try {
+ $h->fix_on_event( $config, $event );
+ } catch ( Util_Environment_Exceptions $ex ) {
+ $exs->push( $ex );
+ }
+ }
+
+ try {
+ do_action( 'w3tc_environment_fix_on_event',
+ $config, $event );
+ } catch ( Util_Environment_Exceptions $ex ) {
+ $exs->push( $ex );
+ }
+
+ if ( count( $exs->exceptions() ) > 0 )
+ throw $exs;
+ }
+
+ /**
+ * Fixes environment after plugin deactivation
+ *
+ * @param Config $config
+ * @throws Util_Environment_Exceptions
+ */
+ public function fix_after_deactivation() {
+ $exs = new Util_Environment_Exceptions();
+
+ // call plugin-related handlers
+ foreach ( $this->get_handlers() as $h ) {
+ try {
+ $h->fix_after_deactivation();
+ } catch ( Util_Environment_Exceptions $ex ) {
+ $exs->push( $ex );
+ }
+ }
+
+ try {
+ do_action( 'w3tc_environment_fix_after_deactivation' );
+ } catch ( Util_Environment_Exceptions $ex ) {
+ $exs->push( $ex );
+ }
+
+ if ( count( $exs->exceptions() ) > 0 )
+ throw $exs;
+ }
+
+ /**
+ * Returns an array[filename]=rules of rules for .htaccess or nginx files
+ *
+ * @param Config $config
+ * @return array
+ */
+ public function get_required_rules( $config ) {
+ $required_rules = array();
+ foreach ( $this->get_handlers() as $h ) {
+ $required_rules_current = $h->get_required_rules( $config );
+
+ if ( !is_null( $required_rules_current ) )
+ $required_rules = array_merge( $required_rules, $required_rules_current );
+ }
+
+ $required_rules = apply_filters( 'w3tc_environment_get_required_rules',
+ $required_rules, $config );
+
+
+ $rewrite_rules_descriptors = array();
+
+ foreach ( $required_rules as $descriptor ) {
+ $filename = $descriptor['filename'];
+
+ if ( isset( $rewrite_rules_descriptors[$filename] ) )
+ $content = $rewrite_rules_descriptors[$filename]['content'];
+ else
+ $content = array();
+
+ if ( !isset( $descriptor['position'] ) )
+ $content[] = $descriptor['content'];
+ else {
+ $position = $descriptor['position'];
+
+ if ( isset( $content[$position] ) )
+ $content[$position] .= $descriptor['content'];
+ else
+ $content[$position] = $descriptor['content'];
+ }
+
+ $rewrite_rules_descriptors[$filename] = array(
+ 'filename' => $filename,
+ 'content' => $content
+ );
+ }
+
+ $rewrite_rules_descriptors_out = array();
+ foreach ( $rewrite_rules_descriptors as $filename => $descriptor ) {
+ $rewrite_rules_descriptors_out[$filename] = array(
+ 'filename' => $filename,
+ 'content' => implode( '', $descriptor['content'] )
+ );
+ }
+ ksort( $rewrite_rules_descriptors_out );
+ return $rewrite_rules_descriptors_out;
+ }
+
+ /**
+ * Returns plugin-related environment handlers
+ *
+ * @param Config $config
+ * @return array
+ */
+ private function get_handlers() {
+ $a = array(
+ new Generic_Environment(),
+ new Minify_Environment(),
+ new PgCache_Environment(),
+ new BrowserCache_Environment(),
+ new ObjectCache_Environment(),
+ new DbCache_Environment(),
+ new Cdn_Environment(),
+ new Extension_ImageService_Environment(),
+ );
+
+ return $a;
+ }
+
+ public function get_other_instructions( $config ) {
+ $instructions_descriptors = array();
+
+ foreach ( $this->get_handlers() as $h ) {
+ if ( method_exists( $h, 'get_instructions' ) ) {
+ $instructions = $h->get_instructions( $config );
+ if ( !is_null( $instructions ) ) {
+ foreach ( $instructions as $descriptor ) {
+ $area = $descriptor['area'];
+ $instructions_descriptors[$area][] = array(
+ 'title' => $descriptor['title'],
+ 'content' => $descriptor['content']
+ );
+ }
+ }
+ }
+
+ }
+ return $instructions_descriptors;
+ }
+}
diff --git a/wp-content/plugins/w3-total-cache/Root_Loader.php b/wp-content/plugins/w3-total-cache/Root_Loader.php
new file mode 100644
index 0000000000..8b88360f58
--- /dev/null
+++ b/wp-content/plugins/w3-total-cache/Root_Loader.php
@@ -0,0 +1,219 @@
+get_boolean( 'dbcache.enabled' ) )
+ $plugins[] = new DbCache_Plugin();
+ if ( $c->get_boolean( 'objectcache.enabled' ) )
+ $plugins[] = new ObjectCache_Plugin();
+ if ( $c->get_boolean( 'pgcache.enabled' ) )
+ $plugins[] = new PgCache_Plugin();
+ if ( $c->get_boolean( 'cdn.enabled' ) )
+ $plugins[] = new Cdn_Plugin();
+ if ( $c->get_boolean( 'cdnfsd.enabled' ) )
+ $plugins[] = new Cdnfsd_Plugin();
+ if ( $c->get_boolean( 'lazyload.enabled' ) )
+ $plugins[] = new UserExperience_LazyLoad_Plugin();
+ if ( $c->get_boolean( 'browsercache.enabled' ) )
+ $plugins[] = new BrowserCache_Plugin();
+ if ( $c->get_boolean( 'minify.enabled' ) )
+ $plugins[] = new Minify_Plugin();
+ if ( $c->get_boolean( 'varnish.enabled' ) )
+ $plugins[] = new Varnish_Plugin();
+ if ( $c->get_boolean( 'stats.enabled' ) )
+ $plugins[] = new UsageStatistics_Plugin();
+
+ if ( is_admin() ) {
+ $plugins[] = new Generic_Plugin_Admin();
+ $plugins[] = new BrowserCache_Plugin_Admin();
+ $plugins[] = new DbCache_Plugin_Admin();
+ $plugins[] = new UserExperience_Plugin_Admin();
+ $plugins[] = new ObjectCache_Plugin_Admin();
+ $plugins[] = new PgCache_Plugin_Admin();
+ $plugins[] = new Minify_Plugin_Admin();
+ $plugins[] = new Generic_WidgetSpreadTheWord_Plugin();
+ $plugins[] = new Generic_Plugin_WidgetNews();
+ $plugins[] = new Generic_Plugin_WidgetForum();
+ $plugins[] = new SystemOpCache_Plugin_Admin();
+
+ $plugins[] = new Cdn_Plugin_Admin();
+ $plugins[] = new Cdnfsd_Plugin_Admin();
+ $cdn_engine = $c->get_string( 'cdn.engine' );
+ if ( $cdn_engine == 'maxcdn' ) {
+ $plugins[] = new Cdn_Plugin_WidgetMaxCdn();
+ }
+
+ if ( $c->get_boolean( 'widget.pagespeed.enabled' ) )
+ $plugins[] = new PageSpeed_Plugin_Widget();
+
+ $plugins[] = new Generic_Plugin_AdminCompatibility();
+ $plugins[] = new Licensing_Plugin_Admin();
+
+ if ( $c->get_boolean( 'pgcache.enabled' ) ||
+ $c->get_boolean( 'varnish.enabled' ) )
+ $plugins[] = new Generic_Plugin_AdminRowActions();
+
+ $plugins[] = new Extensions_Plugin_Admin();
+ $plugins[] = new Generic_Plugin_AdminNotifications();
+ $plugins[] = new UsageStatistics_Plugin_Admin();
+ $plugins[] = new SetupGuide_Plugin_Admin();
+ $plugins[] = new FeatureShowcase_Plugin_Admin();
+ } else {
+ if ( $c->get_boolean( 'jquerymigrate.disabled' ) ) {
+ $plugins[] = new UserExperience_Plugin_Jquery();
+ }
+ }
+
+ $this->_loaded_plugins = $plugins;
+
+ register_activation_hook( W3TC_FILE, array(
+ $this,
+ 'activate'
+ ) );
+
+ register_deactivation_hook( W3TC_FILE, array(
+ $this,
+ 'deactivate'
+ ) );
+ }
+
+ /**
+ * Run plugins
+ */
+ function run() {
+ foreach ( $this->_loaded_plugins as $plugin ) {
+ $plugin->run();
+ }
+
+ if ( method_exists( $GLOBALS['wpdb'], 'on_w3tc_plugins_loaded' ) ) {
+ $o = $GLOBALS['wpdb'];
+ $o->on_w3tc_plugins_loaded();
+ }
+
+ $this->run_extensions();
+ }
+
+ /**
+ * Activation action hook
+ */
+ public function activate( $network_wide ) {
+ Root_AdminActivation::activate( $network_wide );
+ }
+
+ /**
+ * Deactivation action hook
+ */
+ public function deactivate() {
+ Root_AdminActivation::deactivate();
+ }
+
+ /**
+ * Loads extensions stored in config
+ */
+ function run_extensions() {
+ $c = Dispatcher::config();
+ $extensions = $c->get_array( 'extensions.active' );
+
+ $frontend = $c->get_array( 'extensions.active_frontend' );
+ foreach ( $frontend as $extension => $nothing ) {
+ if ( isset( $extensions[$extension] ) ) {
+ $path = $extensions[$extension];
+ $filename = W3TC_EXTENSION_DIR . '/' .
+ str_replace( '..', '', trim( $path, '/' ) );
+
+ if ( file_exists( $filename ) ) {
+ include_once( $filename );
+ }
+ }
+ }
+
+ if ( is_admin() ) {
+ foreach ( $extensions as $extension => $path ) {
+ $filename = W3TC_EXTENSION_DIR . '/' .
+ str_replace( '..', '', trim( $path, '/' ) );
+
+ if ( file_exists( $filename ) ) {
+ include_once( $filename );
+ }
+ }
+ }
+
+ w3tc_do_action( 'wp_loaded' );
+ do_action( 'w3tc_extension_load' );
+ if ( is_admin() ) {
+ do_action( 'w3tc_extension_load_admin' );
+ }
+
+ // Hide Image Service media.
+ add_action(
+ 'pre_get_posts',
+ function( $query ) {
+ if ( ! is_admin() || ! $query->is_main_query() ) {
+ return;
+ }
+
+ $screen = get_current_screen();
+
+ if ( ! $screen || 'upload' !== $screen->id || 'attachment' !== $screen->post_type ) {
+ return;
+ }
+
+ $query->set(
+ 'meta_query',
+ array(
+ array(
+ 'key' => 'w3tc_imageservice_file',
+ 'compare' => 'NOT EXISTS',
+ ),
+ )
+ );
+
+ return;
+ }
+ );
+
+ add_filter(
+ 'ajax_query_attachments_args',
+ function( $args ) {
+ if ( ! is_admin() ) {
+ return;
+ }
+
+ // Modify the query.
+ $args['meta_query'] = array( // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query
+ array(
+ 'key' => 'w3tc_imageservice_file',
+ 'compare' => 'NOT EXISTS',
+ ),
+ );
+
+ return $args;
+ }
+ );
+ }
+}
+
+global $w3tc_root;
+if ( is_null( $w3tc_root ) ) {
+ $w3tc_root = new \W3TC\Root_Loader();
+ $w3tc_root->run();
+}
diff --git a/wp-content/plugins/w3-total-cache/SetupGuide_Plugin_Admin.php b/wp-content/plugins/w3-total-cache/SetupGuide_Plugin_Admin.php
new file mode 100644
index 0000000000..9be5b11309
--- /dev/null
+++ b/wp-content/plugins/w3-total-cache/SetupGuide_Plugin_Admin.php
@@ -0,0 +1,1411 @@
+get_config() );
+ }
+ }
+ }
+
+ /**
+ * Run.
+ *
+ * Needed by the Root_Loader.
+ *
+ * @since 2.0.0
+ */
+ public function run() {
+ }
+
+ /**
+ * Display the setup guide.
+ *
+ * @since 2.0.0
+ *
+ * @see \W3TC\Wizard\Template::render()
+ */
+ public function load() {
+ self::$template->render();
+ }
+
+ /**
+ * Admin-Ajax: Set option to skip the setup guide.
+ *
+ * @since 2.0.0
+ */
+ public function skip() {
+ if ( wp_verify_nonce( $_POST['_wpnonce'], 'w3tc_wizard' ) ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput
+ update_site_option( 'w3tc_setupguide_completed', time() );
+ wp_send_json_success();
+ } else {
+ wp_send_json_error( __( 'Security violation', 'w3-total-cache' ), 403 );
+ }
+ }
+
+ /**
+ * Admin-Ajax: Set the terms of service choice.
+ *
+ * @since 2.0.0
+ *
+ * @uses $_POST['choice'] TOS choice: accept/decline.
+ */
+ public function set_tos_choice() {
+ if ( wp_verify_nonce( $_POST['_wpnonce'], 'w3tc_wizard' ) ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput
+ $choice = empty( $_POST['choice'] ) ? null : sanitize_key( $_POST['choice'] );
+ $allowed_choices = array(
+ 'accept',
+ 'decline',
+ );
+
+ if ( in_array( $choice, $allowed_choices, true ) ) {
+ $config = new Config();
+
+ if ( ! Util_Environment::is_w3tc_pro( $config ) ) {
+ $state_master = Dispatcher::config_state_master();
+ $state_master->set( 'license.community_terms', $choice );
+ $state_master->save();
+
+ $config->set( 'common.track_usage', ( 'accept' === $choice ) );
+ $config->save();
+ }
+
+ wp_send_json_success();
+ } else {
+ wp_send_json_error( __( 'Invalid choice', 'w3-total-cache' ), 400 );
+ }
+ } else {
+ wp_send_json_error( __( 'Security violation', 'w3-total-cache' ), 403 );
+ }
+ }
+
+ /**
+ * Abbreviate a URL for display in a small space.
+ *
+ * @since 2.0.0
+ *
+ * @param string $url URL.
+ * @return string
+ */
+ public function abbreviate_url( $url ) {
+ $url = untrailingslashit(
+ str_replace(
+ array(
+ 'https://',
+ 'http://',
+ 'www.',
+ ),
+ '',
+ $url
+ )
+ );
+
+ if ( strlen( $url ) > 35 ) {
+ $url = substr( $url, 0, 10 ) . '…' . substr( $url, -20 );
+ }
+
+ return $url;
+ }
+
+ /**
+ * Admin-Ajax: Test Page Cache.
+ *
+ * @since 2.0.0
+ *
+ * @see self::abbreviate_url()
+ * @see \W3TC\Util_Http::ttfb()
+ */
+ public function test_pgcache() {
+ if ( wp_verify_nonce( $_POST['_wpnonce'], 'w3tc_wizard' ) ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput
+ $nocache = ! empty( $_POST['nocache'] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput
+ $url = site_url();
+ $results = array(
+ 'nocache' => $nocache,
+ 'url' => $url,
+ 'urlshort' => $this->abbreviate_url( $url ),
+ );
+
+ if ( ! $nocache ) {
+ Util_Http::get( $url, array( 'user-agent' => 'WordPress/' . get_bloginfo( 'version' ) . '; ' . get_bloginfo( 'url' ) ) );
+ }
+
+ $results['ttfb'] = Util_Http::ttfb( $url, $nocache );
+
+ wp_send_json_success( $results );
+ } else {
+ wp_send_json_error( __( 'Security violation', 'w3-total-cache' ), 403 );
+ }
+ }
+
+ /**
+ * Admin-Ajax: Get the page cache settings.
+ *
+ * @since 2.0.0
+ *
+ * @see \W3TC\Config::get_boolean()
+ * @see \W3TC\Config::get_string()
+ */
+ public function get_pgcache_settings() {
+ if ( wp_verify_nonce( $_POST['_wpnonce'], 'w3tc_wizard' ) ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput
+ $config = new Config();
+
+ wp_send_json_success(
+ array(
+ 'enabled' => $config->get_boolean( 'pgcache.enabled' ),
+ 'engine' => $config->get_string( 'pgcache.engine' ),
+ )
+ );
+ } else {
+ wp_send_json_error( __( 'Security violation', 'w3-total-cache' ), 403 );
+ }
+ }
+
+ /**
+ * Admin-Ajax: Configure the page cache settings.
+ *
+ * @since 2.0.0
+ *
+ * @see \W3TC\Config::get_boolean()
+ * @see \W3TC\Config::get_string()
+ * @see \W3TC\Util_Installed::$engine()
+ * @see \W3TC\Config::set()
+ * @see \W3TC\Config::save()
+ * @see \W3TC\Dispatcher::component()
+ * @see \W3TC\CacheFlush::flush_posts()
+ */
+ public function config_pgcache() {
+ if ( wp_verify_nonce( $_POST['_wpnonce'], 'w3tc_wizard' ) ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput
+ $enable = ! empty( $_POST['enable'] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput
+ $engine = empty( $_POST['engine'] ) ? '' : esc_attr( trim( $_POST['engine'] ) ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput
+ $is_updating = false;
+ $success = false;
+ $config = new Config();
+ $pgcache_enabled = $config->get_boolean( 'pgcache.enabled' );
+ $pgcache_engine = $config->get_string( 'pgcache.engine' );
+ $allowed_engines = array(
+ '',
+ 'file',
+ 'file_generic',
+ 'redis',
+ 'memcached',
+ 'nginx_memcached',
+ 'apc',
+ 'eaccelerator',
+ 'xcache',
+ 'wincache',
+ );
+
+ if ( in_array( $engine, $allowed_engines, true ) ) {
+ if ( empty( $engine ) || 'file' === $engine || 'file_generic' === $engine || Util_Installed::$engine() ) {
+ if ( $pgcache_enabled !== $enable ) {
+ $config->set( 'pgcache.enabled', $enable );
+ $is_updating = true;
+ }
+
+ if ( ! empty( $engine ) && $pgcache_engine !== $engine ) {
+ $config->set( 'pgcache.engine', $engine );
+ $is_updating = true;
+ }
+
+ if ( $is_updating ) {
+ $config->save();
+
+ $f = Dispatcher::component( 'CacheFlush' );
+ $f->flush_posts();
+
+ $e = Dispatcher::component( 'PgCache_Environment' );
+ $e->fix_on_wpadmin_request( $config, true );
+ }
+
+ if ( $config->get_boolean( 'pgcache.enabled' ) === $enable &&
+ ( ! $enable || $config->get_string( 'pgcache.engine' ) === $engine ) ) {
+ $success = true;
+ $message = __( 'Settings updated', 'w3-total-cache' );
+ } else {
+ $message = __( 'Settings not updated', 'w3-total-cache' );
+ }
+ } else {
+ $message = __( 'Requested cache storage engine is not available', 'w3-total-cache' );
+ }
+ } elseif ( ! $is_allowed_engine ) {
+ $message = __( 'Requested cache storage engine is invalid', 'w3-total-cache' );
+ }
+
+ wp_send_json_success(
+ array(
+ 'success' => $success,
+ 'message' => $message,
+ 'enable' => $enable,
+ 'engine' => $engine,
+ 'current_enabled' => $config->get_boolean( 'pgcache.enabled' ),
+ 'current_engine' => $config->get_string( 'pgcache.engine' ),
+ 'previous_enabled' => $pgcache_enabled,
+ 'previous_engine' => $pgcache_engine,
+ )
+ );
+ } else {
+ wp_send_json_error( __( 'Security violation', 'w3-total-cache' ), 403 );
+ }
+ }
+
+ /**
+ * Admin-Ajax: Test database cache.
+ *
+ * @since 2.0.0
+ *
+ * @see \W3TC\Config::get_boolean()
+ * @see \W3TC\Config::get_string()
+ *
+ * @global $wpdb WordPress database object.
+ */
+ public function test_dbcache() {
+ if ( wp_verify_nonce( $_POST['_wpnonce'], 'w3tc_wizard' ) ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput
+ $config = new Config();
+ $results = array(
+ 'enabled' => $config->get_boolean( 'dbcache.enabled' ),
+ 'engine' => $config->get_string( 'dbcache.engine' ),
+ 'elapsed' => null,
+ );
+
+ global $wpdb;
+
+ $wpdb->flush();
+
+ $start_time = microtime( true );
+ $wpdb->timer_start();
+
+ // Test insert, get, and delete 200 records.
+ $table = $wpdb->prefix . 'options';
+ $option = 'w3tc_test_dbcache_';
+
+ // phpcs:disable WordPress.DB.DirectDatabaseQuery
+
+ for ( $x = 0; $x < 200; $x++ ) {
+ $wpdb->insert(
+ $table,
+ array(
+ 'option_name' => $option . $x,
+ 'option_value' => 'blah',
+ )
+ );
+
+ /*
+ * @see https://developer.wordpress.org/reference/classes/wpdb/prepare/
+ * I had to use %1$s as the method does not encapsulate the value with quotes,
+ * which would be a syntax error.
+ */
+ $select = $wpdb->prepare(
+ 'SELECT `option_value` FROM `%1$s` WHERE `option_name` = %s AND `option_name` NOT LIKE %s', // phpcs:ignore WordPress.DB.PreparedSQLPlaceholders.UnquotedComplexPlaceholder
+ $table,
+ $option . $x,
+ 'NotAnOption'
+ );
+
+ $wpdb->get_var( $select ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
+
+ $wpdb->get_var( $select ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
+
+ $wpdb->update(
+ $table,
+ array( 'option_name' => $option . $x ),
+ array( 'option_value' => 'This is a dummy test.' )
+ );
+
+ $wpdb->delete( $table, array( 'option_name' => $option . $x ) );
+ }
+
+ // phpcs:enable WordPress.DB.DirectDatabaseQuery
+
+ $results['wpdb_time'] = $wpdb->timer_stop();
+ $results['exec_time'] = microtime( true ) - $start_time;
+ $results['elapsed'] = $results['wpdb_time'];
+
+ wp_send_json_success( $results );
+ } else {
+ wp_send_json_error( __( 'Security violation', 'w3-total-cache' ), 403 );
+ }
+ }
+
+ /**
+ * Admin-Ajax: Get the database cache settings.
+ *
+ * @since 2.0.0
+ *
+ * @see \W3TC\Config::get_boolean()
+ * @see \W3TC\Config::get_string()
+ */
+ public function get_dbcache_settings() {
+ if ( wp_verify_nonce( $_POST['_wpnonce'], 'w3tc_wizard' ) ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput
+ $config = new Config();
+
+ wp_send_json_success(
+ array(
+ 'enabled' => $config->get_boolean( 'dbcache.enabled' ),
+ 'engine' => $config->get_string( 'dbcache.engine' ),
+ )
+ );
+ } else {
+ wp_send_json_error( __( 'Security violation', 'w3-total-cache' ), 403 );
+ }
+ }
+
+ /**
+ * Admin-Ajax: Configure the database cache settings.
+ *
+ * @since 2.0.0
+ *
+ * @see \W3TC\Config::get_boolean()
+ * @see \W3TC\Config::get_string()
+ * @see \W3TC\Util_Installed::$engine()
+ * @see \W3TC\Config::set()
+ * @see \W3TC\Config::save()
+ * @see \W3TC\Dispatcher::component()
+ * @see \W3TC\CacheFlush::dbcache_flush()
+ */
+ public function config_dbcache() {
+ if ( wp_verify_nonce( $_POST['_wpnonce'], 'w3tc_wizard' ) ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput
+ $enable = ! empty( $_POST['enable'] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput
+ $engine = empty( $_POST['engine'] ) ? '' : esc_attr( trim( $_POST['engine'] ) ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput
+ $is_updating = false;
+ $success = false;
+ $config = new Config();
+ $old_enabled = $config->get_boolean( 'dbcache.enabled' );
+ $old_engine = $config->get_string( 'dbcache.engine' );
+ $allowed_engines = array(
+ '',
+ 'file',
+ 'redis',
+ 'memcached',
+ 'apc',
+ 'eaccelerator',
+ 'xcache',
+ 'wincache',
+ );
+
+ if ( in_array( $engine, $allowed_engines, true ) ) {
+ if ( empty( $engine ) || 'file' === $engine || Util_Installed::$engine() ) {
+ if ( $old_enabled !== $enable ) {
+ $config->set( 'dbcache.enabled', $enable );
+ $is_updating = true;
+ }
+
+ if ( ! empty( $engine ) && $old_engine !== $engine ) {
+ $config->set( 'dbcache.engine', $engine );
+ $is_updating = true;
+ }
+
+ if ( $is_updating ) {
+ $config->save();
+
+ $f = Dispatcher::component( 'CacheFlush' );
+ $f->dbcache_flush();
+ }
+
+ if ( $config->get_boolean( 'dbcache.enabled' ) === $enable &&
+ ( ! $enable || $config->get_string( 'dbcache.engine' ) === $engine ) ) {
+ $success = true;
+ $message = __( 'Settings updated', 'w3-total-cache' );
+ } else {
+ $message = __( 'Settings not updated', 'w3-total-cache' );
+ }
+ } else {
+ $message = __( 'Requested cache storage engine is not available', 'w3-total-cache' );
+ }
+ } elseif ( ! $is_allowed_engine ) {
+ $message = __( 'Requested cache storage engine is invalid', 'w3-total-cache' );
+ }
+
+ wp_send_json_success(
+ array(
+ 'success' => $success,
+ 'message' => $message,
+ 'enable' => $enable,
+ 'engine' => $engine,
+ 'current_enabled' => $config->get_boolean( 'dbcache.enabled' ),
+ 'current_engine' => $config->get_string( 'dbcache.engine' ),
+ 'previous_enabled' => $old_enabled,
+ 'previous_engine' => $old_engine,
+ )
+ );
+ } else {
+ wp_send_json_error( __( 'Security violation', 'w3-total-cache' ), 403 );
+ }
+ }
+
+ /**
+ * Admin-Ajax: Test object cache.
+ *
+ * @since 2.0.0
+ *
+ * @see \W3TC\Config::get_boolean()
+ * @see \W3TC\Config::get_string()
+ */
+ public function test_objcache() {
+ if ( wp_verify_nonce( $_POST['_wpnonce'], 'w3tc_wizard' ) ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput
+ $config = new Config();
+ $results = array(
+ 'enabled' => $config->get_boolean( 'objectcache.enabled' ),
+ 'engine' => $config->get_string( 'objectcache.engine' ),
+ 'elapsed' => null,
+ );
+
+ $start_time = microtime( true );
+
+ $posts = get_posts(
+ array(
+ 'post_type' => array(
+ 'page',
+ 'post',
+ ),
+ )
+ );
+
+ $results['elapsed'] = microtime( true ) - $start_time;
+ $results['post_ct'] = count( $posts );
+
+ wp_send_json_success( $results );
+ } else {
+ wp_send_json_error( __( 'Security violation', 'w3-total-cache' ), 403 );
+ }
+ }
+
+ /**
+ * Admin-Ajax: Get the object cache settings.
+ *
+ * @since 2.0.0
+ *
+ * @see \W3TC\Config::get_boolean()
+ * @see \W3TC\Config::get_string()
+ */
+ public function get_objcache_settings() {
+ if ( wp_verify_nonce( $_POST['_wpnonce'], 'w3tc_wizard' ) ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput
+ $config = new Config();
+
+ wp_send_json_success(
+ array(
+ 'enabled' => $config->get_boolean( 'objectcache.enabled' ),
+ 'engine' => $config->get_string( 'objectcache.engine' ),
+ )
+ );
+ } else {
+ wp_send_json_error( __( 'Security violation', 'w3-total-cache' ), 403 );
+ }
+ }
+
+ /**
+ * Admin-Ajax: Configure the object cache settings.
+ *
+ * @since 2.0.0
+ *
+ * @see \W3TC\Config::get_boolean()
+ * @see \W3TC\Config::get_string()
+ * @see \W3TC\Util_Installed::$engine()
+ * @see \W3TC\Config::set()
+ * @see \W3TC\Config::save()
+ * @see \W3TC\Dispatcher::component()
+ * @see \W3TC\CacheFlush::objcache_flush()
+ */
+ public function config_objcache() {
+ if ( wp_verify_nonce( $_POST['_wpnonce'], 'w3tc_wizard' ) ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput
+ $enable = ! empty( $_POST['enable'] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput
+ $engine = empty( $_POST['engine'] ) ? '' : esc_attr( trim( $_POST['engine'] ) ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput
+ $is_updating = false;
+ $success = false;
+ $config = new Config();
+ $old_enabled = $config->get_boolean( 'objectcache.enabled' );
+ $old_engine = $config->get_string( 'objectcache.engine' );
+ $allowed_engines = array(
+ '',
+ 'file',
+ 'redis',
+ 'memcached',
+ 'apc',
+ 'eaccelerator',
+ 'xcache',
+ 'wincache',
+ );
+
+ if ( in_array( $engine, $allowed_engines, true ) ) {
+ if ( empty( $engine ) || 'file' === $engine || Util_Installed::$engine() ) {
+ if ( $old_enabled !== $enable ) {
+ $config->set( 'objectcache.enabled', $enable );
+ $is_updating = true;
+ }
+
+ if ( ! empty( $engine ) && $old_engine !== $engine ) {
+ $config->set( 'objectcache.engine', $engine );
+ $is_updating = true;
+ }
+
+ if ( $is_updating ) {
+ $config->save();
+
+ $f = Dispatcher::component( 'CacheFlush' );
+ $f->objectcache_flush();
+ }
+
+ if ( $config->get_boolean( 'objectcache.enabled' ) === $enable &&
+ ( ! $enable || $config->get_string( 'objectcache.engine' ) === $engine ) ) {
+ $success = true;
+ $message = __( 'Settings updated', 'w3-total-cache' );
+ } else {
+ $message = __( 'Settings not updated', 'w3-total-cache' );
+ }
+ } else {
+ $message = __( 'Requested cache storage engine is not available', 'w3-total-cache' );
+ }
+ } elseif ( ! $is_allowed_engine ) {
+ $message = __( 'Requested cache storage engine is invalid', 'w3-total-cache' );
+ }
+
+ wp_send_json_success(
+ array(
+ 'success' => $success,
+ 'message' => $message,
+ 'enable' => $enable,
+ 'engine' => $engine,
+ 'current_enabled' => $config->get_boolean( 'objectcache.enabled' ),
+ 'current_engine' => $config->get_string( 'objectcache.engine' ),
+ 'previous_enabled' => $old_enabled,
+ 'previous_engine' => $old_engine,
+ )
+ );
+ } else {
+ wp_send_json_error( __( 'Security violation', 'w3-total-cache' ), 403 );
+ }
+ }
+
+ /**
+ * Admin-Ajax: Test URL addreses for Browser Cache header.
+ *
+ * @since 2.0.0
+ *
+ * @see \W3TC\CacheFlush::browsercache_flush()
+ * @see \W3TC\Util_Http::get_headers()
+ */
+ public function test_browsercache() {
+ if ( wp_verify_nonce( $_POST['_wpnonce'], 'w3tc_wizard' ) ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput
+ $results = array();
+ $urls = array(
+ trailingslashit( site_url() ),
+ esc_url( plugin_dir_url( __FILE__ ) . 'pub/css/setup-guide.css' ),
+ esc_url( plugin_dir_url( __FILE__ ) . 'pub/js/setup-guide.js' ),
+ );
+
+ $f = Dispatcher::component( 'CacheFlush' );
+ $f->browsercache_flush();
+
+ $header_missing = esc_html__( 'Not present', 'w3-total-cache' );
+
+ foreach ( $urls as $url ) {
+ $headers = Util_Http::get_headers( $url );
+
+ $results[] = array(
+ 'url' => $url,
+ 'filename' => basename( $url ),
+ 'header' => empty( $headers['cache-control'] ) ? $header_missing : $headers['cache-control'],
+ 'headers' => empty( $headers ) || ! is_array( $headers ) ? array() : $headers,
+ );
+ }
+
+ wp_send_json_success( $results );
+ } else {
+ wp_send_json_error( __( 'Security violation', 'w3-total-cache' ), 403 );
+ }
+ }
+
+ /**
+ * Admin-Ajax: Get the browser cache settings.
+ *
+ * @since 2.0.0
+ *
+ * @see \W3TC\Config::get_boolean()
+ * @see \W3TC\Config::get_string()
+ */
+ public function get_browsercache_settings() {
+ if ( wp_verify_nonce( $_POST['_wpnonce'], 'w3tc_wizard' ) ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput
+ $config = new Config();
+
+ wp_send_json_success(
+ array(
+ 'enabled' => $config->get_boolean( 'browsercache.enabled' ),
+ 'cssjs.cache.control' => $config->get_boolean( 'browsercache.cssjs.cache.control' ),
+ 'cssjs.cache.policy' => $config->get_string( 'browsercache.cssjs.cache.policy' ),
+ 'html.cache.control' => $config->get_boolean( 'browsercache.html.cache.control' ),
+ 'html.cache.policy' => $config->get_string( 'browsercache.html.cache.policy' ),
+ 'other.cache.control' => $config->get_boolean( 'browsercache.other.cache.control' ),
+ 'other.cache.policy' => $config->get_string( 'browsercache.other.cache.policy' ),
+ )
+ );
+ } else {
+ wp_send_json_error( __( 'Security violation', 'w3-total-cache' ), 403 );
+ }
+ }
+
+ /**
+ * Admin-Ajax: Configure the browser cache settings.
+ *
+ * @since 2.0.0
+ *
+ * @see \W3TC\Dispatcher::component()
+ * @see \W3TC\Config::get_boolean()
+ * @see \W3TC\Config::set()
+ * @see \W3TC\Config::save()
+ * @see \W3TC\CacheFlush::browsercache_flush()
+ * @see \W3TC\BrowserCache_Environment::fix_on_wpadmin_request()
+ *
+ * @uses $_POST['enable']
+ */
+ public function config_browsercache() {
+ if ( wp_verify_nonce( $_POST['_wpnonce'], 'w3tc_wizard' ) ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput
+ $enable = ! empty( $_POST['enable'] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput
+ $config = new Config();
+ $browsercache_enabled = $config->get_boolean( 'browsercache.enabled' );
+
+ if ( $browsercache_enabled !== $enable ) {
+ $config->set( 'browsercache.enabled', $enable );
+ $config->set( 'browsercache.cssjs.cache.control', true );
+ $config->set( 'browsercache.cssjs.cache.policy', 'cache_public_maxage' );
+ $config->set( 'browsercache.html.cache.control', true );
+ $config->set( 'browsercache.html.cache.policy', 'cache_public_maxage' );
+ $config->set( 'browsercache.other.cache.control', true );
+ $config->set( 'browsercache.other.cache.policy', 'cache_public_maxage' );
+ $config->save();
+
+ $f = Dispatcher::component( 'CacheFlush' );
+ $f->browsercache_flush();
+
+ $e = Dispatcher::component( 'BrowserCache_Environment' );
+ $e->fix_on_wpadmin_request( $config, true );
+ }
+
+ $is_enabled = $config->get_boolean( 'browsercache.enabled' );
+
+ wp_send_json_success(
+ array(
+ 'success' => $is_enabled === $enable,
+ 'enable' => $enable,
+ 'browsercache_enabled' => $config->get_boolean( 'browsercache.enabled' ),
+ 'browsercache_previous' => $browsercache_enabled,
+ )
+ );
+ } else {
+ wp_send_json_error( __( 'Security violation', 'w3-total-cache' ), 403 );
+ }
+ }
+
+ /**
+ * Admin-Ajax: Get the lazy load settings.
+ *
+ * @since 2.0.0
+ *
+ * @see \W3TC\Config::get_boolean()
+ * @see \W3TC\Config::get_string()
+ * @see \W3TC\Config::get_array()
+ */
+ public function get_lazyload_settings() {
+ if ( wp_verify_nonce( $_POST['_wpnonce'], 'w3tc_wizard' ) ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput
+ $config = new Config();
+
+ wp_send_json_success(
+ array(
+ 'enabled' => $config->get_boolean( 'lazyload.enabled' ),
+ 'process_img' => $config->get_boolean( 'lazyload.process_img' ),
+ 'process_background' => $config->get_boolean( 'lazyload_process_background' ),
+ 'exclude' => $config->get_array( 'lazyload.exclude' ),
+ 'embed_method' => $config->get_string( 'lazyload.embed_method' ),
+ )
+ );
+ } else {
+ wp_send_json_error( __( 'Security violation', 'w3-total-cache' ), 403 );
+ }
+ }
+
+ /**
+ * Admin-Ajax: Configure lazy load.
+ *
+ * @since 2.0.0
+ *
+ * @see \W3TC\Dispatcher::component()
+ * @see \W3TC\Config::get_boolean()
+ * @see \W3TC\Config::set()
+ * @see \W3TC\Config::save()
+ * @see \W3TC\Dispatcher::component()
+ * @see \W3TC\CacheFlush::flush_posts()
+ *
+ * @uses $_POST['enable']
+ */
+ public function config_lazyload() {
+ if ( wp_verify_nonce( $_POST['_wpnonce'], 'w3tc_wizard' ) ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput
+ $enable = ! empty( $_POST['enable'] );
+ $config = new Config();
+ $lazyload_enabled = $config->get_boolean( 'lazyload.enabled' );
+
+ if ( $lazyload_enabled !== $enable ) {
+ $config->set( 'lazyload.enabled', $enable );
+ $config->set( 'lazyload.process_img', true );
+ $config->set( 'lazyload_process_background', true );
+ $config->set( 'lazyload.embed_method', 'async_head' );
+ $config->save();
+
+ $f = Dispatcher::component( 'CacheFlush' );
+ $f->flush_posts();
+
+ $e = Dispatcher::component( 'PgCache_Environment' );
+ $e->fix_on_wpadmin_request( $config, true );
+ }
+
+ $is_enabled = $config->get_boolean( 'lazyload.enabled' );
+
+ wp_send_json_success(
+ array(
+ 'success' => $is_enabled === $enable,
+ 'enable' => $enable,
+ 'lazyload_enabled' => $config->get_boolean( 'lazyload.enabled' ),
+ 'lazyload_previous' => $lazyload_enabled,
+ )
+ );
+ } else {
+ wp_send_json_error( __( 'Security violation', 'w3-total-cache' ), 403 );
+ }
+ }
+
+ /**
+ * Get the terms of service choice.
+ *
+ * @since 2.0.0
+ *
+ * @see \W3TC\Util_Environment::is_w3tc_pro()
+ * @see \W3TC\Dispatcher::config_state()
+ * @see \W3TC\Dispatcher::config_state_master()
+ * @see \W3TC\ConfigState::get_string()
+ *
+ * @return string
+ */
+ private function get_tos_choice() {
+ $config = new Config();
+
+ if ( Util_Environment::is_w3tc_pro( $config ) ) {
+ $state = Dispatcher::config_state();
+ $terms = $state->get_string( 'license.terms' );
+ } else {
+ $state_master = Dispatcher::config_state_master();
+ $terms = $state_master->get_string( 'license.community_terms' );
+ }
+
+ return $terms;
+ }
+
+ /**
+ * Display the terms of service dialog if needed.
+ *
+ * @since 2.0.0
+ * @access private
+ *
+ * @see self::get_tos_choice()
+ *
+ * @return bool
+ */
+ private function maybe_ask_tos() {
+ if ( defined( 'W3TC_PRO' ) ) {
+ return false;
+ }
+
+ $terms = $this->get_tos_choice();
+
+ return 'accept' !== $terms && 'decline' !== $terms && 'postpone' !== $terms;
+ }
+
+ /**
+ * Get configuration.
+ *
+ * @since 2.0.0
+ * @access private
+ *
+ * @global $wp_version WordPress version string.
+ * @global $wpdb WordPress database connection.
+ *
+ * @see \W3TC\Config::get_boolean()
+ * @see \W3TC\Util_Request::get_string()
+ * @see \W3TC\Dispatcher::config_state()
+ * @see \W3TC\Util_Environment::home_url_host()
+ * @see \W3TC\Util_Environment::w3tc_edition()
+ * @see \W3TC\Util_Widget::list_widgets()
+ *
+ * @return array
+ */
+ private function get_config() {
+ global $wp_version, $wpdb;
+
+ $config = new Config();
+ $browsercache_enabled = $config->get_boolean( 'browsercache.enabled' );
+ $page = Util_Request::get_string( 'page' );
+ $state = Dispatcher::config_state();
+ $force_master_config = $config->get_boolean( 'common.force_master' );
+
+ if ( 'w3tc_extensions' === $page ) {
+ $page = 'extensions/' . Util_Request::get_string( 'extension' );
+ }
+
+ return array(
+ 'title' => esc_html__( 'Setup Guide', 'w3-total-cache' ),
+ 'scripts' => array(
+ array(
+ 'handle' => 'setup-guide',
+ 'src' => esc_url( plugin_dir_url( __FILE__ ) . 'pub/js/setup-guide.js' ),
+ 'deps' => array( 'jquery' ),
+ 'version' => W3TC_VERSION,
+ 'in_footer' => false,
+ 'localize' => array(
+ 'object_name' => 'W3TC_SetupGuide',
+ 'data' => array(
+ 'page' => $page,
+ 'wp_version' => $wp_version,
+ 'php_version' => phpversion(),
+ 'w3tc_version' => W3TC_VERSION,
+ 'server_software' => isset( $_SERVER['SERVER_SOFTWARE'] ) ?
+ sanitize_text_field( wp_unslash( $_SERVER['SERVER_SOFTWARE'] ) ) : null,
+ 'db_version' => $wpdb->db_version(),
+ 'home_url_host' => Util_Environment::home_url_host(),
+ 'install_version' => esc_attr( $state->get_string( 'common.install_version' ) ),
+ 'w3tc_edition' => esc_attr( Util_Environment::w3tc_edition( $config ) ),
+ 'list_widgets' => esc_attr( Util_Widget::list_widgets() ),
+ 'ga_profile' => ( defined( 'W3TC_DEBUG' ) && W3TC_DEBUG ) ? 'UA-2264433-7' : 'UA-2264433-8',
+ 'tos_choice' => $this->get_tos_choice(),
+ 'track_usage' => $config->get_boolean( 'common.track_usage' ),
+ 'test_complete_msg' => __(
+ 'Testing complete. Click Next to advance to the section and see the results.',
+ 'w3-total-cache'
+ ),
+ 'test_error_msg' => __(
+ 'Could not perform this test. Please reload the page to try again or click skip button to abort the setup guide.',
+ 'w3-total-cache'
+ ),
+ 'config_error_msg' => __(
+ 'Could not update configuration. Please reload the page to try again or click skip button to abort the setup guide.',
+ 'w3-total-cache'
+ ),
+ 'unavailable_text' => __( 'Unavailable', 'w3-total-cache' ),
+ 'none' => __( 'None', 'w3-total-cache' ),
+ 'disk' => __( 'Disk', 'w3-total-cache' ),
+ 'disk_basic' => __( 'Disk: Basic', 'w3-total-cache' ),
+ 'disk_enhanced' => __( 'Disk: Enhanced', 'w3-total-cache' ),
+ 'enabled' => __( 'Enabled', 'w3-total-cache' ),
+ 'notEnabled' => __( 'Not Enabled', 'w3-total-cache' ),
+ 'dashboardUrl' => esc_url( Util_Ui::admin_url( 'admin.php?page=w3tc_dashboard' ) ),
+ ),
+ ),
+ ),
+ ),
+ 'styles' => array(
+ array(
+ 'handle' => 'setup-guide',
+ 'src' => esc_url( plugin_dir_url( __FILE__ ) . 'pub/css/setup-guide.css' ),
+ 'version' => W3TC_VERSION,
+ ),
+ ),
+ 'actions' => array(
+ array(
+ 'tag' => 'wp_ajax_w3tc_wizard_skip',
+ 'function' => array(
+ $this,
+ 'skip',
+ ),
+ ),
+ array(
+ 'tag' => 'wp_ajax_w3tc_tos_choice',
+ 'function' => array(
+ $this,
+ 'set_tos_choice',
+ ),
+ ),
+ array(
+ 'tag' => 'wp_ajax_w3tc_get_pgcache_settings',
+ 'function' => array(
+ $this,
+ 'get_pgcache_settings',
+ ),
+ ),
+ array(
+ 'tag' => 'wp_ajax_w3tc_test_pgcache',
+ 'function' => array(
+ $this,
+ 'test_pgcache',
+ ),
+ ),
+ array(
+ 'tag' => 'wp_ajax_w3tc_config_pgcache',
+ 'function' => array(
+ $this,
+ 'config_pgcache',
+ ),
+ ),
+ array(
+ 'tag' => 'wp_ajax_w3tc_get_dbcache_settings',
+ 'function' => array(
+ $this,
+ 'get_dbcache_settings',
+ ),
+ ),
+ array(
+ 'tag' => 'wp_ajax_w3tc_test_dbcache',
+ 'function' => array(
+ $this,
+ 'test_dbcache',
+ ),
+ ),
+ array(
+ 'tag' => 'wp_ajax_w3tc_config_dbcache',
+ 'function' => array(
+ $this,
+ 'config_dbcache',
+ ),
+ ),
+ array(
+ 'tag' => 'wp_ajax_w3tc_get_objcache_settings',
+ 'function' => array(
+ $this,
+ 'get_objcache_settings',
+ ),
+ ),
+ array(
+ 'tag' => 'wp_ajax_w3tc_test_objcache',
+ 'function' => array(
+ $this,
+ 'test_objcache',
+ ),
+ ),
+ array(
+ 'tag' => 'wp_ajax_w3tc_config_objcache',
+ 'function' => array(
+ $this,
+ 'config_objcache',
+ ),
+ ),
+ array(
+ 'tag' => 'wp_ajax_w3tc_get_browsercache_settings',
+ 'function' => array(
+ $this,
+ 'get_browsercache_settings',
+ ),
+ ),
+ array(
+ 'tag' => 'wp_ajax_w3tc_test_browsercache',
+ 'function' => array(
+ $this,
+ 'test_browsercache',
+ ),
+ ),
+ array(
+ 'tag' => 'wp_ajax_w3tc_config_browsercache',
+ 'function' => array(
+ $this,
+ 'config_browsercache',
+ ),
+ ),
+ array(
+ 'tag' => 'wp_ajax_w3tc_get_lazyload_settings',
+ 'function' => array(
+ $this,
+ 'get_lazyload_settings',
+ ),
+ ),
+ array(
+ 'tag' => 'wp_ajax_w3tc_config_lazyload',
+ 'function' => array(
+ $this,
+ 'config_lazyload',
+ ),
+ ),
+ ),
+ 'steps_location' => 'left',
+ 'steps' => array(
+ array(
+ 'id' => 'welcome',
+ 'text' => __( 'Welcome', 'w3-total-cache' ),
+ ),
+ array(
+ 'id' => 'pgcache',
+ 'text' => __( 'Page Cache', 'w3-total-cache' ),
+ ),
+ array(
+ 'id' => 'dbcache',
+ 'text' => __( 'Database Cache', 'w3-total-cache' ),
+ ),
+ array(
+ 'id' => 'objectcache',
+ 'text' => __( 'Object Cache', 'w3-total-cache' ),
+ ),
+ array(
+ 'id' => 'browsercache',
+ 'text' => __( 'Browser Cache', 'w3-total-cache' ),
+ ),
+ array(
+ 'id' => 'lazyload',
+ 'text' => __( 'Lazy Load', 'w3-total-cache' ),
+ ),
+ array(
+ 'id' => 'more',
+ 'text' => __( 'More Caching Options', 'w3-total-cache' ),
+ ),
+ ),
+ 'slides' => array(
+ array( // Welcome.
+ 'headline' => __( 'Welcome to the W3 Total Cache Setup Guide!', 'w3-total-cache' ),
+ 'id' => 'welcome',
+ 'markup' => 'maybe_ask_tos() ? ' class="hidden"' : '' ) . '>
+ ' .
+ esc_html__(
+ 'You have selected the Performance Suite that professionals have consistently ranked #1 for options and speed improvements.',
+ 'w3-total-cache'
+ ) . '
+ ' . esc_html__( 'W3 Total Cache', 'w3-total-cache' ) . '
+ ' . esc_html__(
+ 'provides many options to help your website perform faster. While the ideal settings vary for every website, there are a few settings we recommend that you enable now.',
+ 'w3-total-cache'
+ ) . '
+ ' .
+ sprintf(
+ // translators: 1: Anchor/link open tag, 2: Anchor/link close tag.
+ esc_html__(
+ 'If you prefer to configure the settings on your own, you can %1$sskip this setup guide%2$s.',
+ 'w3-total-cache'
+ ),
+ ' ',
+ ''
+ ) . '
+ ' . ( $this->maybe_ask_tos() ?
+ '' : '' ),
+ ),
+ array( // Page Cache.
+ 'headline' => __( 'Page Cache', 'w3-total-cache' ),
+ 'id' => 'pc1',
+ 'markup' => '' . sprintf(
+ // translators: 1: HTML emphesis open tag, 2: HTML emphesis close tag.
+ esc_html__(
+ 'The time it takes between a visitor\'s browser page request and receiving the first byte of a response is referred to as %1$sTime to First Byte%2$s.',
+ 'w3-total-cache'
+ ),
+ '',
+ ''
+ ) . '
+
+ ' . esc_html__( 'W3 Total Cache', 'w3-total-cache' ) . ' ' .
+ esc_html__( 'can help you speed up', 'w3-total-cache' ) .
+ ' ' . esc_html__( 'Time to First Byte', 'w3-total-cache' ) . ' by using Page Cache.
+
+ ' .
+ esc_html__(
+ 'We\'ll test your homepage with Page Cache disabled and then with several storage engines. You should review the test results and choose the best for your website.',
+ 'w3-total-cache'
+ ) . '
+
+
+ ' . esc_html__( 'Measuring', 'w3-total-cache' ) .
+ ' ' . esc_html__( 'Time to First Byte', 'w3-total-cache' ) . '…
+
+
+
+ ' . esc_html__( 'Test URL:', 'w3-total-cache' ) . '
+
+
+
+
+ ' . esc_html__( 'Select', 'w3-total-cache' ) . ' |
+ ' . esc_html__( 'Storage Engine', 'w3-total-cache' ) . ' |
+ ' . esc_html__( 'Time (ms)', 'w3-total-cache' ) . ' |
+
+
+
+ ',
+ ),
+ array( // Database Cache.
+ 'headline' => __( 'Database Cache', 'w3-total-cache' ),
+ 'id' => 'dbc1',
+ 'markup' => '' .
+ esc_html__(
+ 'Many database queries are made in every dynamic page request. A database cache may speed up the generation of dynamic pages. Database Cache serves query results directly from a storage engine.',
+ 'w3-total-cache'
+ ) . '
+
+
+ ' . esc_html__( 'Testing', 'w3-total-cache' ) .
+ ' ' . esc_html__( 'Database Cache', 'w3-total-cache' ) . '…
+
+
+
+
+
+ ' . esc_html__( 'Select', 'w3-total-cache' ) . ' |
+ ' . esc_html__( 'Storage Engine', 'w3-total-cache' ) . ' |
+ ' . esc_html__( 'Time (ms)', 'w3-total-cache' ) . ' |
+
+
+
+
+
+ Recommended
+ ' .
+ esc_html__(
+ 'By default, this feature is disabled. We recommend using Redis or Memcached, otherwise leave this feature disabled as the server database engine may be faster than using disk caching.',
+ 'w3-total-cache'
+ ) . '
+ ',
+ ),
+ array( // Object Cache.
+ 'headline' => __( 'Object Cache', 'w3-total-cache' ),
+ 'id' => 'oc1',
+ 'markup' => '' .
+ esc_html__(
+ 'WordPress caches objects used to build pages, but does not reuse them for future page requests.',
+ 'w3-total-cache'
+ ) . '
+ ' . esc_html__( 'W3 Total Cache', 'w3-total-cache' ) . ' ' .
+ esc_html__( 'can help you speed up dynamic pages by persistently storing objects.', 'w3-total-cache' ) .
+ '
+
+
+ ' . esc_html__( 'Testing', 'w3-total-cache' ) .
+ ' ' . esc_html__( 'Object Cache', 'w3-total-cache' ) . '…
+
+
+
+
+
+ ' . esc_html__( 'Select', 'w3-total-cache' ) . ' |
+ ' . esc_html__( 'Storage Engine', 'w3-total-cache' ) . ' |
+ ' . esc_html__( 'Time (ms)', 'w3-total-cache' ) . ' |
+
+
+
+ ',
+ ),
+ array( // Browser Cache.
+ 'headline' => __( 'Browser Cache', 'w3-total-cache' ),
+ 'id' => 'bc1',
+ 'markup' => '' .
+ esc_html__(
+ 'To render your website, browsers must download many different types of assets, including javascript files, CSS stylesheets, images, and more. For most assets, once a browser has downloaded them, they shouldn\'t have to download them again.',
+ 'w3-total-cache'
+ ) . '
+ ' . esc_html__( 'W3 Total Cache', 'w3-total-cache' ) . ' ' .
+ esc_html__(
+ 'can help ensure browsers are properly caching your assets.',
+ 'w3-total-cache'
+ ) . '
+ ' . sprintf(
+ // translators: 1: HTML emphesis open tag, 2: HTML emphesis close tag.
+ esc_html__(
+ 'The %1$sCache-Control%2$s header tells your browser how it should cache specific files. The %1$smax-age%2$s setting tells your browser how long, in seconds, it should use its cached version of a file before requesting an updated one.',
+ 'w3-total-cache'
+ ),
+ '',
+ ''
+ ) . '
+ ' . sprintf(
+ // translators: 1: HTML emphesis open tag, 2: HTML emphesis close tag.
+ esc_html__(
+ 'To improve %1$sBrowser Cache%2$s, we recommend enabling %1$sBrowser Cache%2$s.',
+ 'w3-total-cache'
+ ),
+ '',
+ ''
+ ) . '
+
+ ' . esc_html__( 'Testing', 'w3-total-cache' ) .
+ ' ' . esc_html__( 'Browser Cache', 'w3-total-cache' ) . '…
+
+
+
+
+
+ ' . esc_html__( 'Setting', 'w3-total-cache' ) . ' |
+ ' . esc_html__( 'File', 'w3-total-cache' ) . ' |
+ ' . esc_html__( 'Cache-Control Header', 'w3-total-cache' ) . ' |
+
+
+
+ ',
+ ),
+ array( // Lazy load.
+ 'headline' => __( 'Lazy Load', 'w3-total-cache' ),
+ 'id' => 'll1',
+ 'markup' => '' .
+ esc_html__(
+ 'Pages containing images and other objects can have their load time reduced by deferring them until they are needed. For example, images can be loaded when a visitor scrolls down the page to make them visible.',
+ 'w3-total-cache'
+ ) . '
+
+ ',
+ ),
+ array( // Setup complete.
+ 'headline' => __( 'Setup Complete!', 'w3-total-cache' ),
+ 'id' => 'complete',
+ 'markup' => '' .
+ sprintf(
+ // translators: 1: HTML strong open tag, 2: HTML strong close tag, 3: Label.
+ esc_html__(
+ '%1$sPage Cache%2$s engine set to %1$s%3$s%2$s',
+ 'w3-total-cache'
+ ),
+ '',
+ '',
+ '' . esc_html__( 'UNKNOWN', 'w3-total-cache' ) . ''
+ ) . '
+ ' .
+ sprintf(
+ // translators: 1: HTML strong open tag, 2: HTML strong close tag.
+ esc_html__(
+ '%1$sTime to First Byte%2$s has changed by %1$s%3$s%2$s',
+ 'w3-total-cache'
+ ),
+ '',
+ '',
+ '0%'
+ ) . '
+ ' .
+ sprintf(
+ // translators: 1: HTML strong open tag, 2: HTML strong close tag, 3: Label.
+ esc_html__(
+ '%1$sDatabase Cache%2$s engine set to %1$s%3$s%2$s',
+ 'w3-total-cache'
+ ),
+ '',
+ '',
+ '' . esc_html__( 'UNKNOWN', 'w3-total-cache' ) . ''
+ ) . '
+ ' .
+ sprintf(
+ // translators: 1: HTML strong open tag, 2: HTML strong close tag, 3: Label.
+ esc_html__(
+ '%1$sObject Cache%2$s engine set to %1$s%3$s%2$s',
+ 'w3-total-cache'
+ ),
+ '',
+ '',
+ '' . esc_html__( 'UNKNOWN', 'w3-total-cache' ) . ''
+ ) . '
+ ' .
+ sprintf(
+ // translators: 1: HTML strong open tag, 2: HTML strong close tag, 3: Label.
+ esc_html__(
+ '%1$sBrowser Cache%2$s headers set for JavaScript, CSS, and images? %1$s%3$s%2$s',
+ 'w3-total-cache'
+ ),
+ '',
+ '',
+ '' . esc_html__( 'UNKNOWN', 'w3-total-cache' ) . ''
+ ) . '
+ ' . sprintf(
+ // translators: 1: HTML strong open tag, 2: HTML strong close tag, 3: Label.
+ esc_html__(
+ '%1$sLazy Load%2$s images? %1$s%3$s%2$s',
+ 'w3-total-cache'
+ ),
+ '',
+ '',
+ '' . esc_html__( 'UNKNOWN', 'w3-total-cache' ) . ''
+ ) . '
+ ' . esc_html__( 'What\'s Next?', 'w3-total-cache' ) . '
+ ' .
+ sprintf(
+ // translators: 1: HTML emphesis open tag, 2: HTML emphesis close tag.
+ esc_html__(
+ 'Your website\'s performance can still be improved by configuring %1$sminify%2$s settings, setting up a %1$sCDN%2$s, and more!',
+ 'w3-total-cache'
+ ),
+ '',
+ ''
+ ) . '
+ ' .
+ sprintf(
+ // translators: 1: Anchor/link open tag, 2: Anchor/link close tag.
+ esc_html__(
+ 'Please visit %1$sGeneral Settings%2$s to learn more about these features.',
+ 'w3-total-cache'
+ ),
+ '',
+ ''
+ ) . '
+ ' . esc_html__( 'Need help?', 'w3-total-cache' ) . '
+ ' .
+ sprintf(
+ // translators: 1: Anchor/link open tag, 2: Anchor/link close tag.
+ esc_html__(
+ 'We\'re here to help you! Visit our %1$sSupport Center%2$s for helpful information and to ask questions.',
+ 'w3-total-cache'
+ ),
+ '',
+ ''
+ ) . ' ',
+ ),
+ ),
+ );
+ }
+}
diff --git a/wp-content/plugins/w3-total-cache/Support_AdminActions.php b/wp-content/plugins/w3-total-cache/Support_AdminActions.php
new file mode 100644
index 0000000000..2bf097a395
--- /dev/null
+++ b/wp-content/plugins/w3-total-cache/Support_AdminActions.php
@@ -0,0 +1,200 @@
+ $v )
+ $post[$p] = $v;
+
+ $post['user_agent'] = $_SERVER['HTTP_USER_AGENT'];
+ $post['version'] = W3TC_VERSION;
+
+ $license_level = 'community';
+ if ( Util_Environment::is_w3tc_pro( $c ) )
+ $license_level = 'pro';
+
+ $post['license_level'] = $license_level . ' ' .
+ $c->get_string( 'plugin.license_key' );
+
+
+ /**
+ * Add attachments
+ */
+ $attachments = array();
+
+ $attach_files = array(
+ /**
+ * Attach WP config file
+ */
+ Util_Environment::wp_config_path(),
+
+ /**
+ * Attach .htaccess files
+ */
+ Util_Rule::get_pgcache_rules_core_path(),
+ Util_Rule::get_pgcache_rules_cache_path(),
+ Util_Rule::get_browsercache_rules_cache_path(),
+ Util_Rule::get_browsercache_rules_no404wp_path(),
+ Util_Rule::get_minify_rules_core_path(),
+ Util_Rule::get_minify_rules_cache_path()
+ );
+
+ /**
+ * Attach config files
+ */
+ if ( $handle = opendir( W3TC_CONFIG_DIR ) ) {
+ while ( ( $entry = @readdir( $handle ) ) !== false ) {
+ if ( $entry == '.' || $entry == '..' || $entry == 'index.html' )
+ continue;
+
+ $attach_file[] = W3TC_CONFIG_DIR . '/' . $entry;
+ }
+ closedir( $handle );
+ }
+
+
+ foreach ( $attach_files as $attach_file ) {
+ if ( $attach_file && file_exists( $attach_file ) &&
+ !in_array( $attach_file, $attachments ) ) {
+ $attachments[] = array(
+ 'filename' => basename( $attach_file ),
+ 'content' => file_get_contents( $attach_file )
+ );
+ }
+ }
+
+ /**
+ * Attach server info
+ */
+ $server_info = print_r( $this->get_server_info(), true );
+ $server_info = str_replace( "\n", "\r\n", $server_info );
+
+ $attachments[] = array(
+ 'filename' => 'server_info.txt',
+ 'content' => $server_info
+ );
+
+ /**
+ * Attach phpinfo
+ */
+ ob_start();
+ phpinfo();
+ $php_info = ob_get_contents();
+ ob_end_clean();
+
+ $attachments[] = array(
+ 'filename' => 'php_info.html',
+ 'content' => $php_info
+ );
+
+ /**
+ * Attach self-test
+ */
+ ob_start();
+ $this->self_test();
+ $self_test = ob_get_contents();
+ ob_end_clean();
+
+ $attachments[] = array(
+ 'filename' => 'self_test.html',
+ 'content' => $self_test
+ );
+
+ $post['attachments'] = $attachments;
+
+ $response = wp_remote_post( W3TC_SUPPORT_REQUEST_URL, array(
+ 'body' => $post,
+ 'timeout' => $c->get_integer( 'timelimit.email_send' )
+ ) );
+
+ if ( !is_wp_error( $response ) )
+ $result = $response['response']['code'] == 200 && $response['body'] == 'ok';
+ else {
+ $result = false;
+ }
+
+ echo $result ? 'ok' : 'error';
+ }
+
+ /**
+ * Self test action
+ */
+ private function self_test() {
+ include W3TC_INC_DIR . '/lightbox/self_test.php';
+ }
+
+ /**
+ * Returns server info
+ *
+ * @return array
+ */
+ private function get_server_info() {
+ global $wp_version, $wp_db_version, $wpdb;
+
+ $wordpress_plugins = get_plugins();
+ $wordpress_plugins_active = array();
+
+ foreach ( $wordpress_plugins as $wordpress_plugin_file => $wordpress_plugin ) {
+ if ( is_plugin_active( $wordpress_plugin_file ) ) {
+ $wordpress_plugins_active[$wordpress_plugin_file] = $wordpress_plugin;
+ }
+ }
+
+ $mysql_version = $wpdb->get_var( 'SELECT VERSION()' );
+ $mysql_variables_result = (array) $wpdb->get_results( 'SHOW VARIABLES', ARRAY_N );
+ $mysql_variables = array();
+
+ foreach ( $mysql_variables_result as $mysql_variables_row ) {
+ $mysql_variables[$mysql_variables_row[0]] = $mysql_variables_row[1];
+ }
+
+ $server_info = array(
+ 'w3tc' => array(
+ 'version' => W3TC_VERSION,
+ 'server' => ( !empty( $_SERVER['SERVER_SOFTWARE'] ) ? $_SERVER['SERVER_SOFTWARE'] : 'Unknown' ),
+ 'dir' => W3TC_DIR,
+ 'cache_dir' => W3TC_CACHE_DIR,
+ 'blog_id' => Util_Environment::blog_id(),
+ 'home_domain_root_url' => Util_Environment::home_domain_root_url(),
+ 'home_url_maybe_https' => Util_Environment::home_url_maybe_https(),
+ 'site_path' => Util_Environment::site_path(),
+ 'document_root' => Util_Environment::document_root(),
+ 'site_root' => Util_Environment::site_root(),
+ 'site_url_uri' => Util_Environment::site_url_uri(),
+ 'home_url_host' => Util_Environment::home_url_host(),
+ 'home_url_uri' => Util_Environment::home_url_uri(),
+ 'network_home_url_uri' => Util_Environment::network_home_url_uri(),
+ 'host_port' => Util_Environment::host_port(),
+ 'host' => Util_Environment::host(),
+ 'wp_config_path' => Util_Environment::wp_config_path()
+ ),
+ 'wp' => array(
+ 'version' => $wp_version,
+ 'db_version' => $wp_db_version,
+ 'abspath' => ABSPATH,
+ 'home' => get_option( 'home' ),
+ 'siteurl' => get_option( 'siteurl' ),
+ 'email' => get_option( 'admin_email' ),
+ 'upload_info' => (array) Util_Http::upload_info(),
+ 'theme' => Util_Theme::get_current_theme(),
+ 'wp_cache' => ( ( defined( 'WP_CACHE' ) && WP_CACHE ) ? 'true' : 'false' ),
+ 'plugins' => $wordpress_plugins_active
+ ),
+ 'mysql' => array(
+ 'version' => $mysql_version,
+ 'variables' => $mysql_variables
+ )
+ );
+
+ return $server_info;
+ }
+}
diff --git a/wp-content/plugins/w3-total-cache/Support_Page.php b/wp-content/plugins/w3-total-cache/Support_Page.php
new file mode 100644
index 0000000000..3982811abe
--- /dev/null
+++ b/wp-content/plugins/w3-total-cache/Support_Page.php
@@ -0,0 +1,78 @@
+ $url,
+ 'email' => get_bloginfo( 'admin_email' ),
+ 'first_name' => $u->first_name,
+ 'last_name' => $u->last_name,
+ 'form_hash' => $w3tc_support_form_hash,
+ 'field_name' => $w3tc_support_field_name,
+ 'field_value' => $w3tc_support_field_value,
+ 'postprocess' => urlencode( urlencode(
+ Util_Ui::admin_url(
+ wp_nonce_url( 'admin.php', 'w3tc' ) . '&page=w3tc_support&done'
+ ) ) )
+ )
+ );
+ }
+ /**
+ * Support tab
+ *
+ * @return void
+ */
+ function options() {
+ if ( isset( $_GET['done'] ) ) {
+ $postprocess_url =
+ 'admin.php?page=w3tc_support&w3tc_support_send_details' .
+ '&_wpnonce=' . urlencode( $_GET['_wpnonce'] );
+ foreach ( $_GET as $p => $v ) {
+ if ( $p != 'page' && $p != '_wpnonce' && $p != 'done' )
+ $postprocess_url .= '&' . urlencode( $p ) . '=' . urlencode( $v );
+ }
+
+ // terms accepted as a part of form
+ Licensing_Core::terms_accept();
+
+ include W3TC_DIR . '/Support_Page_View_DoneContent.php';
+ } else
+ include W3TC_DIR . '/Support_Page_View_PageContent.php';
+ }
+}
diff --git a/wp-content/plugins/w3-total-cache/Support_Page_View_DoneContent.php b/wp-content/plugins/w3-total-cache/Support_Page_View_DoneContent.php
new file mode 100644
index 0000000000..4f00ba8fe2
--- /dev/null
+++ b/wp-content/plugins/w3-total-cache/Support_Page_View_DoneContent.php
@@ -0,0 +1,4 @@
+
+ Thank you for filling out the form
+
+
diff --git a/wp-content/plugins/w3-total-cache/Support_Page_View_PageContent.php b/wp-content/plugins/w3-total-cache/Support_Page_View_PageContent.php
new file mode 100644
index 0000000000..dbdec2267a
--- /dev/null
+++ b/wp-content/plugins/w3-total-cache/Support_Page_View_PageContent.php
@@ -0,0 +1,36 @@
+
+
+
+ |