Skip to content

Instantly share code, notes, and snippets.

@onyxfish
Created June 28, 2011 21:32
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save onyxfish/1052296 to your computer and use it in GitHub Desktop.
Save onyxfish/1052296 to your computer and use it in GitHub Desktop.
Newsapps Varnish plugin for Wordpress (handles targeted invalidation)
<?php
if($_POST['varnish_hidden'] == 'Y') {
//Process form data
$varnish_server1 = (!isset($_POST['varnish_server1'])? '': $_POST['varnish_server1']);
update_site_option('varnish_server1', $varnish_server1);
$varnish_server2 = (!isset($_POST['varnish_server2'])? '': $_POST['varnish_server2']);
update_site_option('varnish_server2', $varnish_server2);
$varnish_server3 = (!isset($_POST['varnish_server3'])? '': $_POST['varnish_server3']);
update_site_option('varnish_server3', $varnish_server3);
$varnish_server4 = (!isset($_POST['varnish_server4'])? '': $_POST['varnish_server4']);
update_site_option('varnish_server4', $varnish_server4);
$varnish_debug = (!isset($_POST['varnish_debug'])? '': $_POST['varnish_debug']);
update_site_option('varnish_debug', $varnish_debug);
?>
<div class="updated"><p><strong><?php _e('Options saved.' ); ?></strong></p></div>
<?php
} else {
$varnish_server1 = get_site_option('varnish_server1');
$varnish_server2 = get_site_option('varnish_server2');
$varnish_server3 = get_site_option('varnish_server3');
$varnish_server4 = get_site_option('varnish_server4');
$varnish_debug = get_site_option('varnish_debug');
}
?>
<div class="wrap">
<h2>Newsapps Varnish</h2>
<form name="varnish" method="post" action="<?php echo str_replace( '%7E', '~', $_SERVER['REQUEST_URI']); ?>">
<input type="hidden" name="varnish_hidden" value="Y">
<h4>Varnish Servers</h4>
<p>Enter up to four server hostnames (or IP addresses).<br />If the server is running on a port other than 80, enter it after the hostname, separated by a colon.</p>
<div>
<p><?php _e("Hostname 1: "); ?><input type="text" name="varnish_server1" value="<?php echo $varnish_server1 ?>" /> (Example: localhost:80)</p>
<p><?php _e("Hostname 2: "); ?><input type="text" name="varnish_server2" value="<?php echo $varnish_server2 ?>" /></p>
<p><?php _e("Hostname 3: "); ?><input type="text" name="varnish_server3" value="<?php echo $varnish_server3 ?>" /></p>
<p><?php _e("Hostname 4: "); ?><input type="text" name="varnish_server4" value="<?php echo $varnish_server4 ?>" /></p>
</div>
<div>
<p><input type="checkbox" name="varnish_debug" value="True" <?php if ($varnish_debug == 'True') { echo 'checked'; } ?>/> Enable debug mode (log cache purges to PHP error_log)</input></p>
</div>
<p class="submit"><input type="submit" name="Submit" value="Update Options" /></p>
</form>
</div>
<?php
/*
Plugin Name: Newsapps Varnish
Plugin URI: http://apps.chicagotribune.com
Version: 0.2
Author: Chris Groskopf, Brian Boyer, inspired by http://github.com/pkhamre/wp-varnish
Description: Purges varnish cache when posts are changed.
Network: true
*/
class NewsAppsVarnish {
function NewsAppsVarnish() {
add_action('network_admin_menu', array(&$this, 'VarnishAdminActions'));
add_action('save_post', array(&$this, 'PurgePost'), 99);
add_action('edit_comment', array(&$this, 'PurgePostOnComment'), 99);
add_action('comment_post', array(&$this, 'PurgePostOnComment'), 99);
add_action('wp_set_comment_status', array(&$this, 'PurgePostOnComment'), 99);
}
function VarnishAdmin() {
include('newsapps-varnish-admin.php');
}
function VarnishAdminActions($args) {
add_menu_page(
"Varnish",
"Varnish",
"manage_network_options",
"varnish_admin_actions_file_str",
array(&$this, 'VarnishAdmin')
);
}
function PurgePost($post_id) {
//if the permalink doesn't end with autosave -- wordpress fires edit_post on autosave. wheee.
//also, save is called twice, once for your update, and once for updating the revision, which we don't care about busting.
//if this ends up being weird, maybe check out wp_is_post_revision?
$debug = (get_site_option('varnish_debug') == 'True') ? True : False ;
$post = get_post($post_id);
if ($post->post_status == 'auto-draft') {
if ($debug) {
error_log('Skipped purging auto-draft.');
}
return;
}
if ($post->post_status == 'draft') {
if ($debug) {
error_log('Skipped purging draft.');
}
return;
}
if ($post->post_status == 'inherit') {
if ($debug) {
error_log('Skipped purging inherit (attached image).');
}
return;
}
$post_host = parse_url(get_permalink($post_id), PHP_URL_HOST);
$site_host = parse_url(get_bloginfo('wpurl'), PHP_URL_HOST);
$post_path = parse_url(get_permalink($post_id), PHP_URL_PATH);
$blog_path = parse_url(get_bloginfo('wpurl'), PHP_URL_PATH);
if(!preg_match('/(autosave|\d+-revision)/', $post_path)) {
$to_purge = array();
array_push($to_purge, $post_path);
if ($blog_path) {
array_push($to_purge, $blog_path . '/');
array_push($to_purge, $blog_path . '/rss/');
array_push($to_purge, $blog_path . '/sitemap-web.xml');
array_push($to_purge, $blog_path . '/sitemap-news-google.xml');
array_push($to_purge, $blog_path . '/sitemap-news-yahoo.xml');
}
$this->Purge($to_purge);
}
}
function PurgePostOnComment($comment_id) {
$comment = get_comment($comment_id, ARRAY_A);
$post_id = $comment['comment_post_ID'];
$post_path = parse_url(get_permalink($post_id), PHP_URL_PATH);
$this->Purge($post_path);
}
function Purge($urls) {
$servers = array();
$servers[0] = get_site_option('varnish_server1');
$servers[1] = get_site_option('varnish_server2');
$servers[2] = get_site_option('varnish_server3');
$servers[3] = get_site_option('varnish_server4');
$debug = (get_site_option('varnish_debug') == 'True') ? True : False ;
// Accept strings as well as arrays
if(is_string($urls)){
$urls = array($urls);
}
// Note: Purge wants unescaped periods
$urls_regex = '(' . implode('|', $urls) . ')$';
$blog_hostname = parse_url(get_bloginfo('wpurl'), PHP_URL_HOST);
// Construct purge request
$purge = "PURGE $urls_regex HTTP/1.0\r\n";
$purge .= "Host: $blog_hostname\r\n";
$purge .= "Connection: Close\r\n\r\n";
foreach($servers as $server) {
if (empty($server)) {
continue;
}
if ($p = strpos($server, ':')) {
$varnish_host = substr($server, 0, $p);
$varnish_port = substr($server, $p + 1);
} else {
$varnish_host = $server;
$varnish_port = "80";
}
$varnish_sock = fsockopen($varnish_host, $varnish_port, $errno, $errstr, 30);
// Log response
if (!$varnish_sock) {
if ($debug) {
error_log("NEWSAPPS-VARNISH: $errstr ($errno)");
}
} else {
if ($debug) {
error_log("NEWSAPPS-VARNISH: $purge");
}
fwrite($varnish_sock, $purge);
fclose($varnish_sock);
}
}
}
}
$varnish = & new NewsAppsVarnish();
?>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment