Feature Enhancement – Configurable Page Expiry Times
This solution currently only applies to disk page caching.
The current implementation of the W3TC allows for one global TTL (Time to Live) cache expiry setting for all pages in the site. In many cases site pages may have dynamic content. This means that the global TTL should be set to a small time value so that cache is refreshed frequently. Other pages may be completely static and can be cached for a long period of time. This would mean that the TTL should be set to a large value. One global TTL cache setting does not facilitate development of a flexible site cache strategy.
The solution shown here permits user configuration of different TTL for page URLs matched through regular expressions. Consider, for example, that the site contains thousands of images on static pages identified with a ‘.jpg.html’ extension. In this case a large TTL could be set for all URL ending with an ‘html’ extension. Similarly, if all site posts were static and identified with a URL that contained the year and month and day of posting in a form YYYY/MM/DD, then a large TTL could be assigned to all pages that match with a ‘/MM/’ structure in the URL. On the other hand, if the site has pages with dynamic content that should be refrreshed frequently with advertisements or images that are chosen randomly, then a short TTL could be assigned to these pages by matching the URL with the specific page name. The global site TTL will continue to apply to all pages not matched by any expression.
The configuration is specified in the Advanced Settings section of the Page Cache section of the W3TC options.

w3-total-cache/lib/W3/PgCache.php
For basic mode disk caching.
.
.
.
/**
* Store cache data
*/
if ($this->_enhanced_mode) {
$cache->set($_page_key, $buffers[$_compression]);
} else {
$_data = array(
'404' => $is_404,
'headers' => $headers,
'time' => $time,
'content' => &$buffers[$_compression]
);
/**
* Set page expiry times
*/
$expires = $this->_lifetime;
$expire_uri = $this->_config->get_array('pgcache.expire.uri');
foreach ($expire_uri as $expr) {
$args = preg_split("/:/", trim($expr), 2);
$expr = (count($args) > 1) ? $args[1] : '';
if ($expr != '' && preg_match('~' . $expr . '~i', $this->_request_uri)) {
$expires = (int) $args[0];
break;
}
}
$cache->set($_page_key, $_data, $expires);
.
.
.
w3-total-cache/lib/W3/PgCache.php
For enhanced mode disk caching.
.
.
.
/**
* Returns cache object
*
* @return W3_Cache_Base
*/
function &_get_cache() {
static $cache = array();
if (!isset($cache[0])) {
$engine = $this->_config->get_string('pgcache.engine');
switch ($engine) {
case 'memcached':
$engineConfig = array(
'servers' => $this->_config->get_array('pgcache.memcached.servers'),
'persistant' => $this->_config->get_boolean('pgcache.memcached.persistant')
);
break;
case 'file':
$engineConfig = array(
'cache_dir' => W3TC_CACHE_FILE_PGCACHE_DIR,
'locking' => $this->_config->get_boolean('pgcache.file.locking'),
'flush_timelimit' => $this->_config->get_integer('timelimit.cache_flush')
);
break;
case 'file_generic':
$engineConfig = array(
'exclude' => array(
'.htaccess'
),
'expire' => $this->_lifetime,
'cache_dir' => W3TC_CACHE_FILE_PGCACHE_DIR,
'locking' => $this->_config->get_boolean('pgcache.file.locking'),
'flush_timelimit' => $this->_config->get_integer('timelimit.cache_flush'),
'expire_uri' => $this->_config->get_array('pgcache.expire.uri')
);
break;
default:
$engineConfig = array();
}
.
.
.
w3-total-cache/lib/W3/Cache/File/Generic.php
For enhanced mode disk caching.
/**
* Class W3_Cache_File_Generic
*/
class W3_Cache_File_Generic extends W3_Cache_File {
/**
* Expire
*
* @var integer
*/
var $_expire = 0;
/**
* Expire_uri
*
* @var array
*/
var $_expire_uri = array();
/**
* PHP5-style constructor
*
* @param array $config
*/
function __construct($config = array()) {
parent::__construct($config);
$this->_expire = (isset($config['expire']) ? (int) $config['expire'] : 0);
$this->_expire_uri = (isset($config['expire_uri']) ? (array) $config['expire_uri'] : array());
if (!$this->_expire || $this->_expire > W3TC_CACHE_FILE_EXPIRE_MAX) {
$this->_expire = W3TC_CACHE_FILE_EXPIRE_MAX;
}
}
.
.
.
/**
* Returns data
*
* @param string $key
* @return string
*/
function get($key) {
$var = false;
$path = $this->_cache_dir . '/' . $this->_get_path($key);
if (is_readable($path)) {
$ftime = @filemtime($path);
if ($ftime && $ftime > (time() - $this->_get_expiry($key))) {
$fp = @fopen($path, 'r');
if ($fp) {
if ($this->_locking) {
@flock($fp, LOCK_SH);
}
$var = '';
while (!@feof($fp)) {
$var .= @fread($fp, 4096);
}
@fclose($fp);
if ($this->_locking) {
@flock($fp, LOCK_UN);
}
}
}
}
return $var;
}
.
.
.
/**
* Returns cache file expiry time by key
*
* @param string $key
* @return int
*/
function _get_expiry($key) {
$expires = $this->_expire;
$expire_uri = $this->_expire_uri;
foreach ($expire_uri as $expr) {
$args = preg_split("/:/", trim($expr), 2);
$expr = (count($args) > 1) ? $args[1] : '';
if ($expr != '' && preg_match('~' . $expr . '~i', $key)) {
$expires = (int) $args[0];
break;
}
}
return $expires;
}
w3-total-cache/inc/options/pgcache.php
For the user interface to create the option block in the Advanced Settings section of the Page Cache section of the W3TC options.
.
.
.
<tr>
<th><label for="pgcache_cache_headers">Specify page headers:</label></th>
<td>
<textarea id="pgcache_cache_headers" name="pgcache.cache.headers" cols="40" rows="5"<?php if (!W3TC_PHP5 || $this->_config->get_string('pgcache.engine') == 'file_generic'): ?> disabled="disabled"<?php endif; ?>><?php echo htmlspecialchars(implode("rn", $this->_config->get_array('pgcache.cache.headers'))); ?></textarea><br />
<span class="description">Specify additional page headers to cache.</span>
</td>
</tr>
<tr>
<th><label for="pgcache_expire_uri">Specify page expiry times:</label></th>
<td>
<textarea id="pgcache_expire_uri" name="pgcache.expire.uri" cols="40" rows="5"><?php echo htmlspecialchars(implode("rn", $this->_config->get_array('pgcache.expire.uri'))); ?></textarea><br />
<span class="description">Format is: expiry_seconds:match_regex<br />Specify the cache expiry time for the matching page.<br />The delimiter is a colon and match_regex is a regular expression to match the page.</span>
</td>
</tr>
</table>
.
.
.
w3-total-cache/lib/W3/Config.php
To define the ‘pgcache.expire.uri’ configuration variable in the W3 Config object.
.
.
.
'pgcache.reject.uri' => 'array',
'pgcache.reject.ua' => 'array',
'pgcache.reject.cookie' => 'array',
'pgcache.expire.uri' => 'array',
'pgcache.purge.home' => 'boolean',
'pgcache.purge.post' => 'boolean',
.
.
.
'pgcache.reject.uri' => array(
'wp-.*.php',
'index.php'
),
'pgcache.reject.ua' => array(),
'pgcache.reject.cookie' => array(),
'pgcache.expire.uri' => array(),
'pgcache.purge.home' => true,
'pgcache.purge.post' => true,
.
.
.
Excellent, thanks for the hard but good work !
I was wondering when they will ever fix Fault 1 especially, as it generates an error in my server error logs and filling it up …
Thank you so much, this really improved the website, page speed went from 52 to 65 on desktop, so the improvement was greatly needed.
I had to turn it off though, the lightbox effect didn’t function on the single portfolio pages (using the Angular theme and their premium support is no help, just said to use the W3TC plugin)
W3TC doesn’t work correctly in WP 3.2.2, selecting the minify and page cache options breaks it the same way your version does, but with no speed improvement. also using better WP minify, google libraries and lazy loading, but not much more improvement. this theme doesn’t work with super cache and other plugins haven’t been updated, like smush.it, things would be helpful at this time.
Yours is the only one that really helped, its a real shame. Would you have any idea why it does that? Any help would be greatly appreciated on that. But I wanted to let you know that your efforts made a major improvement and I’m sure would benefit others.
Great work! Thank you