Skip to content

Instantly share code, notes, and snippets.

@JimWestergren
Last active February 11, 2023 18:28
Show Gist options
  • Star 38 You must be signed in to star a gist
  • Fork 19 You must be signed in to fork a gist
  • Save JimWestergren/3053250 to your computer and use it in GitHub Desktop.
Save JimWestergren/3053250 to your computer and use it in GitHub Desktop.
Redis as a Frontend Cache for WordPress
<?php
/*
Author: Jim Westergren & Jeedo Aquino
File: index-with-redis.php
Updated: 2012-10-25
This is a redis caching system for wordpress.
see more here: www.jimwestergren.com/wordpress-with-redis-as-a-frontend-cache/
Originally written by Jim Westergren but improved by Jeedo Aquino.
some caching mechanics are different from jim's script which is summarized below:
- cached pages do not expire not unless explicitly deleted or reset
- appending a ?c=y to a url deletes the entire cache of the domain, only works when you are logged in
- appending a ?r=y to a url deletes the cache of that url
- submitting a comment deletes the cache of that page
- refreshing (f5) a page deletes the cache of that page
- includes a debug mode, stats are displayed at the bottom most part after </html>
for setup and configuration see more here:
www.jeedo.net/lightning-fast-wordpress-with-nginx-redis/
use this script at your own risk. i currently use this albeit a slightly modified version
to display a redis badge whenever a cache is displayed.
*/
// change vars here
$cf = 1; // set to 1 if you are using cloudflare
$debug = 0; // set to 1 if you wish to see execution time and cache actions
$display_powered_by_redis = 1; // set to 1 if you want to display a powered by redis message with execution time, see below
$start = microtime(); // start timing page exec
// if cloudflare is enabled
if ($cf) {
if (isset($_SERVER['HTTP_CF_CONNECTING_IP'])) {
$_SERVER['REMOTE_ADDR'] = $_SERVER['HTTP_CF_CONNECTING_IP'];
}
}
// from wp
define('WP_USE_THEMES', true);
// init predis
include("predis.php");
$redis = new Predis\Client('');
// init vars
$domain = $_SERVER['HTTP_HOST'];
$url = "http://".$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'];
$url = str_replace('?r=y', '', $url);
$url = str_replace('?c=y', '', $url);
$dkey = md5($domain);
$ukey = md5($url);
// check if page isn't a comment submission
(isset($_SERVER['HTTP_CACHE_CONTROL']) && $_SERVER['HTTP_CACHE_CONTROL'] == 'max-age=0') ? $submit = 1 : $submit = 0;
// check if logged in to wp
$cookie = var_export($_COOKIE, true);
$loggedin = preg_match("/wordpress_logged_in/", $cookie);
// check if a cache of the page exists
if ($redis->hexists($dkey, $ukey) && !$loggedin && !$submit && !strpos($url, '/feed/')) {
echo $redis->hget($dkey, $ukey);
$cached = 1;
$msg = 'this is a cache';
// if a comment was submitted or clear page cache request was made delete cache of page
} else if ($submit || substr($_SERVER['REQUEST_URI'], -4) == '?r=y') {
require('./wp-blog-header.php');
$redis->hdel($dkey, $ukey);
$msg = 'cache of page deleted';
// delete entire cache, works only if logged in
} else if ($loggedin && substr($_SERVER['REQUEST_URI'], -4) == '?c=y') {
require('./wp-blog-header.php');
if ($redis->exists($dkey)) {
$redis->del($dkey);
$msg = 'domain cache flushed';
} else {
$msg = 'no cache to flush';
}
// if logged in don't cache anything
} else if ($loggedin) {
require('./wp-blog-header.php');
$msg = 'not cached';
// cache the page
} else {
// turn on output buffering
ob_start();
require('./wp-blog-header.php');
// get contents of output buffer
$html = ob_get_contents();
// clean output buffer
ob_end_clean();
echo $html;
// Store to cache only if the page exist and is not a search result.
if (!is_404() && !is_search()) {
// store html contents to redis cache
$redis->hset($dkey, $ukey, $html);
$msg = 'cache is set';
}
}
$end = microtime(); // get end execution time
// show messages if debug is enabled
if ($debug) {
echo $msg.': ';
echo t_exec($start, $end);
}
if ($cached && $display_powered_by_redis) {
// You should move this CSS to your CSS file and change the: float:right;margin:20px 0;
echo "<style>#redis_powered{float:right;margin:20px 0;background:url(http://images.staticjw.com/jim/3959/redis.png) 10px no-repeat #fff;border:1px solid #D7D8DF;padding:10px;width:190px;}
#redis_powered div{width:190px;text-align:right;font:10px/11px arial,sans-serif;color:#000;}</style>";
echo "<a href=\"http://www.jimwestergren.com/wordpress-with-redis-as-a-frontend-cache/\" style=\"text-decoration:none;\"><div id=\"redis_powered\"><div>Page generated in<br/> ".t_exec($start, $end)." sec</div></div></a>";
}
// time diff
function t_exec($start, $end) {
$t = (getmicrotime($end) - getmicrotime($start));
return round($t,5);
}
// get time
function getmicrotime($t) {
list($usec, $sec) = explode(" ",$t);
return ((float)$usec + (float)$sec);
}
?>
@lonetwin
Copy link

