Plugin Directory

Changeset 3723494


Ignore:
Timestamp:
10/01/2026 04:36:35 PM (3 weeks ago)
Author:
boldgrid
Message:

Release 2.10.7, see readme.txt for the changelog.

Location:
w3-total-cache/tags/2.10.7
Files:
2 added
38 edited

Legend:

Unmodified
Added
Removed
  • w3-total-cache/tags/2.10.7/BrowserCache_Plugin.php

    r3585227 r3723494  
    207207                        // without quotes.
    208208                        $buffer = preg_replace_callback(
    209                                 '~(href|src|action|extsrc|asyncsrc)=((' . $domain_url_regexp . ')?(/[^\\s>][^\\s>]*\.([a-z-_]+)([\?#][^\\s>]*)?))([\\s>])~Ui',
     209                                '~(href|src|action|extsrc|asyncsrc)=((' . $domain_url_regexp . ')?(/[^\\s>][^\\s>]*\.([a-z-_]+)([\?#][^\\s>\'"]*)?))([\\s>])~Ui',
    210210                                array( $this, 'link_replace_callback_noquote' ),
    211211                                $buffer
  • w3-total-cache/tags/2.10.7/Cdn_Core.php

    r3680101 r3723494  
    106106
    107107                if ( $upload_info ) {
    108                         $w3tc_file   = $this->normalize_attachment_file( $w3tc_file );
     108                        $w3tc_file = $this->normalize_attachment_file( $w3tc_file );
     109                        if ( '' === $w3tc_file ) {
     110                                return $files;
     111                        }
     112
    109113                        $local_file  = $upload_info['basedir'] . '/' . $w3tc_file;
    110114                        $parsed      = wp_parse_url( rtrim( $upload_info['baseurl'], '/' ) . '/' . $w3tc_file );
    … …  
    351355                $upload_info = Util_Http::upload_info();
    352356
    353                 if ( $upload_info ) {
    354                         $w3tc_file = ltrim( str_replace( $upload_info['basedir'], '', $w3tc_file ), '/\\' );
    355                         $matches   = null;
    356 
    357                         if ( preg_match( '~(\d{4}/\d{2}/)?[^/]+$~', $w3tc_file, $matches ) ) {
    358                                 $w3tc_file = $matches[0];
    359                         }
     357                if ( ! $upload_info ) {
     358                        return '';
     359                }
     360
     361                return $this->normalize_attachment_file_under_basedir( $upload_info['basedir'], $w3tc_file );
     362        }
     363
     364        /**
     365         * Normalize an attachment path against a specific uploads basedir.
     366         *
     367         * @since 2.10.7
     368         *
     369         * @param string $basedir   Upload basedir.
     370         * @param string $w3tc_file Candidate attachment path.
     371         *
     372         * @return string Relative path under basedir, or empty string when rejected.
     373         */
     374        private function normalize_attachment_file_under_basedir( $basedir, $w3tc_file ) {
     375                if ( ! is_string( $basedir ) || '' === $basedir || ! is_string( $w3tc_file ) || '' === $w3tc_file || false !== strpos( $w3tc_file, "\0" ) ) {
     376                        return '';
     377                }
     378
     379                $basedir   = Util_Environment::normalize_path( $basedir );
     380                $w3tc_file = Util_Environment::normalize_path( $w3tc_file );
     381
     382                if ( preg_match( '~^(?:/|[a-zA-Z]:/)~', $w3tc_file ) ) {
     383                        $basedir_prefix = $basedir . '/';
     384
     385                        if ( ! $this->absolute_path_has_prefix( $w3tc_file, $basedir_prefix ) ) {
     386                                return '';
     387                        }
     388
     389                        $w3tc_file = substr( $w3tc_file, strlen( $basedir_prefix ) );
     390                }
     391
     392                if ( '' === $w3tc_file || preg_match( '~(?:^|/)\.{1,2}(?:/|$)~', $w3tc_file ) ) {
     393                        return '';
    360394                }
    361395
    362396                return $w3tc_file;
     397        }
     398
     399        /**
     400         * Whether an absolute path is contained by a basedir prefix.
     401         *
     402         * Drive-letter case is ignored for Windows-style paths; the remainder
     403         * of the path comparison stays case-sensitive.
     404         *
     405         * @since 2.10.7
     406         *
     407         * @param string $path   Normalized absolute path.
     408         * @param string $prefix Normalized basedir prefix ending in `/`.
     409         *
     410         * @return bool
     411         */
     412        private function absolute_path_has_prefix( $path, $prefix ) {
     413                if ( preg_match( '~^[a-zA-Z]:/~', $path ) && preg_match( '~^[a-zA-Z]:/~', $prefix ) ) {
     414                        $path   = \strtoupper( $path[0] ) . \substr( $path, 1 );
     415                        $prefix = \strtoupper( $prefix[0] ) . \substr( $prefix, 1 );
     416                }
     417
     418                return 0 === \strpos( $path, $prefix );
    363419        }
    364420
  • w3-total-cache/tags/2.10.7/Cdn_Core_Admin.php

    r3680101 r3723494  
    280280                                                $w3tc_file = $common->normalize_attachment_file( $post->file );
    281281
    282                                                 $local_file  = $upload_info['basedir'] . '/' . $w3tc_file;
    283                                                 $remote_file = ltrim( $upload_info['baseurlpath'] . $w3tc_file, '/' );
    284 
    285                                                 $post_files[] = $common->build_file_descriptor( $local_file, $remote_file );
     282                                                if ( '' !== $w3tc_file ) {
     283                                                        $local_file  = $upload_info['basedir'] . '/' . $w3tc_file;
     284                                                        $remote_file = ltrim( $upload_info['baseurlpath'] . $w3tc_file, '/' );
     285
     286                                                        $post_files[] = $common->build_file_descriptor( $local_file, $remote_file );
     287                                                }
    286288                                        }
    287289
  • w3-total-cache/tags/2.10.7/Cli.php

    r3585227 r3723494  
    591591                                ( isset( $vars['start'] ) ? $vars['start'] - 1 : null ),
    592592                                ( isset( $vars['limit'] ) ? $vars['limit'] : null ),
    593                                 $log_callback
     593                                $log_callback,
     594                                false
    594595                        );
    595596
  • w3-total-cache/tags/2.10.7/ConfigKeys.php

    r3680101 r3723494  
    196196                'type'    => 'boolean',
    197197                'default' => false,
     198        ),
     199        'dbcache.wp_cron'                                      => array(
     200                'type'    => 'boolean',
     201                'default' => false,
     202        ),
     203        'dbcache.wp_cron_time'                                 => array(
     204                'type'    => 'integer',
     205                'default' => 0,
     206        ),
     207        'dbcache.wp_cron_interval'                             => array(
     208                'type'    => 'string',
     209                'default' => 'daily',
    198210        ),
    199211        'docroot_fix.enable'                                   => array(
    … …  
    385397                'default' => false,
    386398        ),
     399        'objectcache.wp_cron'                                  => array(
     400                'type'    => 'boolean',
     401                'default' => false,
     402        ),
     403        'objectcache.wp_cron_time'                             => array(
     404                'type'    => 'integer',
     405                'default' => 0,
     406        ),
     407        'objectcache.wp_cron_interval'                         => array(
     408                'type'    => 'string',
     409                'default' => 'daily',
     410        ),
     411        'allcache.wp_cron'                                     => array(
     412                'type'    => 'boolean',
     413                'default' => false,
     414        ),
     415        'allcache.wp_cron_time'                                => array(
     416                'type'    => 'integer',
     417                'default' => 0,
     418        ),
     419        'allcache.wp_cron_interval'                            => array(
     420                'type'    => 'string',
     421                'default' => 'daily',
     422        ),
    387423        'pgcache.configuration_overloaded'                     => array(
    388424                'type'    => 'boolean',
    … …  
    708744                'type'    => 'integer',
    709745                'default' => 10,
     746        ),
     747        'pgcache.prime.sitemap_one_pass'                       => array(
     748                'type'    => 'boolean',
     749                'default' => false,
    710750        ),
    711751        'pgcache.prime.sitemap'                                => array(
    … …  
    757797                ),
    758798        ),
     799        'pgcache.wp_cron'                                      => array(
     800                'type'    => 'boolean',
     801                'default' => false,
     802        ),
     803        'pgcache.wp_cron_time'                                 => array(
     804                'type'    => 'integer',
     805                'default' => 0,
     806        ),
     807        'pgcache.wp_cron_interval'                             => array(
     808                'type'    => 'string',
     809                'default' => 'daily',
     810        ),
    759811        'stats.enabled'                                        => array(
    760812                'type'    => 'boolean',
    … …  
    12181270                'type'    => 'boolean',
    12191271                'default' => false,
     1272        ),
     1273        'minify.wp_cron'                                       => array(
     1274                'type'    => 'boolean',
     1275                'default' => false,
     1276        ),
     1277        'minify.wp_cron_time'                                  => array(
     1278                'type'    => 'integer',
     1279                'default' => 0,
     1280        ),
     1281        'minify.wp_cron_interval'                              => array(
     1282                'type'    => 'string',
     1283                'default' => 'daily',
    12201284        ),
    12211285        'cdn.configuration_overloaded'                         => array(
  • w3-total-cache/tags/2.10.7/ConfigState.php

    r3585227 r3723494  
    8282
    8383        /**
     84         * Whether stored option data has been loaded.
     85         *
     86         * @var bool
     87         */
     88        private $_loaded;
     89
     90        /**
     91         * Encoded option payload from the last successful load or save.
     92         *
     93         * @since 2.10.7
     94         *
     95         * @var string|null
     96         */
     97        private $_saved_encoded;
     98
     99        /**
    84100         * Initializes the configuration state.
    85101         *
    … …  
    89105         */
    90106        public function __construct( $is_master ) {
    91                 $this->_is_master = $is_master;
    92 
    93                 if ( $is_master ) {
    94                         $data_raw = get_site_option( 'w3tc_state' );
     107                $this->_is_master     = $is_master;
     108                $this->_data          = array();
     109                $this->_loaded        = false;
     110                $this->_saved_encoded = null;
     111
     112                $this->load();
     113        }
     114
     115        /**
     116         * Retrieves a value from the configuration state by key.
     117         *
     118         * @param string $w3tc_key           The key to retrieve.
     119         * @param mixed  $default_value The default value to return if the key is not set.
     120         *
     121         * @return mixed The value associated with the key, or the default value.
     122         */
     123        public function get( $w3tc_key, $default_value ) {
     124                $this->load();
     125
     126                if ( ! isset( $this->_data[ $w3tc_key ] ) ) {
     127                        return $default_value;
     128                }
     129
     130                return $this->_data[ $w3tc_key ];
     131        }
     132
     133        /**
     134         * Retrieves a string value from the configuration state.
     135         *
     136         * @param string $w3tc_key           The key to retrieve.
     137         * @param string $default_value The default string to return if the key is not set. Default is an empty string.
     138         * @param bool   $trim          Whether to trim the returned string. Default is true.
     139         *
     140         * @return string The string value associated with the key, or the default string.
     141         */
     142        public function get_string( $w3tc_key, $default_value = '', $trim = true ) {
     143                $w3tc_value = (string) $this->get( $w3tc_key, $default_value );
     144
     145                return $trim ? trim( $w3tc_value ) : $w3tc_value;
     146        }
     147
     148        /**
     149         * Retrieves an integer value from the configuration state.
     150         *
     151         * @param string $w3tc_key           The key to retrieve.
     152         * @param int    $default_value The default integer to return if the key is not set. Default is 0.
     153         *
     154         * @return int The integer value associated with the key, or the default integer.
     155         */
     156        public function get_integer( $w3tc_key, $default_value = 0 ) {
     157                return (int) $this->get( $w3tc_key, $default_value );
     158        }
     159
     160        /**
     161         * Retrieves a boolean value from the configuration state.
     162         *
     163         * @param string $w3tc_key           The key to retrieve.
     164         * @param bool   $default_value The default boolean to return if the key is not set. Default is false.
     165         *
     166         * @return bool The boolean value associated with the key, or the default boolean.
     167         */
     168        public function get_boolean( $w3tc_key, $default_value = false ) {
     169                $v = $this->get( $w3tc_key, $default_value );
     170                if ( 'false' === $v || empty( $v ) ) {
     171                        $v = false;
     172                }
     173
     174                return (bool) $v;
     175        }
     176
     177        /**
     178         * Retrieves an array value from the configuration state.
     179         *
     180         * @param string $w3tc_key           The key to retrieve.
     181         * @param array  $default_value The default array to return if the key is not set. Default is an empty array.
     182         *
     183         * @return array The array value associated with the key, or the default array.
     184         */
     185        public function get_array( $w3tc_key, $default_value = array() ) {
     186                return (array) $this->get( $w3tc_key, $default_value );
     187        }
     188
     189        /**
     190         * Sets a value in the configuration state.
     191         *
     192         * @param string $w3tc_key   The key to set.
     193         * @param mixed  $w3tc_value The value to associate with the key.
     194         *
     195         * @return void
     196         */
     197        public function set( $w3tc_key, $w3tc_value ) {
     198                $this->load();
     199
     200                $this->_data[ $w3tc_key ] = $w3tc_value;
     201        }
     202
     203        /**
     204         * Resets the configuration state to its default values.
     205         *
     206         * @return void
     207         */
     208        public function reset() {
     209                $this->_data          = array();
     210                $this->_loaded        = true;
     211                $this->_saved_encoded = null;
     212                $this->apply_defaults();
     213        }
     214
     215        /**
     216         * Saves the current configuration state.
     217         *
     218         * @return void
     219         */
     220        public function save() {
     221                $this->load();
     222
     223                if ( ! $this->_loaded ) {
     224                        return;
     225                }
     226
     227                $encoded = \wp_json_encode( $this->_data );
     228                if ( false === $encoded || $encoded === $this->_saved_encoded ) {
     229                        return;
     230                }
     231
     232                if ( $this->_is_master ) {
     233                        if ( ! \function_exists( 'update_site_option' ) ) {
     234                                return;
     235                        }
     236                        $saved = \update_site_option( 'w3tc_state', $encoded );
    95237                } else {
    96                         $data_raw = get_option( 'w3tc_state' );
    97                 }
    98 
    99                 $this->_data = @json_decode( $data_raw, true );
     238                        if ( ! \function_exists( 'update_option' ) ) {
     239                                return;
     240                        }
     241                        $saved = \update_option( 'w3tc_state', $encoded );
     242                }
     243
     244                if ( $saved ) {
     245                        $this->_saved_encoded = $encoded;
     246                }
     247        }
     248
     249        /**
     250         * Loads stored option data when the Options API is available.
     251         *
     252         * @since 2.10.7
     253         *
     254         * @return void
     255         */
     256        private function load() {
     257                if ( $this->_loaded ) {
     258                        return;
     259                }
     260
     261                if ( $this->_is_master ) {
     262                        if ( ! \function_exists( 'get_site_option' ) ) {
     263                                return;
     264                        }
     265                        $data_raw = \get_site_option( 'w3tc_state' );
     266                } else {
     267                        if ( ! \function_exists( 'get_option' ) ) {
     268                                return;
     269                        }
     270                        $data_raw = \get_option( 'w3tc_state' );
     271                }
     272
     273                $this->_loaded = true;
     274                $this->_data   = @json_decode( $data_raw, true );
    100275                if ( ! is_array( $this->_data ) ) {
    101276                        $this->_data = array();
    102277                        $this->apply_defaults();
    103278                        $this->save();
    104                 }
    105         }
    106 
    107         /**
    108          * Retrieves a value from the configuration state by key.
    109          *
    110          * @param string $w3tc_key           The key to retrieve.
    111          * @param mixed  $default_value The default value to return if the key is not set.
    112          *
    113          * @return mixed The value associated with the key, or the default value.
    114          */
    115         public function get( $w3tc_key, $default_value ) {
    116                 if ( ! isset( $this->_data[ $w3tc_key ] ) ) {
    117                         return $default_value;
    118                 }
    119 
    120                 return $this->_data[ $w3tc_key ];
    121         }
    122 
    123         /**
    124          * Retrieves a string value from the configuration state.
    125          *
    126          * @param string $w3tc_key           The key to retrieve.
    127          * @param string $default_value The default string to return if the key is not set. Default is an empty string.
    128          * @param bool   $trim          Whether to trim the returned string. Default is true.
    129          *
    130          * @return string The string value associated with the key, or the default string.
    131          */
    132         public function get_string( $w3tc_key, $default_value = '', $trim = true ) {
    133                 $w3tc_value = (string) $this->get( $w3tc_key, $default_value );
    134 
    135                 return $trim ? trim( $w3tc_value ) : $w3tc_value;
    136         }
    137 
    138         /**
    139          * Retrieves an integer value from the configuration state.
    140          *
    141          * @param string $w3tc_key           The key to retrieve.
    142          * @param int    $default_value The default integer to return if the key is not set. Default is 0.
    143          *
    144          * @return int The integer value associated with the key, or the default integer.
    145          */
    146         public function get_integer( $w3tc_key, $default_value = 0 ) {
    147                 return (int) $this->get( $w3tc_key, $default_value );
    148         }
    149 
    150         /**
    151          * Retrieves a boolean value from the configuration state.
    152          *
    153          * @param string $w3tc_key           The key to retrieve.
    154          * @param bool   $default_value The default boolean to return if the key is not set. Default is false.
    155          *
    156          * @return bool The boolean value associated with the key, or the default boolean.
    157          */
    158         public function get_boolean( $w3tc_key, $default_value = false ) {
    159                 $v = $this->get( $w3tc_key, $default_value );
    160                 if ( 'false' === $v || empty( $v ) ) {
    161                         $v = false;
    162                 }
    163 
    164                 return (bool) $v;
    165         }
    166 
    167         /**
    168          * Retrieves an array value from the configuration state.
    169          *
    170          * @param string $w3tc_key           The key to retrieve.
    171          * @param array  $default_value The default array to return if the key is not set. Default is an empty array.
    172          *
    173          * @return array The array value associated with the key, or the default array.
    174          */
    175         public function get_array( $w3tc_key, $default_value = array() ) {
    176                 return (array) $this->get( $w3tc_key, $default_value );
    177         }
    178 
    179         /**
    180          * Sets a value in the configuration state.
    181          *
    182          * @param string $w3tc_key   The key to set.
    183          * @param mixed  $w3tc_value The value to associate with the key.
    184          *
    185          * @return void
    186          */
    187         public function set( $w3tc_key, $w3tc_value ) {
    188                 $this->_data[ $w3tc_key ] = $w3tc_value;
    189         }
    190 
    191         /**
    192          * Resets the configuration state to its default values.
    193          *
    194          * @return void
    195          */
    196         public function reset() {
    197                 $this->_data = array();
    198                 $this->apply_defaults();
    199         }
    200 
    201         /**
    202          * Saves the current configuration state.
    203          *
    204          * @return void
    205          */
    206         public function save() {
    207                 if ( $this->_is_master ) {
    208                         update_site_option( 'w3tc_state', wp_json_encode( $this->_data ) );
    209                 } else {
    210                         update_option( 'w3tc_state', wp_json_encode( $this->_data ) );
    211                 }
     279                        return;
     280                }
     281
     282                $this->_saved_encoded = \wp_json_encode( $this->_data );
    212283        }
    213284
  • w3-total-cache/tags/2.10.7/Generic_AdminActions_Config.php

    r3585227 r3723494  
    559559         * Saves the "Support Us" configuration settings.
    560560         *
    561          * Updates settings based on user actions like tweeting or signing up.
     561         * Updates settings based on user actions like tweeting or accepting
     562         * the community terms.
    562563         *
    563564         * @return void
    … …  
    565566        public function w3tc_config_save_support_us() {
    566567                $tweeted      = Util_Request::get_boolean( 'tweeted' );
    567                 $signmeup     = Util_Request::get_boolean( 'signmeup' );
    568568                $accept_terms = Util_Request::get_boolean( 'accept_terms' );
    569569                $this->_config->set( 'common.tweeted', $tweeted );
    … …  
    576576                $state_master->save();
    577577
    578                 if ( $signmeup ) {
    579                         if ( Util_Environment::is_w3tc_pro( $this->_config ) ) {
    580                                 $w3tc_license = 'pro';
    581                         } else {
    582                                 $w3tc_license = 'community';
    583                         }
    584 
    585                         /**
    586                          * RT9-218: Bind the mailing-list signup to the currently
    587                          * authenticated admin's verified WordPress account email,
    588                          * rather than trusting whatever address was POSTed. The
    589                          * original handler took `email` straight from the request
    590                          * body, which let any admin (or anyone driving the shared
    591                          * `w3tc` nonce) submit arbitrary third-party addresses to
    592                          * `api.w3-edge.com/v1/signup-newsletter` as an outbound
    593                          * abuse primitive. wp_get_current_user() is safe here
    594                          * because the surrounding admin-page dispatcher already
    595                          * gates this action behind an authenticated session.
    596                          */
    597                         $current = \wp_get_current_user();
    598                         $email   = ( $current instanceof \WP_User && ! empty( $current->user_email ) )
    599                                 ? $current->user_email
    600                                 : '';
    601 
    602                         if ( \is_string( $email ) && '' !== $email
    603                                 && false !== \filter_var( $email, FILTER_VALIDATE_EMAIL )
    604                         ) {
    605                                 wp_remote_post(
    606                                         W3TC_MAILLINGLIST_SIGNUP_URL,
    607                                         array(
    608                                                 'body' => array(
    609                                                         'email'   => $email,
    610                                                         'license' => $w3tc_license,
    611                                                 ),
    612                                         )
    613                                 );
    614                         }
    615                 }
    616578                $this->_config->save();
    617579
  • w3-total-cache/tags/2.10.7/Generic_Plugin.php

    r3680101 r3723494  
    11861186                        foreach ( $rejected_roles as $role ) {
    11871187                                Util_Cookie::clear( 'w3tc_logged_' . Util_Cookie::role_cookie_name( $role ) );
    1188                                 /**
    1189                                  * Always clear leftover MD5-named cookies on logout even
    1190                                  * though cache-auth readers no longer honor them by
    1191                                  * default. Stale names would otherwise linger in the
    1192                                  * browser until expiry.
    1193                                  */
    1194                                 Util_Cookie::clear( 'w3tc_logged_' . Util_Cookie::role_cookie_name_legacy( $role ) );
    11951188                        }
    11961189
  • w3-total-cache/tags/2.10.7/Licensing_Plugin_Admin.php

    r3680101 r3723494  
    687687                                );
    688688
     689                        /*
     690                         * Longer prefixes must be tested first. _status_is() is a prefix
     691                         * match, so inactive.by_rooturi also matches
     692                         * inactive.by_rooturi.activations_limit_reached.
     693                         */
     694                        case $this->_status_is( $status, 'inactive.by_rooturi.activations_limit_reached' ):
     695                                return sprintf(
     696                                        // Translators: 1 Product name.
     697                                        __(
     698                                                'Your %1$s license key is not active and cannot be activated due to the license activation limit being reached.',
     699                                                'w3-total-cache'
     700                                        ),
     701                                        W3TC_POWERED_BY
     702                                );
     703
    689704                        case $this->_status_is( $status, 'inactive.by_rooturi' ) || $this->_status_is( $status, 'inactive.by_rooturi.activations_limit_not_reached' ):
    690705                                // Only show this notice if there's actually a license key.
    … …  
    707722                                        '<a class="w3tc_licensing_reset_rooturi" href="' . esc_url( $reset_url ) . '">',
    708723                                        '</a>'
    709                                 );
    710 
    711                         case $this->_status_is( $status, 'inactive.by_rooturi.activations_limit_reached' ):
    712                                 return sprintf(
    713                                         // Translators: 1 Product name.
    714                                         __(
    715                                                 'Your %1$s license key is not active and cannot be activated due to the license activation limit being reached.',
    716                                                 'w3-total-cache'
    717                                         ),
    718                                         W3TC_POWERED_BY
    719724                                );
    720725
  • w3-total-cache/tags/2.10.7/Minify_AutoJs.php

    r3585227 r3723494  
    251251                if ( 'url' === $step1_result ) {
    252252                        $w3tc_file = $script_src;
     253                        if ( ! $this->minify_helpers->is_external_script_cached( $script_src ) ) {
     254                                $step1_result = '';
     255                        }
    253256                }
    254257
  • w3-total-cache/tags/2.10.7/Minify_MinifiedFileRequestHandler.php

    r3680101 r3723494  
    7474         */
    7575        const PROBE_TOKEN_HEADER = 'X-W3TC-Minify-Probe';
     76
     77        /**
     78         * Limits for external JavaScript retrieval.
     79         *
     80         * @since 2.10.7
     81         */
     82        const EXTERNAL_JS_TIMEOUT  = 5;
     83        const EXTERNAL_JS_MAX_SIZE = 1048576;
     84
     85        /**
     86         * Cron hook that retrieves selected external JavaScript.
     87         *
     88         * @since 2.10.7
     89         */
     90        const EXTERNAL_JS_PRECACHE_HOOK = 'w3tc_minify_precache_external_script';
    7691
    7792        /**
    … …  
    859874        public function _precache_file( $w3tc_url, $type ) {
    860875                $w3tc_url = Util_Url::normalize_protocol_relative_url( $w3tc_url );
    861                 if ( '' === $w3tc_url || ! Util_Url::is_allowed_outbound_url( $w3tc_url ) ) {
     876                if ( ! in_array( $type, array( 'css', 'js' ), true ) || '' === $w3tc_url ) {
    862877                        return false;
    863878                }
    864879
    865                 $lifetime   = $this->_config->get_integer( 'minify.lifetime' );
    866                 $cache_path = sprintf( '%s/minify_%s.%s', Util_Environment::cache_blog_dir( 'minify' ), md5( $w3tc_url ), $type );
     880                if ( 'js' === $type ) {
     881                        $cache_path = $this->external_javascript_cache_path( $w3tc_url );
     882                        if ( '' === $cache_path ) {
     883                                return false;
     884                        }
     885
     886                        $lifetime = $this->external_javascript_lifetime();
     887                } else {
     888                        if ( ! Util_Url::is_allowed_outbound_url( $w3tc_url ) ) {
     889                                return false;
     890                        }
     891
     892                        $lifetime   = $this->_config->get_integer( 'minify.lifetime' );
     893                        $cache_path = sprintf( '%s/minify_%s.%s', Util_Environment::cache_blog_dir( 'minify' ), md5( $w3tc_url ), $type );
     894                }
    867895
    868896                if ( ! file_exists( $cache_path ) || @filemtime( $cache_path ) < ( time() - $lifetime ) ) {
    … …  
    871899                        }
    872900
     901                        $download_path = $cache_path;
     902                        $download_args = array(
     903                                'user-agent' => 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.92',
     904                        );
     905                        if ( 'js' === $type ) {
     906                                $download_path                           .= '.' . \uniqid( 'tmp-', true );
     907                                $download_args['timeout']                 = self::EXTERNAL_JS_TIMEOUT;
     908                                $download_args['w3tc_public_only']        = true;
     909                                $download_args['w3tc_https_only']         = true;
     910                                $download_args['w3tc_same_host']          = true;
     911                                $download_args['w3tc_max_response_size']  = self::EXTERNAL_JS_MAX_SIZE;
     912                                $download_args['w3tc_response_validator'] = array( __CLASS__, 'validate_external_javascript_response' );
     913                        }
     914
    873915                        // google-fonts (most used for external inclusion) doesnt return full content (unicode-range) for simple useragents.
    874                         Util_Http::download(
     916                        $downloaded = Util_Http::download(
    875917                                $w3tc_url,
    876                                 $cache_path,
    877                                 array(
    878                                         'user-agent' => 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.92',
    879                                 )
     918                                $download_path,
     919                                $download_args
    880920                        );
     921
     922                        if ( 'js' === $type ) {
     923                                if ( $downloaded ) {
     924                                        @rename( $download_path, $cache_path );
     925                                }
     926                                if ( file_exists( $download_path ) ) {
     927                                        @unlink( $download_path );
     928                                }
     929                        }
    881930                }
    882931
    883932                return file_exists( $cache_path ) ? $this->_get_minify_source( $cache_path, $w3tc_url, $type ) : false;
     933        }
     934
     935        /**
     936         * Retrieves an existing external JavaScript cache entry without refreshing it.
     937         *
     938         * @since 2.10.7
     939         *
     940         * @param string $w3tc_url Script URL.
     941         *
     942         * @return mixed The minified source or false when no usable cache exists.
     943         */
     944        public function get_cached_external_script( $w3tc_url ) {
     945                $w3tc_url   = Util_Url::normalize_protocol_relative_url( $w3tc_url );
     946                $cache_path = $this->external_javascript_cache_path( $w3tc_url );
     947
     948                if ( '' === $cache_path || ! file_exists( $cache_path ) ) {
     949                        return false;
     950                }
     951
     952                return $this->_get_minify_source( $cache_path, $w3tc_url, 'js' );
     953        }
     954
     955        /**
     956         * Queues retrieval of an external script that has no usable cache yet.
     957         *
     958         * Page output must never wait on the network, so the first copy is fetched
     959         * by cron. Once a copy exists the tag is rewritten to the minify URL and
     960         * the minify request handler keeps it refreshed.
     961         *
     962         * @since 2.10.7
     963         *
     964         * @param string $w3tc_url Script URL.
     965         *
     966         * @return bool Whether retrieval is queued.
     967         */
     968        public function schedule_external_script_precache( $w3tc_url ) {
     969                $w3tc_url   = Util_Url::normalize_protocol_relative_url( $w3tc_url );
     970                $cache_path = $this->external_javascript_cache_path( $w3tc_url );
     971
     972                if ( '' === $cache_path ) {
     973                        return false;
     974                }
     975
     976                if ( file_exists( $cache_path ) && @filemtime( $cache_path ) >= ( time() - $this->external_javascript_lifetime() ) ) {
     977                        return false;
     978                }
     979
     980                $args = array( $w3tc_url );
     981                if ( \wp_next_scheduled( self::EXTERNAL_JS_PRECACHE_HOOK, $args ) ) {
     982                        return true;
     983                }
     984
     985                return true === \wp_schedule_single_event( time(), self::EXTERNAL_JS_PRECACHE_HOOK, $args );
     986        }
     987
     988        /**
     989         * Returns the cache path of an external script eligible for local caching.
     990         *
     991         * @since 2.10.7
     992         *
     993         * @param string $w3tc_url Normalized script URL.
     994         *
     995         * @return string Empty string when the URL may not be cached.
     996         */
     997        private function external_javascript_cache_path( $w3tc_url ) {
     998                if (
     999                        '' === $w3tc_url ||
     1000                        'https' !== \wp_parse_url( $w3tc_url, PHP_URL_SCHEME ) ||
     1001                        ! Util_Url::is_public_host( $w3tc_url )
     1002                ) {
     1003                        return '';
     1004                }
     1005
     1006                return sprintf( '%s/minify_%s.js', Util_Environment::cache_blog_dir( 'minify' ), md5( $w3tc_url ) );
     1007        }
     1008
     1009        /**
     1010         * Returns the bounded refresh interval for external scripts.
     1011         *
     1012         * @since 2.10.7
     1013         *
     1014         * @return int
     1015         */
     1016        private function external_javascript_lifetime() {
     1017                return max( HOUR_IN_SECONDS, min( WEEK_IN_SECONDS, $this->_config->get_integer( 'minify.lifetime' ) ) );
     1018        }
     1019
     1020        /**
     1021         * Accepts only non-empty responses with a JavaScript content type.
     1022         *
     1023         * @since 2.10.7
     1024         *
     1025         * @param array $response HTTP response.
     1026         *
     1027         * @return bool
     1028         */
     1029        public static function validate_external_javascript_response( $response ) {
     1030                $body = isset( $response['body'] ) && \is_string( $response['body'] ) ? $response['body'] : '';
     1031                if ( '' === $body ) {
     1032                        return false;
     1033                }
     1034
     1035                $content_type       = \strtolower( \trim( \wp_remote_retrieve_header( $response, 'content-type' ) ) );
     1036                $content_type_parts = \explode( ';', $content_type );
     1037                $content_type       = \trim( $content_type_parts[0] );
     1038
     1039                return \in_array(
     1040                        $content_type,
     1041                        array(
     1042                                'application/javascript',
     1043                                'application/ecmascript',
     1044                                'application/x-ecmascript',
     1045                                'application/x-javascript',
     1046                                'text/ecmascript',
     1047                                'text/javascript',
     1048                                'text/x-ecmascript',
     1049                                'text/x-javascript',
     1050                        ),
     1051                        true
     1052                );
    8841053        }
    8851054
    … …  
    11741343                                }
    11751344
    1176                                 $segments  = explode( '.', $remote_url );
    1177                                 $w3tc_ext  = strtolower( array_pop( $segments ) );
     1345                                $w3tc_ext = self::remote_source_type( $remote_url, $type );
     1346                                if ( '' === $w3tc_ext ) {
     1347                                        return false;
     1348                                }
     1349
    11781350                                $pc_source = $this->_precache_file( $remote_url, $w3tc_ext );
    11791351                                if ( ! $pc_source || empty( $pc_source->filepath ) ) {
    … …  
    13081480
    13091481        /**
     1482         * Resolves the asset type of a remote minify source.
     1483         *
     1484         * The URL path is authoritative when it carries a css/js extension;
     1485         * versioned or extensionless URLs (e.g. "app.js?ver=1") fall back to
     1486         * the type of the group being hashed.
     1487         *
     1488         * @since 2.10.7
     1489         *
     1490         * @param string $remote_url Remote asset URL.
     1491         * @param string $group_type Type of the group being hashed (css/js).
     1492         *
     1493         * @return string Asset type, or an empty string when neither is usable.
     1494         */
     1495        private static function remote_source_type( $remote_url, $group_type ) {
     1496                $path      = \wp_parse_url( $remote_url, PHP_URL_PATH );
     1497                $extension = \is_string( $path ) ? \strtolower( \pathinfo( $path, PATHINFO_EXTENSION ) ) : '';
     1498
     1499                if ( \in_array( $extension, array( 'css', 'js' ), true ) ) {
     1500                        return $extension;
     1501                }
     1502
     1503                return \in_array( $group_type, array( 'css', 'js' ), true ) ? $group_type : '';
     1504        }
     1505
     1506        /**
    13101507         * Flattens a multidimensional array into a single-dimensional array.
    13111508         *
  • w3-total-cache/tags/2.10.7/Minify_Plugin.php

    r3680101 r3723494  
    9090                add_filter( 'cron_schedules', array( $this, 'cron_schedules' ) ); // phpcs:ignore WordPress.WP.CronInterval.ChangeDetected
    9191                add_action( 'w3tc_minifycache_purge_wpcron', array( $this, 'w3tc_minifycache_purge_wpcron' ) );
     92                add_action(
     93                        Minify_MinifiedFileRequestHandler::EXTERNAL_JS_PRECACHE_HOOK,
     94                        array( $this, 'w3tc_minify_precache_external_script' )
     95                );
    9296
    9397                add_filter( 'w3tc_admin_bar_menu', array( $this, 'w3tc_admin_bar_menu' ) );
    … …  
    182186                $flusher = Dispatcher::component( 'CacheFlush' );
    183187                $flusher->minifycache_flush();
     188        }
     189
     190        /**
     191         * Retrieves a queued external script outside of page generation.
     192         *
     193         * @since 2.10.7
     194         *
     195         * @param string $w3tc_url Script URL.
     196         *
     197         * @return void
     198         */
     199        public function w3tc_minify_precache_external_script( $w3tc_url ) {
     200                if ( ! is_string( $w3tc_url ) || '' === $w3tc_url ) {
     201                        return;
     202                }
     203
     204                // The selection may have changed since the event was queued.
     205                $helpers = new _W3_MinifyHelpers( $this->_config );
     206                if ( 'url' !== $helpers->is_file_for_minification( $w3tc_url, null ) ) {
     207                        return;
     208                }
     209
     210                $minify = Dispatcher::component( 'Minify_MinifiedFileRequestHandler' );
     211                $minify->_precache_file( $w3tc_url, 'js' );
    184212        }
    185213
    … …  
    12071235
    12081236        /**
     1237         * Confirms that an external script already has a usable cached source.
     1238         *
     1239         * This check must not retrieve the script because it runs while page HTML
     1240         * is being generated. Cache population and refresh happen in the minify
     1241         * request handler.
     1242         *
     1243         * @since 2.10.7
     1244         *
     1245         * @param string $w3tc_url Script URL.
     1246         *
     1247         * @return bool
     1248         */
     1249        public function is_external_script_cached( $w3tc_url ) {
     1250                $minify = Dispatcher::component( 'Minify_MinifiedFileRequestHandler' );
     1251                $cached = false !== $minify->get_cached_external_script( $w3tc_url );
     1252
     1253                if ( ! $cached ) {
     1254                        $minify->schedule_external_script_precache( $w3tc_url );
     1255                }
     1256
     1257                return $cached;
     1258        }
     1259
     1260        /**
    12091261         * Retrieves the minified content for a given set of files and type.
    12101262         *
  • w3-total-cache/tags/2.10.7/ObjectCache_WpObjectCache_Regular.php

    r3680101 r3723494  
    206206                        $found      = true;
    207207                        $w3tc_value = $this->cache[ $w3tc_key ];
    208                 } elseif (
    209                         $this->_caching
    210                         && ! in_array( $w3tc_group, $this->nonpersistent_groups, true )
    211                         && $this->_check_can_cache_runtime( $w3tc_group )
    212                 ) {
     208                } elseif ( $this->_should_use_persistent_cache( $id, $w3tc_group ) ) {
    213209                        $cache = $this->_get_cache( null, $w3tc_group );
    214210                        $v     = $cache->get( $w3tc_key, $w3tc_group );
    … …  
    346342                }
    347343
     344                $persistent_misses = array_filter(
     345                        $runtime_misses,
     346                        function ( $storage_key, $id ) use ( $w3tc_group ) {
     347                                return $this->_should_use_persistent_cache( $id, $w3tc_group );
     348                        },
     349                        ARRAY_FILTER_USE_BOTH
     350                );
     351
    348352                // Attempt a batched persistent fetch for the remaining keys when allowed.
    349                 if (
    350                         ! empty( $runtime_misses ) &&
    351                         $this->_caching &&
    352                         ! in_array( $w3tc_group, $this->nonpersistent_groups, true ) &&
    353                         $this->_check_can_cache_runtime( $w3tc_group )
    354                 ) {
     353                if ( ! empty( $persistent_misses ) ) {
    355354                        $cache       = $this->_get_cache( null, $w3tc_group );
    356                         $storage_map = $runtime_misses;
     355                        $storage_map = $persistent_misses;
    357356                        $raw_values  = array();
    358357
    … …  
    365364                        }
    366365
    367                         foreach ( $runtime_misses as $id => $storage_key ) {
     366                        foreach ( $persistent_misses as $id => $storage_key ) {
    368367                                ++$cache_total_inc;
    369368                                $v = isset( $raw_values[ $storage_key ] ) ? $raw_values[ $storage_key ] : null;
    … …  
    382381                                }
    383382                        }
    384                 } else {
    385                         // Not eligible for persistent fetch; fall back to per-key get() honoring $force.
    386                         foreach ( $runtime_misses as $id => $unused_key ) {
     383                }
     384
     385                // Fall back for keys that were not eligible for persistent fetch.
     386                foreach ( $runtime_misses as $id => $unused_key ) {
     387                        if ( ! array_key_exists( $id, $results ) ) {
    387388                                $results[ $id ] = $this->get( $id, $w3tc_group, $force );
    388389                        }
    … …  
    436437                $cache_sets_inc           = 0;
    437438
    438                 if (
    439                         $this->_caching
    440                                 && ! in_array( $w3tc_group, $this->nonpersistent_groups, true )
    441                                 && $this->_check_can_cache_runtime( $w3tc_group )
    442                 ) {
     439                if ( $this->_should_use_persistent_cache( $id, $w3tc_group ) ) {
    443440                        $cache = $this->_get_cache( null, $w3tc_group );
    444441
    … …  
    528525                }
    529526
    530                 $results            = array();
    531                 $payload            = array();
    532                 $cache_key_to_id    = array();
    533                 $cache_sets_inc     = 0;
    534                 $time_start_debug   = ( $this->_debug || $this->stats_enabled ) ? Util_Debug::microtime() : 0;
    535                 $key_version_all    = $this->key_version_all_get();
    536                 $persistent_allowed = (
    537                         $this->_caching &&
    538                         ! in_array( $w3tc_group, $this->nonpersistent_groups, true ) &&
    539                         $this->_check_can_cache_runtime( $w3tc_group )
    540                 );
     527                $results          = array();
     528                $payload          = array();
     529                $cache_key_to_id  = array();
     530                $cache_sets_inc   = 0;
     531                $time_start_debug = ( $this->_debug || $this->stats_enabled ) ? Util_Debug::microtime() : 0;
     532                $key_version_all  = $this->key_version_all_get();
    541533
    542534                foreach ( $items as $id => $w3tc_value ) {
    … …  
    552544                        $results[ $id ]            = true;
    553545
    554                         if ( $persistent_allowed ) {
     546                        if ( $this->_should_use_persistent_cache( $id, $w3tc_group ) ) {
    555547                                $stored_content = $stored;
    556548
    … …  
    570562                }
    571563
    572                 if ( $persistent_allowed && ! empty( $payload ) ) {
     564                if ( ! empty( $payload ) ) {
    573565                        $cache          = $this->_get_cache( null, $w3tc_group );
    574566                        $results        = $this->set_multiple_to_cache(
    … …  
    609601         */
    610602        public function delete( $id, $w3tc_group = 'default', $force = false ) {
    611                 if ( ! $force && $this->get( $id, $w3tc_group ) === false ) {
    612                         return false;
     603                if ( empty( $w3tc_group ) ) {
     604                        $w3tc_group = 'default';
    613605                }
    614606
    615607                $w3tc_key = $this->_get_cache_key( $id, $w3tc_group );
    616                 $return   = true;
     608
     609                $can_persist = $this->_caching && ! in_array( $w3tc_group, $this->nonpersistent_groups, true );
     610
     611                if ( ! $force && ! isset( $this->cache[ $w3tc_key ] ) ) {
     612                        $should_check_exists = ! $can_persist || $this->_check_can_cache_runtime( $w3tc_group );
     613
     614                        if ( $should_check_exists && $this->get( $id, $w3tc_group ) === false ) {
     615                                return false;
     616                        }
     617                }
     618
     619                $return = true;
    617620
    618621                unset( $this->cache[ $w3tc_key ] );
    619622
    620                 if ( $this->_caching && ! in_array( $w3tc_group, $this->nonpersistent_groups, true ) ) {
     623                if ( $can_persist ) {
    621624                        $cache  = $this->_get_cache( null, $w3tc_group );
    622625                        $return = $cache->delete( $w3tc_key, $w3tc_group );
    … …  
    13581361
    13591362        /**
     1363         * Whether a key should use the persistent backend.
     1364         *
     1365         * Admin requests typically skip persistent cache so admin queries are not stored.
     1366         * `last_changed` still writes through so frontend query salts invalidate.
     1367         *
     1368         * @since 2.10.7
     1369         *
     1370         * @param string $id         Cache key.
     1371         * @param string $w3tc_group Cache group.
     1372         *
     1373         * @return bool
     1374         */
     1375        private function _should_use_persistent_cache( $id, $w3tc_group ) {
     1376                if ( ! $this->_caching || in_array( $w3tc_group, $this->nonpersistent_groups, true ) ) {
     1377                        return false;
     1378                }
     1379
     1380                if ( $this->_check_can_cache_runtime( $w3tc_group ) ) {
     1381                        return true;
     1382                }
     1383
     1384                return 'last_changed' === (string) $id;
     1385        }
     1386
     1387        /**
    13601388         * Checks if caching is allowed for runtime based on the group.
    13611389         *
  • w3-total-cache/tags/2.10.7/PageSpeed_Api.php

    r3680101 r3723494  
    1818 */
    1919class PageSpeed_Api {
     20        /**
     21         * Delay automatic retries after a failed token refresh.
     22         *
     23         * @var int
     24         */
     25        const REFRESH_RETRY_DELAY = 15 * MINUTE_IN_SECONDS;
     26
    2027        /**
    2128         * Config.
    … …  
    231238                $w3tc_site_id       = Util_Http::generate_site_id();
    232239                $w3tc_pagespeed_key = $this->w3tc_config->get_string( 'widget.pagespeed.w3tc_pagespeed_key' );
    233                 if ( $this->client->isAccessTokenExpired() && ! empty( $w3tc_pagespeed_key ) ) {
     240                $retry_after        = (int) get_option( 'w3tcps_refresh_retry_after' );
     241
     242                if (
     243                        $this->client->isAccessTokenExpired() &&
     244                        ! empty( $w3tc_pagespeed_key ) &&
     245                        $retry_after <= time()
     246                ) {
    234247                        $this->refresh_token( $w3tc_site_id, $w3tc_pagespeed_key );
    235248                }
    … …  
    246259        public function refresh_token( $w3tc_site_id, $w3tc_pagespeed_key ) {
    247260                if ( empty( $w3tc_site_id ) || empty( $w3tc_pagespeed_key ) ) {
    248                         update_option(
    249                                 'w3tcps_refresh_fail',
     261                        $this->set_refresh_failure(
    250262                                __( 'Google PageSpeed access token refresh missing required parameters!', 'w3-total-cache' )
    251263                        );
    … …  
    262274                );
    263275
    264                 $response_body_json = wp_remote_retrieve_body( $response );
    265                 $response_body      = json_decode( $response_body_json, true );
    266 
    267276                if ( is_wp_error( $response ) ) {
    268                         return wp_json_encode(
    269                                 array(
    270                                         'error' => array(
    271                                                 'code'    => $response->get_error_code(),
    272                                                 'message' => $response->get_error_message(),
     277                        $this->set_refresh_failure(
     278                                __( 'Google PageSpeed access token refresh failed.', 'w3-total-cache' ),
     279                                $response->get_error_message()
     280                        );
     281                        return;
     282                }
     283
     284                $response_code = (int) wp_remote_retrieve_response_code( $response );
     285                $response_body = json_decode( wp_remote_retrieve_body( $response ), true );
     286                if ( ! is_array( $response_body ) ) {
     287                        $response_body = array();
     288                }
     289
     290                $w3tc_error_id = '';
     291                if ( isset( $response_body['error'] ) && is_array( $response_body['error'] ) ) {
     292                        $w3tc_error_id = isset( $response_body['error']['id'] ) ? (string) $response_body['error']['id'] : '';
     293                }
     294
     295                if (
     296                        $response_code < 200 ||
     297                        $response_code >= 300 ||
     298                        isset( $response_body['error'] )
     299                ) {
     300                        $this->set_refresh_failure(
     301                                __( 'Google PageSpeed access token refresh failed.', 'w3-total-cache' ),
     302                                $this->get_refresh_failure_message( $w3tc_error_id, $response_body, $response_code )
     303                        );
     304
     305                        if (
     306                                in_array(
     307                                        $w3tc_error_id,
     308                                        array(
     309                                                'refresh-token-not-found',
     310                                                'refresh-token-missing-refresh-token',
    273311                                        ),
     312                                        true
    274313                                )
    275                         );
    276                 } elseif ( isset( $response_body['error']['code'] ) && 200 !== $response_body['error']['code'] ) {
    277                         if ( 'refresh-token-missing-site-id' === $response_body['error']['id'] ) {
    278                                 $w3tc_message = __( 'No site ID provided for access key refresh!', 'w3-total-cache' );
    279                         } elseif ( 'refresh-token-missing-w3tc-pagespeed-key' === $response_body['error']['id'] ) {
    280                                 $w3tc_message = __( 'No W3TC API key provided for access key refresh!', 'w3-total-cache' );
    281                         } elseif ( 'refresh-token-not-found' === $response_body['error']['id'] ) {
    282                                 $w3tc_message = __( 'No matching Google access record found for W3TC API key!', 'w3-total-cache' );
    283                         } elseif ( 'refresh-token-missing-refresh-token' === $response_body['error']['id'] ) {
    284                                 $w3tc_message = __( 'Matching Google access record found but the refresh token value is blank!', 'w3-total-cache' );
     314                        ) {
     315                                $this->clear_pagespeed_credentials();
    285316                        }
    286 
    287                         update_option(
    288                                 'w3tcps_refresh_fail',
    289                                 __( 'Google PageSpeed access token refresh failed.', 'w3-total-cache' )
    290                         );
    291                         update_option(
    292                                 'w3tcps_refresh_fail_message',
    293                                 $w3tc_message
    294                         );
    295 
    296                         // Reset the token and key.
    297                         $this->w3tc_config->set( 'widget.pagespeed.access_token', '' );
    298                         $this->w3tc_config->set( 'widget.pagespeed.w3tc_pagespeed_key', '' );
    299                         $this->w3tc_config->save();
    300 
    301317                        return;
    302318                }
    303319
    304                 $w3tc_access_token = $response_body_json;
    305 
    306                 if ( empty( $w3tc_access_token ) || empty( $response_body['access_token'] ) ) {
    307                         update_option(
    308                                 'w3tcps_refresh_fail',
    309                                 __( 'Google PageSpeed access token refresh failed due to response missing access token.', 'w3-total-cache' )
     320                $w3tc_access_token = self::prepare_access_token_json( $response_body );
     321                if ( false === $w3tc_access_token ) {
     322                        $this->set_refresh_failure(
     323                                __( 'Google PageSpeed access token refresh failed due to an unusable token response.', 'w3-total-cache' )
    310324                        );
    311325                        return;
    … …  
    315329                $this->w3tc_config->save();
    316330                $this->client->setAccessToken( $w3tc_access_token );
     331                self::clear_failure_notices();
     332        }
     333
     334        /**
     335         * Records a token refresh failure for the admin notice.
     336         *
     337         * @since 2.10.7
     338         *
     339         * @param string $title   Notice title.
     340         * @param string $message Optional failure detail.
     341         *
     342         * @return void
     343         */
     344        private function set_refresh_failure( $title, $message = '' ) {
     345                update_option( 'w3tcps_refresh_fail', $title );
     346                update_option( 'w3tcps_refresh_fail_message', $message );
     347                update_option( 'w3tcps_refresh_retry_after', time() + self::REFRESH_RETRY_DELAY );
     348        }
     349
     350        /**
     351         * Returns operator-facing text for a token refresh failure.
     352         *
     353         * @since 2.10.7
     354         *
     355         * @param string $w3tc_error_id Nested W3 API error ID, if any.
     356         * @param array  $response_body Decoded response body.
     357         * @param int    $response_code HTTP response code.
     358         *
     359         * @return string
     360         */
     361        private function get_refresh_failure_message( $w3tc_error_id, $response_body, $response_code ) {
     362                switch ( $w3tc_error_id ) {
     363                        case 'refresh-token-missing-site-id':
     364                                return __( 'No site ID provided for access key refresh!', 'w3-total-cache' );
     365
     366                        case 'refresh-token-missing-w3tc-pagespeed-key':
     367                                return __( 'No W3TC API key provided for access key refresh!', 'w3-total-cache' );
     368
     369                        case 'refresh-token-not-found':
     370                                return __( 'No matching Google access record found for W3TC API key!', 'w3-total-cache' );
     371
     372                        case 'refresh-token-missing-refresh-token':
     373                                return __( 'Matching Google access record found but the refresh token value is blank!', 'w3-total-cache' );
     374
     375                        case 'refresh-token-google-failed':
     376                                return __( 'Google rejected the access token refresh. Local authorization was kept for retry.', 'w3-total-cache' );
     377
     378                        case 'refresh-token-persist-failed':
     379                                return __( 'The renewed Google access token could not be saved by the W3 API. Local authorization was kept for retry.', 'w3-total-cache' );
     380                }
     381
     382                if ( isset( $response_body['error'] ) && is_string( $response_body['error'] ) ) {
     383                        return __( 'Google rejected the access token refresh. Local authorization was kept for retry.', 'w3-total-cache' );
     384                }
     385
     386                return sprintf(
     387                        /* translators: %d: HTTP response code. */
     388                        __( 'Unexpected token refresh response (HTTP %d).', 'w3-total-cache' ),
     389                        $response_code
     390                );
     391        }
     392
     393        /**
     394         * Removes local PageSpeed credentials after an irrecoverable API response.
     395         *
     396         * @since 2.10.7
     397         *
     398         * @return void
     399         */
     400        private function clear_pagespeed_credentials() {
     401                $this->w3tc_config->set( 'widget.pagespeed.access_token', '' );
     402                $this->w3tc_config->set( 'widget.pagespeed.w3tc_pagespeed_key', '' );
     403                $this->w3tc_config->save();
     404                delete_option( 'w3tcps_refresh_retry_after' );
     405                self::clear_pagespeed_cache();
     406        }
     407
     408        /**
     409         * Validates a Google access token payload and stamps its creation time.
     410         *
     411         * `W3TCG_Google_Auth_OAuth2::isAccessTokenExpired()` treats a missing `created`
     412         * value as expired, so every persist path must set it.
     413         *
     414         * @since 2.10.7
     415         *
     416         * @param array|string $w3tc_access_token Token payload or token JSON.
     417         *
     418         * @return string|false Token JSON to persist, or false when unusable.
     419         */
     420        public static function prepare_access_token_json( $w3tc_access_token ) {
     421                if ( is_string( $w3tc_access_token ) ) {
     422                        $w3tc_access_token = json_decode( $w3tc_access_token, true );
     423                }
     424
     425                if ( ! is_array( $w3tc_access_token ) ) {
     426                        return false;
     427                }
     428
     429                if (
     430                        empty( $w3tc_access_token['access_token'] ) ||
     431                        ! is_string( $w3tc_access_token['access_token'] ) ||
     432                        empty( $w3tc_access_token['expires_in'] ) ||
     433                        ! is_numeric( $w3tc_access_token['expires_in'] )
     434                ) {
     435                        return false;
     436                }
     437
     438                $w3tc_access_token['created'] = time();
     439
     440                $w3tc_access_token_json = wp_json_encode( $w3tc_access_token );
     441
     442                return is_string( $w3tc_access_token_json ) ? $w3tc_access_token_json : false;
     443        }
     444
     445        /**
     446         * Removes stored PageSpeed analysis results.
     447         *
     448         * Cache-first AJAX handlers must not serve scores once authorization is gone.
     449         *
     450         * @since 2.10.7
     451         *
     452         * @return void
     453         */
     454        public static function clear_pagespeed_cache() {
     455                global $wpdb;
     456
     457                delete_option( 'w3tc_pagespeed_data_' . get_home_url() );
     458
     459                $option_names = $wpdb->get_col( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
     460                        $wpdb->prepare(
     461                                "SELECT option_name FROM {$wpdb->options} WHERE option_name LIKE %s",
     462                                $wpdb->esc_like( 'w3tc_pagespeed_data_' ) . '%'
     463                        )
     464                );
     465
     466                foreach ( (array) $option_names as $option_name ) {
     467                        delete_option( $option_name );
     468                }
     469        }
     470
     471        /**
     472         * Returns operator-facing text for PageSpeed access that was never authorized.
     473         *
     474         * @since 2.10.7
     475         *
     476         * @return string
     477         */
     478        public static function get_authorize_required_message() {
     479                return sprintf(
     480                        // translators: 1 HTML a tag to W3TC settings page Google PageSpeed meta box.
     481                        __(
     482                                'Before you can get started using the Google PageSpeed tool, you’ll first need to authorize access. Please click %1$s.',
     483                                'w3-total-cache'
     484                        ),
     485                        '<a href="' . esc_url( Util_Ui::admin_url( 'admin.php?page=w3tc_general#google_pagespeed' ) ) . '" target="_blank">' . esc_html__( 'here', 'w3-total-cache' ) . '</a>'
     486                );
     487        }
     488
     489        /**
     490         * Returns operator-facing text for stored PageSpeed access that could not be renewed.
     491         *
     492         * @since 2.10.7
     493         *
     494         * @return string
     495         */
     496        public static function get_refresh_pending_message() {
     497                return sprintf(
     498                        // translators: 1 HTML a tag to W3TC settings page Google PageSpeed meta box.
     499                        __(
     500                                'Google PageSpeed access is authorized but could not be renewed on the last attempt. W3 Total Cache will retry automatically. If this continues, reauthorize access %1$s.',
     501                                'w3-total-cache'
     502                        ),
     503                        '<a href="' . esc_url( Util_Ui::admin_url( 'admin.php?page=w3tc_general#google_pagespeed' ) ) . '" target="_blank">' . esc_html__( 'here', 'w3-total-cache' ) . '</a>'
     504                );
    317505        }
    318506
    … …  
    387575
    388576        /**
     577         * Returns operator-facing text for an authorization failure.
     578         *
     579         * @since 2.10.7
     580         *
     581         * @param string $error_json W3 API authorization error JSON.
     582         *
     583         * @return string
     584         */
     585        public static function get_authorize_failure_message( $error_json ) {
     586                if ( ! is_string( $error_json ) ) {
     587                        $error_json = '';
     588                }
     589
     590                $error    = json_decode( $error_json );
     591                $error_id = isset( $error->error->id ) ? (string) $error->error->id : '';
     592                if ( 1 !== preg_match( '/\A[a-z0-9-]+\z/', $error_id ) ) {
     593                        $error_id = '';
     594                }
     595
     596                switch ( $error_id ) {
     597                        case 'authorize-in-missing-site-id':
     598                                return __( 'Unique site ID missing for authorize request!', 'w3-total-cache' );
     599
     600                        case 'authorize-in-missing-auth-url':
     601                                return __( 'Authorize URL missing for authorize request!', 'w3-total-cache' );
     602
     603                        case 'authorize-in-missing-return-url':
     604                                return __( 'Return URL missing for authorize request!', 'w3-total-cache' );
     605
     606                        case 'authorize-in-failed':
     607                                return __( 'Failed to process authorize request!', 'w3-total-cache' );
     608
     609                        case 'authorize-out-code-missing':
     610                                return __( 'No authorize code returned to W3-API from Google!', 'w3-total-cache' );
     611
     612                        case 'authorize-out-site-id-missing':
     613                                return __( 'Unique site ID missing during Google authorization return processing!', 'w3-total-cache' );
     614
     615                        case 'authorize-out-w3tc-pagespeed-key-missing':
     616                                return __( 'No W3Key returned to W3-API from Google!', 'w3-total-cache' );
     617
     618                        case 'authorize-out-not-found':
     619                                return __( 'No W3-API matching record found during Google authorization return processing!', 'w3-total-cache' );
     620
     621                        case 'authorize-out-token-missing':
     622                                return __( 'No Google access token found during Google authorization return processing!', 'w3-total-cache' );
     623
     624                        case 'authorize-out-google-failed':
     625                                return __( 'Google rejected the authorization request. Please try authorizing Google PageSpeed again.', 'w3-total-cache' );
     626
     627                        case 'authorize-out-refresh-token-missing':
     628                                return __( 'Google did not return a refresh token. Please authorize Google PageSpeed again.', 'w3-total-cache' );
     629
     630                        case 'authorize-out-refresh-token-persist-failed':
     631                                return __( 'The Google refresh token could not be saved by the W3 API. Please try authorizing again after the service is updated.', 'w3-total-cache' );
     632                }
     633
     634                return sprintf(
     635                        /* translators: %s: Google authorization error ID. */
     636                        __( 'Unexpected Google PageSpeed authorization error: %s', 'w3-total-cache' ),
     637                        '' !== $error_id ? $error_id : __( 'unknown', 'w3-total-cache' )
     638                );
     639        }
     640
     641        /**
     642         * Clears PageSpeed failure notices and automatic refresh cooldown.
     643         *
     644         * @since 2.10.7
     645         *
     646         * @return void
     647         */
     648        public static function clear_failure_notices() {
     649                delete_option( 'w3tcps_refresh_fail' );
     650                delete_option( 'w3tcps_refresh_fail_message' );
     651                delete_option( 'w3tcps_refresh_retry_after' );
     652                delete_option( 'w3tcps_revoke_fail' );
     653                delete_option( 'w3tcps_revoke_fail_message' );
     654        }
     655
     656        /**
    389657         * Reset authentication.
    390658         *
    391659         * @since 2.3.0
     660         *
     661         * @return bool Whether local and remote authorization were reset.
    392662         */
    393663        public function reset() {
    … …  
    401671                                __( 'Google PageSpeed access token revocation missing required parameters!', 'w3-total-cache' )
    402672                        );
    403                         return;
     673                        return false;
    404674                }
    405675
    … …  
    413683                );
    414684
    415                 $response_body_json = wp_remote_retrieve_body( $response );
    416                 $response_body      = json_decode( $response_body_json, true );
    417 
    418685                if ( is_wp_error( $response ) ) {
    419                         return wp_json_encode(
    420                                 array(
    421                                         'error' => array(
    422                                                 'code'    => $response->get_error_code(),
    423                                                 'message' => $response->get_error_message(),
    424                                         ),
    425                                 )
    426                         );
    427                 } elseif ( isset( $response_body['error']['code'] ) && 200 !== $response_body['error']['code'] ) {
    428                         if ( 'revoke-token-access-token-missing' === $response_body['error']['id'] ) {
    429                                 $w3tc_message = __( 'No access token provided for revoke!', 'w3-total-cache' );
    430                         } elseif ( 'revoke-token-api-key-missing' === $response_body['error']['id'] ) {
    431                                 $w3tc_message = __( 'No W3TC API key provided for revoke!', 'w3-total-cache' );
    432                         } elseif ( 'revoke-token-not-found' === $response_body['error']['id'] ) {
    433                                 $w3tc_message = __( 'No matching Google access record found for W3TC API key!', 'w3-total-cache' );
     686                        $this->set_revoke_failure(
     687                                $response->get_error_message()
     688                        );
     689                        return false;
     690                }
     691
     692                $response_code = (int) wp_remote_retrieve_response_code( $response );
     693                $response_body = json_decode( wp_remote_retrieve_body( $response ), true );
     694                if ( ! is_array( $response_body ) ) {
     695                        $response_body = array();
     696                }
     697
     698                $w3tc_error_id = '';
     699                if ( isset( $response_body['error'] ) && is_array( $response_body['error'] ) ) {
     700                        $w3tc_error_id = isset( $response_body['error']['id'] ) ? (string) $response_body['error']['id'] : '';
     701                }
     702
     703                if (
     704                        $response_code < 200 ||
     705                        $response_code >= 300 ||
     706                        isset( $response_body['error'] )
     707                ) {
     708                        if ( 'revoke-token-not-found' === $w3tc_error_id ) {
     709                                $this->clear_pagespeed_credentials();
     710                                self::clear_failure_notices();
     711                                return true;
    434712                        }
    435713
    436                         update_option(
    437                                 'w3tcps_revoke_fail',
    438                                 __( 'Google PageSpeed Access Token revocation failed.', 'w3-total-cache' )
    439                         );
    440                         update_option(
    441                                 'w3tcps_revoke_fail_message',
    442                                 $w3tc_message
    443                         );
    444 
    445                         return;
    446                 }
    447 
    448                 $this->w3tc_config->set( 'widget.pagespeed.access_token', '' );
    449                 $this->w3tc_config->set( 'widget.pagespeed.w3tc_pagespeed_key', '' );
    450                 $this->w3tc_config->save();
     714                        $this->set_revoke_failure(
     715                                $this->get_revoke_failure_message( $w3tc_error_id, $response_code )
     716                        );
     717                        return false;
     718                }
     719
     720                $this->clear_pagespeed_credentials();
     721                self::clear_failure_notices();
     722                return true;
     723        }
     724
     725        /**
     726         * Records a token revocation failure for the admin notice.
     727         *
     728         * @since 2.10.7
     729         *
     730         * @param string $message Failure detail.
     731         *
     732         * @return void
     733         */
     734        private function set_revoke_failure( $message ) {
     735                update_option(
     736                        'w3tcps_revoke_fail',
     737                        __( 'Google PageSpeed Access Token revocation failed.', 'w3-total-cache' )
     738                );
     739                update_option( 'w3tcps_revoke_fail_message', $message );
     740        }
     741
     742        /**
     743         * Returns operator-facing text for a token revocation failure.
     744         *
     745         * @since 2.10.7
     746         *
     747         * @param string $w3tc_error_id Nested W3 API error ID, if any.
     748         * @param int    $response_code HTTP response code.
     749         *
     750         * @return string
     751         */
     752        private function get_revoke_failure_message( $w3tc_error_id, $response_code ) {
     753                if ( 1 !== preg_match( '/\A[a-z0-9-]+\z/', $w3tc_error_id ) ) {
     754                        $w3tc_error_id = '';
     755                }
     756
     757                switch ( $w3tc_error_id ) {
     758                        case 'revoke-token-access-token-missing':
     759                                return __( 'No access token provided for revoke!', 'w3-total-cache' );
     760
     761                        case 'revoke-token-site-id-missing':
     762                                return __( 'No site ID provided for revoke!', 'w3-total-cache' );
     763
     764                        case 'revoke-token-api-key-missing':
     765                                return __( 'No W3TC API key provided for revoke!', 'w3-total-cache' );
     766
     767                        case 'revoke-token-not-found':
     768                                return __( 'No matching Google access record found for W3TC API key!', 'w3-total-cache' );
     769
     770                        case 'revoke-token-google-failed':
     771                                return __( 'Google rejected the access token revocation. Local authorization was kept for retry.', 'w3-total-cache' );
     772
     773                        case 'revoke-token-persist-failed':
     774                                return __( 'Google revoked the access token, but the W3 API could not save the result. Local authorization was kept for retry.', 'w3-total-cache' );
     775                }
     776
     777                return sprintf(
     778                        /* translators: 1: HTTP response code, 2: API error ID. */
     779                        __( 'Unexpected token revocation response (HTTP %1$d, error %2$s).', 'w3-total-cache' ),
     780                        $response_code,
     781                        '' !== $w3tc_error_id ? $w3tc_error_id : __( 'unknown', 'w3-total-cache' )
     782                );
    451783        }
    452784}
  • w3-total-cache/tags/2.10.7/PageSpeed_Page.php

    r3585227 r3723494  
    101101                        $w3tc_config       = Dispatcher::config();
    102102                        $w3tc_access_token = ! empty( $w3tc_config->get_string( 'widget.pagespeed.access_token' ) ) ? $w3tc_config->get_string( 'widget.pagespeed.access_token' ) : null;
    103 
    104                         if ( empty( $w3tc_access_token ) ) {
     103                        $w3tc_w3_pagespeed = empty( $w3tc_access_token ) ? null : new PageSpeed_Api( $w3tc_access_token );
     104
     105                        // Construction may clear credentials when a refresh is irrecoverable, so re-read the stored token.
     106                        $w3tc_stored_token = $w3tc_config->get_string( 'widget.pagespeed.access_token' );
     107
     108                        if ( empty( $w3tc_w3_pagespeed ) || empty( $w3tc_stored_token ) ) {
    105109                                echo wp_json_encode(
    106110                                        array(
    107                                                 'missing_token' => sprintf(
    108                                                         // translators: 1 HTML a tag to W3TC settings page Google PageSpeed meta box.
    109                                                         __(
    110                                                                 'Before you can get started using the Google PageSpeed tool, you’ll first need to authorize access. Please click %1$s.',
    111                                                                 'w3-total-cache'
    112                                                         ),
    113                                                         '<a href="' . esc_url( Util_Ui::admin_url( 'admin.php?page=w3tc_general#google_pagespeed' ) ) . '" target="_blank">' . esc_html__( 'here', 'w3-total-cache' ) . '</a>'
    114                                                 ),
     111                                                'missing_token' => PageSpeed_Api::get_authorize_required_message(),
    115112                                        )
    116113                                );
    … …  
    118115                        }
    119116
    120                         $w3tc_w3_pagespeed = new PageSpeed_Api( $w3tc_access_token );
    121                         $api_response      = $w3tc_w3_pagespeed->analyze( $w3tc_url );
     117                        if ( $w3tc_w3_pagespeed->client->isAccessTokenExpired() ) {
     118                                echo wp_json_encode(
     119                                        array(
     120                                                'refresh_failed' => PageSpeed_Api::get_refresh_pending_message(),
     121                                        )
     122                                );
     123                                return;
     124                        }
     125
     126                        $api_response = $w3tc_w3_pagespeed->analyze( $w3tc_url );
    122127
    123128                        if ( ! $api_response ) {
  • w3-total-cache/tags/2.10.7/PageSpeed_Page_View.js

    r3585227 r3723494  
    6060            .removeClass("w3tc_none");
    6161          return;
    62         } else if (data.missing_token) {
     62        } else if (data.missing_token || data.refresh_failed) {
    6363          $(".w3tcps_buttons").addClass("w3tc_none");
    6464          $("#" + page_post_id)
    6565            .prev()
    6666            .find(".w3tcps_missing_token")
    67             .html(data.missing_token);
     67            .html(data.missing_token || data.refresh_failed);
    6868          $("#" + page_post_id)
    6969            .prev()
  • w3-total-cache/tags/2.10.7/PageSpeed_Widget.php

    r3585227 r3723494  
    140140                        $w3tc_config       = Dispatcher::config();
    141141                        $w3tc_access_token = ! empty( $w3tc_config->get_string( 'widget.pagespeed.access_token' ) ) ? $w3tc_config->get_string( 'widget.pagespeed.access_token' ) : null;
    142 
    143                         if ( empty( $w3tc_access_token ) ) {
     142                        $w3tc_w3_pagespeed = empty( $w3tc_access_token ) ? null : new PageSpeed_Api( $w3tc_access_token );
     143
     144                        // Construction may clear credentials when a refresh is irrecoverable, so re-read the stored token.
     145                        $w3tc_stored_token = $w3tc_config->get_string( 'widget.pagespeed.access_token' );
     146
     147                        if ( empty( $w3tc_w3_pagespeed ) || empty( $w3tc_stored_token ) ) {
    144148                                echo wp_json_encode(
    145149                                        array(
    146                                                 'missing_token' => sprintf(
    147                                                         // translators: 1 HTML a tag to W3TC settings page Google PageSpeed meta box.
    148                                                         __(
    149                                                                 'Before you can get started using the Google PageSpeed tool, you’ll first need to authorize access. Please click %1$s.',
    150                                                                 'w3-total-cache'
    151                                                         ),
    152                                                         '<a href="' . esc_url( Util_Ui::admin_url( 'admin.php?page=w3tc_general#google_pagespeed' ) ) . '" target="_blank">' . esc_html__( 'here', 'w3-total-cache' ) . '</a>'
    153                                                 ),
     150                                                'missing_token' => PageSpeed_Api::get_authorize_required_message(),
    154151                                        )
    155152                                );
    … …  
    157154                        }
    158155
    159                         $w3tc_w3_pagespeed = new PageSpeed_Api( $w3tc_access_token );
    160                         $api_response      = $w3tc_w3_pagespeed->analyze( $home_url );
     156                        if ( $w3tc_w3_pagespeed->client->isAccessTokenExpired() ) {
     157                                echo wp_json_encode(
     158                                        array(
     159                                                'refresh_failed' => PageSpeed_Api::get_refresh_pending_message(),
     160                                        )
     161                                );
     162                                return;
     163                        }
     164
     165                        $api_response = $w3tc_w3_pagespeed->analyze( $home_url );
    161166
    162167                        if ( ! $api_response ) {
  • w3-total-cache/tags/2.10.7/PageSpeed_Widget_View.js

    r3585227 r3723494  
    4444          $(".w3tcps_error").removeClass("w3tc_none");
    4545          return;
    46         } else if (data.missing_token) {
     46        } else if (data.missing_token || data.refresh_failed) {
    4747          $(".w3tcps_analyze").addClass("w3tc_none");
    48           $(".w3tcps_missing_token").html(data.missing_token);
     48          $(".w3tcps_missing_token").html(
     49            data.missing_token || data.refresh_failed,
     50          );
    4951          $(".w3tcps_missing_token").removeClass("w3tc_none");
    5052          return;
  • w3-total-cache/tags/2.10.7/PgCache_ConfigLabels.php

    r3409715 r3723494  
    6868                                'pgcache.prime.interval'            => __( 'Update interval:', 'w3-total-cache' ),
    6969                                'pgcache.prime.limit'               => __( 'Pages per interval:', 'w3-total-cache' ),
     70                                'pgcache.prime.sitemap_one_pass'    => __( 'Preload the sitemap once', 'w3-total-cache' ),
    7071                                'pgcache.prime.sitemap'             => wp_kses(
    7172                                        sprintf(
  • w3-total-cache/tags/2.10.7/PgCache_ContentGrabber.php

    r3680101 r3723494  
    760760                }
    761761
    762                 /**
    763                  * Rewrite rules always list leftover MD5 names so a later
    764                  * grace-constant toggle reaches PHP. That request must not
    765                  * write a rejected-role page into the shared store when the
    766                  * reader is still fail-closed.
    767                  */
    768762                if ( $this->_config->get_boolean( 'pgcache.reject.logged_roles' ) ) {
    769763                        $roles = $this->_config->get_array( 'pgcache.reject.roles' );
    770                         if ( ! empty( $roles ) && Util_Cookie::request_has_legacy_role_cookie( $roles ) ) {
    771                                 $this->cache_reject_reason = 'Rejected user role leftover cookie';
     764                        if ( Util_Cookie::current_user_has_rejected_role( $roles ) ) {
     765                                $this->cache_reject_reason = 'Rejected user role is logged in';
    772766                                $this->process_status      = 'miss_logged_in';
    773767                                return false;
    … …  
    12901284                }
    12911285
    1292                 /**
    1293                  * HMAC names always reject cache. Legacy MD5 names reject
    1294                  * cache only when `W3TC_COOKIE_LEGACY_NAMES_ACCEPTED` is
    1295                  * defined true in wp-config.php (default false as of 2.10.6).
    1296                  */
    12971286                return ! Util_Cookie::request_has_rejected_role_cookie( $roles );
    12981287        }
  • w3-total-cache/tags/2.10.7/PgCache_Environment.php

    r3680101 r3723494  
    122122
    123123                // Schedule prime event.
    124                 if ( $pgcache_enabled && $w3tc_config->get_boolean( 'pgcache.prime.enabled' ) ) {
     124                $prime_enabled = $pgcache_enabled && $w3tc_config->get_boolean( 'pgcache.prime.enabled' );
     125                $one_pass      = $w3tc_config->get_boolean( 'pgcache.prime.sitemap_one_pass' );
     126                $restart_prime = false;
     127                $signature     = $this->prime_settings_signature( $w3tc_config );
     128
     129                if ( null !== $old_config ) {
     130                        $old_prime_enabled = (
     131                                $old_config->get_boolean( 'pgcache.enabled' ) &&
     132                                $old_config->get_boolean( 'pgcache.prime.enabled' )
     133                        );
     134                        $restart_prime     = $prime_enabled && (
     135                                ! $old_prime_enabled ||
     136                                $one_pass !== $old_config->get_boolean( 'pgcache.prime.sitemap_one_pass' ) ||
     137                                $w3tc_config->get_string( 'pgcache.prime.sitemap' ) !==
     138                                        $old_config->get_string( 'pgcache.prime.sitemap' )
     139                        );
     140                } else {
     141                        $stored_signature = get_option( PgCache_Plugin_Admin::PRIME_SETTINGS_OPTION, false );
     142                        $restart_prime    = (
     143                                $prime_enabled &&
     144                                false !== $stored_signature &&
     145                                ! hash_equals( (string) $stored_signature, $signature )
     146                        );
     147                }
     148
     149                if ( 'activate' === $event && $prime_enabled ) {
     150                        $restart_prime = true;
     151                }
     152
     153                if ( ! $prime_enabled || $restart_prime ) {
     154                        PgCache_Plugin_Admin::reset_prime();
     155                }
     156
     157                update_option( PgCache_Plugin_Admin::PRIME_SETTINGS_OPTION, $signature, false );
     158
     159                $prime_completed = (
     160                        $one_pass &&
     161                        PgCache_Plugin_Admin::prime_generation() ===
     162                                get_option( PgCache_Plugin_Admin::PRIME_COMPLETED_OPTION, false )
     163                );
     164
     165                if ( $prime_enabled && ! $prime_completed ) {
    125166                        $new_interval = $w3tc_config->get_integer( 'pgcache.prime.interval' );
    126167                        $old_interval = $old_config ? $old_config->get_integer( 'pgcache.prime.interval' ) : -1;
    127168
    128                         if ( null !== $old_config && $new_interval !== $old_interval ) {
     169                        if ( $restart_prime || ( null !== $old_config && $new_interval !== $old_interval ) ) {
    129170                                $this->unschedule_prime();
    130171                        }
    … …  
    146187                        }
    147188                }
     189        }
     190
     191        /**
     192         * Creates the per-site signature for effective preload settings.
     193         *
     194         * @since 2.10.7
     195         *
     196         * @param Config $w3tc_config W3TC configuration.
     197         *
     198         * @return string
     199         */
     200        private function prime_settings_signature( $w3tc_config ) {
     201                return hash(
     202                        'sha256',
     203                        wp_json_encode(
     204                                array(
     205                                        'enabled'  => (
     206                                                $w3tc_config->get_boolean( 'pgcache.enabled' ) &&
     207                                                $w3tc_config->get_boolean( 'pgcache.prime.enabled' )
     208                                        ),
     209                                        'one_pass' => $w3tc_config->get_boolean( 'pgcache.prime.sitemap_one_pass' ),
     210                                        'sitemap'  => $w3tc_config->get_string( 'pgcache.prime.sitemap' ),
     211                                )
     212                        )
     213                );
    148214        }
    149215
    … …  
    190256                $this->unschedule_prime();
    191257                $this->unschedule_purge_wpcron();
     258                PgCache_Plugin_Admin::reset_prime();
    192259
    193260                if ( count( $exs->exceptions() ) > 0 ) {
    … …  
    496563        private function wp_config_add_directive() {
    497564                $config_path = Util_Environment::wp_config_path();
     565                if ( ! is_string( $config_path ) || '' === $config_path ) {
     566                        return;
     567                }
    498568
    499569                $config_data = @file_get_contents( $config_path );
    … …  
    540610        private function wp_config_remove_directive() {
    541611                $config_path = Util_Environment::wp_config_path();
     612                if ( ! is_string( $config_path ) || '' === $config_path ) {
     613                        return;
     614                }
    542615
    543616                $config_data = @file_get_contents( $config_path );
  • w3-total-cache/tags/2.10.7/PgCache_Plugin.php

    r3610528 r3723494  
    134134         */
    135135        public function prime() {
    136                 $this->get_admin()->prime();
     136                $one_pass   = $this->_config->get_boolean( 'pgcache.prime.sitemap_one_pass' );
     137                $generation = PgCache_Plugin_Admin::prime_generation();
     138
     139                if (
     140                        $one_pass &&
     141                        get_option( PgCache_Plugin_Admin::PRIME_COMPLETED_OPTION, false ) === $generation
     142                ) {
     143                        wp_clear_scheduled_hook( 'w3_pgcache_prime' );
     144                        return;
     145                }
     146
     147                $lock = PgCache_Plugin_Admin::acquire_prime_lock();
     148                if ( false === $lock ) {
     149                        return;
     150                }
     151
     152                try {
     153                        $result = $this->get_admin()->prime( null, null, null, true, $lock['generation'] );
     154
     155                        if (
     156                                $one_pass &&
     157                                ! empty( $result['success'] ) &&
     158                                ! empty( $result['complete'] ) &&
     159                                empty( $result['stale'] ) &&
     160                                PgCache_Plugin_Admin::prime_generation() === $lock['generation']
     161                        ) {
     162                                update_option( PgCache_Plugin_Admin::PRIME_COMPLETED_OPTION, $lock['generation'], false );
     163
     164                                if ( PgCache_Plugin_Admin::prime_generation() === $lock['generation'] ) {
     165                                        wp_clear_scheduled_hook( 'w3_pgcache_prime' );
     166                                }
     167                        }
     168                } finally {
     169                        PgCache_Plugin_Admin::release_prime_lock( $lock['token'] );
     170                }
    137171        }
    138172
  • w3-total-cache/tags/2.10.7/PgCache_Plugin_Admin.php

    r3585227 r3723494  
    1717class PgCache_Plugin_Admin {
    1818        /**
     19         * Option storing the next sitemap entry to preload.
     20         *
     21         * @since 2.10.7
     22         *
     23         * @var string
     24         */
     25        const PRIME_OFFSET_OPTION = 'w3tc_pgcache_prime_offset';
     26
     27        /**
     28         * Option recording completion of a one-pass preload.
     29         *
     30         * @since 2.10.7
     31         *
     32         * @var string
     33         */
     34        const PRIME_COMPLETED_OPTION = 'w3tc_pgcache_prime_completed';
     35
     36        /**
     37         * Option identifying the current preload pass.
     38         *
     39         * @since 2.10.7
     40         *
     41         * @var string
     42         */
     43        const PRIME_GENERATION_OPTION = 'w3tc_pgcache_prime_generation';
     44
     45        /**
     46         * Option coordinating overlapping preload callbacks.
     47         *
     48         * @since 2.10.7
     49         *
     50         * @var string
     51         */
     52        const PRIME_LOCK_OPTION = 'w3tc_pgcache_prime_lock';
     53
     54        /**
     55         * Option storing the effective preload settings signature.
     56         *
     57         * @since 2.10.7
     58         *
     59         * @var string
     60         */
     61        const PRIME_SETTINGS_OPTION = 'w3tc_pgcache_prime_settings';
     62
     63        /**
     64         * Maximum preload lock lifetime.
     65         *
     66         * @since 2.10.7
     67         *
     68         * @var int
     69         */
     70        const PRIME_LOCK_TTL = 3600;
     71
     72        /**
     73         * Sitemap traversal completed.
     74         *
     75         * @since 2.10.7
     76         *
     77         * @var string
     78         */
     79        const SITEMAP_OUTCOME_SUCCESS = 'success';
     80
     81        /**
     82         * Sitemap entry was excluded by traversal policy.
     83         *
     84         * @since 2.10.7
     85         *
     86         * @var string
     87         */
     88        const SITEMAP_OUTCOME_SKIPPED = 'skipped';
     89
     90        /**
     91         * Sitemap traversal encountered a retryable failure.
     92         *
     93         * @since 2.10.7
     94         *
     95         * @var string
     96         */
     97        const SITEMAP_OUTCOME_FAILURE = 'failure';
     98
     99        /**
    19100         * Config
    20101         *
    … …  
    30111        public function __construct() {
    31112                $this->_config = Dispatcher::config();
     113        }
     114
     115        /**
     116         * Returns the current per-site preload generation.
     117         *
     118         * @since 2.10.7
     119         *
     120         * @return string
     121         */
     122        public static function prime_generation() {
     123                $generation = get_option( self::PRIME_GENERATION_OPTION, '' );
     124
     125                if ( '' === $generation ) {
     126                        $generation = wp_generate_uuid4();
     127                        add_option( self::PRIME_GENERATION_OPTION, $generation, '', false );
     128                        $generation = get_option( self::PRIME_GENERATION_OPTION, $generation );
     129                }
     130
     131                return (string) $generation;
     132        }
     133
     134        /**
     135         * Resets per-site preload progress and starts a new generation.
     136         *
     137         * The lock is retained so an in-flight callback remains the only writer.
     138         * Its generation becomes stale and it will discard any progress.
     139         *
     140         * @since 2.10.7
     141         *
     142         * @return string New generation.
     143         */
     144        public static function reset_prime() {
     145                $generation = wp_generate_uuid4();
     146
     147                update_option( self::PRIME_GENERATION_OPTION, $generation, false );
     148                update_option( self::PRIME_OFFSET_OPTION, 0, false );
     149                delete_option( self::PRIME_COMPLETED_OPTION );
     150
     151                return $generation;
     152        }
     153
     154        /**
     155         * Acquires the per-site preload lock.
     156         *
     157         * @since 2.10.7
     158         *
     159         * @return array|false Lock data, or false when another run is active.
     160         */
     161        public static function acquire_prime_lock() {
     162                $lock = get_option( self::PRIME_LOCK_OPTION, false );
     163
     164                if ( is_array( $lock ) && isset( $lock['expires'] ) && (int) $lock['expires'] <= time() ) {
     165                        delete_option( self::PRIME_LOCK_OPTION );
     166                        $lock = false;
     167                }
     168
     169                if ( false !== $lock ) {
     170                        return false;
     171                }
     172
     173                $lock = array(
     174                        'token'      => wp_generate_uuid4(),
     175                        'generation' => self::prime_generation(),
     176                        'expires'    => time() + self::PRIME_LOCK_TTL,
     177                );
     178
     179                if ( ! add_option( self::PRIME_LOCK_OPTION, $lock, '', false ) ) {
     180                        return false;
     181                }
     182
     183                return $lock;
     184        }
     185
     186        /**
     187         * Releases a preload lock owned by the supplied token.
     188         *
     189         * @since 2.10.7
     190         *
     191         * @param string $token Lock token.
     192         *
     193         * @return void
     194         */
     195        public static function release_prime_lock( $token ) {
     196                $lock = get_option( self::PRIME_LOCK_OPTION, false );
     197
     198                if ( is_array( $lock ) && isset( $lock['token'] ) && hash_equals( (string) $lock['token'], (string) $token ) ) {
     199                        delete_option( self::PRIME_LOCK_OPTION );
     200                }
    32201        }
    33202
    … …  
    137306         * @param int|null      $w3tc_limit        The limit for how many pages to prime, or null for the default limit.
    138307         * @param callable|null $log_callback A callback function for logging progress, or null to disable logging.
    139          *
    140          * @return void
    141          */
    142         public function prime( $start = null, $w3tc_limit = null, $log_callback = null ) {
     308         * @param bool          $update_progress Whether to update scheduled preload progress.
     309         * @param string|null   $generation Preload generation allowed to update progress.
     310         *
     311         * @return array Preload result.
     312         */
     313        public function prime(
     314                $start = null,
     315                $w3tc_limit = null,
     316                $log_callback = null,
     317                $update_progress = true,
     318                $generation = null
     319        ) {
     320                $result = array(
     321                        'success'   => false,
     322                        'processed' => 0,
     323                        'complete'  => false,
     324                        'stale'     => false,
     325                );
     326
    143327                if ( is_null( $start ) ) {
    144                         $start = get_option( 'w3tc_pgcache_prime_offset' );
     328                        $start = get_option( self::PRIME_OFFSET_OPTION );
    145329                }
    146330
    … …  
    149333                }
    150334
    151                 $interval = $this->_config->get_integer( 'pgcache.prime.interval' );
    152335                if ( is_null( $w3tc_limit ) ) {
    153336                        $w3tc_limit = $this->_config->get_integer( 'pgcache.prime.limit' );
    … …  
    166349                }
    167350
    168                 // Parse XML sitemap.
    169                 $urls = $this->parse_sitemap( $sitemap );
     351                $parse_outcome = self::SITEMAP_OUTCOME_FAILURE;
     352                $urls          = $this->parse_sitemap( $sitemap, null, 0, $parse_outcome );
     353
     354                if ( self::SITEMAP_OUTCOME_FAILURE === $parse_outcome ) {
     355                        return $result;
     356                }
     357
     358                if ( empty( $urls ) ) {
     359                        $result['success']  = true;
     360                        $result['complete'] = true;
     361
     362                        if ( $update_progress ) {
     363                                if ( self::prime_generation() !== $generation ) {
     364                                        $result['stale'] = true;
     365                                        return $result;
     366                                }
     367
     368                                update_option( self::PRIME_OFFSET_OPTION, 0, false );
     369                        }
     370
     371                        return $result;
     372                }
    170373
    171374                // Queue URLs.
    … …  
    178381                }
    179382
    180                 update_option( 'w3tc_pgcache_prime_offset', $next_offset, false );
     383                if ( empty( $queue ) ) {
     384                        if ( $update_progress && self::prime_generation() === $generation ) {
     385                                update_option( self::PRIME_OFFSET_OPTION, 0, false );
     386                        }
     387
     388                        return $result;
     389                }
    181390
    182391                /**
    … …  
    185394                 */
    186395                foreach ( $queue as $w3tc_url ) {
    187                         Util_Http::get( $w3tc_url, array( 'user-agent' => 'WordPress' ) );
     396                        $response = Util_Http::get( $w3tc_url, array( 'user-agent' => 'WordPress' ) );
     397
     398                        if (
     399                                is_wp_error( $response ) ||
     400                                200 > wp_remote_retrieve_response_code( $response ) ||
     401                                500 <= wp_remote_retrieve_response_code( $response )
     402                        ) {
     403                                return $result;
     404                        }
    188405
    189406                        if ( ! is_null( $log_callback ) ) {
    … …  
    191408                        }
    192409                }
     410
     411                $result['success']   = true;
     412                $result['processed'] = count( $queue );
     413                $result['complete']  = 0 === $next_offset;
     414
     415                if ( $update_progress ) {
     416                        if ( self::prime_generation() !== $generation ) {
     417                                $result['stale'] = true;
     418                                return $result;
     419                        }
     420
     421                        update_option( self::PRIME_OFFSET_OPTION, $next_offset, false );
     422
     423                        if ( self::prime_generation() !== $generation ) {
     424                                update_option( self::PRIME_OFFSET_OPTION, 0, false );
     425                                $result['stale'] = true;
     426                        }
     427                }
     428
     429                return $result;
    193430        }
    194431
    … …  
    216453         *                                   fetches must match. Auto-populated.
    217454         * @param int         $depth         Internal: current recursion depth (0-based).
     455         * @param string|null $outcome       Set to a SITEMAP_OUTCOME_* value.
    218456         *
    219457         * @return array The list of URLs parsed from the sitemap.
    220458         */
    221         public function parse_sitemap( $w3tc_url, $origin_host = null, $depth = 0 ) {
     459        public function parse_sitemap( $w3tc_url, $origin_host = null, $depth = 0, &$outcome = null ) {
     460                $outcome = self::SITEMAP_OUTCOME_FAILURE;
     461
    222462                if ( ! Util_Environment::is_url( $w3tc_url ) ) {
    223463                        $w3tc_url = home_url( $w3tc_url );
    … …  
    235475                 */
    236476                if ( $depth > 3 ) {
     477                        $outcome = self::SITEMAP_OUTCOME_SKIPPED;
    237478                        return array();
    238479                }
    … …  
    243484                 */
    244485                if ( ! Util_Url::is_public_host( $w3tc_url ) ) {
     486                        // A refused root may be a transient resolution failure and must retry.
     487                        if ( $depth > 0 ) {
     488                                $outcome = self::SITEMAP_OUTCOME_SKIPPED;
     489                        }
    245490                        return array();
    246491                }
    … …  
    255500                         * drop it from the fetch list.
    256501                         */
     502                        $outcome = self::SITEMAP_OUTCOME_SKIPPED;
    257503                        return array();
    258504                }
    259505
    260                 $urls     = array( $w3tc_url );
     506                $urls     = array();
    261507                $response = Util_Http::get( $w3tc_url );
    262508
    263                 if ( ! is_wp_error( $response ) && 200 === $response['response']['code'] ) {
    264                         $url_matches     = null;
    265                         $sitemap_matches = null;
    266 
    267                         /**
    268                          * Parse the fetched sitemap XML with XXE protections. The body is
    269                          * fetched from an admin-configured (and origin-host-constrained)
    270                          * sitemap URL, so a hostile or compromised endpoint must not be
    271                          * able to use external entities to read local files or pivot to
    272                          * internal services. Util_Environment::safe_simplexml_load_string()
    273                          * also handles the libxml error-suppression dance.
    274                          */
    275                         $xml = Util_Environment::safe_simplexml_load_string( $response['body'] );
    276 
    277                         // Check if the XML load failed; return the URLs found so far (sitemap URL).
    278                         if ( false === $xml ) {
    279                                 return $urls;
    280                         }
    281 
    282                         if ( $xml->getName() === 'sitemapindex' ) {
    283                                 foreach ( $xml->sitemap as $sitemap ) {
    284                                         if ( $sitemap->loc ) {
    285                                                 $urls = array_merge(
    286                                                         $urls,
    287                                                         $this->parse_sitemap( (string) $sitemap->loc, $origin_host, $depth + 1 )
    288                                                 );
     509                if ( is_wp_error( $response ) || 200 !== wp_remote_retrieve_response_code( $response ) ) {
     510                        return $urls;
     511                }
     512
     513                /**
     514                 * Parse the fetched sitemap XML with XXE protections. The body is
     515                 * fetched from an admin-configured (and origin-host-constrained)
     516                 * sitemap URL, so a hostile or compromised endpoint must not be
     517                 * able to use external entities to read local files or pivot to
     518                 * internal services. Util_Environment::safe_simplexml_load_string()
     519                 * also handles the libxml error-suppression dance.
     520                 */
     521                $xml = Util_Environment::safe_simplexml_load_string( $response['body'] );
     522
     523                if ( false === $xml ) {
     524                        return $urls;
     525                }
     526
     527                if ( $xml->getName() === 'sitemapindex' ) {
     528                        foreach ( $xml->sitemap as $sitemap ) {
     529                                if ( $sitemap->loc ) {
     530                                        $child_outcome = self::SITEMAP_OUTCOME_FAILURE;
     531                                        $child_urls    = $this->parse_sitemap(
     532                                                (string) $sitemap->loc,
     533                                                $origin_host,
     534                                                $depth + 1,
     535                                                $child_outcome
     536                                        );
     537
     538                                        if ( self::SITEMAP_OUTCOME_FAILURE === $child_outcome ) {
     539                                                return array();
    289540                                        }
     541
     542                                        $urls = array_merge( $urls, $child_urls );
    290543                                }
    291                         } elseif ( $xml->getName() === 'urlset' ) {
    292                                 $locs = array();
    293 
    294                                 foreach ( $xml->url as $w3tc_url ) {
    295                                         if ( $w3tc_url->loc ) {
    296                                                 $priority                        = isset( $w3tc_url->priority ) ? (float) $w3tc_url->priority : 0.5;
    297                                                 $locs[ (string) $w3tc_url->loc ] = $priority;
    298                                         }
     544                        }
     545                } elseif ( $xml->getName() === 'urlset' ) {
     546                        $locs = array();
     547
     548                        foreach ( $xml->url as $w3tc_url ) {
     549                                if ( $w3tc_url->loc ) {
     550                                        $priority                        = isset( $w3tc_url->priority ) ? (float) $w3tc_url->priority : 0.5;
     551                                        $locs[ (string) $w3tc_url->loc ] = $priority;
    299552                                }
    300 
    301                                 arsort( $locs );
    302 
    303                                 $urls = array_merge( $urls, array_keys( $locs ) );
    304                         } elseif ( $xml->getName() === 'rss' ) {
    305                                 foreach ( $xml->channel->item as $w3tc_item ) {
    306                                         if ( $w3tc_item->link ) {
    307                                                 $urls[] = (string) $w3tc_item->link;
    308                                         }
     553                        }
     554
     555                        arsort( $locs );
     556
     557                        $urls = array_keys( $locs );
     558                } elseif ( $xml->getName() === 'rss' ) {
     559                        foreach ( $xml->channel->item as $w3tc_item ) {
     560                                if ( $w3tc_item->link ) {
     561                                        $urls[] = (string) $w3tc_item->link;
    309562                                }
    310563                        }
    311                 }
    312 
     564                } else {
     565                        return $urls;
     566                }
     567
     568                $outcome = self::SITEMAP_OUTCOME_SUCCESS;
    313569                return $urls;
    314570        }
  • w3-total-cache/tags/2.10.7/Root_Environment.php

    r3585227 r3723494  
    7979                foreach ( $this->get_handlers() as $h ) {
    8080                        try {
    81                                 $h->fix_on_event( $w3tc_config, $event );
     81                                $h->fix_on_event( $w3tc_config, $event, $old_config );
    8282                        } catch ( Util_Environment_Exceptions $ex ) {
    8383                                $exs->push( $ex );
  • w3-total-cache/tags/2.10.7/Util_Cookie.php

    r3680101 r3723494  
    4242 *    `AUTH_KEY`/`AUTH_SALT` invalidates these cookies cleanly.
    4343 *
    44  *    Migration: HMAC names are written and accepted. Legacy MD5
    45  *    names are no longer accepted on the cache-auth read path
    46  *    unless `W3TC_COOKIE_LEGACY_NAMES_ACCEPTED` is defined true in
    47  *    wp-config.php. Rewrite-rule emitters always list both names so
    48  *    a later constant toggle reaches PHP on disk-enhanced installs
    49  *    without regenerating rules. The PHP writer still refuses to
    50  *    store a response when a leftover MD5 name is present, so the
    51  *    rewrite superset cannot land a rejected-role page in the
    52  *    shared store. Logout still clears leftover legacy cookies.
     44 *    Role cookies use HMAC names only. Pre-HMAC leftover cookies
     45 *    are ignored on read and write.
    5346 *
    5447 * @since 2.10.0
    5548 */
    5649class Util_Cookie {
    57 
    58         /**
    59          * Whether a legacy role cookie has already been audit-logged
    60          * this request.
    61          *
    62          * @since 2.10.6
    63          *
    64          * @var bool
    65          */
    66         private static $legacy_honor_logged = false;
    67 
    68         /**
    69          * Role slug waiting to be audit-logged after plugins load.
    70          *
    71          * @since 2.10.6
    72          *
    73          * @var string|null
    74          */
    75         private static $legacy_honor_pending_role = null;
    7650
    7751        /**
    … …  
    205179
    206180        /**
    207          * Returns the legacy MD5 cookie-name suffix for a given WP role.
    208          *
    209          * Writers always use `role_cookie_name()`. Cache-auth readers
    210          * honor this only when `legacy_role_names_accepted()` is true.
    211          * Rewrite-rule emitters always list it so toggling the
    212          * wp-config constant does not require regenerating rules.
    213          * Logout still uses it to clear leftover pre-upgrade cookies.
    214          *
    215          * @since 2.10.0
    216          *
    217          * @param string $role WordPress role slug.
    218          *
    219          * @return string 32-char lowercase hex.
    220          */
    221         public static function role_cookie_name_legacy( $role ) {
    222                 $nonce_key = defined( 'NONCE_KEY' ) ? (string) NONCE_KEY : '';
    223 
    224                 return \md5( $nonce_key . (string) $role );
    225         }
    226 
    227         /**
    228          * Whether cache-auth readers may honor the pre-HMAC MD5
    229          * role-cookie name.
    230          *
    231          * Default is false (fail closed). The only production switch is
    232          * `W3TC_COOKIE_LEGACY_NAMES_ACCEPTED` defined true in
    233          * wp-config.php. A plugin filter cannot reach the
    234          * `advanced-cache.php` path and is therefore not consulted.
    235          * Rewrite reject lists always include both names; this method
    236          * is the live PHP read decision. The PHP writer uses
    237          * `request_has_legacy_role_cookie()` and refuses leftover MD5
    238          * names even when this returns false.
    239          *
    240          * @since 2.10.6
    241          *
    242          * @return bool
    243          */
    244         public static function legacy_role_names_accepted() {
    245                 return defined( 'W3TC_COOKIE_LEGACY_NAMES_ACCEPTED' ) && true === W3TC_COOKIE_LEGACY_NAMES_ACCEPTED;
    246         }
    247 
    248         /**
    249181         * Cookie names written into page-cache rewrite reject lists
    250182         * for a given role.
    251          *
    252          * Always includes the HMAC name and the leftover MD5 name.
    253          * Disk-enhanced Apache/Nginx serve static files before PHP
    254          * runs, so the leftover name must stay in the generated rules
    255          * or a later `W3TC_COOKIE_LEGACY_NAMES_ACCEPTED` toggle cannot
    256          * take effect until rules are rewritten. The PHP reader still
    257          * consults `legacy_role_names_accepted()` on every request.
    258183         *
    259184         * @since 2.10.6
    … …  
    266191                return array(
    267192                        'w3tc_logged_' . self::role_cookie_name( $role ),
    268                         'w3tc_logged_' . self::role_cookie_name_legacy( $role ),
    269193                );
    270194        }
    … …  
    272196        /**
    273197         * Whether a request cookie name matches a rejected role.
    274          *
    275          * HMAC names always match. Legacy MD5 names match only when
    276          * `legacy_role_names_accepted()` is true; a match is audit-logged
    277          * once per request so a site that turns the grace window on is
    278          * visible in `w3tc_audit_log`.
    279198         *
    280199         * Malformed or unrecognized `w3tc_logged_*` names never match.
    … …  
    292211                }
    293212
    294                 $role = (string) $role;
    295 
    296                 if ( false !== \strstr( $cookie_name, self::role_cookie_name( $role ) ) ) {
    297                         return true;
    298                 }
    299 
    300                 if ( ! self::cookie_matches_legacy_role_name( $cookie_name, $role ) ) {
    301                         return false;
    302                 }
    303 
    304                 if ( ! self::legacy_role_names_accepted() ) {
    305                         return false;
    306                 }
    307 
    308                 self::log_legacy_role_cookie_honored( $role );
    309                 return true;
    310         }
    311 
    312         /**
    313          * Whether a request cookie name is the leftover MD5 name for a role.
    314          *
    315          * Independent of `legacy_role_names_accepted()`. Used to refuse
    316          * page-cache writes so a rewrite-listed leftover cookie cannot
    317          * store a rejected-role response.
    318          *
    319          * @since 2.10.6
    320          *
    321          * @param string $cookie_name Raw cookie name from the request.
    322          * @param string $role        WordPress role slug.
    323          *
    324          * @return bool
    325          */
    326         public static function cookie_matches_legacy_role_name( $cookie_name, $role ) {
    327                 if ( ! is_string( $cookie_name ) || 0 !== \strpos( $cookie_name, 'w3tc_logged_' ) ) {
    328                         return false;
    329                 }
    330 
    331                 return false !== \strstr( $cookie_name, self::role_cookie_name_legacy( (string) $role ) );
     213                return false !== \strstr( $cookie_name, self::role_cookie_name( (string) $role ) );
    332214        }
    333215
    … …  
    362244
    363245        /**
    364          * Whether the current request carries a leftover MD5 role cookie.
    365          *
    366          * True regardless of `W3TC_COOKIE_LEGACY_NAMES_ACCEPTED`. Page
    367          * cache must not *write* in that case; *read* still follows
    368          * `request_has_rejected_role_cookie()`.
    369          *
    370          * @since 2.10.6
     246         * Whether the current WordPress user has a rejected page-cache role.
     247         *
     248         * Used on the page-cache write path after WordPress has loaded.
     249         * The early `advanced-cache.php` read path cannot use this.
     250         *
     251         * @since 2.10.7
    371252         *
    372253         * @param string[] $roles Role slugs configured for cache rejection.
    … …  
    374255         * @return bool
    375256         */
    376         public static function request_has_legacy_role_cookie( $roles ) {
     257        public static function current_user_has_rejected_role( $roles ) {
    377258                if ( ! is_array( $roles ) || empty( $roles ) ) {
    378259                        return false;
    379260                }
    380261
    381                 if ( empty( $_COOKIE ) || ! is_array( $_COOKIE ) ) {
    382                         return false;
    383                 }
    384 
    385                 foreach ( \array_keys( $_COOKIE ) as $cookie_name ) {
    386                         foreach ( $roles as $role ) {
    387                                 if ( self::cookie_matches_legacy_role_name( (string) $cookie_name, (string) $role ) ) {
    388                                         return true;
    389                                 }
     262                if ( ! \function_exists( 'is_user_logged_in' ) || ! \function_exists( 'wp_get_current_user' ) ) {
     263                        return false;
     264                }
     265
     266                if ( ! \is_user_logged_in() ) {
     267                        return false;
     268                }
     269
     270                $current_user = \wp_get_current_user();
     271
     272                if ( empty( $current_user->roles ) || ! is_array( $current_user->roles ) ) {
     273                        return false;
     274                }
     275
     276                foreach ( $current_user->roles as $role ) {
     277                        if ( \in_array( $role, $roles, true ) ) {
     278                                return true;
    390279                        }
    391280                }
    … …  
    393282                return false;
    394283        }
    395 
    396         /**
    397          * Audit-log that a legacy MD5 role cookie was honored.
    398          *
    399          * Once per request. Does not record cookie names. When this
    400          * runs from `advanced-cache.php`, `w3tc_audit_log` subscribers
    401          * have not registered yet, so the event is deferred until
    402          * `plugins_loaded`. Honoring the cookie skips page cache, so
    403          * WordPress continues and the hook fires.
    404          *
    405          * @since 2.10.6
    406          *
    407          * @param string $role WordPress role slug.
    408          *
    409          * @return void
    410          */
    411         private static function log_legacy_role_cookie_honored( $role ) {
    412                 if ( self::$legacy_honor_logged ) {
    413                         return;
    414                 }
    415 
    416                 self::$legacy_honor_logged       = true;
    417                 self::$legacy_honor_pending_role = (string) $role;
    418 
    419                 if ( \function_exists( 'did_action' ) && \function_exists( 'add_action' ) && ! \did_action( 'plugins_loaded' ) ) {
    420                         \add_action(
    421                                 'plugins_loaded',
    422                                 array( __CLASS__, 'flush_legacy_honor_log' ),
    423                                 \PHP_INT_MAX
    424                         );
    425                         return;
    426                 }
    427 
    428                 self::flush_legacy_honor_log();
    429         }
    430 
    431         /**
    432          * Dispatch a deferred legacy-honor audit event.
    433          *
    434          * @since 2.10.6
    435          *
    436          * @internal Invoked from `plugins_loaded`. Unit tests may call directly.
    437          *
    438          * @return void
    439          */
    440         public static function flush_legacy_honor_log() {
    441                 if ( null === self::$legacy_honor_pending_role ) {
    442                         return;
    443                 }
    444 
    445                 $role                            = self::$legacy_honor_pending_role;
    446                 self::$legacy_honor_pending_role = null;
    447 
    448                 Util_Debug::audit_log(
    449                         'cookie.legacy_role_name',
    450                         array(
    451                                 'role' => $role,
    452                         )
    453                 );
    454         }
    455 
    456         /**
    457          * Resets the once-per-request legacy honor log.
    458          *
    459          * @since 2.10.6
    460          *
    461          * @internal Unit tests only.
    462          *
    463          * @return void
    464          */
    465         public static function reset_legacy_honor_log() {
    466                 self::$legacy_honor_logged       = false;
    467                 self::$legacy_honor_pending_role = null;
    468 
    469                 if ( \function_exists( 'remove_action' ) ) {
    470                         \remove_action( 'plugins_loaded', array( __CLASS__, 'flush_legacy_honor_log' ), \PHP_INT_MAX );
    471                 }
    472         }
    473284}
  • w3-total-cache/tags/2.10.7/Util_Environment.php

    r3680101 r3723494  
    22072207                                        $cidrs = array();
    22082208                                }
    2209                         } catch ( \Exception $e ) { // phpcs:ignore Generic.CodeAnalysis.EmptyStatement.DetectedCatch
     2209                        } catch ( \Throwable $e ) { // phpcs:ignore Generic.CodeAnalysis.EmptyStatement.DetectedCatch
    22102210                                $cidrs = array();
    22112211                        }
    … …  
    22492249                                        );
    22502250                                }
    2251                         } catch ( \Exception $e ) { // phpcs:ignore Generic.CodeAnalysis.EmptyStatement.DetectedCatch
     2251                        } catch ( \Throwable $e ) { // phpcs:ignore Generic.CodeAnalysis.EmptyStatement.DetectedCatch
    22522252                                $cidrs = array();
    22532253                        }
  • w3-total-cache/tags/2.10.7/Util_Http.php

    r3680101 r3723494  
    103103                }
    104104
     105                $public_only = ! empty( $args['w3tc_public_only'] );
     106                $https_only  = ! empty( $args['w3tc_https_only'] );
     107                $same_host   = ! empty( $args['w3tc_same_host'] );
     108                $max_size    = isset( $args['w3tc_max_response_size'] ) ? (int) $args['w3tc_max_response_size'] : 0;
     109                $validator   = isset( $args['w3tc_response_validator'] ) && \is_callable( $args['w3tc_response_validator'] ) ?
     110                        $args['w3tc_response_validator'] :
     111                        null;
     112                unset(
     113                        $args['w3tc_public_only'],
     114                        $args['w3tc_https_only'],
     115                        $args['w3tc_same_host'],
     116                        $args['w3tc_max_response_size'],
     117                        $args['w3tc_response_validator']
     118                );
     119
     120                $original_host = self::normalized_url_host( $w3tc_url );
     121                if ( $same_host && '' === $original_host ) {
     122                        return false;
     123                }
     124
    105125                /**
    106126                 * Follow Location responses manually so each hop is evaluated
    107                  * with {@see Util_Url::is_allowed_outbound_url()} before the next
    108                  * request. Automatic redirect following would skip that check.
     127                 * against the requested policy before the next request.
    109128                 */
    110129                $max_redirects = 5;
    111130                for ( $hop = 0; $hop <= $max_redirects; $hop++ ) {
    112                         if ( ! Util_Url::is_allowed_outbound_url( $w3tc_url ) ) {
     131                        if ( $https_only && 'https' !== \wp_parse_url( $w3tc_url, PHP_URL_SCHEME ) ) {
     132                                return false;
     133                        }
     134
     135                        if ( $same_host && self::normalized_url_host( $w3tc_url ) !== $original_host ) {
     136                                return false;
     137                        }
     138
     139                        $allowed = $public_only ?
     140                                Util_Url::is_public_host( $w3tc_url ) :
     141                                Util_Url::is_allowed_outbound_url( $w3tc_url );
     142                        if ( ! $allowed ) {
    113143                                return false;
    114144                        }
    … …  
    120150                                )
    121151                        );
     152                        if ( $max_size > 0 ) {
     153                                $request_args['limit_response_size'] = $max_size + 1;
     154                        }
    122155
    123156                        $response = self::get( $w3tc_url, $request_args );
    … …  
    145178                        }
    146179
    147                         return (bool) @file_put_contents( $w3tc_file, $response['body'] );
     180                        $body = isset( $response['body'] ) && \is_string( $response['body'] ) ? $response['body'] : '';
     181                        if ( ( $max_size > 0 && \strlen( $body ) > $max_size ) || ( $validator && ! \call_user_func( $validator, $response ) ) ) {
     182                                return false;
     183                        }
     184
     185                        return (bool) @file_put_contents( $w3tc_file, $body );
    148186                }
    149187
    150188                return false;
     189        }
     190
     191        /**
     192         * Returns a normalized host for redirect comparisons.
     193         *
     194         * @since 2.10.7
     195         *
     196         * @param string $url URL to inspect.
     197         *
     198         * @return string
     199         */
     200        private static function normalized_url_host( $url ) {
     201                $host = \wp_parse_url( $url, PHP_URL_HOST );
     202
     203                return \is_string( $host ) ? \strtolower( \rtrim( $host, '.' ) ) : '';
    151204        }
    152205
    … …  
    196249                }
    197250
    198                 $location = Util_Url::normalize_protocol_relative_url( $location );
    199                 if ( '' === $location ) {
    200                         return '';
    201                 }
    202 
    203                 if ( Util_Environment::is_url( $location ) ) {
    204                         return $location;
    205                 }
    206 
    207251                $parts = \wp_parse_url( $current );
    208252                if ( ! \is_array( $parts ) || empty( $parts['scheme'] ) || empty( $parts['host'] ) ) {
    … …  
    210254                }
    211255
    212                 $authority = $parts['scheme'] . '://' . $parts['host'];
    213                 if ( ! empty( $parts['port'] ) ) {
    214                         $authority .= ':' . $parts['port'];
    215                 }
    216 
    217                 if ( isset( $location[0] ) && '/' === $location[0] ) {
    218                         return $authority . $location;
    219                 }
    220 
    221                 $base_path = isset( $parts['path'] ) ? $parts['path'] : '/';
    222                 $base_dir  = \trailingslashit( \dirname( $base_path ) );
    223 
    224                 return $authority . $base_dir . $location;
     256                // A protocol-relative Location keeps the scheme of the hop that returned it.
     257                if ( 0 === \strpos( $location, '//' ) ) {
     258                        $location = $parts['scheme'] . ':' . $location;
     259                }
     260
     261                if ( ! \class_exists( '\WP_Http' ) ) {
     262                        return '';
     263                }
     264
     265                $resolved = \WP_Http::make_absolute_url( $location, $current );
     266
     267                return Util_Url::is_valid_http_scheme( $resolved ) ? $resolved : '';
    225268        }
    226269
  • w3-total-cache/tags/2.10.7/changelog.txt

    r3680101 r3723494  
    11=== W3 Total Cache Changelog ===
     2
     3= 2.10.7 =
     4* Feature: Minify: Cache selected external scripts locally for auto minify
     5* Feature: Page Cache: Add a one-pass mode for sitemap cache preload
     6* Enhancement: Developers: Add a generated reference of supported actions and filters
     7* Fix: Browser Cache: Constrain unquoted URL rewriting when removing query strings from static resources
     8* Fix: Page Cache: Remove the expired role-cookie compatibility path and skip caching for rejected roles
     9* Fix: Page Cache: Avoid Options API calls before WordPress has loaded them during early bootstrap
     10* Fix: Object Cache: Persist cache invalidation from wp-admin when admin object caching is disabled
     11* Fix: CDN: Preserve custom attachment directories when pushing media
     12* Fix: Google PageSpeed: Renew expired access tokens without discarding authorization
     13* Fix: Licensing: Show the activation-limit notice for licenses that have reached their limit
     14* Fix: Settings: Persist Purge via WP-Cron schedule settings
     15* Fix: Settings: Skip unchanged w3tc_state option writes
     16* Update: Remove leftover newsletter signup code
     17* Update: Build: Omit development-only files from the release ZIP
    218
    319= 2.10.6 =
  • w3-total-cache/tags/2.10.7/inc/options/common/footer.php

    r3585227 r3723494  
    112112                        <div class="w3tc-footer-inner-column-50">
    113113                                <h2><?php esc_html_e( 'Follow Us', 'w3-total-cache' ); ?></h2>
    114                                 <a class="w3tc-footer-link" target="_blank" href="<?php echo esc_url( 'https://www.boldgrid.com/w3-total-cache/newsletter-signup/?utm_source=w3tc&utm_medium=footer_link&utm_campaign=newsletter_signup' ); ?>">
    115                                 <span class="dashicons dashicons-email-alt"></span><?php esc_html_e( 'Newsletter Sign Up', 'w3-total-cache' ); ?>
    116                                 </a>
    117114                                <a class="w3tc-footer-link" target="_blank" href="<?php echo esc_url( 'https://twitter.com/w3edge' ); ?>" alt="<?php esc_attr_e( 'W3 Edge', 'w3-total-cache' ); ?>">
    118115                                        <span class="dashicons dashicons-twitter"></span><?php esc_html_e( 'W3 Edge', 'w3-total-cache' ); ?>
  • w3-total-cache/tags/2.10.7/inc/options/general.php

    r3680101 r3723494  
    12661266
    12671267                if ( ! empty( $w3tc_authorize_error ) ) {
    1268                         $w3tc_authorize_error = json_decode( $w3tc_authorize_error );
    1269 
    1270                         if ( 'authorize-in-missing-site-id' === $w3tc_authorize_error->error->id ) {
    1271                                 $w3tc_message = __( 'Unique site ID missing for authorize request!', 'w3-total-cache' );
    1272                         } elseif ( 'authorize-in-missing-auth-url' === $w3tc_authorize_error->error->id ) {
    1273                                 $w3tc_message = __( 'Authorize URL missing for authorize request!', 'w3-total-cache' );
    1274                         } elseif ( 'authorize-in-missing-return-url' === $w3tc_authorize_error->error->id ) {
    1275                                 $w3tc_message = __( 'Return URL missing for authorize request!', 'w3-total-cache' );
    1276                         } elseif ( 'authorize-in-failed' === $w3tc_authorize_error->error->id ) {
    1277                                 $w3tc_message = __( 'Failed to process authorize request!', 'w3-total-cache' );
    1278                         }
    1279 
    1280                         if ( 'authorize-out-code-missing' === $w3tc_authorize_error->error->id ) {
    1281                                 $w3tc_message = __( 'No authorize code returned to W3-API from Google!', 'w3-total-cache' );
    1282                         } elseif ( 'authorize-out-w3tc-pagespeed-key-missing' === $w3tc_authorize_error->error->id ) {
    1283                                 $w3tc_message = __( 'No W3Key return to W3-API from Google!', 'w3-total-cache' );
    1284                         } elseif ( 'authorize-out-not-found' === $w3tc_authorize_error->error->id ) {
    1285                                 $w3tc_message = __( 'No W3-API matching record found during Google authorization return processing!', 'w3-total-cache' );
    1286                         } elseif ( 'authorize-out-token-missing' === $w3tc_authorize_error->error->id ) {
    1287                                 $w3tc_message = __( 'No Google access token found during Google authorization return processing!', 'w3-total-cache' );
    1288                         }
     1268                        $w3tc_message = PageSpeed_Api::get_authorize_failure_message( $w3tc_authorize_error );
    12891269
    12901270                        update_option(
    … …  
    13001280                        exit;
    13011281                } elseif ( ! empty( $w3tc_access_token ) && ! empty( $w3tc_pagespeed_key ) ) {
    1302                         $this->_config->set( 'widget.pagespeed.access_token', $w3tc_access_token );
    1303                         $this->_config->set( 'widget.pagespeed.w3tc_pagespeed_key', $w3tc_pagespeed_key );
    1304                         $this->_config->save();
     1282                        $w3tc_access_token_prepared = PageSpeed_Api::prepare_access_token_json( $w3tc_access_token );
     1283
     1284                        if ( false === $w3tc_access_token_prepared ) {
     1285                                update_option(
     1286                                        'w3tcps_authorize_fail',
     1287                                        __( 'Google PageSpeed Insights API authorization failed.', 'w3-total-cache' )
     1288                                );
     1289                                update_option(
     1290                                        'w3tcps_authorize_fail_message',
     1291                                        __( 'Google PageSpeed authorization returned an unusable access token.', 'w3-total-cache' )
     1292                                );
     1293                        } else {
     1294                                $this->_config->set( 'widget.pagespeed.access_token', $w3tc_access_token_prepared );
     1295                                $this->_config->set( 'widget.pagespeed.w3tc_pagespeed_key', $w3tc_pagespeed_key );
     1296                                $this->_config->save();
     1297                                PageSpeed_Api::clear_failure_notices();
     1298                        }
    13051299
    13061300                        wp_safe_redirect( $w3tc_return_url );
    13071301                        exit;
    13081302                } elseif ( $w3tc_deauthorize ) {
    1309                         $w3tc_w3_pagespeed->reset();
    1310                         update_option(
    1311                                 'w3tcps_authorize_success',
    1312                                 __( 'Google PageSpeed Insights API authorization successfully reset.', 'w3-total-cache' )
    1313                         );
     1303                        if ( $w3tc_w3_pagespeed->reset() ) {
     1304                                update_option(
     1305                                        'w3tcps_authorize_success',
     1306                                        __( 'Google PageSpeed Insights API authorization successfully reset.', 'w3-total-cache' )
     1307                                );
     1308                        }
    13141309                        wp_safe_redirect( $w3tc_return_url );
    13151310                        exit;
  • w3-total-cache/tags/2.10.7/inc/options/pgcache.php

    r3598169 r3723494  
    400400                                        </p>
    401401                                </td>
     402                        </tr>
     403                        <tr>
     404                                <th colspan="2">
     405                                        <?php $this->checkbox( 'pgcache.prime.sitemap_one_pass' ); ?> <?php Util_Ui::e_config_label( 'pgcache.prime.sitemap_one_pass' ); ?></label>
     406                                        <p class="description">
     407                                                <?php esc_html_e( 'Stop cache preloading after every URL in the sitemap has been processed. Disable and re-enable cache preloading to start a new pass.', 'w3-total-cache' ); ?>
     408                                        </p>
     409                                </th>
    402410                        </tr>
    403411                        <tr>
  • w3-total-cache/tags/2.10.7/languages/w3-total-cache.pot

    r3680101 r3723494  
    33msgid ""
    44msgstr ""
    5 "Project-Id-Version: W3 Total Cache 2.10.6\n"
     5"Project-Id-Version: W3 Total Cache 2.10.7\n"
    66"Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/w3-total-cache\n"
    77"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
    … …  
    1010"Content-Type: text/plain; charset=UTF-8\n"
    1111"Content-Transfer-Encoding: 8bit\n"
    12 "POT-Creation-Date: 2026-09-03T16:54:00+00:00\n"
     12"POT-Creation-Date: 2026-10-01T16:35:43+00:00\n"
    1313"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
    1414"X-Generator: WP-CLI 2.12.0\n"
    … …  
    3636#. Author of the plugin
    3737#: w3-total-cache.php
     38#: inc/options/common/footer.php:117
     39#: inc/options/common/footer.php:118
    3840#: inc/options/common/footer.php:120
    3941#: inc/options/common/footer.php:121
    40 #: inc/options/common/footer.php:123
    41 #: inc/options/common/footer.php:124
    4242msgid "BoldGrid"
    4343msgstr ""
    … …  
    156156#: inc/options/minify.php:908
    157157#: inc/options/minify.php:1211
    158 #: inc/options/pgcache.php:1118
     158#: inc/options/pgcache.php:1126
    159159#: Minify_ConfigLabels.php:176
    160160#: Minify_ConfigLabels.php:195
    161 #: PgCache_ConfigLabels.php:130
     161#: PgCache_ConfigLabels.php:131
    162162msgid "Hypertext Transfer Protocol"
    163163msgstr ""
    … …  
    268268#: inc/options/browsercache.php:594
    269269#: inc/options/browsercache.php:920
    270 #: inc/options/pgcache.php:739
    271 #: inc/options/pgcache.php:842
     270#: inc/options/pgcache.php:747
     271#: inc/options/pgcache.php:850
    272272#: Minify_ConfigLabels.php:87
    273 #: PgCache_ConfigLabels.php:77
     273#: PgCache_ConfigLabels.php:78
    274274msgid "Uniform Resource Locator"
    275275msgstr ""
    … …  
    10791079#: inc/options/objectcache.php:233
    10801080#: inc/options/pgcache.php:273
    1081 #: inc/options/pgcache.php:662
    1082 #: inc/options/pgcache.php:675
    1083 #: inc/options/pgcache.php:1056
     1081#: inc/options/pgcache.php:670
     1082#: inc/options/pgcache.php:683
     1083#: inc/options/pgcache.php:1064
    10841084#: Minify_ConfigLabels.php:98
    10851085#: Minify_ConfigLabels.php:133
    10861086#: Minify_ConfigLabels.php:185
    1087 #: PgCache_ConfigLabels.php:105
     1087#: PgCache_ConfigLabels.php:106
    10881088#: SystemOpCache_GeneralPage_View.php:62
    10891089#: UsageStatistics_GeneralPage_View.php:42
    … …  
    14911491#: Cdn_BunnyCdn_Page_View.php:32
    14921492#: Cdn_BunnyCdn_Popup_View_Deauthorize.php:59
    1493 #: inc/options/general.php:1330
     1493#: inc/options/general.php:1325
    14941494msgid "Deauthorize"
    14951495msgstr ""
    … …  
    15031503#: Cdn_RackSpaceCloudFiles_Page_View.php:20
    15041504#: Extension_CloudFlare_Page_View.php:68
    1505 #: inc/options/general.php:1341
     1505#: inc/options/general.php:1336
    15061506msgid "Authorize"
    15071507msgstr ""
    … …  
    27622762#: Cdn_ConfigLabels.php:193
    27632763#: Minify_ConfigLabels.php:239
    2764 #: PgCache_ConfigLabels.php:143
     2764#: PgCache_ConfigLabels.php:144
    27652765msgid "Rejected user agents:"
    27662766msgstr ""
    … …  
    27702770msgstr ""
    27712771
    2772 #: Cdn_Core_Admin.php:815
     2772#: Cdn_Core_Admin.php:817
    27732773msgid "Purge from CDN"
    27742774msgstr ""
    … …  
    30453045#: inc/options/minify.php:204
    30463046#: inc/options/minify.php:230
    3047 #: inc/options/pgcache.php:1120
     3047#: inc/options/pgcache.php:1128
    30483048#: Minify_ConfigLabels.php:38
    30493049#: Util_Ui.php:2388
    … …  
    31123112#: inc/options/general.php:747
    31133113#: inc/options/general.php:782
    3114 #: inc/options/pgcache.php:563
    3115 #: inc/options/pgcache.php:635
     3114#: inc/options/pgcache.php:571
     3115#: inc/options/pgcache.php:643
    31163116msgid "Application Programming Interface"
    31173117msgstr ""
    … …  
    34563456
    34573457#. translators: 1: Error message.
    3458 #: Cli.php:600
     3458#: Cli.php:601
    34593459#, php-format
    34603460msgid "PageCache Priming did failed: %1$s"
    34613461msgstr ""
    34623462
    3463 #: Cli.php:606
     3463#: Cli.php:607
    34643464msgid "PageCache Priming triggered successfully."
    34653465msgstr ""
    34663466
    3467 #: Cli.php:617
     3467#: Cli.php:618
    34683468msgid "Always Cached feature is not enabled."
    34693469msgstr ""
    34703470
    34713471#. translators: 1: Error message.
    3472 #: Cli.php:628
     3472#: Cli.php:629
    34733473#, php-format
    34743474msgid "Always Cached queue processer failed: %1$s"
    34753475msgstr ""
    34763476
    3477 #: Cli.php:634
     3477#: Cli.php:635
    34783478msgid "Always Cached queue processed successfully."
    34793479msgstr ""
    34803480
    3481 #: Cli.php:645
     3481#: Cli.php:646
    34823482msgid "Always Cached feature is not enabled"
    34833483msgstr ""
    34843484
    34853485#. translators: 1: Error message.
    3486 #: Cli.php:656
     3486#: Cli.php:657
    34873487#, php-format
    34883488msgid "Always Cached queue empty failed: %1$s"
    34893489msgstr ""
    34903490
    3491 #: Cli.php:662
     3491#: Cli.php:663
    34923492msgid "Always Cached queue emptied successfully."
    34933493msgstr ""
    … …  
    37913791
    37923792#: DbCache_ConfigLabels.php:29
    3793 #: PgCache_ConfigLabels.php:139
     3793#: PgCache_ConfigLabels.php:140
    37943794msgid "Maximum lifetime of cache objects:"
    37953795msgstr ""
    … …  
    37993799#: Minify_ConfigLabels.php:205
    38003800#: ObjectCache_ConfigLabels.php:29
    3801 #: PgCache_ConfigLabels.php:140
     3801#: PgCache_ConfigLabels.php:141
    38023802msgid "Garbage collection interval:"
    38033803msgstr ""
    38043804
    38053805#: DbCache_ConfigLabels.php:31
    3806 #: PgCache_ConfigLabels.php:145
     3806#: PgCache_ConfigLabels.php:146
    38073807msgid "Never cache the following pages:"
    38083808msgstr ""
    … …  
    38283828#: Extension_AlwaysCached_Page_View_BoxCron.php:35
    38293829#: inc/options/general.php:565
    3830 #: inc/options/pgcache.php:1055
     3830#: inc/options/pgcache.php:1063
    38313831#: Minify_ConfigLabels.php:242
    38323832#: ObjectCache_ConfigLabels.php:34
    … …  
    38373837#: Extension_AlwaysCached_Page_View_BoxCron.php:59
    38383838#: inc/options/general.php:584
    3839 #: inc/options/pgcache.php:1075
     3839#: inc/options/pgcache.php:1083
    38403840#: Minify_ConfigLabels.php:243
    38413841#: ObjectCache_ConfigLabels.php:35
    … …  
    38483848#: Extension_AlwaysCached_Page_View_BoxCron.php:73
    38493849#: inc/options/general.php:595
    3850 #: inc/options/pgcache.php:1086
     3850#: inc/options/pgcache.php:1094
    38513851#: Minify_ConfigLabels.php:244
    38523852#: ObjectCache_ConfigLabels.php:36
    … …  
    41994199#: inc/options/minify.php:1172
    42004200#: inc/options/objectcache.php:257
    4201 #: inc/options/pgcache.php:1078
     4201#: inc/options/pgcache.php:1086
    42024202msgid "This setting controls the initial start time of the cron job. If the selected time has already passed, it will schedule the job for the following day at the selected time."
    42034203msgstr ""
    … …  
    42084208#: inc/options/minify.php:1183
    42094209#: inc/options/objectcache.php:268
    4210 #: inc/options/pgcache.php:1089
     4210#: inc/options/pgcache.php:1097
    42114211msgid "Hourly"
    42124212msgstr ""
    … …  
    42174217#: inc/options/minify.php:1184
    42184218#: inc/options/objectcache.php:269
    4219 #: inc/options/pgcache.php:1090
     4219#: inc/options/pgcache.php:1098
    42204220msgid "Twice Daily"
    42214221msgstr ""
    … …  
    42264226#: inc/options/minify.php:1185
    42274227#: inc/options/objectcache.php:270
    4228 #: inc/options/pgcache.php:1091
     4228#: inc/options/pgcache.php:1099
    42294229msgid "Daily"
    42304230msgstr ""
    … …  
    42354235#: inc/options/minify.php:1186
    42364236#: inc/options/objectcache.php:271
    4237 #: inc/options/pgcache.php:1092
     4237#: inc/options/pgcache.php:1100
    42384238msgid "Weekly"
    42394239msgstr ""
    … …  
    42444244#: inc/options/minify.php:1188
    42454245#: inc/options/objectcache.php:273
    4246 #: inc/options/pgcache.php:1094
     4246#: inc/options/pgcache.php:1102
    42474247msgid "This setting controls the interval that the cron job should occur."
    42484248msgstr ""
    … …  
    51655165#: inc/options/objectcache.php:200
    51665166#: inc/options/pgcache.php:30
    5167 #: inc/options/pgcache.php:1020
     5167#: inc/options/pgcache.php:1028
    51685168#: ObjectCache_DiskPopup_View.php:33
    51695169#: UserExperience_Preload_Requests_Page_View.php:31
    … …  
    52245224#: inc/options/minify.php:943
    52255225#: inc/options/objectcache.php:79
    5226 #: inc/options/pgcache.php:654
     5226#: inc/options/pgcache.php:662
    52275227#: Util_Ui.php:2367
    52285228#: Util_Ui.php:2441
    … …  
    52525252#: inc/options/objectcache.php:105
    52535253#: inc/options/pgcache.php:344
    5254 #: inc/options/pgcache.php:759
    5255 #: inc/options/pgcache.php:785
    5256 #: inc/options/pgcache.php:797
     5254#: inc/options/pgcache.php:767
     5255#: inc/options/pgcache.php:793
     5256#: inc/options/pgcache.php:805
    52575257msgid "seconds"
    52585258msgstr ""
    … …  
    52685268#: inc/options/minify.php:979
    52695269#: inc/options/objectcache.php:107
    5270 #: inc/options/pgcache.php:787
     5270#: inc/options/pgcache.php:795
    52715271msgid "If caching to disk, specify how frequently expired cache data is removed. For busy sites, a lower value is best."
    52725272msgstr ""
    … …  
    60876087#: PageSpeed_Instructions.php:263
    60886088#: PgCache_ConfigLabels.php:27
    6089 #: PgCache_Plugin.php:353
    6090 #: PgCache_Plugin.php:361
    6091 #: PgCache_Plugin.php:369
    6092 #: PgCache_Plugin.php:389
     6089#: PgCache_Plugin.php:387
     6090#: PgCache_Plugin.php:395
     6091#: PgCache_Plugin.php:403
     6092#: PgCache_Plugin.php:423
    60936093#: Root_AdminMenu.php:63
    60946094#: Root_AdminMenu.php:64
    … …  
    88968896#. translators: 1 W3TC_CACHE_FILE_EXPIRE_MAX constant name, 2 W3TC_CACHE_FILE_EXPIRE_MAX value.
    88978897#: inc/options/browsercache.php:681
    8898 #: inc/options/pgcache.php:766
     8898#: inc/options/pgcache.php:774
    88998899#, php-format
    89008900msgid "Max lifetime is limited by the %1$s constant (%2$s seconds) which can be overridden in wp-config.php."
    … …  
    95379537msgstr ""
    95389538
     9539#: inc/options/common/footer.php:114
    95399540#: inc/options/common/footer.php:115
    9540 msgid "Newsletter Sign Up"
    9541 msgstr ""
    9542 
    9543 #: inc/options/common/footer.php:117
    9544 #: inc/options/common/footer.php:118
    95459541msgid "W3 Edge"
    95469542msgstr ""
    95479543
    9548 #: inc/options/common/footer.php:128
     9544#: inc/options/common/footer.php:125
    95499545msgid "Partners"
    95509546msgstr ""
    … …  
    96629658#: inc/options/minify.php:1104
    96639659#: inc/options/objectcache.php:195
    9664 #: inc/options/pgcache.php:1010
     9660#: inc/options/pgcache.php:1018
    96659661#: Util_Ui.php:2284
    96669662#: Util_Ui.php:2368
    … …  
    96779673#: inc/options/dbcache.php:218
    96789674#: inc/options/minify.php:1113
    9679 #: inc/options/pgcache.php:1019
     9675#: inc/options/pgcache.php:1027
    96809676msgid "Scheduling Page Cache purges"
    96819677msgstr ""
    … …  
    97069702#: inc/options/edd/buy.php:47
    97079703#: inc/options/pgcache.php:105
     9704#: PageSpeed_Api.php:485
     9705#: PageSpeed_Api.php:503
    97089706#: PageSpeed_Instructions.php:295
    97099707#: PageSpeed_Instructions.php:362
    9710 #: PageSpeed_Page.php:113
    97119708#: PageSpeed_Widget.php:104
    9712 #: PageSpeed_Widget.php:152
    97139709msgid "here"
    97149710msgstr ""
    … …  
    1025210248msgstr ""
    1025310249
    10254 #: inc/options/general.php:1271
    10255 msgid "Unique site ID missing for authorize request!"
    10256 msgstr ""
    10257 
    10258 #: inc/options/general.php:1273
    10259 msgid "Authorize URL missing for authorize request!"
    10260 msgstr ""
    10261 
    10262 #: inc/options/general.php:1275
    10263 msgid "Return URL missing for authorize request!"
    10264 msgstr ""
    10265 
    10266 #: inc/options/general.php:1277
    10267 msgid "Failed to process authorize request!"
    10268 msgstr ""
    10269 
    10270 #: inc/options/general.php:1281
    10271 msgid "No authorize code returned to W3-API from Google!"
    10272 msgstr ""
    10273 
    10274 #: inc/options/general.php:1283
    10275 msgid "No W3Key return to W3-API from Google!"
    10276 msgstr ""
    10277 
    10278 #: inc/options/general.php:1285
    10279 msgid "No W3-API matching record found during Google authorization return processing!"
    10280 msgstr ""
    10281 
     10250#: inc/options/general.php:1272
    1028210251#: inc/options/general.php:1287
    10283 msgid "No Google access token found during Google authorization return processing!"
    10284 msgstr ""
    10285 
    10286 #: inc/options/general.php:1292
    1028710252msgid "Google PageSpeed Insights API authorization failed."
    1028810253msgstr ""
    1028910254
    10290 #: inc/options/general.php:1312
     10255#: inc/options/general.php:1291
     10256msgid "Google PageSpeed authorization returned an unusable access token."
     10257msgstr ""
     10258
     10259#: inc/options/general.php:1306
    1029110260msgid "Google PageSpeed Insights API authorization successfully reset."
    1029210261msgstr ""
    1029310262
    10294 #: inc/options/general.php:1325
     10263#: inc/options/general.php:1320
    1029510264msgid "Valid"
    1029610265msgstr ""
    1029710266
    10298 #: inc/options/general.php:1342
     10267#: inc/options/general.php:1337
    1029910268msgid "Allow W3 Total Cache to connect to the PageSpeed Insights API on your behalf."
    1030010269msgstr ""
    1030110270
    10302 #: inc/options/general.php:1358
     10271#: inc/options/general.php:1353
    1030310272#: Util_Ui.php:2332
    1030410273msgid "Import / Export Settings"
    1030510274msgstr ""
    1030610275
    10307 #: inc/options/general.php:1359
     10276#: inc/options/general.php:1354
    1030810277msgid "This tool allows users to easily transfer their W3 Total Cache plugin settings between different WordPress installations by exporting the current configuration as a file and importing it on another site, ensuring consistent caching and performance optimizations across multiple websites."
    1030910278msgstr ""
    1031010279
    10311 #: inc/options/general.php:1370
     10280#: inc/options/general.php:1365
    1031210281msgid "Import configuration:"
    1031310282msgstr ""
    1031410283
     10284#: inc/options/general.php:1368
     10285msgid "Upload"
     10286msgstr ""
     10287
     10288#: inc/options/general.php:1369
     10289msgid "Upload and replace the active settings file."
     10290msgstr ""
     10291
    1031510292#: inc/options/general.php:1373
    10316 msgid "Upload"
    10317 msgstr ""
    10318 
    10319 #: inc/options/general.php:1374
    10320 msgid "Upload and replace the active settings file."
    10321 msgstr ""
    10322 
    10323 #: inc/options/general.php:1378
    1032410293msgid "Export configuration:"
    1032510294msgstr ""
    1032610295
     10296#: inc/options/general.php:1375
     10297msgid "Download"
     10298msgstr ""
     10299
     10300#: inc/options/general.php:1376
     10301msgid "Download the active settings file."
     10302msgstr ""
     10303
    1032710304#: inc/options/general.php:1380
    10328 msgid "Download"
    10329 msgstr ""
    10330 
    10331 #: inc/options/general.php:1381
    10332 msgid "Download the active settings file."
    10333 msgstr ""
    10334 
    10335 #: inc/options/general.php:1385
    1033610305msgid "Reset configuration:"
    1033710306msgstr ""
    1033810307
    10339 #: inc/options/general.php:1387
     10308#: inc/options/general.php:1382
    1034010309msgid "Restore Default Settings"
    1034110310msgstr ""
    1034210311
    10343 #: inc/options/general.php:1388
     10312#: inc/options/general.php:1383
    1034410313msgid "Revert all settings to the defaults. Any settings staged in preview mode will not be modified."
    1034510314msgstr ""
    … …  
    1078910758
    1079010759#: inc/options/minify.php:1237
    10791 #: inc/options/pgcache.php:808
    10792 #: inc/options/pgcache.php:810
     10760#: inc/options/pgcache.php:816
     10761#: inc/options/pgcache.php:818
    1079310762msgid "Time to Live"
    1079410763msgstr ""
    … …  
    1122111190
    1122211191#: inc/options/pgcache.php:407
     11192msgid "Stop cache preloading after every URL in the sitemap has been processed. Disable and re-enable cache preloading to start a new pass."
     11193msgstr ""
     11194
     11195#: inc/options/pgcache.php:415
    1122311196msgid "Only applies to pages, posts, and custom post types whose status transitioned from a non-published status to the \"published\" status."
    1122411197msgstr ""
    1122511198
    11226 #: inc/options/pgcache.php:416
     11199#: inc/options/pgcache.php:424
    1122711200msgid "Applies after updating any page, post, or custom post type with the final status being \"published\"."
    1122811201msgstr ""
    1122911202
    11230 #: inc/options/pgcache.php:436
     11203#: inc/options/pgcache.php:444
    1123111204msgid "Purge Policy: "
    1123211205msgstr ""
    1123311206
    11234 #: inc/options/pgcache.php:442
     11207#: inc/options/pgcache.php:450
    1123511208msgid "Specify the pages and feeds to purge when posts are created, edited, or comments posted. The defaults are recommended because additional options may reduce server performance:"
    1123611209msgstr ""
    1123711210
    11238 #: inc/options/pgcache.php:443
     11211#: inc/options/pgcache.php:451
    1123911212msgid "Specify pages and feeds to purge"
    1124011213msgstr ""
    1124111214
    11242 #: inc/options/pgcache.php:479
     11215#: inc/options/pgcache.php:487
    1124311216msgid "Choose which feed types should be automatically purged."
    1124411217msgstr ""
    1124511218
    1124611219#. translators: 1 HTML line break tag.
    11247 #: inc/options/pgcache.php:506
     11220#: inc/options/pgcache.php:514
    1124811221#, php-format
    1124911222msgid "Specify number of pages that lists posts (archive etc.) that should be purged on post updates etc., i.e. example.com/ ... example.com/page/5. %1$s0 means all pages that lists posts are purged, i.e. example.com/page/2 ... "
    1125011223msgstr ""
    1125111224
    11252 #: inc/options/pgcache.php:530
     11225#: inc/options/pgcache.php:538
    1125311226msgid "Specify additional pages to purge. Including parent page in path. Ex: parent/posts."
    1125411227msgstr ""
    1125511228
    11256 #: inc/options/pgcache.php:542
     11229#: inc/options/pgcache.php:550
    1125711230msgid "Specify a regular expression that matches your sitemaps."
    1125811231msgstr ""
    1125911232
    1126011233#. translators: 3 opening HTML acronym tag, 4 closing HTML acronym tag.
    11261 #: inc/options/pgcache.php:557
     11234#: inc/options/pgcache.php:565
    1126211235#, php-format
    1126311236msgid "%1$sREST%2$s %3$sAPI%4$s"
    1126411237msgstr ""
    1126511238
    11266 #: inc/options/pgcache.php:561
    11267 #: inc/options/pgcache.php:633
     11239#: inc/options/pgcache.php:569
     11240#: inc/options/pgcache.php:641
    1126811241msgid "REpresentational State Transfer"
    1126911242msgstr ""
    1127011243
    1127111244#. translators: 1 opening HTML acronym tag, 2 closing HTML acronym tag, 3 opening HTML acronym tag, 4 closing HTML acronym tag.
    11272 #: inc/options/pgcache.php:582
     11245#: inc/options/pgcache.php:590
    1127311246#, php-format
    1127411247msgid "Use these controls to determine how the WordPress %1$sREST%2$s %3$sAPI%4$s responds to visitors and integrations. Caching API responses can dramatically reduce load when headless frontends, mobile apps, or third-party services request the same data repeatedly, but you can keep responses uncached for highly dynamic endpoints or disable the API altogether when it is not needed to reduce attack surface."
    1127511248msgstr ""
    1127611249
    11277 #: inc/options/pgcache.php:597
     11250#: inc/options/pgcache.php:605
    1127811251msgid "REST API"
    1127911252msgstr ""
    1128011253
    11281 #: inc/options/pgcache.php:609
     11254#: inc/options/pgcache.php:617
    1128211255msgid "Don't cache"
    1128311256msgstr ""
    1128411257
    11285 #: inc/options/pgcache.php:611
     11258#: inc/options/pgcache.php:619
    1128611259msgid "Cache"
    1128711260msgstr ""
    1128811261
    11289 #: inc/options/pgcache.php:614
     11262#: inc/options/pgcache.php:622
    1129011263msgid "If you're using the WordPress API make sure to use caching to scale performance."
    1129111264msgstr ""
    1129211265
    11293 #: inc/options/pgcache.php:616
     11266#: inc/options/pgcache.php:624
    1129411267msgid "If you use WordPress as a backend for integrations, API caching may be for you. Similar to page caching, repeat requests will benefit by having significantly lower response times and consume fewer resources to deliver. If WordPress is not used as a backend, for additional security, the API can be disabled completely."
    1129511268msgstr ""
    1129611269
    11297 #: inc/options/pgcache.php:619
     11270#: inc/options/pgcache.php:627
    1129811271msgid "Potential API Response Time Gain"
    1129911272msgstr ""
    1130011273
    11301 #: inc/options/pgcache.php:621
     11274#: inc/options/pgcache.php:629
    1130211275msgid "API Response Time"
    1130311276msgstr ""
    1130411277
    11305 #: inc/options/pgcache.php:622
     11278#: inc/options/pgcache.php:630
    1130611279msgid "In a recent test, enabling REST API Caching increased API response times by 84&#37;!"
    1130711280msgstr ""
    1130811281
    1130911282#. translators: 3 opening HTML acronym tag, 4 closing HTML acronym tag.
    11310 #: inc/options/pgcache.php:629
     11283#: inc/options/pgcache.php:637
    1131111284#, php-format
    1131211285msgid "Disable %1$sREST%2$s %3$sAPI%4$s"
    1131311286msgstr ""
    1131411287
    11315 #: inc/options/pgcache.php:658
     11288#: inc/options/pgcache.php:666
    1131611289msgid "Late initialization:"
    1131711290msgstr ""
    1131811291
    11319 #: inc/options/pgcache.php:664
     11292#: inc/options/pgcache.php:672
    1132011293msgid "Enables support for WordPress functionality in fragment caching for the page caching engine. Use of this feature may increase response times."
    1132111294msgstr ""
    1132211295
    11323 #: inc/options/pgcache.php:665
     11296#: inc/options/pgcache.php:673
    1132411297msgid "Late initialization"
    1132511298msgstr ""
    1132611299
    11327 #: inc/options/pgcache.php:671
     11300#: inc/options/pgcache.php:679
    1132811301msgid "Late caching:"
    1132911302msgstr ""
    1133011303
    11331 #: inc/options/pgcache.php:677
     11304#: inc/options/pgcache.php:685
    1133211305msgid "Overwrites key of page caching via custom filters by postponing entry extraction during the init action."
    1133311306msgstr ""
    1133411307
    11335 #: inc/options/pgcache.php:678
     11308#: inc/options/pgcache.php:686
    1133611309msgid "Late caching"
    1133711310msgstr ""
    1133811311
    11339 #: inc/options/pgcache.php:694
     11312#: inc/options/pgcache.php:702
    1134011313msgid "Compatibility mode:"
    1134111314msgstr ""
    1134211315
    11343 #: inc/options/pgcache.php:699
     11316#: inc/options/pgcache.php:707
    1134411317msgid "Decreases performance by ~20% at scale in exchange for increasing interoperability with more hosting environments and WordPress idiosyncrasies. Enable this option if you experience issues with the Apache rules."
    1134511318msgstr ""
    1134611319
    11347 #: inc/options/pgcache.php:707
     11320#: inc/options/pgcache.php:715
    1134811321msgid "Charset:"
    1134911322msgstr ""
    1135011323
    11351 #: inc/options/pgcache.php:712
     11324#: inc/options/pgcache.php:720
    1135211325msgid "Resolve issues incorrect odd character encoding that may appear in cached pages."
    1135311326msgstr ""
    1135411327
    11355 #: inc/options/pgcache.php:720
     11328#: inc/options/pgcache.php:728
    1135611329msgid "Reject HEAD requests:"
    1135711330msgstr ""
    1135811331
    1135911332#. translators: 1 opening HTML acronym tag, 2 closing HTML acronym tag.
    11360 #: inc/options/pgcache.php:735
     11333#: inc/options/pgcache.php:743
    1136111334#, php-format
    1136211335msgid "If disabled, HEAD requests can often be cached resulting in \"empty pages\" being returned for subsequent requests for a %1$sURL%2$s."
    1136311336msgstr ""
    1136411337
    11365 #: inc/options/pgcache.php:760
     11338#: inc/options/pgcache.php:768
    1136611339msgid "Determines the natural expiration time of cache items. The higher the value, the larger the cache."
    1136711340msgstr ""
    1136811341
    1136911342#. translators: 3 opening HTML acronym tag, 4 closing HTML acronym tag.
    11370 #: inc/options/pgcache.php:804
     11343#: inc/options/pgcache.php:812
    1137111344#, php-format
    1137211345msgid "Significantly reduce the default %1$sTTL%2$s for comment cookies to reduce the number of authenticated user traffic. Enter -1 to revert to default %3$sTTL%4$s."
    … …  
    1137411347
    1137511348#. translators: 1 opening HTML acronym tag, 2 closing HTML acronym tag.
    11376 #: inc/options/pgcache.php:838
     11349#: inc/options/pgcache.php:846
    1137711350#, php-format
    1137811351msgid "Always cache %1$sURL%2$ss that use these query string name-value pairs. The value part is not required. But if used, separate name-value pairs with an equals sign (i.e., name=value). Each pair should be on their own line."
    1137911352msgstr ""
    1138011353
    11381 #: inc/options/pgcache.php:865
     11354#: inc/options/pgcache.php:873
    1138211355msgid "Never send cache pages for these user agents."
    1138311356msgstr ""
    1138411357
    11385 #: inc/options/pgcache.php:879
     11358#: inc/options/pgcache.php:887
    1138611359msgid "Never cache pages that use the specified cookies."
    1138711360msgstr ""
    1138811361
    11389 #: inc/options/pgcache.php:894
     11362#: inc/options/pgcache.php:902
    1139011363msgid "Always ignore the specified pages / directories. Supports regular expressions."
    1139111364msgstr ""
    1139211365
    11393 #: inc/options/pgcache.php:908
     11366#: inc/options/pgcache.php:916
    1139411367msgid "Always ignore all pages filed under the specified category slugs."
    1139511368msgstr ""
    1139611369
    11397 #: inc/options/pgcache.php:922
     11370#: inc/options/pgcache.php:930
    1139811371msgid "Always ignore all pages filed under the specified tag slugs."
    1139911372msgstr ""
    1140011373
    11401 #: inc/options/pgcache.php:936
     11374#: inc/options/pgcache.php:944
    1140211375msgid "Always ignore all pages filed under the specified author usernames."
    1140311376msgstr ""
    1140411377
    11405 #: inc/options/pgcache.php:950
     11378#: inc/options/pgcache.php:958
    1140611379msgid "Always ignore all pages filed under the specified custom fields. Separate name-value pairs with an equals sign (i.e., name=value)."
    1140711380msgstr ""
    1140811381
    11409 #: inc/options/pgcache.php:966
     11382#: inc/options/pgcache.php:974
    1141011383msgid "Cache the specified pages / directories even if listed in the \"never cache the following pages\" field. Supports regular expression."
    1141111384msgstr ""
    1141211385
    11413 #: inc/options/pgcache.php:986
     11386#: inc/options/pgcache.php:994
    1141411387msgid "Cache the specified pages even if they don't have trailing slash."
    1141511388msgstr ""
    1141611389
    11417 #: inc/options/pgcache.php:1001
     11390#: inc/options/pgcache.php:1009
    1141811391msgid "Specify additional page headers to cache."
    1141911392msgstr ""
    1142011393
    11421 #: inc/options/pgcache.php:1014
     11394#: inc/options/pgcache.php:1022
    1142211395msgid "Enabling this will schedule a WP-Cron event that will flush the Page Cache. If you prefer to use a system cron job instead of WP-Cron, you can schedule the following command to run at your desired interval: \"wp w3tc flush posts\". If the Always Cached extension is active and enabled, page cache entries will instead be added to the queue instead of being purged from the cache."
    1142311396msgstr ""
    1142411397
    1142511398#. Translators: 3 closing HTML a tag, 4 closing HTML p tag followed by closing HTML div tag.
    11426 #: inc/options/pgcache.php:1034
     11399#: inc/options/pgcache.php:1042
    1142711400#, php-format
    1142811401msgid "%1$sPage Cache is disabled! Enable it %2$shere%3$s to enable this feature.%4$s"
    1142911402msgstr ""
    1143011403
    11431 #: inc/options/pgcache.php:1102
     11404#: inc/options/pgcache.php:1110
    1143211405#: Util_Ui.php:2369
    1143311406#: Util_Ui.php:2443
    … …  
    1143711410
    1143811411#. translators: 5 opening HTML a tag to W3TC BrowserCache admin page, 6 closing HTML a tag.
    11439 #: inc/options/pgcache.php:1114
     11412#: inc/options/pgcache.php:1122
    1144011413#, php-format
    1144111414msgid "Enable %1$sHTTP%2$s compression in the \"%3$sHTML%4$s\" section on %5$sBrowser Cache</a> Settings tab."
    … …  
    1165811631
    1165911632#: lib/NetDNA/NetDNAPresentation.php:74
     11633#: PageSpeed_Api.php:637
     11634#: PageSpeed_Api.php:781
    1166011635msgid "unknown"
    1166111636msgstr ""
    … …  
    1173511710msgstr ""
    1173611711
     11712#. Translators: 1 Product name.
     11713#: Licensing_Plugin_Admin.php:697
     11714#, php-format
     11715msgid "Your %1$s license key is not active and cannot be activated due to the license activation limit being reached."
     11716msgstr ""
     11717
    1173711718#. Translators: 1 Product name, 2 opening HTML a tag to reset license URIs, 3 closing HTML a tag.
    11738 #: Licensing_Plugin_Admin.php:702
     11719#: Licensing_Plugin_Admin.php:717
    1173911720#, php-format
    1174011721msgid "Your %1$s license key is not active for this site. You can switch your license to this website following %2$sthis link%3$s"
    … …  
    1174211723
    1174311724#. Translators: 1 Product name.
    11744 #: Licensing_Plugin_Admin.php:714
    11745 #, php-format
    11746 msgid "Your %1$s license key is not active and cannot be activated due to the license activation limit being reached."
    11747 msgstr ""
    11748 
    11749 #. Translators: 1 Product name.
    11750 #: Licensing_Plugin_Admin.php:724
     11725#: Licensing_Plugin_Admin.php:729
    1175111726#, php-format
    1175211727msgid "The %1$s license key is not active."
    … …  
    1175411729
    1175511730#. Translators: 1 Product name, 2 opening HTML a tag to license setting, 3 closing HTML a tag.
    11756 #: Licensing_Plugin_Admin.php:737
     11731#: Licensing_Plugin_Admin.php:742
    1175711732#, php-format
    1175811733msgid "Your current %1$s Pro license key is not valid. %2$sPlease confirm it%3$s."
    … …  
    1176011735
    1176111736#. translators: 1: Product name, 2: HTML anchor open tag, 3: HTML anchor close tag.
    11762 #: Licensing_Plugin_Admin.php:752
     11737#: Licensing_Plugin_Admin.php:757
    1176311738#, php-format
    1176411739msgid "The %1$s license key cannot be verified. Please %2$scontact support%3$s for assistance."
    1176511740msgstr ""
    1176611741
    11767 #: Licensing_Plugin_Admin.php:861
     11742#: Licensing_Plugin_Admin.php:866
    1176811743#: SetupGuide_Plugin_Admin.php:1574
    1176911744msgid "Accept"
    1177011745msgstr ""
    1177111746
    11772 #: Licensing_Plugin_Admin.php:865
     11747#: Licensing_Plugin_Admin.php:870
    1177311748#: SetupGuide_Plugin_Admin.php:1575
    1177411749msgid "Decline"
    … …  
    1177611751
    1177711752#. translators: 1 opening HTML a tag to W3TC Terms page, 2 closing HTML a tag.
    11778 #: Licensing_Plugin_Admin.php:890
     11753#: Licensing_Plugin_Admin.php:895
    1177911754#, php-format
    1178011755msgid "Our terms of use and privacy policies have been updated. Please %1$sreview%2$s and accept them."
    … …  
    1178211757
    1178311758#. translators: 1: Product name, 2: HTML break tag, 3: Anchor/link open tag, 4: Anchor/link close tag.
    11784 #: Licensing_Plugin_Admin.php:900
     11759#: Licensing_Plugin_Admin.php:905
    1178511760#, php-format
    1178611761msgid "By allowing us to collect data about how %1$s is used, we can improve our features and experience for everyone. This data will not include any personally identifiable information.%2$sFeel free to review our %3$sterms of use and privacy policy%4$s."
    … …  
    1211112086msgstr ""
    1211212087
    12113 #: Minify_MinifiedFileRequestHandler.php:793
     12088#: Minify_MinifiedFileRequestHandler.php:808
    1211412089msgid "Too many minify requests."
    1211512090msgstr ""
    1211612091
    1211712092#. translators: 1 interval in seconds.
    12118 #: Minify_Plugin.php:165
     12093#: Minify_Plugin.php:169
    1211912094#, php-format
    1212012095msgid "[W3TC] Minify Cache file GC (every %d seconds)"
    1212112096msgstr ""
    1212212097
    12123 #: Minify_Plugin.php:363
     12098#: Minify_Plugin.php:391
    1212412099#: Minify_Plugin_Admin.php:68
    1212512100msgid "Minify Cache"
    … …  
    1212712102
    1212812103#. Translators: 1 engine name, 2 reject reason.
    12129 #: Minify_Plugin.php:385
     12104#: Minify_Plugin.php:413
    1213012105#, php-format
    1213112106msgid "Minified using %1$s%2$s"
    … …  
    1222512200
    1222612201#. translators: 1: Cache hits, 2: Cache total cache objects, 3: Engine anme, 4: Reason.
    12227 #: ObjectCache_WpObjectCache_Regular.php:1416
     12202#: ObjectCache_WpObjectCache_Regular.php:1444
    1222812203#, php-format
    1222912204msgid "Object Caching %1$d/%2$d objects using %3$s%4$s"
    1223012205msgstr ""
    1223112206
    12232 #: ObjectCache_WpObjectCache_Regular.php:1425
     12207#: ObjectCache_WpObjectCache_Regular.php:1453
    1223312208msgid "Object Cache debug info:"
    1223412209msgstr ""
    1223512210
    12236 #: ObjectCache_WpObjectCache_Regular.php:1477
     12211#: ObjectCache_WpObjectCache_Regular.php:1505
    1223712212msgid "Object caching is disabled"
    1223812213msgstr ""
    1223912214
    12240 #: ObjectCache_WpObjectCache_Regular.php:1479
     12215#: ObjectCache_WpObjectCache_Regular.php:1507
    1224112216msgid "DONOTCACHEOBJECT constant is defined"
    1224212217msgstr ""
    1224312218
    12244 #: PageSpeed_Api.php:148
     12219#: PageSpeed_Api.php:155
    1224512220msgid "Missing Google access token."
    1224612221msgstr ""
    1224712222
    12248 #: PageSpeed_Api.php:250
     12223#: PageSpeed_Api.php:262
    1224912224msgid "Google PageSpeed access token refresh missing required parameters!"
    1225012225msgstr ""
    1225112226
    1225212227#: PageSpeed_Api.php:278
     12228#: PageSpeed_Api.php:301
     12229msgid "Google PageSpeed access token refresh failed."
     12230msgstr ""
     12231
     12232#: PageSpeed_Api.php:323
     12233msgid "Google PageSpeed access token refresh failed due to an unusable token response."
     12234msgstr ""
     12235
     12236#: PageSpeed_Api.php:364
    1225312237msgid "No site ID provided for access key refresh!"
    1225412238msgstr ""
    1225512239
    12256 #: PageSpeed_Api.php:280
     12240#: PageSpeed_Api.php:367
    1225712241msgid "No W3TC API key provided for access key refresh!"
    1225812242msgstr ""
    1225912243
    12260 #: PageSpeed_Api.php:282
    12261 #: PageSpeed_Api.php:433
     12244#: PageSpeed_Api.php:370
     12245#: PageSpeed_Api.php:768
    1226212246msgid "No matching Google access record found for W3TC API key!"
    1226312247msgstr ""
    1226412248
    12265 #: PageSpeed_Api.php:284
     12249#: PageSpeed_Api.php:373
    1226612250msgid "Matching Google access record found but the refresh token value is blank!"
    1226712251msgstr ""
    1226812252
    12269 #: PageSpeed_Api.php:289
    12270 msgid "Google PageSpeed access token refresh failed."
    12271 msgstr ""
    12272 
    12273 #: PageSpeed_Api.php:309
    12274 msgid "Google PageSpeed access token refresh failed due to response missing access token."
    12275 msgstr ""
    12276 
    12277 #: PageSpeed_Api.php:401
     12253#: PageSpeed_Api.php:376
     12254#: PageSpeed_Api.php:383
     12255msgid "Google rejected the access token refresh. Local authorization was kept for retry."
     12256msgstr ""
     12257
     12258#: PageSpeed_Api.php:379
     12259msgid "The renewed Google access token could not be saved by the W3 API. Local authorization was kept for retry."
     12260msgstr ""
     12261
     12262#. translators: %d: HTTP response code.
     12263#: PageSpeed_Api.php:388
     12264#, php-format
     12265msgid "Unexpected token refresh response (HTTP %d)."
     12266msgstr ""
     12267
     12268#. translators: 1 HTML a tag to W3TC settings page Google PageSpeed meta box.
     12269#: PageSpeed_Api.php:481
     12270#: PageSpeed_Widget.php:100
     12271#, php-format
     12272msgid "Before you can get started using the Google PageSpeed tool, you’ll first need to authorize access. Please click %1$s."
     12273msgstr ""
     12274
     12275#. translators: 1 HTML a tag to W3TC settings page Google PageSpeed meta box.
     12276#: PageSpeed_Api.php:499
     12277#, php-format
     12278msgid "Google PageSpeed access is authorized but could not be renewed on the last attempt. W3 Total Cache will retry automatically. If this continues, reauthorize access %1$s."
     12279msgstr ""
     12280
     12281#: PageSpeed_Api.php:598
     12282msgid "Unique site ID missing for authorize request!"
     12283msgstr ""
     12284
     12285#: PageSpeed_Api.php:601
     12286msgid "Authorize URL missing for authorize request!"
     12287msgstr ""
     12288
     12289#: PageSpeed_Api.php:604
     12290msgid "Return URL missing for authorize request!"
     12291msgstr ""
     12292
     12293#: PageSpeed_Api.php:607
     12294msgid "Failed to process authorize request!"
     12295msgstr ""
     12296
     12297#: PageSpeed_Api.php:610
     12298msgid "No authorize code returned to W3-API from Google!"
     12299msgstr ""
     12300
     12301#: PageSpeed_Api.php:613
     12302msgid "Unique site ID missing during Google authorization return processing!"
     12303msgstr ""
     12304
     12305#: PageSpeed_Api.php:616
     12306msgid "No W3Key returned to W3-API from Google!"
     12307msgstr ""
     12308
     12309#: PageSpeed_Api.php:619
     12310msgid "No W3-API matching record found during Google authorization return processing!"
     12311msgstr ""
     12312
     12313#: PageSpeed_Api.php:622
     12314msgid "No Google access token found during Google authorization return processing!"
     12315msgstr ""
     12316
     12317#: PageSpeed_Api.php:625
     12318msgid "Google rejected the authorization request. Please try authorizing Google PageSpeed again."
     12319msgstr ""
     12320
     12321#: PageSpeed_Api.php:628
     12322msgid "Google did not return a refresh token. Please authorize Google PageSpeed again."
     12323msgstr ""
     12324
     12325#: PageSpeed_Api.php:631
     12326msgid "The Google refresh token could not be saved by the W3 API. Please try authorizing again after the service is updated."
     12327msgstr ""
     12328
     12329#. translators: %s: Google authorization error ID.
     12330#: PageSpeed_Api.php:636
     12331#, php-format
     12332msgid "Unexpected Google PageSpeed authorization error: %s"
     12333msgstr ""
     12334
     12335#: PageSpeed_Api.php:671
    1227812336msgid "Google PageSpeed access token revocation missing required parameters!"
    1227912337msgstr ""
    1228012338
    12281 #: PageSpeed_Api.php:429
     12339#: PageSpeed_Api.php:737
     12340msgid "Google PageSpeed Access Token revocation failed."
     12341msgstr ""
     12342
     12343#: PageSpeed_Api.php:759
    1228212344msgid "No access token provided for revoke!"
    1228312345msgstr ""
    1228412346
    12285 #: PageSpeed_Api.php:431
     12347#: PageSpeed_Api.php:762
     12348msgid "No site ID provided for revoke!"
     12349msgstr ""
     12350
     12351#: PageSpeed_Api.php:765
    1228612352msgid "No W3TC API key provided for revoke!"
    1228712353msgstr ""
    1228812354
    12289 #: PageSpeed_Api.php:438
    12290 msgid "Google PageSpeed Access Token revocation failed."
     12355#: PageSpeed_Api.php:771
     12356msgid "Google rejected the access token revocation. Local authorization was kept for retry."
     12357msgstr ""
     12358
     12359#: PageSpeed_Api.php:774
     12360msgid "Google revoked the access token, but the W3 API could not save the result. Local authorization was kept for retry."
     12361msgstr ""
     12362
     12363#. translators: 1: HTTP response code, 2: API error ID.
     12364#: PageSpeed_Api.php:779
     12365#, php-format
     12366msgid "Unexpected token revocation response (HTTP %1$d, error %2$s)."
    1229112367msgstr ""
    1229212368
    … …  
    1292713003msgstr ""
    1292813004
    12929 #. translators: 1 HTML a tag to W3TC settings page Google PageSpeed meta box.
    12930 #: PageSpeed_Page.php:109
    12931 #: PageSpeed_Widget.php:100
    12932 #: PageSpeed_Widget.php:148
    12933 #, php-format
    12934 msgid "Before you can get started using the Google PageSpeed tool, you’ll first need to authorize access. Please click %1$s."
    12935 msgstr ""
    12936 
    12937 #: PageSpeed_Page.php:125
    12938 #: PageSpeed_Widget.php:164
     13005#: PageSpeed_Page.php:130
     13006#: PageSpeed_Widget.php:169
    1293913007msgid "API request failed!"
    1294013008msgstr ""
    1294113009
    12942 #: PageSpeed_Page.php:126
    12943 #: PageSpeed_Page.php:135
    12944 #: PageSpeed_Page.php:148
    12945 #: PageSpeed_Widget.php:165
    12946 #: PageSpeed_Widget.php:174
    12947 #: PageSpeed_Widget.php:187
     13010#: PageSpeed_Page.php:131
     13011#: PageSpeed_Page.php:140
     13012#: PageSpeed_Page.php:153
     13013#: PageSpeed_Widget.php:170
     13014#: PageSpeed_Widget.php:179
     13015#: PageSpeed_Widget.php:192
    1294813016msgid "Analyze URL : "
    1294913017msgstr ""
    1295013018
    12951 #: PageSpeed_Page.php:134
    12952 #: PageSpeed_Page.php:147
    12953 #: PageSpeed_Widget.php:173
    12954 #: PageSpeed_Widget.php:186
     13019#: PageSpeed_Page.php:139
     13020#: PageSpeed_Page.php:152
     13021#: PageSpeed_Widget.php:178
     13022#: PageSpeed_Widget.php:191
    1295513023msgid "API request error!"
    1295613024msgstr ""
    1295713025
    12958 #: PageSpeed_Page.php:136
    12959 #: PageSpeed_Widget.php:175
     13026#: PageSpeed_Page.php:141
     13027#: PageSpeed_Widget.php:180
    1296013028msgid "Response Code : "
    1296113029msgstr ""
    1296213030
    12963 #: PageSpeed_Page.php:137
    12964 #: PageSpeed_Widget.php:176
     13031#: PageSpeed_Page.php:142
     13032#: PageSpeed_Widget.php:181
    1296513033msgid "Response Message : "
    1296613034msgstr ""
    1296713035
    12968 #: PageSpeed_Page.php:149
    12969 #: PageSpeed_Widget.php:188
     13036#: PageSpeed_Page.php:154
     13037#: PageSpeed_Widget.php:193
    1297013038msgid "Mobile response Code : "
    1297113039msgstr ""
    1297213040
    12973 #: PageSpeed_Page.php:150
    12974 #: PageSpeed_Widget.php:189
     13041#: PageSpeed_Page.php:155
     13042#: PageSpeed_Widget.php:194
    1297513043msgid "Mobile response Message : "
    1297613044msgstr ""
    1297713045
    12978 #: PageSpeed_Page.php:151
    12979 #: PageSpeed_Widget.php:190
     13046#: PageSpeed_Page.php:156
     13047#: PageSpeed_Widget.php:195
    1298013048msgid "Desktop response Code : "
    1298113049msgstr ""
    1298213050
    12983 #: PageSpeed_Page.php:152
    12984 #: PageSpeed_Widget.php:191
     13051#: PageSpeed_Page.php:157
     13052#: PageSpeed_Widget.php:196
    1298513053msgid "Desktop response Message : "
    1298613054msgstr ""
    … …  
    1318813256msgstr ""
    1318913257
     13258#: PgCache_ConfigLabels.php:70
     13259msgid "Preload the sitemap once"
     13260msgstr ""
     13261
    1319013262#. translators: 1: opening acronym tag for URL, 2: closing acronym tag.
    13191 #: PgCache_ConfigLabels.php:73
     13263#: PgCache_ConfigLabels.php:74
    1319213264#, php-format
    1319313265msgid "Sitemap %1$sURL%2$s:"
    1319413266msgstr ""
    1319513267
    13196 #: PgCache_ConfigLabels.php:86
     13268#: PgCache_ConfigLabels.php:87
    1319713269msgid "Preload cache upon publishing a post"
    1319813270msgstr ""
    1319913271
    13200 #: PgCache_ConfigLabels.php:87
     13272#: PgCache_ConfigLabels.php:88
    1320113273msgid "Preload cache upon updating a post"
    1320213274msgstr ""
    1320313275
    13204 #: PgCache_ConfigLabels.php:88
    1320513276#: PgCache_ConfigLabels.php:89
     13277#: PgCache_ConfigLabels.php:90
    1320613278msgid "Front page"
    1320713279msgstr ""
    1320813280
    13209 #: PgCache_ConfigLabels.php:89
     13281#: PgCache_ConfigLabels.php:90
    1321013282msgid "Posts page"
    1321113283msgstr ""
    1321213284
    13213 #: PgCache_ConfigLabels.php:90
     13285#: PgCache_ConfigLabels.php:91
    1321413286msgid "Post page"
    1321513287msgstr ""
    1321613288
    13217 #: PgCache_ConfigLabels.php:91
     13289#: PgCache_ConfigLabels.php:92
    1321813290msgid "Blog feed"
    1321913291msgstr ""
    1322013292
    13221 #: PgCache_ConfigLabels.php:92
     13293#: PgCache_ConfigLabels.php:93
    1322213294msgid "Post comments pages"
    1322313295msgstr ""
    1322413296
    13225 #: PgCache_ConfigLabels.php:93
     13297#: PgCache_ConfigLabels.php:94
    1322613298msgid "Post author pages"
    1322713299msgstr ""
    1322813300
    13229 #: PgCache_ConfigLabels.php:94
     13301#: PgCache_ConfigLabels.php:95
    1323013302msgid "Post terms pages"
    1323113303msgstr ""
    1323213304
    13233 #: PgCache_ConfigLabels.php:95
     13305#: PgCache_ConfigLabels.php:96
    1323413306msgid "Post comments feed"
    1323513307msgstr ""
    1323613308
    13237 #: PgCache_ConfigLabels.php:96
     13309#: PgCache_ConfigLabels.php:97
    1323813310msgid "Post author feed"
    1323913311msgstr ""
    1324013312
    13241 #: PgCache_ConfigLabels.php:97
     13313#: PgCache_ConfigLabels.php:98
    1324213314msgid "Post terms feeds"
    1324313315msgstr ""
    1324413316
    13245 #: PgCache_ConfigLabels.php:98
     13317#: PgCache_ConfigLabels.php:99
    1324613318msgid "Daily archive pages"
    1324713319msgstr ""
    1324813320
    13249 #: PgCache_ConfigLabels.php:99
     13321#: PgCache_ConfigLabels.php:100
    1325013322msgid "Monthly archive pages"
    1325113323msgstr ""
    1325213324
    13253 #: PgCache_ConfigLabels.php:100
     13325#: PgCache_ConfigLabels.php:101
    1325413326msgid "Yearly archive pages"
    1325513327msgstr ""
    1325613328
    13257 #: PgCache_ConfigLabels.php:101
     13329#: PgCache_ConfigLabels.php:102
    1325813330msgid "Specify the feed types to purge:"
    1325913331msgstr ""
    1326013332
    13261 #: PgCache_ConfigLabels.php:102
     13333#: PgCache_ConfigLabels.php:103
    1326213334msgid "Purge limit:"
    1326313335msgstr ""
    1326413336
    13265 #: PgCache_ConfigLabels.php:103
     13337#: PgCache_ConfigLabels.php:104
    1326613338msgid "Additional pages:"
    1326713339msgstr ""
    1326813340
    13269 #: PgCache_ConfigLabels.php:104
     13341#: PgCache_ConfigLabels.php:105
    1327013342msgid "Purge sitemaps:"
    1327113343msgstr ""
    1327213344
    1327313345#. translators: 1: opening acronym tag for UTF, 2: closing acronym tag.
    13274 #: PgCache_ConfigLabels.php:109
     13346#: PgCache_ConfigLabels.php:110
    1327513347#, php-format
    1327613348msgid "Disable %1$sUTF%2$s-8 blog charset support"
    1327713349msgstr ""
    1327813350
    13279 #: PgCache_ConfigLabels.php:113
    13280 #: PgCache_ConfigLabels.php:160
     13351#: PgCache_ConfigLabels.php:114
     13352#: PgCache_ConfigLabels.php:161
    1328113353msgid "Unicode Transformation Format"
    1328213354msgstr ""
    1328313355
    1328413356#. translators: 1: opening acronym tag for HTTP, 2: closing acronym tag.
    13285 #: PgCache_ConfigLabels.php:126
     13357#: PgCache_ConfigLabels.php:127
    1328613358#, php-format
    1328713359msgid " Disable caching of HEAD %1$sHTTP%2$s requests"
    1328813360msgstr ""
    1328913361
    13290 #: PgCache_ConfigLabels.php:141
     13362#: PgCache_ConfigLabels.php:142
    1329113363msgid "Comment cookie lifetime:"
    1329213364msgstr ""
    1329313365
    13294 #: PgCache_ConfigLabels.php:142
     13366#: PgCache_ConfigLabels.php:143
    1329513367msgid "Accepted query strings:"
    1329613368msgstr ""
    1329713369
    13298 #: PgCache_ConfigLabels.php:144
     13370#: PgCache_ConfigLabels.php:145
    1329913371msgid "Rejected cookies:"
    1330013372msgstr ""
    1330113373
    13302 #: PgCache_ConfigLabels.php:146
     13374#: PgCache_ConfigLabels.php:147
    1330313375msgid "Never cache pages associated with these categories:"
    1330413376msgstr ""
    1330513377
    13306 #: PgCache_ConfigLabels.php:147
     13378#: PgCache_ConfigLabels.php:148
    1330713379msgid "Never cache pages that use these tags:"
    1330813380msgstr ""
    1330913381
    13310 #: PgCache_ConfigLabels.php:148
     13382#: PgCache_ConfigLabels.php:149
    1331113383msgid "Never cache pages by these authors:"
    1331213384msgstr ""
    1331313385
    13314 #: PgCache_ConfigLabels.php:149
     13386#: PgCache_ConfigLabels.php:150
    1331513387msgid "Never cache pages that use these custom fields:"
    1331613388msgstr ""
    1331713389
    13318 #: PgCache_ConfigLabels.php:150
     13390#: PgCache_ConfigLabels.php:151
    1331913391msgid "Cache exception list:"
    1332013392msgstr ""
    1332113393
    13322 #: PgCache_ConfigLabels.php:151
     13394#: PgCache_ConfigLabels.php:152
    1332313395msgid "Non-trailing slash pages:"
    1332413396msgstr ""
    1332513397
    13326 #: PgCache_ConfigLabels.php:152
     13398#: PgCache_ConfigLabels.php:153
    1332713399msgid "Specify page headers:"
    1332813400msgstr ""
    1332913401
    1333013402#. translators: 1: opening acronym tag for UTF, 2: closing acronym tag.
    13331 #: PgCache_ConfigLabels.php:156
     13403#: PgCache_ConfigLabels.php:157
    1333213404#, php-format
    1333313405msgid "Handle %1$sXML%2$s mime type"
    1333413406msgstr ""
    1333513407
    13336 #: PgCache_ConfigLabels.php:169
     13408#: PgCache_ConfigLabels.php:170
    1333713409msgid "Cache alias hostnames:"
    1333813410msgstr ""
    1333913411
    13340 #: PgCache_ConfigLabels.php:170
     13412#: PgCache_ConfigLabels.php:171
    1334113413msgid "Additional home URLs:"
    1334213414msgstr ""
    1334313415
    1334413416#. translators: 1: Engine name, 2: Reject reason placeholder, 3: Page key extension.
    13345 #: PgCache_ContentGrabber.php:1839
     13417#: PgCache_ContentGrabber.php:1828
    1334613418#, php-format
    1334713419msgid "Page Caching using %1$s%2$s%3$s"
    … …  
    1335313425
    1335413426#. translators: 1 interval in seconds.
    13355 #: PgCache_Plugin.php:166
     13427#: PgCache_Plugin.php:200
    1335613428#, php-format
    1335713429msgid "[W3TC] Page Cache file GC (every %d seconds)"
    … …  
    1335913431
    1336013432#. translators: 1 interval in seconds.
    13361 #: PgCache_Plugin.php:178
     13433#: PgCache_Plugin.php:212
    1336213434#, php-format
    1336313435msgid "[W3TC] Page Cache prime (every %d seconds)"
    1336413436msgstr ""
    1336513437
    13366 #: PgCache_Plugin.php:402
     13438#: PgCache_Plugin.php:436
    1336713439msgid "Page Cache: Current Page"
    1336813440msgstr ""
    1336913441
    1337013442#. Translators: 1 memcached servers.
    13371 #: PgCache_Plugin_Admin.php:434
     13443#: PgCache_Plugin_Admin.php:690
    1337213444#, php-format
    1337313445msgid "Page Cache: %1$s."
  • w3-total-cache/tags/2.10.7/pub/css/lightbox.css

    r3598169 r3723494  
    429429}
    430430
    431 .w3tc_signup_email {
    432     margin-bottom: 5px;
    433 }
    434 
    435431.w3tc-overlay-logo {
    436432    margin-top: -57px;
  • w3-total-cache/tags/2.10.7/pub/js/options.js

    r3680101 r3723494  
    18311831  });
    18321832
    1833   // Footer subscribe hide response.
    1834   jQuery("#mc-embedded-subscribe").on("click", function (e) {
    1835     // Hide response after 20 seconds.
    1836     setTimeout(function () {
    1837       jQuery("#w3tc-footer .response").hide();
    1838     }, 20000);
    1839   });
    1840 
    18411833  // Bootstrap dropdown hide on click away.
    18421834  jQuery(document).mouseup(function (e) {
  • w3-total-cache/tags/2.10.7/readme.txt

    r3680101 r3723494  
    44Requires at least: 6.0
    55Tested up to: 7.1
    6 Stable tag: 2.10.6
     6Stable tag: 2.10.7
    77License: GPLv2 or later
    88License URI: http://www.gnu.org/licenses/gpl-2.0.html
    … …  
    366366== Changelog ==
    367367
     368= 2.10.7 =
     369* Feature: Minify: Cache selected external scripts locally for auto minify
     370* Feature: Page Cache: Add a one-pass mode for sitemap cache preload
     371* Enhancement: Developers: Add a generated reference of supported actions and filters
     372* Fix: Browser Cache: Constrain unquoted URL rewriting when removing query strings from static resources
     373* Fix: Page Cache: Remove the expired role-cookie compatibility path and skip caching for rejected roles
     374* Fix: Page Cache: Avoid Options API calls before WordPress has loaded them during early bootstrap
     375* Fix: Object Cache: Persist cache invalidation from wp-admin when admin object caching is disabled
     376* Fix: CDN: Preserve custom attachment directories when pushing media
     377* Fix: Google PageSpeed: Renew expired access tokens without discarding authorization
     378* Fix: Licensing: Show the activation-limit notice for licenses that have reached their limit
     379* Fix: Settings: Persist Purge via WP-Cron schedule settings
     380* Fix: Settings: Skip unchanged w3tc_state option writes
     381* Update: Remove leftover newsletter signup code
     382* Update: Build: Omit development-only files from the release ZIP
     383
     384
    368385= 2.10.6 =
    369386* Fix: Database Cluster: Restore placeholder unescape so admin searches with wildcards match
    … …  
    460477== Upgrade Notice ==
    461478
     479= 2.10.7 =
     480This is a security update. All users are strongly encouraged to update.
     481This update also adds local caching of selected external scripts, one-pass sitemap preload, and fixes for CDN media paths, Google PageSpeed authorization, and settings persistence.
     482
     483
    462484= 2.10.6 =
    463485This is a security update. All users are strongly encouraged to update.
  • w3-total-cache/tags/2.10.7/vendor/composer/installed.php

    r3680101 r3723494  
    22    'root' => array(
    33        'name' => 'boldgrid/w3-total-cache',
    4         'pretty_version' => '2.10.6',
    5         'version' => '2.10.6.0',
    6         'reference' => '681679d97f9efd065c448b22a80ac1d73f4e0fb2',
     4        'pretty_version' => '2.10.7',
     5        'version' => '2.10.7.0',
     6        'reference' => 'b9385f7c67395655e32e02fe3246800e5be485b7',
    77        'type' => 'wordpress-plugin',
    88        'install_path' => __DIR__ . '/../../',
    … …  
    3939        ),
    4040        'boldgrid/w3-total-cache' => array(
    41             'pretty_version' => '2.10.6',
    42             'version' => '2.10.6.0',
    43             'reference' => '681679d97f9efd065c448b22a80ac1d73f4e0fb2',
     41            'pretty_version' => '2.10.7',
     42            'version' => '2.10.7.0',
     43            'reference' => 'b9385f7c67395655e32e02fe3246800e5be485b7',
    4444            'type' => 'wordpress-plugin',
    4545            'install_path' => __DIR__ . '/../../',
  • w3-total-cache/tags/2.10.7/w3-total-cache-api.php

    r3680101 r3723494  
    1111
    1212define( 'W3TC', true );
    13 define( 'W3TC_VERSION', '2.10.6' );
     13define( 'W3TC_VERSION', '2.10.7' );
    1414define( 'W3TC_POWERED_BY', 'W3 Total Cache' );
    1515define( 'W3TC_EMAIL', 'w3tc@w3-edge.com' );
    … …  
    2929define( 'W3TC_TERMS_URL', 'https://api.w3-edge.com/v1/redirects/policies-terms' );
    3030define( 'W3TC_TERMS_ACCEPT_URL', 'https://api.w3-edge.com/v1/redirects/policies-accept' );
    31 define( 'W3TC_MAILLINGLIST_SIGNUP_URL', 'https://api.w3-edge.com/v1/signup-newsletter' );
    3231define( 'W3TC_NEWRELIC_SIGNUP_URL', 'https://api.w3-edge.com/v1/redirects/newrelic/signup' );
    3332define( 'W3TC_GOOGLE_DRIVE_AUTHORIZE_URL', 'https://api.w3-edge.com/v1/googledrive/authorize' );
  • w3-total-cache/tags/2.10.7/w3-total-cache.php

    r3680101 r3723494  
    44 * Plugin URI:        https://www.boldgrid.com/totalcache/
    55 * Description:       The highest rated and most complete WordPress performance plugin. Dramatically improve the speed and user experience of your site. Add browser, page, object and database caching as well as minify and content delivery network (CDN) to WordPress.
    6  * Version:           2.10.6
     6 * Version:           2.10.7
    77 * Requires at least: 6.0
    88 * Requires PHP:      7.4
Note: See TracChangeset for help on using the changeset viewer.