all repos — wp-ffpc @ 5311bfe4c05db69c5a1f8f2ab6bbe9944e7feff4

Merge branch 'master' of github.com:petermolnar/wp-ffpc into HEAD

git-svn-id: http://plugins.svn.wordpress.org/wp-ffpc/trunk@702793 b8457f37-d9ea-0310-8a92-e5e31aec5664
cadeyrn cadeyrn@b8457f37-d9ea-0310-8a92-e5e31aec5664
Wed, 24 Apr 2013 11:52:47 +0000
commit

5311bfe4c05db69c5a1f8f2ab6bbe9944e7feff4

parent

9a75b952840a536059b234087f9d15c07e98633b

M wp-ffpc-abstract.phpwp-ffpc-abstract.php

@@ -65,7 +65,7 @@ protected $plugin_settings_page;

protected $donation_link; protected $button_save; protected $button_delete; - protected $capability = 10; + protected $capability = 'manage_options'; protected $donation_business_name; protected $donation_item_name; protected $broadcast_message;

@@ -114,47 +114,10 @@

/* set the settings page link string */ $this->settings_link = $this->settings_slug . '?page=' . $this->plugin_settings_page; - /* initialize plugin, plugin specific init functions */ - $this->plugin_init(); - - /* get the options */ - $this->plugin_options_read(); - - /* setup plugin, plugin specific setup functions that need options */ - $this->plugin_setup(); + add_action( 'init', array(&$this,'init')); - /* add admin styling */ - if( is_admin() ) { - /* jquery ui tabs is provided by WordPress */ - wp_enqueue_script ( "jquery-ui-tabs" ); - wp_enqueue_script ( "jquery-ui-slider" ); + add_action( 'admin_enqueue_scripts', array(&$this,'enqueue_admin_css_js')); - /* additional admin styling */ - $css_handle = $this->plugin_constant . '-admin-css'; - $css_file = $this->plugin_constant . '-admin.css'; - if ( @file_exists ( $this->plugin_dir . $css_file ) ) - { - $css_src = $this->plugin_url . $css_file; - wp_register_style( $css_handle, $css_src, false, false, 'all' ); - wp_enqueue_style( $css_handle ); - } - } - - register_activation_hook( $this->plugin_file , array( $this , 'plugin_activate') ); - register_deactivation_hook( $this->plugin_file , array( $this , 'plugin_deactivate') ); - register_uninstall_hook( $this->plugin_file , array( $this , 'plugin_uninstall') ); - - /* register settings pages */ - if ( $this->network ) - add_filter( "network_admin_plugin_action_links_" . $this->plugin_file, array( $this, 'plugin_settings_link' ) ); - else - add_filter( "plugin_action_links_" . $this->plugin_file, array( $this, 'plugin_settings_link' ) ); - - /* register admin init, catches $_POST and adds submenu to admin menu */ - if ( $this->network ) - add_action('network_admin_menu', array( $this , 'plugin_admin_init') ); - else - add_action('admin_menu', array( $this , 'plugin_admin_init') ); } /**

@@ -213,7 +176,7 @@ /* get broadcast message, if available */

$this->broadcast_message = @file_get_contents( $this->broadcast_message ); /* add submenu to settings pages */ - add_submenu_page( $this->settings_slug, $this->plugin_name . __( ' options' , $this->plugin_constant ), $this->plugin_name, $this->capability, $this->plugin_settings_page, array ( $this , 'plugin_admin_panel' ) ); + add_submenu_page( $this->settings_slug, $this->plugin_name . __( ' options' , $this->plugin_constant ), $this->plugin_name, $this->capability, $this->plugin_settings_page, array ( &$this , 'plugin_admin_panel' ) ); } /**

@@ -222,6 +185,36 @@ *

*/ abstract function plugin_hook_admin_init(); + + public function init(){ + /* initialize plugin, plugin specific init functions */ + $this->plugin_init(); + + /* get the options */ + $this->plugin_options_read(); + + /* setup plugin, plugin specific setup functions that need options */ + $this->plugin_setup(); + + register_activation_hook( $this->plugin_file , 'plugin_activate' ); + register_deactivation_hook( $this->plugin_file , 'plugin_deactivate' ); + register_uninstall_hook( $this->plugin_file , 'plugin_uninstall' ); + + /* register settings pages */ + if ( $this->network ) + add_filter( "network_admin_plugin_action_links_" . $this->plugin_file, array( &$this, 'plugin_settings_link' ) ); + else + add_filter( "plugin_action_links_" . $this->plugin_file, array( &$this, 'plugin_settings_link' ) ); + + /* register admin init, catches $_POST and adds submenu to admin menu */ + if ( $this->network ) + add_action('network_admin_menu', array( &$this , 'plugin_admin_init') ); + else + add_action('admin_menu', array( &$this , 'plugin_admin_init') ); + + + } + /** * callback function to add settings link to plugins page *

@@ -234,6 +227,23 @@ array_unshift( $links, $settings_link );

return $links; } + /* add admin styling */ + public function enqueue_admin_css_js(){ + /* jquery ui tabs is provided by WordPress */ + wp_enqueue_script ( "jquery-ui-tabs" ); + wp_enqueue_script ( "jquery-ui-slider" ); + + /* additional admin styling */ + $css_handle = $this->plugin_constant . '-admin-css'; + $css_file = $this->plugin_constant . '-admin.css'; + if ( @file_exists ( $this->plugin_dir . $css_file ) ) + { + $css_src = $this->plugin_url . $css_file; + wp_register_style( $css_handle, $css_src, false, false, 'all' ); + wp_enqueue_style( $css_handle ); + } + } + /** * deletes saved options from database */

@@ -367,14 +377,18 @@ return false;

switch ( $log_level ) { case LOG_ERR : - if ( function_exists( 'syslog' ) ) + if ( function_exists( 'syslog' ) && function_exists ( 'openlog' ) ) { + openlog('wordpress('.$_SERVER['HTTP_HOST'].')',LOG_NDELAY|LOG_PID,LOG_SYSLOG); syslog( $log_level , self::plugin_constant . $message ); + } /* error level is real problem, needs to be displayed on the admin panel */ throw new Exception ( $message ); break; default: - if ( function_exists( 'syslog' ) && $this->config['debug'] ) + if ( function_exists( 'syslog' ) && function_exists ( 'openlog' ) && $this->config['debug'] ) { + openlog('wordpress('.$_SERVER['HTTP_HOST'].')',LOG_NDELAY|LOG_PID,LOG_SYSLOG); syslog( $log_level , self::plugin_constant . $message ); + } break; }

@@ -462,6 +476,7 @@ $check_disabled = true;