hey @k0nsl, @JimWestergren line 61 has a syntax error in the current revision (ie: rev 11) of this gist -- a extra ')' at the end

@JimWestergren
Copy link
Author

Thanks @lonetwin, corrected!

@hans2103
Copy link

hans2103 commented Jun 6, 2013

Why show both $display_powered_by_redis and $debug? They show the same message.

I've changed a couple of things on my implementation since we're using phpredis instead of predis.

My changes regarding debug information.
delete line 34
$display_powered_by_redis = 1;

replace line 124 - 134 with
// show messages if debug is enabled
if ($debug && in_array($ip, $allowed)) {
// You should move this CSS to your CSS file and change the: float:right;margin:20px 0;
// Mind that if the page is served through Cloudflare you might view a cached page from Cloudflare.
echo "<style>#redis_powered{margin:20px auto;background:url(http://images.staticjw.com/jim/3959/redis.png) 10px no-repeat #fff;border:1px solid #D7D8DF;padding:10px;width:240px;}
#redis_powered div{text-align:center;font:10px/11px arial,sans-serif;color:#000;margin-left:100px;}</stylehttps://drupal.org/project/redis";
echo "<a href='http://www.byte.nl/blog/wordpress-with-redis-as-a-frontend-cache/' style='text-decoration:none;'><div id='redis_powered'><div>Page generated in<br/> ".t_exec($start, $end)." sec<br/>".$msg."</div></div></a>";
}

as you can see... I've implemented a new variable -> $allowed
you are allowed to see the Redis debug information only if your IP-address is in the allowed array:
// allow IP-addresses for debug information
$ip = $_SERVER['REMOTE_ADDR'];
$allowed = array(
'255.255.255.255', // ip address of Joe Example @ Home
'1.1.1.1', // ip address of Joe Example @ Work
);

Mind that when your page is server through Cloudflare you might view a cached page from Cloudflare. This can be annoying if you just forgot. ;-)

@boniface
Copy link

Hey Jim, thanks for this and really make WP fly. However, I have noticed a couple of issues with comment form. From time to time the comments form tend to load cached details of another user and so exposing somebody else details including email. Is there a way to tell this setup not to cache form content?

@postme
Copy link

postme commented Aug 3, 2013

Hi, I've made a small adaptation to be able to deal with the distinction between caching plain and ssl pages

if (is_ssl()) {
  $url = "https://".$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'];
} else {
  $url = "http://".$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'];
}

I've used the WordPres is_ssl() function for this

@erdihu
Copy link

erdihu commented Feb 27, 2014

Hi,
This is just a great work. Many thanks to all who contributed.
However, any ideas how to enable auto purge page caches after X seconds for example?

Some ideas to have more control on caching:

  1. Ability to exclude certain pages from cache.
  2. Ability to set different auto purge times to different pages.

I believe using widgets would be easier if these options implemented.

@oneinstack
Copy link

I would love to know how I can make the post view(wp-postviews) counts bypass the cache.

@kevin25
Copy link

kevin25 commented Nov 9, 2016

How can we exclude cart and checkout from Woocommerce?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment