initial release git-svn-id: http://plugins.svn.wordpress.org/wp-ffpc/trunk@505945 b8457f37-d9ea-0310-8a92-e5e31aec5664
cadeyrn cadeyrn@b8457f37-d9ea-0310-8a92-e5e31aec5664
Thu, 16 Feb 2012 14:07:00 +0000
5 files changed,
1159 insertions(+),
0 deletions(-)
A
advanced-cache.php
@@ -0,0 +1,254 @@
+<?php +/** + * part of WordPress plugin WP-FFPC + */ + +/* check for WP cache enabled*/ +if ( !WP_CACHE ) + return false; + +/* check for config */ +if (!isset($wp_ffpc_config)) + return false; + +/* request uri */ +$wp_ffpc_uri = $_SERVER['REQUEST_URI']; +/* query string */ +$wp_ffpc_qs = strpos($wp_ffpc_uri, '?'); + +/* no cache for uri with query strings, things usually go bad that way */ +if ($wp_ffpc_qs !== false) + return false; + +/* no cache for post request (comments, plugins and so on) */ +if ($_SERVER["REQUEST_METHOD"] == 'POST') + return false; + +/** + * Try to avoid enabling the cache if sessions are managed + * with request parameters and a session is active + */ +if (defined('SID') && SID != '') + return false; + +/* no cache for pages starting with /wp- like WP admin */ +if (strpos($wp_ffpc_uri, '/wp-') !== false) + return false; + +/* no cache for robots.txt */ +if ( strpos($wp_ffpc_uri, 'robots.txt') ) + return false; + +/* multisite files can be too large for memcached */ +if (function_exists('is_multisite') && is_multisite() && strpos($wp_ffpc_uri, '/files/') ) + return false; + + +/* no cache for logged in users */ +if (!$wp_ffpc_config['cache_loggedin']) { + foreach ($_COOKIE as $n=>$v) { + // test cookie makes to cache not work!!! + if ($n == 'wordpress_test_cookie') continue; + // wp 2.5 and wp 2.3 have different cookie prefix, skip cache if a post password cookie is present, also + if ( (substr($n, 0, 14) == 'wordpressuser_' || substr($n, 0, 10) == 'wordpress_' || substr($n, 0, 12) == 'wp-postpass_') && !$wp_ffpc_config['cache_loggedin'] ) { + return false; + } + } +} + +global $wp_ffpc_backend_status; +$wp_ffpc_backend_status = wp_ffpc_init( ); + +/* check alive status of backend */ +if ( !$wp_ffpc_backend_status ) + return false; + +/* 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 */ +global $wp_ffpc_data_key; +$wp_ffpc_data_key = $wp_ffpc_config['prefix_data'] . $_SERVER['HTTP_HOST'] . $wp_ffpc_uri; +global $wp_ffpc_meta_key; +$wp_ffpc_meta_key = $wp_ffpc_config['prefix_meta'] . $_SERVER['HTTP_HOST'] . $wp_ffpc_uri; + +/* search for valid data entry */ +global $wp_ffpc_data; +$wp_ffpc_data = wp_ffpc_get ( $wp_ffpc_data_key ); + +/* search for valid meta entry */ +global $wp_ffpc_meta; +$wp_ffpc_meta = wp_ffpc_get ( $wp_ffpc_meta_key ); + +/* data is corrupted or empty */ +if ( !$wp_ffpc_data || !$wp_ffpc_meta ) { + wp_ffpc_start(); + return; +} + +/* 404 status cache */ +if ($wp_ffpc_meta['status'] == 404) { + header("HTTP/1.1 404 Not Found"); + flush(); + die(); +} + +/* server redirect cache */ +if ($wp_ffpc_meta['redirect_location']) { + header('Location: ' . $wp_ffpc_meta['redirect_location']); + flush(); + die(); +} + +/* page is already cached on client side (chrome likes to do this, anyway, it's quite efficient) */ +if (array_key_exists("HTTP_IF_MODIFIED_SINCE", $_SERVER) && !empty($wp_ffpc_meta['lastmodified']) ) { + $if_modified_since = strtotime(preg_replace('/;.*$/', '', $_SERVER["HTTP_IF_MODIFIED_SINCE"])); + /* check is cache is still valid */ + if ( $if_modified_since >= $wp_ffpc_meta['lastmodified'] ) { + header("HTTP/1.0 304 Not Modified"); + flush(); + die(); + } +} + +/* data found & correct, serve it */ +header('Content-Type: ' . $wp_ffpc_meta['mime']); +/* don't allow browser caching of page */ +header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0, post-check=0, pre-check=0'); +header('Pragma: no-cache'); +/* expire at this very moment */ +header('Expires: ' . gmdate("D, d M Y H:i:s", time() ) . " GMT"); + +/* if shortlinks were set */ +if (!empty ( $wp_ffpc_meta['shortlink'] ) ) + header('Link:<'. $wp_ffpc_meta['shortlink'] .'>; rel=shortlink'); + +/* if last modifications were set (for posts & pages) */ +if ( !empty($wp_ffpc_meta['lastmodified']) ) + header('Last-Modified: ' . gmdate("D, d M Y H:i:s", $wp_ffpc_meta['lastmodified'] ). " GMT"); + +/* only set when not multisite, fallback to HTTP HOST */ +$wp_ffpc_pingback_url = (empty( $wp_ffpc_config['url'] )) ? $_SERVER['HTTP_HOST'] : $wp_ffpc_config['url']; + +/* pingback additional header */ +if ($wp_ffpc_config['pingback_status']) + header('X-Pingback: ' . $wp_ffpc_pingback_url . '/xmlrpc.php' ); + +/* for debugging */ +if ($wp_ffpc_config['debug']) + header('X-Cache-Engine: WP-FFPC with ' . $wp_ffpc_config['cache_type']); + +/* HTML data */ +echo $wp_ffpc_data; +flush(); +die(); + +/** + * FUNCTIONS + */ + +/** + * starts caching + * + */ +function wp_ffpc_start( ) { + ob_start('wp_ffpc_callback'); +} + +/** + * write cache function, called when page generation ended + */ +function wp_ffpc_callback($buffer) { + global $wp_ffpc_config; + global $wp_ffpc_data; + global $wp_ffpc_meta; + global $wp_ffpc_redirect; + global $wp_ffpc_meta_key; + global $wp_ffpc_data_key; + + /* no is_home = error */ + if (!function_exists('is_home')) + return $buffer; + + /* no <body> close tag = not HTML, don't cache */ + if (strpos($buffer, '</body>') === false) + return $buffer; + + /* reset meta to solve conflicts */ + $wp_ffpc_meta = array(); + + /* WP is sending a redirect */ + if ($wp_ffpc_redirect) { + $wp_ffpc_meta['redirect_location'] = $wp_ffpc_redirect; + wp_ffpc_write(); + return $buffer; + } + + /* trim unneeded whitespace from beginning / ending of buffer */ + $buffer = trim($buffer); + + /* Can be a trackback or other things without a body. + We do not cache them, WP needs to get those calls. */ + if (strlen($buffer) == 0) + return ''; + + if ( is_home() ) + $wp_ffpc_meta['type'] = 'home'; + elseif (is_feed() ) + $wp_ffpc_meta['type'] = 'feed'; + elseif ( is_archive() ) + $wp_ffpc_meta['type'] = 'archive'; + elseif ( is_single() ) + $wp_ffpc_meta['type'] = 'single'; + else if ( is_page() ) + $wp_ffpc_meta['type'] = 'page'; + else + $wp_ffpc_meta['type'] = 'unknown'; + + /* check if caching is disabled for page type */ + $nocache_key = 'nocache_'. $wp_ffpc_meta['type']; + + if ( $wp_ffpc_config[$nocache_key] == 1 ) { + return $buffer; + } + + if ( is_404() ) + $wp_ffpc_meta['status'] = 404; + + /* feed is xml, all others forced to be HTML */ + if ( is_feed() ) + $wp_ffpc_meta['mime'] = 'text/xml;charset='; + else + $wp_ffpc_meta['mime'] = 'text/html;charset='; + + /* set mimetype */ + $wp_ffpc_meta['mime'] = $wp_ffpc_meta['mime'] . $wp_ffpc_config['charset']; + + /* get shortlink, if possible */ + if (function_exists('wp_get_shortlink')) + { + $shortlink = wp_get_shortlink( ); + if (!empty ( $shortlink ) ) + $wp_ffpc_meta['shortlink'] = $shortlink; + } + + /* try if post is available + if made with archieve, last listed post can make this go bad + */ + global $post; + if ( !empty($post) && ( $wp_ffpc_meta['type'] == 'single' || $wp_ffpc_meta['type'] == 'page' ) ) + { + /* get last modification data */ + if (!empty ( $post->post_modified_gmt ) ) + $wp_ffpc_meta['lastmodified'] = strtotime ( $post->post_modified_gmt ); + } + /* set meta */ + wp_ffpc_set ( $wp_ffpc_meta_key, $wp_ffpc_meta ); + /* set data */ + wp_ffpc_set ( $wp_ffpc_data_key, $buffer ); + + /* vital for nginx version */ + header("HTTP/1.1 200 OK"); + /* echoes HTML out */ + return $buffer; +} + +?>
A
css/wp-ffpc.admin.css
@@ -0,0 +1,53 @@
+dt { + margin-top: 2em; + font-weight:bold; +} + +dd { + +} +fieldset { + display:block; + margin:0 1% 0 1%; + clear:none; +} + +legend { + font-weight:bold; + padding:0; + margin:0; + font-size:130%; + padding-top:3em; +} + +.default { + display:block; + padding-left: 1em; + font-size:90%; + color:#666; +} + +.description { + display:block; +} + +.grid50 { + float:left; + display:block; + text-align:left; + margin:0 1% 0 1%; + width:48%; + overflow:auto; +} + +.clearcolumns { + clear:both; +} + +.error-msg { + color: #990000; +} + +.ok-msg { + color: #009900; +}
A
readme.txt
@@ -0,0 +1,45 @@
+=== WP-FFPC === +Contributors: cadeyrn +Tags: cache, APC, memcached, full page cache +Requires at least: 2.7 +Tested up to: 3.3 +Stable tag: 0.1 + +Fast Full Page Cache, backend can be memcached or APC + + +== Description == +WP-FFPC is a full page cache plugin for WordPress. It can use APC or a memcached server as backend. +PHP has two extension for communication with a memcached server, named Memcache and Memcached. The plugin can utilize both. +A special function is that when used with the Memcache extension it produces memcached entries that can be read and served directly from nginx, making the cache insanely fast. + +The naming stands for Fast Full Page Cache. + +If used in WordPress Network, the configuration will only be available for network admins at the network admin panel, and will be system-wide and will be applied for every blog. + +Some parts were based on Hyper Cache plugin by Satollo (info@satollo.net). + + += Usage = +Configure the plugin at the admin section + +== Installation == +1. Upload contents of `wp-ffpc.zip` to the `/wp-content/plugins/` directory +2. Activate the plugin through the `Plugins` menu in WordPress (please use network wide activation if used in a WordPress Network) +3. Fine tune the settings in `Settings` -> `wp-ffpc` menu in WordPress. For WordPress Network, please visit the Network Admin panel, the options will be available at WP-FFPC menu entry. + +== Frequently Asked Questions == + + +== Screenshots == + + +== Upgrade Notice == + + +== Changelog == + += 0.1 = +2012.02.16 + +* first public release
A
wp-ffpc-common.php
@@ -0,0 +1,180 @@
+<?php +/** + * part of WordPress plugin WP-FFPC + */ + +/** + * function to test if selected backend is available & alive + */ +global $wp_ffpc_backend; +global $wp_nmc_redirect; + +/** + * init and backend alive check function + * + * @param $type [optional] if set, alive will be tested against this + * if false, backend will be globally initiated + * when set, backend will not become global, just tested if alive + */ +function wp_ffpc_init( $type = false ) { + global $wp_ffpc_config; + $wp_ffpc_backend_status = false; + + $reg_backend = $type; + // $type is to test an exact backend */ + if ( !$type ) + $type = $wp_ffpc_config['cache_type']; + + + /* verify selected storage is available */ + switch ($type) + { + /* in case of apc */ + case 'apc': + /* verify apc functions exist, apc ext is loaded */ + if (!function_exists('apc_cache_info')) + return false; + /* verify apc is working */ + if ( !apc_cache_info() ) + return false; + $wp_ffpc_backend_status = true; + break; + + /* in case of Memcache */ + case 'memcache': + /* Memcache class does not exist, Memcache extension is not available */ + if (!class_exists('Memcache')) + return false; + if ($reg_backend) + global $wp_ffpc_backend; + $wp_ffpc_backend = new Memcache(); + $wp_ffpc_backend->addServer( $wp_ffpc_config['host'] , $wp_ffpc_config['port'] ); + $wp_ffpc_backend_status = $wp_ffpc_backend->getServerStatus( $wp_ffpc_config['host'] , $wp_ffpc_config['port'] ); + break; + + /* in case of Memcached */ + case 'memcached': + /* Memcached class does not exist, Memcached extension is not available */ + if (!class_exists('Memcached')) + return false; + if ($reg_backend) + global $wp_ffpc_backend; + $wp_ffpc_backend = new Memcached(); + $wp_ffpc_backend->addServer( $wp_ffpc_config['host'] , $wp_ffpc_config['port'] ); + $wp_ffpc_backend_status = array_key_exists( $wp_ffpc_config['host'] . ':' . $wp_ffpc_config['port'] , $wp_ffpc_backend->getStats() ); + break; + + /* cache type is invalid */ + default: + return false; + } + return $wp_ffpc_backend_status; +} + +/** + * clear cache element or flush cache + * + * @param $post_id [optional] : if registered with invalidation hook, post_id will be passed + */ +function wp_ffpc_clear ( $post_id = false ) { + global $wp_ffpc_config; + global $post; + + /* post invalidation enabled */ + if ( $wp_ffpc_config['invalidation_method'] ) + { + $path = substr ( get_permalink($post_id) , 7 ); + if (empty($path)) + return false; + $meta = $wp_ffpc_config['prefix-meta'] . $path; + $data = $wp_ffpc_config['prefix-data'] . $path; + } + + switch ($wp_ffpc_config['cache_type']) + { + /* in case of apc */ + case 'apc': + if ( $wp_ffpc_config['invalidation_method'] ) + { + apc_delete ( $meta ); + apc_delete ( $data ); + } + else + { + apc_clear_cache('user'); + apc_clear_cache('system'); + } + break; + + /* in case of Memcache */ + case 'memcache': + case 'memcached': + global $wp_ffpc_backend; + if ( $wp_ffpc_config['invalidation_method'] ) + { + $wp_ffpc_backend->delete( $meta ); + $wp_ffpc_backend->delete( $data ); + } + else + { + $wp_ffpc_backend->flush(); + } + break; + + /* cache type is invalid */ + default: + return false; + } + return true; +} + +/** + * sets a key-value pair in backend + * + * @param &$key store key, passed by reference for speed + * @param &$data store value, passed by reference for speed + * + */ +function wp_ffpc_set ( &$key, &$data ) { + global $wp_ffpc_config; + + switch ($wp_ffpc_config['cache_type']) + { + case 'apc': + /* use apc_store to overwrite data is existed */ + apc_store( $key , $data , $wp_ffpc_config['expire']); + break; + case 'memcache': + global $wp_ffpc_backend; + /* false to disable compression, vital for nginx */ + $wp_ffpc_backend->set ( $key, $data , false, $wp_ffpc_config['expire'] ); + break; + case 'memcached': + global $wp_ffpc_backend; + $wp_ffpc_backend->set ( $key, $data , $wp_ffpc_config['expire'] ); + break; + } +} + +/** + * gets cached element by key + * + * @param &$key: key of needed cache element + * + */ +function wp_ffpc_get( &$key ) { + global $wp_ffpc_config; + + switch ($wp_ffpc_config['cache_type']) + { + case 'apc': + return apc_fetch($key); + case 'memcache': + case 'memcached': + global $wp_ffpc_backend; + return $wp_ffpc_backend->get($key); + default: + return false; + } +} +?>
A
wp-ffpc.php
@@ -0,0 +1,627 @@
+<?php +/* +Plugin Name: WP-FFPC +Version: 0.1 +Plugin URI: http://petermolnar.eu/wordpress/wp-ffpc +Description: Fast Full Page Cache, backend can be memcached or APC +Author: Peter Molnar +Author URI: http://petermolnar.eu/ +License: GPL2 +*/ + +/* Copyright 2010-2011 Peter Molnar (email : hello@petermolnar.eu ) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License, version 2, as + published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + +/* fix */ +if ( ! defined( 'WP_PLUGIN_URL' ) ) + define( 'WP_PLUGIN_URL', get_option( 'siteurl' ) . '/wp-content/plugins' ); +if ( ! defined( 'WP_PLUGIN_DIR' ) ) + define( 'WP_PLUGIN_DIR', ABSPATH . 'wp-content/plugins' ); + +/* constants */ +define ( 'WP_FFPC_PARAM' , 'wp-ffpc' ); +define ( 'WP_FFPC_OPTION_GROUP' , 'wp-ffpcparams' ); +define ( 'WP_FFPC_OPTIONS_PAGE' , 'wp-ffpcoptions' ); +define ( 'WP_FFPC_URL' , WP_PLUGIN_URL . '/' . WP_FFPC_PARAM ); +define ( 'WP_FFPC_DIR' , WP_PLUGIN_DIR . '/' . WP_FFPC_PARAM ); +define ( 'WP_FFPC_CONF_DIR' , WP_PLUGIN_DIR . '/' . WP_FFPC_PARAM .'/config' ); +define ( 'WP_FFPC_ACACHE_MAIN_FILE' , ABSPATH . 'wp-content/advanced-cache.php' ); +define ( 'WP_FFPC_ACACHE_INC_FILE' , WP_FFPC_DIR. '/advanced-cache.php' ); +define ( 'WP_FFPC_ACACHE_COMMON_FILE' , WP_FFPC_DIR. '/wp-ffpc-common.php' ); +define ( 'WP_FFPC_CONFIG_VAR' , '$wp_ffpc_config' ); + +include (WP_FFPC_DIR .'/wp-ffpc-common.php'); + +if (!class_exists('WPFFPC')) { + + /** + * main class + * + */ + class WPFFPC { + + /* for options array */ + var $options = array(); + /* for default options array */ + var $defaults = array(); + /* memcached server object */ + var $memcached = NULL; + var $memcached_string = ''; + + /* status, 0 = nothing happened*/ + var $status = 0; + + /** + * constructor + * + */ + function __construct() { + + /* register options */ + $this->get_options(); + + /* check is backend is available */ + $alive = wp_ffpc_init( $this->options['cache_type'] ); + + /* don't register hooks if backend is dead */ + if ($alive) + { + /* init inactivation hooks */ + add_action('switch_theme', array( $this , 'invalidate'), 0); + add_action('edit_post', array( $this , 'invalidate'), 0); + add_action('publish_post', array( $this , 'invalidate'), 0); + add_action('delete_post', array( $this , 'invalidate'), 0); + + /* Capture and register if a redirect is sent back from WP, so the cache + can cache (or ignore) it. Redirects were source of problems for blogs + with more than one host name (eg. domain.com and www.domain.com) comined + with the use of Hyper Cache.*/ + add_filter('redirect_canonical', array( $this , 'redirect_canonical') , 10, 2); + } + + /* add admin styling */ + if( is_admin() ) + { + wp_enqueue_style( WP_FFPC_PARAM . '.admin.css' , WP_FFPC_URL . '/css/'. WP_FFPC_PARAM .'.admin.css', false, '0.1'); + } + + /* on activation */ + register_activation_hook(__FILE__ , array( $this , 'activate') ); + + /* on deactivation */ + register_deactivation_hook(__FILE__ , array( $this , 'deactivate') ); + + /* on uninstall */ + register_uninstall_hook(__FILE__ , array( $this , 'uninstall') ); + + /* init plugin in the admin section */ + /* if multisite, admin page will be on network admin section */ + if ( MULTISITE ) + add_action('network_admin_menu', array( $this , 'admin_init') ); + /* not network, will be in simple admin menu */ + else + add_action('admin_menu', array( $this , 'admin_init') ); + } + + /** + * activation hook: save default settings in order to eliminate bugs. + * + */ + function activate ( ) { + $this->save_settings( true ); + } + + /** + * init function for admin section + * + */ + function admin_init () { + /* register options */ + add_site_option( WP_FFPC_PARAM, $this->options , '' , 'no'); + + /* save parameter updates, if there are any */ + if ( isset($_POST[WP_FFPC_PARAM . '-save']) ) + { + $this->save_settings (); + $this->status = 1; + header("Location: admin.php?page=" . WP_FFPC_OPTIONS_PAGE . "&saved=true"); + } + + add_menu_page('Edit WP-FFPC options', __('WP-FFPC', WP_FFPC_PARAM ), 10, WP_FFPC_OPTIONS_PAGE , array ( $this , 'admin_panel' ) ); + } + + /** + * settings panel at admin section + * + */ + function admin_panel ( ) { + + /** + * security + */ + if( ! function_exists( 'current_user_can' ) || ! current_user_can( 'manage_options' ) ){ + die( ); + } + + /** + * if options were saved + */ + if ($_GET['saved']=='true' || $this->status == 1) : ?> + <div id='setting-error-settings_updated' class='updated settings-error'><p><strong>Settings saved.</strong></p></div> + <?php endif; + + + /** + * the admin panel itself + */ + ?> + <?php if ( !WP_CACHE ) : ?> + <div class="updated settings-error"><p><strong>WARNING: WP_CACHE is disabled, plugin will not work that way. Please add define( 'WP_CACHE', true ); into the beginning of wp-config.php</strong></p></div> + <?php endif; ?> + + <div class="wrap"> + <h2><?php _e( 'NMC settings', WP_FFPC_PARAM ) ; ?></h2> + <form method="post" action="#"> + + <fieldset> + <legend><?php _e( 'Global settings', WP_FFPC_PARAM ); ?></legend> + <dl> + <div class="grid50"> + + <dt> + <label for="cache_type"><?php _e('Cache invalidation method', WP_FFPC_PARAM); ?></label> + </dt> + <dd> + <select name="cache_type" id="cache_type"> + <?php $this->cache_type ( $this->options['cache_type'] ) ?> + </select> + <span class="description"><?php _e('Select cache invalidation method.', WP_FFPC_PARAM); ?></span> + <span class="default"><?php _e('Default ', WP_FFPC_PARAM); ?>: <?php $this->cache_type( $this->defaults['cache_type'] , true ) ; ?></span> + </dd> + + <dt> + <label for="expire"><?php _e('Entry invalidation time', WP_FFPC_PARAM); ?></label> + </dt> + <dd> + <input type="number" name="expire" id="expire" value="<?php echo $this->options['expire']; ?>" /> + <span class="description"><?php _e('How long will an entry be valid', WP_FFPC_PARAM); ?></span> + <span class="default"><?php _e('Default ', WP_FFPC_PARAM); ?>: <?php echo $this->defaults['expire']; ?></span> + </dd> + + <dt> + <label for="charset"><?php _e('Charset to send data with.', WP_FFPC_PARAM); ?></label> + </dt> + <dd> + <input type="text" name="charset" id="charset" value="<?php echo $this->options['charset']; ?>" /> + <span class="description"><?php _e('Charset of HTML and XML (pages and feeds) data.', WP_FFPC_PARAM); ?></span> + <span class="default"><?php _e('Default ', WP_FFPC_PARAM); ?>: <?php echo $this->defaults['charset']; ?></span> + </dd> + + <dt> + <label for="invalidation_method"><?php _e('Cache invalidation method', WP_FFPC_PARAM); ?></label> + </dt> + <dd> + <select name="invalidation_method" id="invalidation_method"> + <?php $this->invalidation_method ( $this->options['invalidation_method'] ) ?> + </select> + <span class="description"><?php _e('Select cache invalidation method. <p><strong>WARNING! When selection "all", the cache will be fully flushed, including elements that were set by other applications.</strong></p>', WP_FFPC_PARAM); ?></span> + <span class="default"><?php _e('Default ', WP_FFPC_PARAM); ?>: <?php $this->invalidation_method( $this->defaults['invalidation_method'] , true ) ; ?></span> + </dd> + + <dt> + <label for="prefix_data"><?php _e('Data prefix', WP_FFPC_PARAM); ?></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.', WP_FFPC_PARAM); ?></span> + <span class="default"><?php _e('Default ', WP_FFPC_PARAM); ?>: <?php echo $this->defaults['prefix_data']; ?></span> + </dd> + + <dt> + <label for="prefix_meta"><?php _e('Meta prefix', WP_FFPC_PARAM); ?></label> + </dt> + <dd> + <input type="text" name="prefix_meta" id="prefix_meta" value="<?php echo $this->options['prefix_meta']; ?>" /> + <span class="description"><?php _e('Prefix for meta content keys, used only with PHP processing.', WP_FFPC_PARAM); ?></span> + <span class="default"><?php _e('Default ', WP_FFPC_PARAM); ?>: <?php echo $this->defaults['prefix_meta']; ?></span> + </dd> + + <dt> + <label for="debug"><?php _e("Enable debug mode", WP_FFPC_PARAM); ?></label> + </dt> + <dd> + <input type="checkbox" name="debug" id="debug" value="1" <?php checked($this->options['debug'],true); ?> /> + <span class="description"><?php _e('An additional header, "X-Cache-Engine" will be added when pages are served through WP-FFPC.', WP_FFPC_PARAM); ?></span> + <span class="default"><?php _e('Default ', WP_FFPC_PARAM); ?>: <?php $this->print_bool( $this->defaults['debug']); ?></span> + </dd> + + <dt> + <label for="pingback_status"><?php _e("Enable pingback links", WP_FFPC_PARAM); ?></label> + </dt> + <dd> + <input type="checkbox" name="pingback_status" id="pingback_status" value="1" <?php checked($this->options['pingback_status'],true); ?> /> + <span class="description"><?php _e('Enable "X-Pingback" headers in cached pages; will always use accessed hostname as host!', WP_FFPC_PARAM); ?></span> + <span class="default"><?php _e('Default ', WP_FFPC_PARAM); ?>: <?php $this->print_bool( $this->defaults['pingback_status']); ?></span> + </dd> + + </div> + + <div class="grid50"> + <dt> + <label for="cache_loggedin"><?php _e('Enable cache for logged in users', WP_FFPC_PARAM); ?></label> + </dt> + <dd> + <input type="checkbox" name="cache_loggedin" id="cache_loggedin" value="1" <?php checked($this->options['cache_loggedin'],true); ?> /> + <span class="description"><?php _e('Cache pages even if user is logged in.', WP_FFPC_PARAM); ?></span> + <span class="default"><?php _e('Default ', WP_FFPC_PARAM); ?>: <?php $this->print_bool( $this->defaults['cache_loggedin']); ?></span> + </dd> + + <dt> + <label for="nocache_home"><?php _e("Don't cache home", WP_FFPC_PARAM); ?></label> + </dt> + <dd> + <input type="checkbox" name="nocache_home" id="nocache_home" value="1" <?php checked($this->options['nocache_home'],true); ?> /> + <span class="description"><?php _e('Exclude home page from caching', WP_FFPC_PARAM); ?></span> + <span class="default"><?php _e('Default ', WP_FFPC_PARAM); ?>: <?php $this->print_bool( $this->defaults['nocache_home']); ?></span> + </dd> + + <dt> + <label for="nocache_feed"><?php _e("Don't cache feeds", WP_FFPC_PARAM); ?></label> + </dt> + <dd> + <input type="checkbox" name="nocache_feed" id="nocache_feed" value="1" <?php checked($this->options['nocache_feed'],true); ?> /> + <span class="description"><?php _e('Exclude feeds from caching.', WP_FFPC_PARAM); ?></span> + <span class="default"><?php _e('Default ', WP_FFPC_PARAM); ?>: <?php $this->print_bool( $this->defaults['nocache_feed']); ?></span> + </dd> + + <dt> + <label for="nocache_archive"><?php _e("Don't cache archives", WP_FFPC_PARAM); ?></label> + </dt> + <dd> + <input type="checkbox" name="nocache_archive" id="nocache_archive" value="1" <?php checked($this->options['nocache_archive'],true); ?> /> + <span class="description"><?php _e('Exclude archives from caching.', WP_FFPC_PARAM); ?></span> + <span class="default"><?php _e('Default ', WP_FFPC_PARAM); ?>: <?php $this->print_bool( $this->defaults['nocache_archive']); ?></span> + </dd> + + <dt> + <label for="nocache_single"><?php _e("Don't cache posts (and single-type entries)", WP_FFPC_PARAM); ?></label> + </dt> + <dd> + <input type="checkbox" name="nocache_single" id="nocache_single" value="1" <?php checked($this->options['nocache_single'],true); ?> /> + <span class="description"><?php _e('Exclude singles from caching.', WP_FFPC_PARAM); ?></span> + <span class="default"><?php _e('Default ', WP_FFPC_PARAM); ?>: <?php $this->print_bool( $this->defaults['nocache_single']); ?></span> + </dd> + + <dt> + <label for="nocache_page"><?php _e("Don't cache pages", WP_FFPC_PARAM); ?></label> + </dt> + <dd> + <input type="checkbox" name="nocache_page" id="nocache_page" value="1" <?php checked($this->options['nocache_page'],true); ?> /> + <span class="description"><?php _e('Exclude pages from caching.', WP_FFPC_PARAM); ?></span> + <span class="default"><?php _e('Default ', WP_FFPC_PARAM); ?>: <?php $this->print_bool( $this->defaults['nocache_page']); ?></span> + </dd> + </div> + </dl> + </fieldset> + + <fieldset class="grid50"> + <legend><?php _e('Settings for memcached backend', WP_FFPC_PARAM); ?></legend> + + <?php if ( !class_exists('Memcache') && !class_exists('Memcached') ): ?> + <h1 class="error">No PHP memcached extension was found. To use memcached, you need PHP Memcache or PHP Memcached extension.</h1> + <?php endif; ?> + + <div> + <strong><?php _e( 'Memcached server status: ', WP_FFPC_PARAM ) ; ?> + <?php + if (class_exists('Memcache')) + $server_status = wp_ffpc_init('memcache'); + elseif (class_exists('Memcached')) + $server_status = wp_ffpc_init('memcached'); + + $server_status = ( $server_status ) ? '<span class="error-msg">down</span>' : '<span class="ok-msg">up & running</span>' ; + echo $server_status; + ?> + </strong> + </div> + + <dl> + + <dt> + <label for="host"><?php _e('Host', WP_FFPC_PARAM); ?></label> + </dt> + <dd> + <input type="text" name="host" id="host" value="<?php echo $this->options['host']; ?>" /> + <span class="description"><?php _e('Hostname for memcached server', WP_FFPC_PARAM); ?></span> + <span class="default"><?php _e('Default ', WP_FFPC_PARAM); ?>: <?php echo $this->defaults['host']; ?></span> + </dd> + + <dt> + <label for="port"><?php _e('Host', WP_FFPC_PARAM); ?></label> + </dt> + <dd> + <input type="number" name="port" id="port" value="<?php echo $this->options['port']; ?>" /> + <span class="description"><?php _e('Port for memcached server', WP_FFPC_PARAM); ?></span> + <span class="default"><?php _e('Default ', WP_FFPC_PARAM); ?>: <?php echo $this->defaults['port']; ?></span> + </dd> + + </dl> + </fieldset> + + <?php if ( $this->options['cache_type'] == 'memcache' ) : ?> + + <fieldset class="grid50"> + <legend><?php _e('Sample config for nginx to utilize the data entries', WP_FFPC_PARAM); ?></legend> + <pre>location / { + try_files $uri $uri/ @memcached; +} + +location @memcached { + default_type text/html; + set $memcached_key <?php echo $this->options['prefix_data'];?>$host$request_uri; + memcached_pass <?php echo $this->options['host'];?>:<?php echo $this->options['port'];?>; + error_page 404 = @rewrites; +} + +location @rewrites { + rewrite ^(.*)$ /index.php?q=$1 last; +}</pre> + </fieldset> + + <? endif; ?> + + <p class="clearcolumns"><input class="button-primary" type="submit" name="<?php echo WP_FFPC_PARAM; ?>-save" id="<?php echo WP_FFPC_PARAM; ?>-save" value="Save Changes" /></p> + </form> + <?php + + } + + /** + * generates cache type select box + * + * @param $current + * the active or required size's identifier + * + * @param $returntext + * boolean: is true, the description will be returned of $current size + * + * @return + * prints either description of $current + * or option list for a <select> input field with $current set as active + * + */ + function cache_type ( $current , $returntext = false ) { + + $e = array ( + 'apc' => 'use APC as store', + 'memcache' => 'use memcached server with Memcache extension', + 'memcached' => 'use memcached server with Memcached extension', + ); + + $this->print_select_options ( $e , $current , $returntext ); + + } + + /** + * deactivation hook: clear advanced-cache config file + * + */ + function deactivate ( ) { + if (@file_exists (WP_FFPC_ACACHE_MAIN_FILE)) + @unlink (WP_FFPC_ACACHE_MAIN_FILE); + } + + /** + * invalidate cache + */ + function invalidate ( $post_id ) { + wp_ffpc_clear ( $post_id ); + } + + /** + * generates invalidation method select box + * + * @param $current + * the active or required size's identifier + * + * @param $returntext + * boolean: is true, the description will be returned of $current size + * + * @return + * prints either description of $current + * or option list for a <select> input field with $current set as active + * + */ + function invalidation_method ( $current , $returntext = false ) { + + $e = array ( + 0 => 'all cached pages (WARNING! Flushes _all_ cached entrys! )', + 1 => 'only modified post', + ); + + $this->print_select_options ( $e , $current , $returntext ); + } + + /** + * generates main advanced-cache system-wide config file + * + */ + function generate_config() { + + $acache = WP_FFPC_ACACHE_MAIN_FILE; + /* is file currently exists, delete it*/ + if ( @file_exists( $acache )) + unlink ($acache); + + /* is deletion was unsuccessful, die, we have no rights to do that */ + if ( @file_exists( $acache )) + return false; + + $string = '<?php'. "\n" . +'global '. WP_FFPC_CONFIG_VAR .' ;' . "\n"; + + foreach($this->options as $key => $val) { + if (is_string($val)) + $val = "'" . $val . "'"; + + $string .= WP_FFPC_CONFIG_VAR . '[\'' . $key . '\']=' . $val . ";\n"; + } + + $string .= "\n\ninclude_once ('" . WP_FFPC_ACACHE_COMMON_FILE . "');\ninclude_once ('" . WP_FFPC_ACACHE_INC_FILE . "');\n"; + + file_put_contents($acache, $string); + return true; + } + + /** + * parameters array with default values; + * + */ + function get_options ( ) { + $defaults = array ( + 'port'=>11211, + 'host'=>'127.0.0.1', + 'expire'=>300, + 'invalidation_method'=>0, + 'prefix_meta' =>'meta-', + 'prefix_data' =>'data-', + 'charset' => 'utf-8', + 'pingback_status'=> false, + 'debug' => 1, + 'cache_type' => 'memcache', + 'cache_loggedin' => false, + 'nocache_home' => false, + 'nocache_feed' => false, + 'nocache_archive' => false, + 'nocache_single' => false, + 'nocache_page' => false, + ); + + $this->defaults = $defaults; + + $this->options = get_site_option( WP_FFPC_PARAM , $defaults, false ); + } + + /** + * prints `true` or `false` depending on a bool variable. + * + * @param $val + * The boolen variable to print status of. + * + */ + function print_bool ( $val ) { + $bool = $val? 'true' : 'false'; + echo $bool; + } + + /** + * select field processor + * + * @param sizes + * array to build <option> values of + * + * @param $current + * the current resize type + * + * @param $returntext + * boolean: is true, the description will be returned of $current type + * + * @return + * prints either description of $current + * or option list for a <select> input field with $current set as active + * + */ + function print_select_options ( $sizes, $current, $returntext=false ) { + + if ( $returntext ) + { + _e( $sizes[ $current ] , WP_FFPC_PARAM); + return; + } + + foreach ($sizes as $ext=>$name) + { + ?> + <option value="<?php echo $ext ?>" <?php selected( $ext , $current ); ?>> + <?php _e( $name , WP_FFPC_PARAM); ?> + </option> + <?php + } + + } + + /** + * function to be able to store redirects + */ + function redirect_canonical($redirect_url, $requested_url) { + global $wp_nmc_redirect; + $wp_nmc_redirect = $redirect_url; + return $redirect_url; + } + + /** + * save settings function + * + */ + function save_settings ( $firstrun = false ) { + + /** + * update params from $_POST + */ + foreach ($this->options as $name=>$optionvalue) + { + if (!empty($_POST[$name])) + { + $update = $_POST[$name]; + if (strlen($update)!=0 && !is_numeric($update)) + $update = stripslashes($update); + } + elseif ( ( empty($_POST[$name]) && is_bool ($this->defaults[$name]) ) || is_numeric( $update ) ) + { + $update = 0; + } + else + { + $update = $this->defaults[$name]; + } + $this->options[$name] = $update; + } + + update_site_option( WP_FFPC_PARAM , $this->options ); + + if ( ! $firstrun ) + $this->generate_config(); + } + + /** + * clean up at uninstall + * + */ + function uninstall ( ) { + delete_site_option( WP_FFPC_PARAM ); + } + + } +} + +/** + * instantiate the class + */ +$wp_nmc = new WPFFPC(); + + +?>