else $check_disabled = false; + $opt = ''; foreach ($elements as $value => $name ) { //$disabled .= ( @array_key_exists( $valid[ $value ] ) && $valid[ $value ] == false ) ? ' disabled="disabled"' : ''; $opt .= '<option value="' . $value . '" ';
M wp-ffpc-acache.phpwp-ffpc-acache.php

@@ -64,36 +64,46 @@ }

} } +/* canonical redirect storage */ $wp_ffpc_redirect = null; + +/* fires up the backend storage array with current config */ $wp_ffpc_backend = new WP_FFPC_Backend( $wp_ffpc_config ); +/* will store time of page generation */ +$wp_ffpc_gentime = 0; + +/* backend connection failed, no caching :( */ if ( $wp_ffpc_backend->status() === false ) return false; -$wp_ffpc_keys = array ( 'meta', 'data' ); +/* try to get data & meta keys for current page */ +$wp_ffpc_keys = array ( 'meta' => $wp_ffpc_config['prefix_meta'], 'data' => $wp_ffpc_config['prefix_data'] ); $wp_ffpc_values = array(); -foreach ( $wp_ffpc_keys as $key ) { +foreach ( $wp_ffpc_keys as $internal => $key ) { $value = $wp_ffpc_backend->get ( $wp_ffpc_backend->key ( $key ) ); if ( ! $value ) { + /* does not matter which is missing, we need both, if one fails, no caching */ wp_ffpc_start(); return; } else { - $wp_ffpc_values[ $key ] = $value; + /* store results */ + $wp_ffpc_values[ $internal ] = $value; } } /* serve cache 404 status */ -if ( $wp_ffpc_values['meta']['status'] == 404 ) { +if ( isset( $wp_ffpc_values['meta']['status'] ) && $wp_ffpc_values['meta']['status'] == 404 ) { header("HTTP/1.1 404 Not Found"); flush(); die(); } /* server redirect cache */ -if ( $wp_ffpc_values['meta']['redirect'] ) { +if ( isset( $wp_ffpc_values['meta']['redirect'] ) && $wp_ffpc_values['meta']['redirect'] ) { header('Location: ' . $wp_ffpc_values['meta']['redirect'] ); flush(); die();

@@ -109,6 +119,8 @@ flush();

die(); } } + +/*** SERVING CACHED PAGE ***/ /* if we reach this point it means data was found & correct, serve it */ header('Content-Type: ' . $wp_ffpc_values['meta']['mime']);

@@ -141,11 +153,20 @@ echo $wp_ffpc_values['data'];

flush(); die(); +/*** END SERVING CACHED PAGE ***/ + + +/*** GENERATING CACHE ENTRY ***/ /** * starts caching function * */ function wp_ffpc_start( ) { + /* set start time */ + global $wp_ffpc_gentime; + $mtime = explode ( " ", microtime() ); + $wp_ffpc_gentime = $mtime[1] + $mtime[0]; + /* start object "colleting" and pass it the the actual storer function */ ob_start('wp_ffpc_callback'); }

@@ -164,16 +185,19 @@ /**

* write cache function, called when page generation ended */ function wp_ffpc_callback( $buffer ) { + /* use global config */ global $wp_ffpc_config; + /* backend was already set up, try to use it */ global $wp_ffpc_backend; + /* check is it's a redirect */ global $wp_ffpc_redirect; - /* no is_home = error */ + /* no is_home = error, WordPress functions are not availabe */ if (!function_exists('is_home')) return $buffer; - /* no <body> close tag = not HTML, don't cache */ - if (stripos($buffer, '</body>') === false) + /* no <body> close tag = not HTML, also no <rss>, not feed, don't cache */ + if ( stripos($buffer, '</body>') === false && stripos($buffer, '</rss>') === false ) return $buffer; /* reset meta to solve conflicts */

@@ -245,8 +269,7 @@ if ( get_option ( 'default_ping_status' ) == 'open' )

$meta['pingback'] = get_bloginfo('pingback_url'); /* sync all http and https requests if enabled */ - if ( $config['sync_protocols'] == '1' ) - { + if ( isset( $config['sync_protocols'] ) && $config['sync_protocols'] == '1' ) { if ( isset( $_SERVER['HTTP_X_FORWARDED_PROTO'] ) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https' ) $_SERVER['HTTPS'] = 'on';

@@ -262,8 +285,20 @@

$buffer = str_replace ( $sync_from, $sync_to, $buffer ); } - $wp_ffpc_backend->set ( $wp_ffpc_backend->key ( 'meta' ) , $meta ); - $wp_ffpc_backend->set ( $wp_ffpc_backend->key ( 'data' ) , $buffer ); + /* add generation info is option is set, but only to HTML */ + if ( $wp_ffpc_config['generate_time'] == '1' && stripos($buffer, '</body>') ) { + global $wp_ffpc_gentime; + $mtime = explode ( " ", microtime() ); + $wp_ffpc_gentime = ( $mtime[1] + $mtime[0] )- $wp_ffpc_gentime; + + $insertion = "\n<!-- \nWP-FFPC \n\tcache engine: ". $wp_ffpc_config['cache_type'] ."\n\tpage generation time: ". round( $wp_ffpc_gentime, 3 ) ." seconds\n\tgeneraton UNIX timestamp: ". time() . "\n\tgeneraton date: ". date( 'c' ) . "\n-->\n"; + $index = stripos( $buffer , '</body>' ); + + $buffer = substr_replace( $buffer, $insertion, $index, 0); + } + + $wp_ffpc_backend->set ( $wp_ffpc_backend->key ( $wp_ffpc_config['prefix_meta'] ) , $meta ); + $wp_ffpc_backend->set ( $wp_ffpc_backend->key ( $wp_ffpc_config['prefix_data'] ) , $buffer ); /* vital for nginx, make no problem at other places */ header("HTTP/1.1 200 OK");

@@ -271,5 +306,6 @@

/* echoes HTML out */ return $buffer; } +/*** END GENERATING CACHE ENTRY ***/ ?>
M wp-ffpc-admin.csswp-ffpc-admin.css

@@ -132,3 +132,63 @@ background-image: -o-linear-gradient(bottom,#ececec,#f9f9f9);

background-image: linear-gradient(to top,#ececec,#f9f9f9); outline: none; } + + +.button-warning { + display: inline-block; + text-decoration: none; + font-size: 12px; + line-height: 23px; + height: 24px; + margin: 0; + padding: 0 10px 1px; + cursor: pointer; + border-width: 1px; + border-style: solid; + -webkit-border-radius: 3px; + -webkit-appearance: none; + border-radius: 3px; + white-space: nowrap; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + background: #f3f3f3; + background-image: -webkit-gradient(linear, left top, left bottom, from(#fefefe), to(#f4f4f4)); + background-image: -webkit-linear-gradient(top, #fefefe, #f4f4f4); + background-image: -moz-linear-gradient(top, #fefefe, #f4f4f4); + background-image: -o-linear-gradient(top, #fefefe, #f4f4f4); + background-image: linear-gradient(to bottom, #fefefe, #f4f4f4); + border-color: #bbb; + color: #900; + text-shadow: 0 1px 0 #fff; +} + +.button-warning:hover, +.button-warning:focus { + background: #f3f3f3; + background-image: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#f3f3f3)); + background-image: -webkit-linear-gradient(top, #fff, #f3f3f3); + background-image: -moz-linear-gradient(top, #fff, #f3f3f3); + background-image: -ms-linear-gradient(top, #fff, #f3f3f3); + background-image: -o-linear-gradient(top, #fff, #f3f3f3); + background-image: linear-gradient(to bottom, #fff, #f3f3f3); + border-color: #900; + color: #a00; + -webkit-box-shadow: 1px 1px 1px rgba(0,0,0,.2); + box-shadow: 1px 1px 1px rgba(0,0,0,.2); +} + +.button-warning:active { + background: #eee; + background-image: -webkit-gradient(linear, left top, left bottom, from(#f4f4f4), to(#fefefe)); + background-image: -webkit-linear-gradient(top, #f4f4f4, #fefefe); + background-image: -moz-linear-gradient(top, #f4f4f4, #fefefe); + background-image: -ms-linear-gradient(top, #f4f4f4, #fefefe); + background-image: -o-linear-gradient(top, #f4f4f4, #fefefe); + background-image: linear-gradient(to bottom, #f4f4f4, #fefefe); + border-color: #900; + color: #a00; + text-shadow: 0 -1px 0 #fff; + -webkit-box-shadow: inset 0 2px 5px -3px rgba( 0, 0, 0, 0.5 ); + box-shadow: inset 0 2px 5px -3px rgba( 0, 0, 0, 0.5 ); +}
M wp-ffpc-backend.phpwp-ffpc-backend.php

@@ -21,7 +21,6 @@

/** * - * @var array $key_prefixes Prefix keys for entries * @var mixed $connection Backend object storage variable * @var array $config Configuration settings array * @var boolean $alive Backend aliveness indicator

@@ -32,16 +31,14 @@ class WP_FFPC_Backend {

const plugin_constant = 'wp-ffpc'; const network_key = 'network'; - const id_prefix = 'wp-ffpc-id-'; - const prefix = 'prefix-'; const host_separator = ','; const port_separator = ':'; - private $key_prefixes = array ( 'meta', 'data' ); private $connection = NULL; - private $options; private $alive = false; - private $status; + private $network = false; + private $options = array(); + private $status = array(); /** * constructor

@@ -49,9 +46,10 @@ *

* @param mixed $config Configuration options * */ - public function __construct( $config ) { + public function __construct( $config, $network = false ) { $this->options = $config; + $this->network = $network; /* no config, nothing is going to work */ if ( empty ( $this->options ) ) {

@@ -73,10 +71,10 @@

/** * build key to make requests with * - * @param string $suffix suffix to add to prefix + * @param string $prefix prefix to add to prefix * */ - public function key ( $suffix = 'meta' ) { + public function key ( &$prefix ) { /* use the full accessed URL string as key, same will be generated by nginx as well we need a data and a meta key: data is string only with content, meta is not used in nginx */ if ( isset( $_SERVER['HTTP_X_FORWARDED_PROTO'] ) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https' )

@@ -84,7 +82,7 @@ $_SERVER['HTTPS'] = 'on';

$protocol = ( isset($_SERVER['HTTPS']) && ( ( strtolower($_SERVER['HTTPS']) == 'on' ) || ( $_SERVER['HTTPS'] == '1' ) ) ) ? 'https://' : 'http://'; - return $suffix . '-' . $protocol . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']; + return $prefix . $protocol . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']; }

@@ -147,20 +145,20 @@ * public get function, transparent proxy to internal function based on backend

* * @param string $key Cache key to invalidate, false mean full flush */ - public function clear ( $post_id = false ) { + public function clear ( $post_id = false, $force = false ) { /* look for backend aliveness, exit on inactive backend */ if ( ! $this->is_alive() ) return false; /* exit if no post_id is specified */ - if ( empty ( $post_id ) && $this->options['invalidation_method'] != 0) { + if ( empty ( $post_id ) && $force === false ) { $this->log ( __translate__('not clearing unidentified post ', self::plugin_constant ), LOG_WARNING ); return false; } /* if invalidation method is set to full, flush cache */ - if ( $this->options['invalidation_method'] === 0 || empty ( $post_id ) ) { + if ( $this->options['invalidation_method'] === 0 || $force === true ) { /* log action */ $this->log ( __translate__('flushing cache', self::plugin_constant ) );

@@ -174,36 +172,125 @@

return $result; } - /* need permalink functions */ - if ( !function_exists('get_permalink') ) - include_once ( ABSPATH . 'wp-includes/link-template.php' ); + /* storage for entries to clear */ + $to_clear = array(); - /* get path from permalink */ - $path = substr ( get_permalink( $post_id ) , 7 ); + /* clear taxonomies if settings requires it */ + if ( $this->options['invalidation_method'] == 2 ) { + /* this will only clear the current blog's entries */ + $this->taxonomy_links( $to_clear ); + } - /* no path, don't do anything */ - if ( empty( $path ) ) { - $this->log ( __translate__('unable to determine path from Post Permalink, post ID: ', self::plugin_constant ) . $post_id , LOG_WARNING ); - return false; + /* if there's a post id pushed, it needs to be invalidated in all cases */ + if ( !empty ( $post_id ) ) { + + /* need permalink functions */ + if ( !function_exists('get_permalink') ) + include_once ( ABSPATH . 'wp-includes/link-template.php' ); + + /* get path from permalink */ + $path = substr ( get_permalink( $post_id ) , 7 ); + + /* no path, don't do anything */ + if ( empty( $path ) ) { + $this->log ( __translate__('unable to determine path from Post Permalink, post ID: ', self::plugin_constant ) . $post_id , LOG_WARNING ); + return false; + } + + if ( isset($_SERVER['HTTPS']) && ( ( strtolower($_SERVER['HTTPS']) == 'on' ) || ( $_SERVER['HTTPS'] == '1' ) ) ) + $protocol = 'https://'; + else + $protocol = 'http://'; + + /* elements to clear + values are keys, faster to process and eliminates duplicates + */ + $to_clear[ $protocol . $path ] = true; } - if ( isset($_SERVER['HTTPS']) && ( ( strtolower($_SERVER['HTTPS']) == 'on' ) || ( $_SERVER['HTTPS'] == '1' ) ) ) - $protocol = 'https://'; - else - $protocol = 'http://'; + foreach ( $to_clear as $link => $dummy ) { + /* clear all feeds as well */ + $to_clear[ $link. 'feed' ] = true; + } - /* elements to clear */ - $to_clear = array ( - $this->options['prefix-meta'] . $protocol . $path, - $this->options['prefix-data'] . $protocol . $path, - ); + /* add data & meta prefixes */ + foreach ( $to_clear as $link => $dummy ) { + unset ( $to_clear [ $link ]); + $to_clear[ $this->options[ 'prefix_meta' ] . $link ] = true; + $to_clear[ $this->options[ 'prefix_data' ] . $link ] = true; + } - /* delete entries */ + /* run clear */ $internal = $this->proxy ( 'clear' ); $this->$internal ( $to_clear ); } /** + * to collect all permalinks of all taxonomy terms used in invalidation & precache + * + * @param array &$links Passed by reference array that has to be filled up with the links + * @param mixed $site Site ID or false; used in WordPress Network + * + */ + public function taxonomy_links ( &$links, $site = false ) { + + if ( $site !== false ) { + $current_blog = get_current_blog_id(); + switch_to_blog( $site ); + + $url = get_blog_option ( $site, 'siteurl' ); + if ( substr( $url, -1) !== '/' ) + $url = $url . '/'; + + $links[ $url ] = true; + } + + /* we're only interested in public taxonomies */ + $args = array( + 'public' => true, + ); + + /* get taxonomies as objects */ + $taxonomies = get_taxonomies( $args, 'objects' ); + + if ( !empty( $taxonomies ) ) { + foreach ( $taxonomies as $taxonomy ) { + /* reset array, just in case */ + $terms = array(); + + /* get all the terms for this taxonomy, only if not empty */ + $sargs = array( + 'hide_empty' => true, + 'fields' => 'all', + 'hierarchical' =>false, + ); + $terms = get_terms ( $taxonomy->name , $sargs ); + + if ( !empty ( $terms ) ) { + foreach ( $terms as $term ) { + /* get the permalink for the term */ + $link = get_term_link ( $term->slug, $taxonomy->name ); + /* add to container */ + $links[ $link ] = true; + /* remove the taxonomy name from the link, lots of plugins remove this for SEO, it's better to include them than leave them out + in worst case, we cache some 404 as well + */ + $link = str_replace ( '/'.$taxonomy->rewrite['slug'], '', $link ); + /* add to container */ + $links[ $link ] = true; + } + } + } + } + + /* switch back to original site if we navigated away */ + if ( $site !== false ) { + switch_to_blog( $current_blog ); + } + + } + + /** * get backend aliveness * * @return array Array of configured servers with aliveness value

@@ -216,7 +303,8 @@ if ( ! $this->is_alive() )

return false; $internal = $this->proxy ( 'status' ); - return $this->status; + $this->$internal(); + return $this->status; } /**

@@ -304,7 +392,7 @@ /* error level is real problem, needs to be displayed on the admin panel */

//throw new Exception ( $message ); break; default: - if ( function_exists( 'syslog' ) && $this->options['debug'] ) + if ( function_exists( 'syslog' ) && isset($this->options['debug']) && $this->options['debug'] ) syslog( $log_level , self::plugin_constant . " with " . $this->options['cache_type'] . ' ' . $message ); break; }

@@ -337,6 +425,7 @@ * @return boolean Aliveness status

* */ private function apc_status () { + $this->status = true; return $this->alive; }

@@ -380,12 +469,12 @@ * Removes entry from APC or flushes APC user entry storage

* * @param mixed $keys Keys to clear, string or array */ - private function apc_clear ( $keys ) { + private function apc_clear ( &$keys ) { /* make an array if only one string is present, easier processing */ if ( !is_array ( $keys ) ) - $keys = array ( $keys ); + $keys = array ( $keys => true ); - foreach ( $keys as $key ) { + foreach ( $keys as $key => $dummy ) { if ( ! apc_delete ( $key ) ) { $this->log ( __translate__('Failed to delete APC entry: ', self::plugin_constant ) . $key, LOG_ERR ); //throw new Exception ( __translate__('Deleting APC entry failed with key ', self::plugin_constant ) . $key );

@@ -430,7 +519,7 @@ }

/* check if initialization was success or not */ if ( $this->connection === NULL ) { - $this->log ( __translate__( 'error initializing Memcached PHP extension, exiting', self::prefix ) ); + $this->log ( __translate__( 'error initializing Memcached PHP extension, exiting', self::plugin_constant ) ); return false; }

@@ -530,13 +619,13 @@ * Removes entry from Memcached or flushes Memcached storage

* * @param mixed $keys String / array of string of keys to delete entries with */ - private function memcached_clear ( $keys ) { + private function memcached_clear ( &$keys ) { /* make an array if only one string is present, easier processing */ if ( !is_array ( $keys ) ) - $keys = array ( $keys ); + $keys = array ( $keys => true ); - foreach ( $keys as $key ) { + foreach ( $keys as $key => $dummy ) { $kresult = $this->connection->delete( $key ); if ( $kresult === false ) {

@@ -573,7 +662,7 @@ $this->connection = new Memcache();

/* check if initialization was success or not */ if ( $this->connection === NULL ) { - $this->log ( __translate__( 'error initializing Memcache PHP extension, exiting', self::prefix ) ); + $this->log ( __translate__( 'error initializing Memcache PHP extension, exiting', self::plugin_constant ) ); return false; }

@@ -646,12 +735,12 @@ * Removes entry from Memcached or flushes Memcached storage

* * @param mixed $keys String / array of string of keys to delete entries with */ - private function memcache_clear ( $keys ) { + private function memcache_clear ( &$keys ) { /* make an array if only one string is present, easier processing */ if ( !is_array ( $keys ) ) - $keys = array ( $keys ); + $keys = array ( $keys => true ); - foreach ( $keys as $key ) { + foreach ( $keys as $key => $dummy ) { $kresult = $this->connection->delete( $key ); if ( $kresult === false ) {
M wp-ffpc-class.phpwp-ffpc-class.php

@@ -34,7 +34,16 @@ const host_separator = ',';

const port_separator = ':'; const donation_id_key = 'hosted_button_id='; const global_config_var = '$wp_ffpc_config'; + const key_save = 'saved'; + const key_delete = 'deleted'; + const key_flush = 'flushed'; const slug_flush = '&flushed=true'; + const key_precache = 'precached'; + const slug_precache = '&precached=true'; + const key_precache_disabled = 'precache_disabled'; + const slug_precache_disabled = '&precache_disabled=true'; + const precache_log = 'wp-ffpc-precache.log'; + private $precache_message = ''; private $global_option = ''; private $global_config_key = ''; private $global_config = array();

@@ -44,9 +53,13 @@ private $acache = '';

private $nginx_sample = ''; private $acache_backend = ''; private $button_flush; + private $button_precache; protected $select_cache_type = array (); protected $select_invalidation_method = array (); protected $valid_cache_type = array (); + private $precache_logfile = ''; + private $shell_function = false; + private $shell_possibilities = array (); /**

@@ -63,8 +76,23 @@ /* backend driver file */

$this->acache_backend = $this->plugin_dir . $this->plugin_constant . '-backend.php'; /* flush button identifier */ $this->button_flush = $this->plugin_constant . '-flush'; + /* precache button identifier */ + $this->button_precache = $this->plugin_constant . '-precache'; /* global options identifier */ $this->global_option = $this->plugin_constant . '-global'; + /* precache log */ + $this->precache_logfile = sys_get_temp_dir() . '/' . self::precache_log; + /* search for a system function */ + $this->shell_possibilities = array ( 'shell_exec', 'exec', 'system', 'passthru' ); + $disabled_functions = array_map('trim', explode(',', ini_get('disable_functions') ) ); + + foreach ( $this->shell_possibilities as $possible ) { + if ( function_exists ($possible) && ! ( ini_get('safe_mode') || in_array( $possible, $disabled_functions ) ) ) { + /* set shell function */ + $this->shell_function = $possible; + break; + } + } /* set global config key; here, because it's needed for migration */ if ( $this->network )

@@ -89,6 +117,7 @@ /* invalidation method possible values array */

$this->select_invalidation_method = array ( 0 => __( 'flush cache' , $this->plugin_constant ), 1 => __( 'only modified post' , $this->plugin_constant ), + 2 => __( 'modified post and all taxonomies' , $this->plugin_constant ), ); }

@@ -100,24 +129,24 @@ */

public function plugin_setup () { /* initiate backend */ - $this->backend = new WP_FFPC_Backend ( $this->options ); + $this->backend = new WP_FFPC_Backend ( $this->options, $this->network ); /* get all available post types */ $post_types = get_post_types( ); /* cache invalidation hooks */ foreach ( $post_types as $post_type ) { - add_action( 'new_to_publish_' .$post_type , array( $this->backend , 'clear' ), 0 ); - add_action( 'draft_to_publish' .$post_type , array( $this->backend , 'clear' ), 0 ); - add_action( 'pending_to_publish' .$post_type , array( $this->backend , 'clear' ), 0 ); - add_action( 'private_to_publish' .$post_type , array( $this->backend , 'clear' ), 0 ); - add_action( 'publish_' . $post_type , array( $this->backend , 'clear' ), 0 ); + add_action( 'new_to_publish_' .$post_type , array( &$this->backend , 'clear' ), 0 ); + add_action( 'draft_to_publish' .$post_type , array( &$this->backend , 'clear' ), 0 ); + add_action( 'pending_to_publish' .$post_type , array( &$this->backend , 'clear' ), 0 ); + add_action( 'private_to_publish' .$post_type , array( &$this->backend , 'clear' ), 0 ); + add_action( 'publish_' . $post_type , array( &$this->backend , 'clear' ), 0 ); } /* invalidation on some other ocasions as well */ - add_action( 'switch_theme', array( $this->backend , 'clear' ), 0 ); - add_action( 'deleted_post', array( $this->backend , 'clear' ), 0 ); - add_action( 'edit_post', array( $this->backend , 'clear' ), 0 ); + add_action( 'switch_theme', array( &$this->backend , 'clear' ), 0 ); + add_action( 'deleted_post', array( &$this->backend , 'clear' ), 0 ); + add_action( 'edit_post', array( &$this->backend , 'clear' ), 0 ); /* add filter for catching canonical redirects */ add_filter('redirect_canonical', 'wp_ffpc_redirect_callback', 10, 2);

@@ -153,6 +182,33 @@ }

} /** + * extending admin init + * + */ + public function plugin_hook_admin_init () { + /* save parameter updates, if there are any */ + if ( isset( $_POST[ $this->button_flush ] ) ) { + $this->backend->clear( false, true ); + $this->status = 3; + header( "Location: ". $this->settings_link . self::slug_flush ); + } + + /* save parameter updates, if there are any */ + if ( isset( $_POST[ $this->button_precache ] ) ) { + + if ( $this->shell_function == false ) { + $this->status = 5; + header( "Location: ". $this->settings_link . self::slug_precache_disabled ); + } + else { + $this->precache_message = $this->precache(); + $this->status = 4; + header( "Location: ". $this->settings_link . self::slug_precache ); + } + } + } + + /** * admin panel, the admin page displayed for plugin settings */ public function plugin_admin_panel() {

@@ -169,12 +225,14 @@

<script> jQuery(document).ready(function($) { jQuery( "#<?php echo $this->plugin_constant ?>-settings" ).tabs(); + jQuery( "#<?php echo $this->plugin_constant ?>-commands" ).tabs(); }); </script> <?php $this->plugin_donation_form(); + /** * if options were saved, display saved message */

@@ -185,25 +243,32 @@

/** * if options were saved, display saved message */ - if ($_GET['saved']=='true' || $this->status == 1) : ?> + if (isset($_GET[ self::key_save ]) && $_GET[ self::key_save ]=='true' || $this->status == 1) : ?> <div class='updated settings-error'><p><strong><?php _e( 'Settings saved.' , $this->plugin_constant ) ?></strong></p></div> <?php endif; /** * if options were delete, display delete message */ - if ($_GET['deleted']=='true' || $this->status == 2) : ?> + if (isset($_GET[ self::key_delete ]) && $_GET[ self::key_delete ]=='true' || $this->status == 2) : ?> <div class='error'><p><strong><?php _e( 'Plugin options deleted.' , $this->plugin_constant ) ?></strong></p></div> <?php endif; /** * if options were saved */ - if ($_GET['flushed']=='true' || $this->status == 3) : ?> + if (isset($_GET[ self::key_flush ]) && $_GET[ self::key_flush ]=='true' || $this->status == 3) : ?> <div class='updated settings-error'><p><strong><?php _e( "Cache flushed." , $this->plugin_constant ); ?></strong></p></div> <?php endif; /** + * if options were saved, display saved message + */ + if ( ( isset($_GET[ self::key_precache ]) && $_GET[ self::key_precache ]=='true' ) || $this->status == 4) : ?> + <div class='updated settings-error'><p><strong><?php _e( 'Precache process was started, it is now running in the background, please be patient, it may take a very long time to finish.' , $this->plugin_constant ) ?></strong></p></div> + <?php endif; + + /** * the admin panel itself */ ?>

@@ -279,6 +344,7 @@ <li><a href="#<?php echo $this->plugin_constant ?>-debug" class="wp-switch-editor"><?php _e( 'Debug & in-depth', $this->plugin_constant ); ?></a></li>

<li><a href="#<?php echo $this->plugin_constant ?>-exceptions" class="wp-switch-editor"><?php _e( 'Cache exceptions', $this->plugin_constant ); ?></a></li> <li><a href="#<?php echo $this->plugin_constant ?>-memcached" class="wp-switch-editor"><?php _e( 'Memcache(d)', $this->plugin_constant ); ?></a></li> <li><a href="#<?php echo $this->plugin_constant ?>-nginx" class="wp-switch-editor"><?php _e( 'nginx', $this->plugin_constant ); ?></a></li> + <li><a href="#<?php echo $this->plugin_constant ?>-precachelog" class="wp-switch-editor"><?php _e( 'Precache log', $this->plugin_constant ); ?></a></li> </ul> <fieldset id="<?php echo $this->plugin_constant ?>-type">

@@ -299,7 +365,7 @@ <label for="expire"><?php _e('Expiration time (ms)', $this->plugin_constant); ?></label>

</dt> <dd> <input type="number" name="expire" id="expire" value="<?php echo $this->options['expire']; ?>" /> - <span class="description"><?php _e('Sets validity time of entry in milliseconds', $this->plugin_constant); ?></span> + <span class="description"><?php _e('Sets validity time of entry in seconds', $this->plugin_constant); ?></span> </dd> <dt>

@@ -317,7 +383,7 @@ <dd>

<select name="invalidation_method" id="invalidation_method"> <?php $this->print_select_options ( $this->select_invalidation_method , $this->options['invalidation_method'] ) ?> </select> - <span class="description"><?php _e('Select cache invalidation method. <p><strong>Be careful! Selecting "flush cache" will flush the whole cache, including elements that might have been set and used by other applications. Also, invalidating only the post will _not_ clear categories, archive and taxonomy pages, therefore only use this if refreshing after publish can wait until the entries expire on their own.</strong></p>', $this->plugin_constant); ?></span> + <span class="description"><?php _e('Select cache invalidation method. <ol><li><em>flush cache</em> - clears everything in storage, <strong>including values set by other applications</strong></li><li><em>only modified post</em> - clear only the modified posts entry, everything else remains in cache</li><li><em>modified post and all taxonomies</em> - removes all taxonomy term cache ( categories, tags, home, etc ) and the modified post as well</li></ol>', $this->plugin_constant); ?></span> </dd> <dt>

@@ -325,7 +391,7 @@ <label for="prefix_data"><?php _e('Data prefix', $this->plugin_constant); ?></label>

</dt> <dd> <input type="text" name="prefix_data" id="prefix_data" value="<?php echo $this->options['prefix_data']; ?>" /> - <span class="description"><?php _e('Prefix for HTML content keys, can be used in nginx.', $this->plugin_constant); ?></span> + <span class="description"><?php _e('Prefix for HTML content keys, can be used in nginx. If you are caching with nginx, you should update your nginx configuration and restart nginx after changing this value.', $this->plugin_constant); ?></span> </dd> <dt>

@@ -366,6 +432,14 @@ <span class="description"><?php _e('Add X-Cache-Engine HTTP header to HTTP responses.', $this->plugin_constant); ?></span>

</dd> <dt> + <label for="generate_time"><?php _e("Add HTML debug comment", $this->plugin_constant); ?></label> + </dt> + <dd> + <input type="checkbox" name="generate_time" id="generate_time" value="1" <?php checked($this->options['generate_time'],true); ?> /> + <span class="description"><?php _e('Adds comment string including plugin name, cache engine and page generation time to every generated entry before closing <body> tag.', $this->plugin_constant); ?></span> + </dd> + + <dt> <label for="sync_protocols"><?php _e("Enable sync protocolls", $this->plugin_constant); ?></label> </dt> <dd>

@@ -455,28 +529,95 @@ <legend><?php _e('Sample config for nginx to utilize the data entries', $this->plugin_constant); ?></legend>

<pre><?php echo $this->nginx_example(); ?></pre> </fieldset> + <fieldset id="<?php echo $this->plugin_constant ?>-precachelog"> + <legend><?php _e('Log from previous pre-cache generation', $this->plugin_constant); ?></legend> + <?php + if ( @file_exists ( $this->precache_logfile ) ) : + $log = file ( $this->precache_logfile ); + $head = explode( "\t", array_shift( $log )); + $gentime = filemtime ( $this->precache_logfile ); + ?> + <p><strong><?php _e( 'Time of run: ') ?><?php echo date('r', $gentime ); ?></strong></p> + <table style="width:100%; border: 1px solid #ccc;"> + <thead><tr> + <th style="width:70%;"><?php echo $head[0]; ?></th> + <th style="width:15%;"><?php echo $head[1]; ?></th> + <th style="width:15%;"><?php echo $head[2]; ?></th> + </tr></thead> + <?php + foreach ( $log as $line ) : + $line = explode ( "\t", $line ); + ?> + <tr> + <td><?php echo $line[0]; ?></td> + <td><?php echo $line[1]; ?></td> + <td><?php echo $line[2]; ?></td> + </tr> + <?php + endforeach; + ?> + </table> + <?php + else : + _e('No precache log was found!', $this->plugin_constant); + endif; + ?></pre> + </fieldset> + <p class="clear"> <input class="button-primary" type="submit" name="<?php echo $this->button_save ?>" id="<?php echo $this->button_save ?>" value="<?php _e('Save Changes', $this->plugin_constant ) ?>" /> - <input class="button-secondary" style="float: right" type="submit" name="<?php echo $this->button_delete ?>" id="<?php echo $this->button_delete ?>" value="<?php _e('Delete options from DB', $this->plugin_constant ) ?>" /> - <input class="button-secondary" style="float: right" type="submit" name="<?php echo $this->button_flush ?>" id="<?php echo $this->button_flush ?>" value="<?php _e('Clear cache', $this->plugin_constant ) ?>" /> </p> </form> + + <form method="post" action="#" id="<?php echo $this->plugin_constant ?>-commands" class="plugin-admin" style="padding-top:2em;"> + + <ul class="tabs"> + <li><a href="#<?php echo $this->plugin_constant ?>-precache" class="wp-switch-editor"><?php _e( 'Precache', $this->plugin_constant ); ?></a></li> + <li><a href="#<?php echo $this->plugin_constant ?>-flush" class="wp-switch-editor"><?php _e( 'Empty cache', $this->plugin_constant ); ?></a></li> + <li><a href="#<?php echo $this->plugin_constant ?>-reset" class="wp-switch-editor"><?php _e( 'Reset settings', $this->plugin_constant ); ?></a></li> + </ul> + + <fieldset id="<?php echo $this->plugin_constant ?>-precache"> + <legend><?php _e( 'Precache', $this->plugin_constant ); ?></legend> + <dl> + <dt> + <?php if ( ( isset( $_GET[ self::key_precache_disabled ] ) && $_GET[ self::key_precache_disabled ] =='true' ) || $this->status == 5 || $this->shell_function == false ) : ?> + <strong><?php _e( "Precache functionality is disabled due to unavailable system call function. <br />Since precaching may take a very long time, it's done through a background CLI process in order not to run out of max execution time of PHP. Please enable one of the following functions if you whish to use precaching: " , $this->plugin_constant ) ?><?php echo join( ',' , $this->shell_possibilities ); ?></strong> + <?php else: ?> + <input class="button-secondary" type="submit" name="<?php echo $this->button_precache ?>" id="<?php echo $this->button_precache ?>" value="<?php _e('Pre-cache', $this->plugin_constant ) ?>" /> + <?php endif; ?> + </dt> + <dd> + <span class="description"><?php _e('Start a background process that visits all permalinks of all blogs it can found thus forces WordPress to generate cached version of all the pages.<br />The plugin tries to visit links of taxonomy terms without the taxonomy name as well. This may generate 404 hits, please be prepared for these in your logfiles if you plan to pre-cache.', $this->plugin_constant); ?></span> + </dd> + </dl> + </fieldset> + <fieldset id="<?php echo $this->plugin_constant ?>-flush"> + <legend><?php _e( 'Precache', $this->plugin_constant ); ?></legend> + <dl> + <dt> + <input class="button-warning" type="submit" name="<?php echo $this->button_flush ?>" id="<?php echo $this->button_flush ?>" value="<?php _e('Clear cache', $this->plugin_constant ) ?>" /> + </dt> + <dd> + <span class="description"><?php _e ( "Clear all entries in the storage, including the ones that were set by other processes.", $this->plugin_constant ); ?> </span> + </dd> + </dl> + </fieldset> + <fieldset id="<?php echo $this->plugin_constant ?>-reset"> + <legend><?php _e( 'Precache', $this->plugin_constant ); ?></legend> + <dl> + <dt> + <input class="button-warning" type="submit" name="<?php echo $this->button_delete ?>" id="<?php echo $this->button_delete ?>" value="<?php _e('Reset options', $this->plugin_constant ) ?>" /> + </dt> + <dd> + <span class="description"><?php _e ( "Reset settings to defaults.", $this->plugin_constant ); ?> </span> + </dd> + </dl> + </fieldset> + </form> </div> <?php - } - - /** - * extending admin init - * - */ - public function plugin_hook_admin_init () { - /* save parameter updates, if there are any */ - if ( isset( $_POST[ $this->button_flush ] ) ) { - $this->backend->clear(); - $this->status = 3; - header( "Location: ". $this->settings_link . self::slug_flush ); - } } /**

@@ -625,10 +766,13 @@ set $memcached_request 0;

}'; /* replace the data prefix with the configured one */ - $nginx = str_replace ( 'DATAPREFIX' , $this->options['prefix_data'] , $nginx ); + $to_replace = array ( 'DATAPREFIX' , 'SERVERROOT', 'SERVERLOG' ); + $replace_with = array ( $this->options['prefix_data'], ABSPATH, $_SERVER['SERVER_NAME'] ); + $nginx = str_replace ( $to_replace , $replace_with , $nginx ); /* set upstream servers from configured servers, best to get from the actual backend */ $servers = $this->backend->get_servers(); + $nginx_servers = ''; foreach ( array_keys( $servers ) as $server ) { $nginx_servers .= " server ". $server .";\n"; }

@@ -664,6 +808,138 @@ $this->deploy_advanced_cache ();

/* save options to database */ update_site_option( $this->global_option , $this->global_config ); + } + + /** + * generate cache entry for every available permalink, might be very-very slow, + * therefore it starts a background process + * + */ + private function precache () { + /* container for links to precache, well be accessed by reference */ + $links = array(); + + /* when plugin is network wide active, we need to pre-cache for all link of all blogs */ + if ( $this->network ) { + /* list all blogs */ + $blog_list = get_blog_list( 0, 'all' ); + foreach ($blog_list as $blog) { + /* get permalinks for this blog */ + $this->precache_list_permalinks ( $links, $blog['blog_id'] ); + } + } + else { + /* no network, better */ + $this->precache_list_permalinks ( $links, false ); + } + + /* temporary php file, will destroy itself after finish in order to clean up */ + $tmpfile = tempnam(sys_get_temp_dir(), 'wp-ffpc'); + + /* double check if we do have any links to pre-cache */ + if ( !empty ( $links ) ) : + + /* this is the precacher php worker file: logs the links, their generation time and the generated content size + * writes the logfile and destroys itself afterwards + */ + $out .= '<?php + $links = ' . var_export ( $links , true ) . '; + + echo "permalink\tgeneration time (s)\tsize ( kbyte )\n"; + foreach ( $links as $permalink => $dummy ) { + $starttime = explode ( " ", microtime() ); + $starttime = $starttime[1] + $starttime[0]; + + $page = file_get_contents( $permalink ); + $size = round ( ( strlen ( $page ) / 1024 ), 3 ); + + $endtime = explode ( " ", microtime() ); + $endtime = ( $endtime[1] + $endtime[0] ) - $starttime; + + echo $permalink . "\t" . $endtime . "\t" . $size . "\n"; + unset ( $page, $size, $starttime, $endtime ); + sleep( 1 ); + } + unlink ( "'. $tmpfile .'" ); + ?>'; + + file_put_contents ( $tmpfile, $out ); + /* call the precache worker file in the background */ + $shellfunction = $this->shell_function; + $shellfunction( 'php '. $tmpfile .' >'. $this->precache_logfile .' 2>&1 &' ); + + endif; + } + + + /** + * gets all post-like entry permalinks for a site, returns values in passed-by-reference array + * + */ + private function precache_list_permalinks ( &$links, $site = false ) { + /* $post will be populated when running throught the posts */ + global $post; + include_once ( ABSPATH . "wp-load.php" ); + + /* if a site id was provided, save current blog and change to the other site */ + if ( $site !== false ) { + $current_blog = get_current_blog_id(); + switch_to_blog( $site ); + + $url = get_blog_option ( $site, 'siteurl' ); + if ( substr( $url, -1) !== '/' ) + $url = $url . '/'; + + $links[ $url ] = true; + } + + + /* get all published posts */ + $args = array ( + 'post_type' => 'any', + 'posts_per_page' => -1, + 'post_status' => 'publish', + ); + $posts = new WP_Query( $args ); + + /* get all the posts, one by one */ + while ( $posts->have_posts() ) { + $posts->the_post(); + + /* get the permalink for currently selected post */ + switch ($post->post_type) { + case 'revision': + case 'nav_menu_item': + break; + case 'page': + $permalink = get_page_link( $post->ID ); + break; + case 'post': + $permalink = get_permalink( $post->ID ); + break; + case 'attachment': + $permalink = get_attachment_link( $post->ID ); + break; + default: + $permalink = get_post_permalink( $post->ID ); + break; + } + + /* collect permalinks */ + $links[ $permalink ] = true; + + } + + //$this->taxonomy_links ( $links ); + $this->backend->taxonomy_links ( $links ); + + /* just in case, reset $post */ + wp_reset_postdata(); + + /* switch back to original site if we navigated away */ + if ( $site !== false ) { + switch_to_blog( $current_blog ); + } } }
M wp-ffpc-nginx-sample.confwp-ffpc-nginx-sample.conf

@@ -1,11 +1,114 @@

http { - ... + + # memcached servers, generated according to wp-ffpc config upstream memcached-servers { MEMCACHED_SERVERS } - ... + + # PHP-FPM upstream; change it accordingly to your local config! + upstream php-fpm { + server 127.0.0.1:9000; + } + server { - ... + ## Listen ports + listen 80; + listen [::]:80; + + # use _ if you want to accept everything, or replace _ with domain + server_name _; + + # root of WordPress + root SERVERROOT; + + # set up logging + access_log /var/log/nginx/SERVERLOG.access.log; + error_log /var/log/nginx/SERVERLOG.error.log; + + # a bit of security; uncomment if you're using any WAF + ## Block SQL injections + location ~union.*select.*\( { deny all; } + location ~union.*all.*select.* { deny all; } + location ~concat.*\( { deny all; } + + ## Block common exploits + location ~ (<|%3C).*script.*(>|%3E) { deny all; } + location ~ base64_(en|de)code\(.*\) { deny all; } + location ~ (\[|\]|\(|\)|<|>|ê|"|\;) { deny all; } + location ~ (%24&x) { deny all; } + location ~ (%0|%A|%B|%C|%D|%E|%F|127\.0) { deny all; } + location ~ \.\.\/ { deny all; } + location ~ ~$ { deny all; } + location ~ proc/self/environ { deny all; } + location ~ /\.(htaccess|htpasswd) { log_not_found off; deny all; } + + ## Block file injections + location ~ [a-zA-Z0-9_]=http:// { deny all; } + location ~ [a-zA-Z0-9_]=(\.\.//?)+ { deny all; } + location ~ [a-zA-Z0-9_]=/([a-z0-9_.]//?)+ { deny all; } + + ## wordpress security + location ~* wp-config.php { deny all; } + location ~* wp-admin/includes { deny all; } + location ~* wp-app\.log { deny all; } + location ~ (licence|readme|license)\.(html|txt) { deny all; } + + location ~ \.(css|js|jpg|jpeg|png|gif)$ { + expires 7d; + add_header Cache-Control "public, must-revalidate, proxy-revalidate"; + add_header "Vary" "Accept-Encoding"; + } + + ## PHP5-FPM + location ~ (\.php) { + # these settings are usually in fastcgi_params + + fastcgi_index index.php; + fastcgi_connect_timeout 10; + fastcgi_send_timeout 180; + fastcgi_read_timeout 180; + fastcgi_buffer_size 512k; + fastcgi_buffers 4 256k; + fastcgi_busy_buffers_size 512k; + fastcgi_temp_file_write_size 512k; + fastcgi_intercept_errors on; + fastcgi_split_path_info ^(.+\.php)(/.*)$; + fastcgi_keep_conn on; + + fastcgi_param QUERY_STRING $query_string; + fastcgi_param REQUEST_METHOD $request_method; + fastcgi_param CONTENT_TYPE $content_type; + fastcgi_param CONTENT_LENGTH $content_length; + fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; + fastcgi_param SCRIPT_NAME $fastcgi_script_name; + fastcgi_param REQUEST_URI $request_uri; + fastcgi_param DOCUMENT_URI $document_uri; + fastcgi_param DOCUMENT_ROOT $document_root; + fastcgi_param SERVER_PROTOCOL $server_protocol; + fastcgi_param GATEWAY_INTERFACE CGI/1.1; + fastcgi_param SERVER_SOFTWARE nginx; + fastcgi_param REMOTE_ADDR $remote_addr; + fastcgi_param REMOTE_PORT $remote_port; + fastcgi_param SERVER_ADDR $server_addr; + fastcgi_param SERVER_PORT $server_port; + fastcgi_param SERVER_NAME $server_name; + fastcgi_param PATH_INFO $fastcgi_path_info; + fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info; + fastcgi_param REDIRECT_STATUS 200; + + # uncomment these for HTTPS usage + #fastcgi_param HTTPS $https if_not_empty; + #fastcgi_param SSL_PROTOCOL $ssl_protocol if_not_empty; + #fastcgi_param SSL_CIPHER $ssl_cipher if_not_empty; + #fastcgi_param SSL_SESSION_ID $ssl_session_id if_not_empty; + #fastcgi_param SSL_CLIENT_VERIFY $ssl_client_verify if_not_empty; + + fastcgi_pass php-fpm; + } + + location / { + try_files $uri $uri/ @memcached; + } # try to get result from memcached location @memcached {

@@ -32,20 +135,14 @@ error_page 404 = @rewrites;

} if ( $memcached_request = 0) { - rewrite ^ /index.php$request_uri last; + rewrite ^ /index.php?$args last; } } ## rewrite rules location @rewrites { - rewrite ^ /index.php$request_uri last; - } - - location / { - try_files $uri $uri/ @memcached; + rewrite ^ /index.php?$args last; } - ... } } -...
M wp-ffpc.phpwp-ffpc.php

@@ -3,7 +3,7 @@ /*

Plugin Name: WP-FFPC Plugin URI: http://petermolnar.eu/wordpress/wp-ffpc Description: WordPress cache plugin for memcached & nginx - unbeatable speed -Version: 1.0 +Version: 1.1 Author: Peter Molnar <hello@petermolnar.eu> Author URI: http://petermolnar.eu/ License: GPLv3

@@ -46,9 +46,10 @@ 'nocache_page' => false,

'sync_protocols' => false, 'persistent' => false, 'response_header' => false, + 'generate_time' => false, ); -$wp_ffpc = new WP_FFPC ( 'wp-ffpc', '1.0', 'WP-FFPC', $wp_ffpc_defaults, 'https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=XU3DG7LLA76WC' ); +$wp_ffpc = new WP_FFPC ( 'wp-ffpc', '1.1', 'WP-FFPC', $wp_ffpc_defaults, 'https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=XU3DG7LLA76WC' ); ?>