trunk replaced with branch v1.0; merge was impossible; files added
git-svn-id: http://plugins.svn.wordpress.org/wp-ffpc/trunk@684134 b8457f37-d9ea-0310-8a92-e5e31aec5664
This commit is contained in:
parent
f845f9f22b
commit
fa71c7a216
7 changed files with 2354 additions and 0 deletions
12
uninstall.php
Normal file
12
uninstall.php
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* uninstall file for WP-FFPC; uninstall hook does not remove the databse options
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* get the worker file */
|
||||||
|
include_once ( 'wp-ffpc.php' );
|
||||||
|
|
||||||
|
/* run uninstall function */
|
||||||
|
$wp_ffpc->plugin_uninstall();
|
||||||
|
|
||||||
|
?>
|
534
wp-ffpc-abstract.php
Normal file
534
wp-ffpc-abstract.php
Normal file
|
@ -0,0 +1,534 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* abstract base class of WP-* plugins from hello@petermolnar.eu
|
||||||
|
*/
|
||||||
|
|
||||||
|
if ( ! defined( 'WP_CONTENT_URL' ) ) define( 'WP_CONTENT_URL', WP_SITEURL . '/wp-content' );
|
||||||
|
if ( ! defined( 'WP_CONTENT_DIR' ) ) define( 'WP_CONTENT_DIR', ABSPATH . 'wp-content' );
|
||||||
|
if ( ! defined( 'WP_PLUGIN_URL' ) ) define( 'WP_PLUGIN_URL', WP_CONTENT_URL . '/plugins' );
|
||||||
|
if ( ! defined( 'WP_PLUGIN_DIR' ) ) define( 'WP_PLUGIN_DIR', WP_CONTENT_DIR . '/plugins' );
|
||||||
|
if ( ! defined( 'WPMU_PLUGIN_URL' ) ) define( 'WPMU_PLUGIN_URL', WP_CONTENT_URL . '/mu-plugins' );
|
||||||
|
if ( ! defined( 'WPMU_PLUGIN_DIR' ) ) define( 'WPMU_PLUGIN_DIR', WP_CONTENT_DIR . '/mu-plugins' );
|
||||||
|
|
||||||
|
if (!class_exists('WP_Plugins_Abstract')) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* abstract class for common, required functionalities
|
||||||
|
*
|
||||||
|
* @var string $plugin_constant The name of the plugin, will be used with strings, names, etc.
|
||||||
|
* @var array $options Plugin options array
|
||||||
|
* @var array $defaults Default options array
|
||||||
|
* @var int $status Save, delete, neutral status storage
|
||||||
|
* @var boolean $network true if plugin is Network Active
|
||||||
|
* @var string $settings_link Link for settings page
|
||||||
|
* @var string $plugin_url URL of plugin directory to be used with url-like includes
|
||||||
|
* @var string $plugin_dir Directory of plugin to be used with standard includes
|
||||||
|
* @var string $plugin_file Filename of main plugin PHP file
|
||||||
|
* @var string $plugin_name Name of the plugin
|
||||||
|
* @var string $plugin_version Plugin version number
|
||||||
|
* @var string $setting_page Setting page URL name
|
||||||
|
* @var string $setting_slug Parent settings page slug
|
||||||
|
* @var string $donation_link Donation link URL
|
||||||
|
* @var string $button_save ID of save button in HTML form
|
||||||
|
* @var string $button_delete ID of delete button in HTML form
|
||||||
|
* @var int $capability Level of admin required to manage plugin settings
|
||||||
|
* @var string $slug_save URL slug to present saved state
|
||||||
|
* @var string $slug_delete URL slug to present delete state
|
||||||
|
* @var string $broadcast_url URL base of broadcast messages
|
||||||
|
* @var string donation_business_id Business ID for donation form
|
||||||
|
* @var string $donation_business_name Business name for donation form
|
||||||
|
* @var string $donation_item_name Donation item name for donation form
|
||||||
|
* @var string donation_business_id Business ID for donation form
|
||||||
|
* @var string $broadcast_message Name of the file to get broadcast message from the web
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
abstract class WP_Plugins_Abstract {
|
||||||
|
|
||||||
|
protected $plugin_constant;
|
||||||
|
protected $options = array();
|
||||||
|
protected $defaults = array();
|
||||||
|
protected $status = 0;
|
||||||
|
protected $network = false;
|
||||||
|
protected $settings_link = '';
|
||||||
|
protected $settings_slug = '';
|
||||||
|
protected $plugin_url;
|
||||||
|
protected $plugin_dir;
|
||||||
|
protected $plugin_file;
|
||||||
|
protected $plugin_name;
|
||||||
|
protected $plugin_version;
|
||||||
|
protected $plugin_settings_page;
|
||||||
|
protected $donation_link;
|
||||||
|
protected $button_save;
|
||||||
|
protected $button_delete;
|
||||||
|
public $capability = 10;
|
||||||
|
const slug_save = '&saved=true';
|
||||||
|
const slug_delete = '&deleted=true';
|
||||||
|
const broadcast_url = 'http://petermolnar.eu/broadcast/';
|
||||||
|
const donation_business_id = 'FA3NT7XDVHPWU';
|
||||||
|
protected $donation_business_name;
|
||||||
|
protected $donation_item_name;
|
||||||
|
protected $broadcast_message;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* constructor
|
||||||
|
*
|
||||||
|
* @param string $plugin_constant General plugin identifier, same as directory & base PHP file name
|
||||||
|
* @param string $plugin_version Version number of the parameter
|
||||||
|
* @param string $plugin_name Readable name of the plugin
|
||||||
|
* @param mixed $defaults Default value(s) for plugin option(s)
|
||||||
|
* @param string $donation_link Donation link of plugin
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function __construct( $plugin_constant, $plugin_version, $plugin_name, $defaults, $donation_link ) {
|
||||||
|
|
||||||
|
$this->plugin_constant = $plugin_constant;
|
||||||
|
|
||||||
|
$this->plugin_url = $this->replace_if_ssl ( WP_PLUGIN_URL ) . '/' . $this->plugin_constant . '/';
|
||||||
|
$this->plugin_dir = WP_PLUGIN_DIR. '/' . $this->plugin_constant . '/';
|
||||||
|
$this->plugin_file = $this->plugin_constant . '/' . $this->plugin_constant . '.php';
|
||||||
|
$this->plugin_version = $plugin_version;
|
||||||
|
$this->plugin_name = $plugin_name;
|
||||||
|
$this->defaults = $defaults;
|
||||||
|
$this->plugin_settings_page = $this->plugin_constant .'-settings';
|
||||||
|
$this->donation_link = $donation_link;
|
||||||
|
$this->button_save = $this->plugin_constant . '-save';
|
||||||
|
$this->button_delete = $this->plugin_constant . '-delete';
|
||||||
|
$this->broadcast_message = self::broadcast_url . $this->plugin_constant . '.message';
|
||||||
|
$this->donation_business_name = 'PeterMolnar_WordPressPlugins_' . $this->plugin_constant . '_HU';
|
||||||
|
$this->donation_item_name = $this->plugin_name;
|
||||||
|
|
||||||
|
/* we need network wide plugin check functions */
|
||||||
|
if ( ! function_exists( 'is_plugin_active_for_network' ) )
|
||||||
|
require_once( ABSPATH . 'wp-admin/includes/plugin.php' );
|
||||||
|
|
||||||
|
/* check if plugin is network-activated */
|
||||||
|
if ( @is_plugin_active_for_network ( $this->plugin_file ) ) {
|
||||||
|
$this->network = true;
|
||||||
|
$this->settings_slug = 'settings.php';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$this->settings_slug = 'options-general.php';
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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 admin styling */
|
||||||
|
if( is_admin() ) {
|
||||||
|
/* 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 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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') );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* activation hook function, to be extended
|
||||||
|
*/
|
||||||
|
abstract function plugin_activate();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* deactivation hook function, to be extended
|
||||||
|
*/
|
||||||
|
abstract function plugin_deactivate ();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* uninstall hook function, to be extended
|
||||||
|
*/
|
||||||
|
abstract function plugin_uninstall();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* first init hook function, to be extended, before options were read
|
||||||
|
*/
|
||||||
|
abstract function plugin_init();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* second init hook function, to be extended, after options were read
|
||||||
|
*/
|
||||||
|
abstract function plugin_setup();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* admin panel, the HTML usually
|
||||||
|
*/
|
||||||
|
abstract function plugin_admin_panel();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* admin init: save/delete setting, add admin panel call hook
|
||||||
|
*/
|
||||||
|
public function plugin_admin_init() {
|
||||||
|
|
||||||
|
/* save parameter updates, if there are any */
|
||||||
|
if ( isset( $_POST[ $this->button_save ] ) ) {
|
||||||
|
$this->plugin_options_save();
|
||||||
|
$this->status = 1;
|
||||||
|
header( "Location: ". $this->settings_link . self::slug_save );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* delete parameters if requested */
|
||||||
|
if ( isset( $_POST[ $this->button_delete ] ) ) {
|
||||||
|
$this->plugin_options_delete();
|
||||||
|
$this->status = 2;
|
||||||
|
header( "Location: ". $this->settings_link . self::slug_delete );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* load additional moves */
|
||||||
|
$this->plugin_hook_admin_init();
|
||||||
|
|
||||||
|
/* 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' ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* to be extended
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
abstract function plugin_hook_admin_init();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* callback function to add settings link to plugins page
|
||||||
|
*
|
||||||
|
* @param array $links Current links to add ours to
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function plugin_settings_link ( $links ) {
|
||||||
|
$settings_link = '<a href="' . $this->settings_link . '">' . __( 'Settings', $this->plugin_constant ) . '</a>';
|
||||||
|
array_unshift( $links, $settings_link );
|
||||||
|
return $links;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* deletes saved options from database
|
||||||
|
*/
|
||||||
|
protected function plugin_options_delete () {
|
||||||
|
/* get the currently saved options */
|
||||||
|
if ( $this->network )
|
||||||
|
delete_site_option( $this->plugin_constant );
|
||||||
|
else
|
||||||
|
delete_option( $this->plugin_constant );
|
||||||
|
|
||||||
|
/* additional moves */
|
||||||
|
$this->plugin_hook_options_delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hook to add functionality into plugin_options_read
|
||||||
|
*/
|
||||||
|
abstract function plugin_hook_options_delete ();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* reads options stored in database and reads merges them with default values
|
||||||
|
*/
|
||||||
|
protected function plugin_options_read () {
|
||||||
|
/* get the currently saved options */
|
||||||
|
if ( $this->network )
|
||||||
|
$options = get_site_option( $this->plugin_constant );
|
||||||
|
else
|
||||||
|
$options = get_option( $this->plugin_constant );
|
||||||
|
|
||||||
|
/* this is the point to make any migrations from previous versions */
|
||||||
|
$this->plugin_hook_options_migrate( $options );
|
||||||
|
|
||||||
|
/* map missing values from default */
|
||||||
|
foreach ( $this->defaults as $key => $default )
|
||||||
|
if ( !@array_key_exists ( $key, $options ) )
|
||||||
|
$options[$key] = $default;
|
||||||
|
|
||||||
|
/* removed unused keys, rare, but possible */
|
||||||
|
foreach ( array_keys ( $options ) as $key )
|
||||||
|
if ( !@array_key_exists( $key, $this->defaults ) )
|
||||||
|
unset ( $options[$key] );
|
||||||
|
|
||||||
|
/* any additional read hook */
|
||||||
|
$this->plugin_hook_options_read( $options );
|
||||||
|
|
||||||
|
$this->options = $options;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hook to add functionality into plugin_options_read
|
||||||
|
*/
|
||||||
|
abstract function plugin_hook_options_read ( &$options );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hook for parameter migration
|
||||||
|
*/
|
||||||
|
abstract function plugin_hook_options_migrate( &$options );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* used on update and to save current options to database
|
||||||
|
*
|
||||||
|
* @param boolean $activating [optional] true on activation hook
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
protected function plugin_options_save ( $activating = false ) {
|
||||||
|
|
||||||
|
/* only try to update defaults if it's not activation hook, $_POST is not empty and the post
|
||||||
|
is ours */
|
||||||
|
if ( !$activating && !empty ( $_POST ) && isset( $_POST[ $this->button_save ] ) ) {
|
||||||
|
/* we'll only update those that exist in the defaults array */
|
||||||
|
$options = $this->defaults;
|
||||||
|
|
||||||
|
foreach ( $options as $key => $default )
|
||||||
|
{
|
||||||
|
/* $_POST element is available */
|
||||||
|
if ( !empty( $_POST[$key] ) ) {
|
||||||
|
$update = $_POST[$key];
|
||||||
|
|
||||||
|
/* get rid of slashes in strings, just in case */
|
||||||
|
if ( is_string ( $update ) )
|
||||||
|
$update = stripslashes($update);
|
||||||
|
|
||||||
|
$options[$key] = $update;
|
||||||
|
}
|
||||||
|
/* empty $_POST element: when HTML form posted, empty checkboxes a 0 input
|
||||||
|
values will not be part of the $_POST array, thus we need to check
|
||||||
|
if this is the situation by checking the types of the elements,
|
||||||
|
since a missing value means update from an integer to 0
|
||||||
|
*/
|
||||||
|
elseif ( empty( $_POST[$key] ) && ( is_bool ( $default ) || is_int( $default ) ) ) {
|
||||||
|
$options[$key] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* update the options array */
|
||||||
|
$this->options = $options;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* set plugin version */
|
||||||
|
$this->options['version'] = $this->plugin_version;
|
||||||
|
|
||||||
|
/* call hook function for additional moves before saving the values */
|
||||||
|
$this->plugin_hook_options_save( $activating );
|
||||||
|
|
||||||
|
/* save options to database */
|
||||||
|
if ( $this->network )
|
||||||
|
update_site_option( $this->plugin_constant , $this->options );
|
||||||
|
else
|
||||||
|
update_option( $this->plugin_constant , $this->options );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hook to add functionality into plugin_options_save
|
||||||
|
*/
|
||||||
|
abstract function plugin_hook_options_save ( $activating );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sends message to sysog
|
||||||
|
*
|
||||||
|
* @param string $message message to add besides basic info
|
||||||
|
* @param int $log_level [optional] Level of log, info by default
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
protected function log ( $message, $log_level = LOG_INFO ) {
|
||||||
|
|
||||||
|
if ( @is_array( $message ) || @is_object ( $message ) )
|
||||||
|
$message = serialize($message);
|
||||||
|
|
||||||
|
if (! $this->config['log'] )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
switch ( $log_level ) {
|
||||||
|
case LOG_ERR :
|
||||||
|
if ( function_exists( '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'] )
|
||||||
|
syslog( $log_level , self::plugin_constant . $message );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* replaces http:// with https:// in an url if server is currently running on https
|
||||||
|
*
|
||||||
|
* @param string $url URL to check
|
||||||
|
*
|
||||||
|
* @return string URL with correct protocol
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
protected function replace_if_ssl ( $url ) {
|
||||||
|
if ( isset( $_SERVER['HTTP_X_FORWARDED_PROTO'] ) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https' )
|
||||||
|
$_SERVER['HTTPS'] = 'on';
|
||||||
|
|
||||||
|
if ( isset($_SERVER['HTTPS']) && (( strtolower($_SERVER['HTTPS']) == 'on' ) || ( $_SERVER['HTTPS'] == '1' ) ))
|
||||||
|
$url = str_replace ( 'http://' , 'https://' , $url );
|
||||||
|
|
||||||
|
return $url;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* function to easily print a variable
|
||||||
|
*
|
||||||
|
* @param mixed $var Variable to dump
|
||||||
|
* @param boolean $ret Return text instead of printing if true
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
protected function print_var ( $var , $ret = false ) {
|
||||||
|
if ( @is_array ( $var ) || @is_object( $var ) || @is_bool( $var ) )
|
||||||
|
$var = var_export ( $var, true );
|
||||||
|
|
||||||
|
if ( $ret )
|
||||||
|
return $var;
|
||||||
|
else
|
||||||
|
echo $var;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* print value of an element from defaults array
|
||||||
|
*
|
||||||
|
* @param mixed $e Element index of $this->defaults array
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
protected function print_default ( $e ) {
|
||||||
|
_e('Default : ', $this->plugin_constant);
|
||||||
|
$select = 'select_' . $e;
|
||||||
|
if ( @is_array ( $this->$select ) ) {
|
||||||
|
$x = $this->$select;
|
||||||
|
$this->print_var ( $x[ $this->defaults[ $e ] ] );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$this->print_var ( $this->defaults[ $e ] );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* select options field processor
|
||||||
|
*
|
||||||
|
* @param elements
|
||||||
|
* array to build <option> values of
|
||||||
|
*
|
||||||
|
* @param $current
|
||||||
|
* the current active element
|
||||||
|
*
|
||||||
|
* @param $print
|
||||||
|
* boolean: is true, the options will be printed, otherwise the string will be returned
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* prints or returns the options string
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
protected function print_select_options ( $elements, $current, $valid = false, $print = true ) {
|
||||||
|
/*
|
||||||
|
foreach ($elements as $value => $name ) : ?>
|
||||||
|
<option value="<?php echo $value ?>" <?php selected( $value , $current ); ?>>
|
||||||
|
<?php echo $name ; ?>
|
||||||
|
</option>
|
||||||
|
<?php endforeach;
|
||||||
|
*/
|
||||||
|
if ( is_array ( $valid ) )
|
||||||
|
$check_disabled = true;
|
||||||
|
else
|
||||||
|
$check_disabled = false;
|
||||||
|
|
||||||
|
foreach ($elements as $value => $name ) {
|
||||||
|
//$disabled .= ( @array_key_exists( $valid[ $value ] ) && $valid[ $value ] == false ) ? ' disabled="disabled"' : '';
|
||||||
|
$opt .= '<option value="' . $value . '" ';
|
||||||
|
$opt .= selected( $value , $current );
|
||||||
|
|
||||||
|
// ugly tree level valid check to prevent array warning messages
|
||||||
|
if ( is_array( $valid ) && isset ( $valid [ $value ] ) && $valid [ $value ] == false )
|
||||||
|
$opt .= ' disabled="disabled"';
|
||||||
|
|
||||||
|
$opt .= '>';
|
||||||
|
$opt .= $name;
|
||||||
|
$opt .= "</option>\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( $print )
|
||||||
|
echo $opt;
|
||||||
|
else
|
||||||
|
return $opt;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
protected function plugin_donation_form () {
|
||||||
|
|
||||||
|
?>
|
||||||
|
<script>
|
||||||
|
jQuery(document).ready(function($) {
|
||||||
|
jQuery(function() {
|
||||||
|
var select = $( "#amount" );
|
||||||
|
var slider = $( '<div id="donation-slider"></div>' ).insertAfter( select ).slider({
|
||||||
|
min: 1,
|
||||||
|
max: 8,
|
||||||
|
range: "min",
|
||||||
|
value: select[ 0 ].selectedIndex + 1,
|
||||||
|
slide: function( event, ui ) {
|
||||||
|
select[ 0 ].selectedIndex = ui.value - 1;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
$( "#amount" ).change(function() {
|
||||||
|
slider.slider( "value", this.selectedIndex + 1 );
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<form action="https://www.paypal.com/cgi-bin/webscr" method="post" class="<?php echo $this->plugin_constant ?>-donation">
|
||||||
|
<label for="amount"><?php _e( "This plugin helped your business? I'd appreciate a coffee in return :) Please!", $this->plugin_constant ); ?></label>
|
||||||
|
<select name="amount" id="amount">
|
||||||
|
<option value="3">3$</option>
|
||||||
|
<option value="5">5$</option>
|
||||||
|
<option value="10" selected="selected">10$</option>
|
||||||
|
<option value="15">15$</option>
|
||||||
|
<option value="30">30$</option>
|
||||||
|
<option value="42">42$</option>
|
||||||
|
<option value="75">75$</option>
|
||||||
|
<option value="100">100$</option>
|
||||||
|
</select>
|
||||||
|
<input type="hidden" id="cmd" name="cmd" value="_donations" />
|
||||||
|
<input type="hidden" id="tax" name="tax" value="0" />
|
||||||
|
<input type="hidden" id="business" name="business" value="<?php echo self::donation_business_id ?>" />
|
||||||
|
<input type="hidden" id="bn" name="bn" value="<?php echo $this->donation_business_name ?>" />
|
||||||
|
<input type="hidden" id="item_name" name="item_name" value="<?php _e('Donation for ', $this->plugin_constant ); echo $this->donation_item_name ?>" />
|
||||||
|
<input type="hidden" id="currency_code" name="currency_code" value="USD" />
|
||||||
|
<input type="submit" name="submit" value="<?php _e('Donate via PayPal', $this->plugin_constant ) ?>" class="button-secondary" />
|
||||||
|
</form>
|
||||||
|
<?php
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
281
wp-ffpc-acache.php
Normal file
281
wp-ffpc-acache.php
Normal file
|
@ -0,0 +1,281 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* advanced cache worker 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;
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
|
||||||
|
/* request uri */
|
||||||
|
$wp_ffpc_uri = $_SERVER['REQUEST_URI'];
|
||||||
|
|
||||||
|
/* no cache for uri with query strings, things usually go bad that way */
|
||||||
|
if ( stripos($wp_ffpc_uri, '?') !== false)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* no cache for pages starting with /wp- like WP admin */
|
||||||
|
if (stripos($wp_ffpc_uri, '/wp-') !== false)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* no cache for robots.txt */
|
||||||
|
if ( stripos($wp_ffpc_uri, 'robots.txt') )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* multisite files can be too large for memcached */
|
||||||
|
if ( function_exists('is_multisite') && stripos($wp_ffpc_uri, '/files/') )
|
||||||
|
if ( is_multisite() )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* check if config is network active: use network config */
|
||||||
|
if (!empty ( $wp_ffpc_config['network'] ) )
|
||||||
|
$wp_ffpc_config = $wp_ffpc_config['network'];
|
||||||
|
/* check if config is active for site : use site config */
|
||||||
|
elseif ( !empty ( $wp_ffpc_config[ $_SERVER['HTTP_HOST'] ] ) )
|
||||||
|
$wp_ffpc_config = $wp_ffpc_config[ $_SERVER['HTTP_HOST'] ];
|
||||||
|
/* plugin config not found :( */
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* no cache for for logged in users normally, only if enabled */
|
||||||
|
if ( $wp_ffpc_config['cache_loggedin'] == 0 ) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$wp_ffpc_redirect = null;
|
||||||
|
$wp_ffpc_backend = new WP_FFPC_Backend( $wp_ffpc_config );
|
||||||
|
|
||||||
|
if ( $wp_ffpc_backend->status() === false )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
$wp_ffpc_keys = array ( 'meta', 'data' );
|
||||||
|
$wp_ffpc_values = array();
|
||||||
|
|
||||||
|
foreach ( $wp_ffpc_keys as $key ) {
|
||||||
|
$value = $wp_ffpc_backend->get ( $wp_ffpc_backend->key ( $key ) );
|
||||||
|
|
||||||
|
if ( ! $value )
|
||||||
|
{
|
||||||
|
wp_ffpc_start();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$wp_ffpc_values[ $key ] = $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* serve cache 404 status */
|
||||||
|
if ( $wp_ffpc_values['meta']['status'] == 404 ) {
|
||||||
|
header("HTTP/1.1 404 Not Found");
|
||||||
|
flush();
|
||||||
|
die();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* server redirect cache */
|
||||||
|
if ( $wp_ffpc_values['meta']['redirect'] ) {
|
||||||
|
header('Location: ' . $wp_ffpc_values['meta']['redirect'] );
|
||||||
|
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_values['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_values['meta']['lastmodified'] ) {
|
||||||
|
header("HTTP/1.0 304 Not Modified");
|
||||||
|
flush();
|
||||||
|
die();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if we reach this point it means data was found & correct, serve it */
|
||||||
|
header('Content-Type: ' . $wp_ffpc_values['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_values['meta']['shortlink'] ) )
|
||||||
|
header( 'Link:<'. $wp_ffpc_values['meta']['shortlink'] .'>; rel=shortlink' );
|
||||||
|
|
||||||
|
/* if last modifications were set (for posts & pages) */
|
||||||
|
if ( !empty($wp_ffpc_values['meta']['lastmodified']) )
|
||||||
|
header( 'Last-Modified: ' . gmdate("D, d M Y H:i:s", $wp_ffpc_values['meta']['lastmodified'] ). " GMT" );
|
||||||
|
|
||||||
|
/* pingback urls, if existx */
|
||||||
|
if ( !empty( $wp_ffpc_values['meta']['pingback'] ) )
|
||||||
|
header( 'X-Pingback: ' . $wp_ffpc_values['meta']['pingback'] );
|
||||||
|
|
||||||
|
/* for debugging */
|
||||||
|
if ( $wp_ffpc_config['response_header'] )
|
||||||
|
header( 'X-Cache-Engine: WP-FFPC with ' . $wp_ffpc_config['cache_type'] );
|
||||||
|
|
||||||
|
/* HTML data */
|
||||||
|
echo $wp_ffpc_values['data'];
|
||||||
|
flush();
|
||||||
|
die();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* starts caching function
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
function wp_ffpc_start( ) {
|
||||||
|
/* start object "colleting" and pass it the the actual storer function */
|
||||||
|
ob_start('wp_ffpc_callback');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* callback function for WordPress redirect urls
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
function wp_ffpc_redirect_callback ($redirect_url, $requested_url) {
|
||||||
|
global $wp_ffpc_redirect;
|
||||||
|
$wp_ffpc_redirect = $redirect_url;
|
||||||
|
return $redirect_url;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* write cache function, called when page generation ended
|
||||||
|
*/
|
||||||
|
function wp_ffpc_callback( $buffer ) {
|
||||||
|
global $wp_ffpc_config;
|
||||||
|
global $wp_ffpc_backend;
|
||||||
|
global $wp_ffpc_redirect;
|
||||||
|
|
||||||
|
/* no is_home = error */
|
||||||
|
if (!function_exists('is_home'))
|
||||||
|
return $buffer;
|
||||||
|
|
||||||
|
/* no <body> close tag = not HTML, don't cache */
|
||||||
|
if (stripos($buffer, '</body>') === false)
|
||||||
|
return $buffer;
|
||||||
|
|
||||||
|
/* reset meta to solve conflicts */
|
||||||
|
$meta = array();
|
||||||
|
|
||||||
|
/* 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() )
|
||||||
|
$meta['type'] = 'home';
|
||||||
|
elseif (is_feed() )
|
||||||
|
$meta['type'] = 'feed';
|
||||||
|
elseif ( is_archive() )
|
||||||
|
$meta['type'] = 'archive';
|
||||||
|
elseif ( is_single() )
|
||||||
|
$meta['type'] = 'single';
|
||||||
|
elseif ( is_page() )
|
||||||
|
$meta['type'] = 'page';
|
||||||
|
else
|
||||||
|
$meta['type'] = 'unknown';
|
||||||
|
|
||||||
|
/* check if caching is disabled for page type */
|
||||||
|
$nocache_key = 'nocache_'. $meta['type'];
|
||||||
|
|
||||||
|
/* don't cache if prevented by rule, also, log it */
|
||||||
|
if ( $wp_ffpc_config[ $nocache_key ] == 1 ) {
|
||||||
|
return $buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( is_404() )
|
||||||
|
$meta['status'] = 404;
|
||||||
|
|
||||||
|
/* redirect page */
|
||||||
|
if ( $wp_ffpc_redirect != null)
|
||||||
|
$meta['redirect'] = $wp_ffpc_redirect;
|
||||||
|
|
||||||
|
/* feed is xml, all others forced to be HTML */
|
||||||
|
if ( is_feed() )
|
||||||
|
$meta['mime'] = 'text/xml;charset=';
|
||||||
|
else
|
||||||
|
$meta['mime'] = 'text/html;charset=';
|
||||||
|
|
||||||
|
/* set mimetype */
|
||||||
|
$meta['mime'] = $meta['mime'] . $wp_ffpc_config['charset'];
|
||||||
|
|
||||||
|
/* try if post is available
|
||||||
|
if made with archieve, last listed post can make this go bad
|
||||||
|
*/
|
||||||
|
global $post;
|
||||||
|
if ( !empty($post) && ( $meta['type'] == 'single' || $meta['type'] == 'page' ) && !empty ( $post->post_modified_gmt ) )
|
||||||
|
{
|
||||||
|
/* get last modification data */
|
||||||
|
$meta['lastmodified'] = strtotime ( $post->post_modified_gmt );
|
||||||
|
|
||||||
|
/* get shortlink, if possible */
|
||||||
|
if (function_exists('wp_get_shortlink'))
|
||||||
|
{
|
||||||
|
$shortlink = wp_get_shortlink( );
|
||||||
|
if (!empty ( $shortlink ) )
|
||||||
|
$meta['shortlink'] = $shortlink;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* store pingback url if pingbacks are enabled */
|
||||||
|
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( $_SERVER['HTTP_X_FORWARDED_PROTO'] ) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https' )
|
||||||
|
$_SERVER['HTTPS'] = 'on';
|
||||||
|
|
||||||
|
if ( isset($_SERVER['HTTPS']) && ( ( strtolower($_SERVER['HTTPS']) == 'on' ) || ( $_SERVER['HTTPS'] == '1' ) ) )
|
||||||
|
{
|
||||||
|
$sync_from = 'http://' . $_SERVER['SERVER_NAME'];
|
||||||
|
$sync_to = 'https://' . $_SERVER['SERVER_NAME'];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$sync_from = 'https://' . $_SERVER['SERVER_NAME'];
|
||||||
|
$sync_to = 'http://' . $_SERVER['SERVER_NAME'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$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 );
|
||||||
|
|
||||||
|
/* vital for nginx, make no problem at other places */
|
||||||
|
header("HTTP/1.1 200 OK");
|
||||||
|
|
||||||
|
/* echoes HTML out */
|
||||||
|
return $buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
141
wp-ffpc-admin.css
Normal file
141
wp-ffpc-admin.css
Normal file
|
@ -0,0 +1,141 @@
|
||||||
|
.plugin-admin dt {
|
||||||
|
margin-top: 2em;
|
||||||
|
font-weight:bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.plugin-admin fieldset {
|
||||||
|
display:block;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0 1em 0 1em;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.plugin-admin legend {
|
||||||
|
display: none;
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.plugin-admin .default {
|
||||||
|
display:block;
|
||||||
|
padding-left: 1em;
|
||||||
|
font-size:90%;
|
||||||
|
color:#666;
|
||||||
|
}
|
||||||
|
|
||||||
|
.plugin-admin .description {
|
||||||
|
display:block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.plugin-admin .tabs {
|
||||||
|
padding:0;
|
||||||
|
margin: 0;
|
||||||
|
list-style-type: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.plugin-admin .tabs li {
|
||||||
|
border-style: solid;
|
||||||
|
border-width: 1px 1px 1px 1px;
|
||||||
|
border-color: #ccc;
|
||||||
|
border-bottom-color: #ccc;
|
||||||
|
line-height: 120%;
|
||||||
|
display: inline-block;
|
||||||
|
padding: 0.5em 2em 0.5em 2em;
|
||||||
|
text-decoration: none;
|
||||||
|
margin-bottom: -1px;
|
||||||
|
-webkit-border-top-left-radius: 3px;
|
||||||
|
-webkit-border-top-right-radius: 3px;
|
||||||
|
border-top-left-radius: 3px;
|
||||||
|
border-top-right-radius: 3px;
|
||||||
|
background: #f1f1f1;
|
||||||
|
background-image: -webkit-gradient(linear,left bottom,left top,from(#ececec),to(#f9f9f9));
|
||||||
|
background-image: -webkit-linear-gradient(bottom,#ececec,#f9f9f9);
|
||||||
|
background-image: -moz-linear-gradient(bottom,#ececec,#f9f9f9);
|
||||||
|
background-image: -o-linear-gradient(bottom,#ececec,#f9f9f9);
|
||||||
|
background-image: linear-gradient(to top,#ececec,#f9f9f9);
|
||||||
|
}
|
||||||
|
|
||||||
|
.plugin-admin .tabs li a {
|
||||||
|
outline: none;
|
||||||
|
text-decoration: none;
|
||||||
|
font-size: 120%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.plugin-admin .tabs li.ui-state-active {
|
||||||
|
background: #fff;
|
||||||
|
border-bottom-color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error p {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-msg {
|
||||||
|
color: #990000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ok-msg {
|
||||||
|
color: #009900;
|
||||||
|
}
|
||||||
|
|
||||||
|
.clear {
|
||||||
|
clear:both;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wp-ffpc-donation {
|
||||||
|
padding: 0.8em;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
background-color: #f6f6f6;
|
||||||
|
-webkit-border-radius: 3px;
|
||||||
|
border-radius: 3px;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.wp-ffpc-donation * {
|
||||||
|
display: inline;
|
||||||
|
line-height: 2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wp-ffpc-donation .currency {
|
||||||
|
padding: 0 0 0 0.3em;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.wp-ffpc-donation .submit {
|
||||||
|
display: inline-block;
|
||||||
|
width: 74px;
|
||||||
|
height: 21px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wp-ffpc-donation .ui-slider {
|
||||||
|
position: relative;
|
||||||
|
text-align: left;
|
||||||
|
display: inline-block;
|
||||||
|
width: 16em;
|
||||||
|
margin: 0 2em 0 2em;
|
||||||
|
height: 0.4em;
|
||||||
|
background-color: #111;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
-webkit-border-radius: 3px;
|
||||||
|
border-radius: 3px;
|
||||||
|
background: #f1f1f1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ui-slider .ui-slider-handle {
|
||||||
|
position: absolute;
|
||||||
|
z-index: 2;
|
||||||
|
width: 1.2em;
|
||||||
|
height: 1.2em;
|
||||||
|
margin-top: -0.4em;
|
||||||
|
cursor: default;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
-webkit-border-radius: 3px;
|
||||||
|
border-radius: 3px;
|
||||||
|
background: #f1f1f1;
|
||||||
|
background-image: -webkit-gradient(linear,left bottom,left top,from(#ececec),to(#f9f9f9));
|
||||||
|
background-image: -webkit-linear-gradient(bottom,#ececec,#f9f9f9);
|
||||||
|
background-image: -moz-linear-gradient(bottom,#ececec,#f9f9f9);
|
||||||
|
background-image: -o-linear-gradient(bottom,#ececec,#f9f9f9);
|
||||||
|
background-image: linear-gradient(to top,#ececec,#f9f9f9);
|
||||||
|
outline: none;
|
||||||
|
|
||||||
|
}
|
672
wp-ffpc-backend.php
Normal file
672
wp-ffpc-backend.php
Normal file
|
@ -0,0 +1,672 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* backend driver for WordPress plugin WP-FFPC
|
||||||
|
*
|
||||||
|
* supported storages:
|
||||||
|
* - APC
|
||||||
|
* - Memcached
|
||||||
|
* - Memcache
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!class_exists('WP_FFPC_Backend')) {
|
||||||
|
/* __ only availabe if we're running from the inside of wordpress, not in advanced-cache.php phase */
|
||||||
|
if ( function_exists ( '__' ) ) {
|
||||||
|
function __translate__ ( $text, $domain ) { return __($text, $domain); }
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
function __translate__ ( $text, $domain ) { return $text; }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @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
|
||||||
|
* @var mixed $status Backend server status storage
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
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;
|
||||||
|
public $status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* constructor
|
||||||
|
*
|
||||||
|
* @param mixed $config Configuration options
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function __construct( $config ) {
|
||||||
|
|
||||||
|
$this->options = $config;
|
||||||
|
|
||||||
|
/* no config, nothing is going to work */
|
||||||
|
if ( empty ( $this->options ) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* split hosts entry to servers */
|
||||||
|
$this->set_servers();
|
||||||
|
|
||||||
|
/* call backend initiator based on cache type */
|
||||||
|
$init = $this->proxy( 'init' );
|
||||||
|
|
||||||
|
$this->log ( __translate__(' init starting', self::plugin_constant ));
|
||||||
|
$this->$init();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************** PUBLIC FUNCTIONS ***********************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* build key to make requests with
|
||||||
|
*
|
||||||
|
* @param string $suffix suffix to add to prefix
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function key ( $suffix = 'meta' ) {
|
||||||
|
/* 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' )
|
||||||
|
$_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'];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* public get function, transparent proxy to internal function based on backend
|
||||||
|
*
|
||||||
|
* @param string $key Cache key to get value for
|
||||||
|
*
|
||||||
|
* @return mixed False when entry not found or entry value on success
|
||||||
|
*/
|
||||||
|
public function get ( &$key ) {
|
||||||
|
|
||||||
|
/* look for backend aliveness, exit on inactive backend */
|
||||||
|
if ( ! $this->is_alive() )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* log the current action */
|
||||||
|
$this->log ( __translate__('get ', self::plugin_constant ). $key );
|
||||||
|
|
||||||
|
/* proxy to internal function */
|
||||||
|
$internal = $this->proxy( 'get' );
|
||||||
|
$result = $this->$internal( $key );
|
||||||
|
|
||||||
|
if ( $result === false )
|
||||||
|
$this->log ( __translate__( "failed to get entry: ", self::plugin_constant ) . $key );
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* public set function, transparent proxy to internal function based on backend
|
||||||
|
*
|
||||||
|
* @param string $key Cache key to set with ( reference only, for speed )
|
||||||
|
* @param mixed $data Data to set ( reference only, for speed )
|
||||||
|
*
|
||||||
|
* @return mixed $result status of set function
|
||||||
|
*/
|
||||||
|
public function set ( &$key, &$data ) {
|
||||||
|
|
||||||
|
/* look for backend aliveness, exit on inactive backend */
|
||||||
|
if ( ! $this->is_alive() )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* log the current action */
|
||||||
|
$this->log( __translate__('set ', self::plugin_constant ) . $key . __translate__(' expiration time: ', self::plugin_constant ) . $this->options['expire']);
|
||||||
|
|
||||||
|
/* proxy to internal function */
|
||||||
|
$internal = $this->options['cache_type'] . '_set';
|
||||||
|
$result = $this->$internal( $key, $data );
|
||||||
|
|
||||||
|
/* check result validity */
|
||||||
|
if ( $result === false )
|
||||||
|
$this->log ( __translate__('failed to set entry: ', self::plugin_constant ) . $key, LOG_WARNING );
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 ) {
|
||||||
|
|
||||||
|
/* 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) {
|
||||||
|
$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 ) ) {
|
||||||
|
/* log action */
|
||||||
|
$this->log ( __translate__('flushing cache', self::plugin_constant ) );
|
||||||
|
|
||||||
|
/* proxy to internal function */
|
||||||
|
$internal = $this->proxy ( 'flush' );
|
||||||
|
$result = $this->$internal();
|
||||||
|
|
||||||
|
if ( $result === false )
|
||||||
|
$this->log ( __translate__('failed to flush cache', self::plugin_constant ), LOG_WARNING );
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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://';
|
||||||
|
|
||||||
|
$to_clear = array (
|
||||||
|
$this->options['prefix-meta'] . $protocol . $path,
|
||||||
|
$this->options['prefix-data'] . $protocol . $path,
|
||||||
|
);
|
||||||
|
|
||||||
|
$internal = $this->proxy ( 'clear' );
|
||||||
|
$this->$internal ( $to_clear );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get backend aliveness
|
||||||
|
*
|
||||||
|
* @return array Array of configured servers with aliveness value
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function status () {
|
||||||
|
|
||||||
|
/* look for backend aliveness, exit on inactive backend */
|
||||||
|
if ( ! $this->is_alive() )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
$internal = $this->proxy ( 'status' );
|
||||||
|
return $this->status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* backend proxy function name generator
|
||||||
|
*
|
||||||
|
* @return string Name of internal function based on cache_type
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private function proxy ( $method ) {
|
||||||
|
return $this->options['cache_type'] . '_' . $method;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* function to check backend aliveness
|
||||||
|
*
|
||||||
|
* @return boolean true if backend is alive, false if not
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private function is_alive() {
|
||||||
|
if ( ! $this->alive ) {
|
||||||
|
$this->log ( __translate__("backend is not active, exiting function ", self::plugin_constant ) . __FUNCTION__, LOG_WARNING );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* split hosts string to backend servers
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private function set_servers () {
|
||||||
|
/* replace servers array in config according to hosts field */
|
||||||
|
$servers = explode( self::host_separator , $this->options['hosts']);
|
||||||
|
|
||||||
|
$options['servers'] = array();
|
||||||
|
|
||||||
|
foreach ( $servers as $snum => $sstring ) {
|
||||||
|
|
||||||
|
$separator = strpos( $sstring , self::port_separator );
|
||||||
|
$host = substr( $sstring, 0, $separator );
|
||||||
|
$port = substr( $sstring, $separator + 1 );
|
||||||
|
|
||||||
|
/* IP server */
|
||||||
|
if ( !empty ( $host ) && !empty($port) && is_numeric($port) ) {
|
||||||
|
$this->options['servers'][$sstring] = array (
|
||||||
|
'host' => $host,
|
||||||
|
'port' => $port
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get current array of servers
|
||||||
|
*
|
||||||
|
* @return array Server list in current config
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function get_servers () {
|
||||||
|
return $this->options['servers'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sends message to sysog
|
||||||
|
*
|
||||||
|
* @param mixed $message message to add besides basic info
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function log ( $message, $log_level = LOG_WARNING ) {
|
||||||
|
|
||||||
|
if ( @is_array( $message ) || @is_object ( $message ) )
|
||||||
|
$message = serialize($message);
|
||||||
|
|
||||||
|
if (! $this->options['log'] )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
switch ( $log_level ) {
|
||||||
|
case LOG_ERR :
|
||||||
|
if ( function_exists( 'syslog' ) )
|
||||||
|
syslog( $log_level , self::plugin_constant . " with " . $this->options['cache_type'] . ' ' . $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->options['debug'] )
|
||||||
|
syslog( $log_level , self::plugin_constant . " with " . $this->options['cache_type'] . ' ' . $message );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************** END PUBLIC FUNCTIONS ***********************/
|
||||||
|
/*********************** APC FUNCTIONS ***********************/
|
||||||
|
/**
|
||||||
|
* init apc backend: test APC availability and set alive status
|
||||||
|
*/
|
||||||
|
private function apc_init () {
|
||||||
|
/* verify apc functions exist, apc extension is loaded */
|
||||||
|
if ( ! function_exists( 'apc_sma_info' ) ) {
|
||||||
|
$this->log ( __translate__('APC extension missing', self::plugin_constant ) );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* verify apc is working */
|
||||||
|
if ( apc_sma_info() ) {
|
||||||
|
$this->log ( __translate__('backend OK', self::plugin_constant ) );
|
||||||
|
$this->alive = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* health checker for APC
|
||||||
|
*
|
||||||
|
* @return boolean Aliveness status
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private function apc_status () {
|
||||||
|
return $this->alive;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get function for APC backend
|
||||||
|
*
|
||||||
|
* @param string $key Key to get values for
|
||||||
|
*
|
||||||
|
* @return mixed Fetched data based on key
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private function apc_get ( &$key ) {
|
||||||
|
return apc_fetch( $key );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set function for APC backend
|
||||||
|
*
|
||||||
|
* @param string $key Key to set with
|
||||||
|
* @param mixed $data Data to set
|
||||||
|
*
|
||||||
|
* @return boolean APC store outcome
|
||||||
|
*/
|
||||||
|
private function apc_set ( &$key, &$data ) {
|
||||||
|
return apc_store( $key , $data , $this->options['expire'] );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flushes APC user entry storage
|
||||||
|
*
|
||||||
|
* @return boolean APC flush outcome status
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private function apc_flush ( ) {
|
||||||
|
return apc_clear_cache('user');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes entry from APC or flushes APC user entry storage
|
||||||
|
*
|
||||||
|
* @param mixed $keys Keys to clear, string or array
|
||||||
|
*/
|
||||||
|
private function apc_clear ( $keys ) {
|
||||||
|
/* make an array if only one string is present, easier processing */
|
||||||
|
if ( !is_array ( $keys ) )
|
||||||
|
$keys = array ( $keys );
|
||||||
|
|
||||||
|
foreach ( $keys as $key ) {
|
||||||
|
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 );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$this->log ( __translate__( 'APC entry delete: ', self::plugin_constant ) . $key );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************** END APC FUNCTIONS ***********************/
|
||||||
|
|
||||||
|
/*********************** MEMCACHED FUNCTIONS ***********************/
|
||||||
|
/**
|
||||||
|
* init memcached backend
|
||||||
|
*/
|
||||||
|
private function memcached_init () {
|
||||||
|
/* Memcached class does not exist, Memcached extension is not available */
|
||||||
|
if (!class_exists('Memcached')) {
|
||||||
|
$this->log ( __translate__(' Memcached extension missing', self::plugin_constant ), LOG_ERR );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check for existing server list, otherwise we cannot add backends */
|
||||||
|
if ( empty ( $this->options['servers'] ) && ! $this->alive ) {
|
||||||
|
$this->log ( __translate__("Memcached servers list is empty, init failed", self::plugin_constant ), LOG_WARNING );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check is there's no backend connection yet */
|
||||||
|
if ( $this->connection === NULL ) {
|
||||||
|
/* persistent backend needs an identifier */
|
||||||
|
if ( $this->options['persistent'] == '1' )
|
||||||
|
$this->connection = new Memcached( self::plugin_constant );
|
||||||
|
else
|
||||||
|
$this->connection = new Memcached();
|
||||||
|
|
||||||
|
/* use binary and not compressed format, good for nginx and still fast */
|
||||||
|
$this->connection->setOption( Memcached::OPT_COMPRESSION , false );
|
||||||
|
//$this->connection->setOption( Memcached::OPT_BINARY_PROTOCOL , true );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check if initialization was success or not */
|
||||||
|
if ( $this->connection === NULL ) {
|
||||||
|
$this->log ( __translate__( 'error initializing Memcached PHP extension, exiting', self::prefix ) );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check if we already have list of servers, only add server(s) if it's not already connected */
|
||||||
|
$servers_alive = array();
|
||||||
|
if ( !empty ( $this->status ) ) {
|
||||||
|
$servers_alive = $this->connection->getServerList();
|
||||||
|
/* create check array if backend servers are already connected */
|
||||||
|
if ( !empty ( $servers ) ) {
|
||||||
|
foreach ( $servers_alive as $skey => $server ) {
|
||||||
|
$skey = $server['host'] . ":" . $server['port'];
|
||||||
|
$servers_alive[ $skey ] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* adding servers */
|
||||||
|
foreach ( $this->options['servers'] as $server_id => $server ) {
|
||||||
|
/* reset server status to unknown */
|
||||||
|
$this->status[$server_id] = -1;
|
||||||
|
|
||||||
|
/* only add servers that does not exists already in connection pool */
|
||||||
|
if ( !@array_key_exists($server_id , $servers_alive ) ) {
|
||||||
|
$this->connection->addServer( $server['host'], $server['port'] );
|
||||||
|
$this->log ( $server_id . __translate__(" added, persistent mode: ", self::plugin_constant ) . $this->options['persistent'] );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* backend is now alive */
|
||||||
|
$this->alive = true;
|
||||||
|
$this->memcached_status();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sets current backend alive status for Memcached servers
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private function memcached_status () {
|
||||||
|
/* server status will be calculated by getting server stats */
|
||||||
|
$this->log ( __translate__("checking server statuses", self::plugin_constant ));
|
||||||
|
/* get servers statistic from connection */
|
||||||
|
$report = $this->connection->getStats();
|
||||||
|
|
||||||
|
foreach ( $report as $server_id => $details ) {
|
||||||
|
/* reset server status to offline */
|
||||||
|
$this->status[$server_id] = 0;
|
||||||
|
/* if server uptime is not empty, it's most probably up & running */
|
||||||
|
if ( !empty($details['uptime']) ) {
|
||||||
|
$this->log ( $server_id . __translate__(" server is up & running", self::plugin_constant ));
|
||||||
|
$this->status[$server_id] = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get function for Memcached backend
|
||||||
|
*
|
||||||
|
* @param string $key Key to get values for
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private function memcached_get ( &$key ) {
|
||||||
|
return $this->connection->get($key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set function for Memcached backend
|
||||||
|
*
|
||||||
|
* @param string $key Key to set with
|
||||||
|
* @param mixed $data Data to set
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private function memcached_set ( &$key, &$data ) {
|
||||||
|
$result = $this->connection->set ( $key, $data , $this->options['expire'] );
|
||||||
|
|
||||||
|
/* if storing failed, log the error code */
|
||||||
|
if ( $result === false ) {
|
||||||
|
$code = $this->connection->getResultCode();
|
||||||
|
$this->log ( __translate__('unable to set entry ', self::plugin_constant ) . $key . __translate__( ', Memcached error code: ', self::plugin_constant ) . $code );
|
||||||
|
//throw new Exception ( __translate__('Unable to store Memcached entry ', self::plugin_constant ) . $key . __translate__( ', error code: ', self::plugin_constant ) . $code );
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Flush memcached entries
|
||||||
|
*/
|
||||||
|
private function memcached_flush ( ) {
|
||||||
|
return $this->connection->flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 ) {
|
||||||
|
|
||||||
|
/* make an array if only one string is present, easier processing */
|
||||||
|
if ( !is_array ( $keys ) )
|
||||||
|
$keys = array ( $keys );
|
||||||
|
|
||||||
|
foreach ( $keys as $key ) {
|
||||||
|
$kresult = $this->connection->delete( $key );
|
||||||
|
|
||||||
|
if ( $kresult === false ) {
|
||||||
|
$code = $this->connection->getResultCode();
|
||||||
|
$this->log ( __translate__('unable to delete entry ', self::plugin_constant ) . $key . __translate__( ', Memcached error code: ', self::plugin_constant ) . $code );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$this->log ( __translate__( 'entry deleted: ', self::plugin_constant ) . $key );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*********************** END MEMCACHED FUNCTIONS ***********************/
|
||||||
|
|
||||||
|
/*********************** MEMCACHE FUNCTIONS ***********************/
|
||||||
|
/**
|
||||||
|
* init memcache backend
|
||||||
|
*/
|
||||||
|
private function memcache_init () {
|
||||||
|
/* Memcached class does not exist, Memcache extension is not available */
|
||||||
|
if (!class_exists('Memcache')) {
|
||||||
|
$this->log ( __translate__('PHP Memcache extension missing', self::plugin_constant ), LOG_ERR );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check for existing server list, otherwise we cannot add backends */
|
||||||
|
if ( empty ( $this->options['servers'] ) && ! $this->alive ) {
|
||||||
|
$this->log ( __translate__("servers list is empty, init failed", self::plugin_constant ), LOG_WARNING );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check is there's no backend connection yet */
|
||||||
|
if ( $this->connection === NULL )
|
||||||
|
$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 ) );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* adding servers */
|
||||||
|
foreach ( $this->options['servers'] as $server_id => $server ) {
|
||||||
|
/* reset server status to unknown */
|
||||||
|
if ( $this->options['persistent'] == '1' )
|
||||||
|
$this->status[$server_id] = $this->connection->pconnect ( $server['host'] , $server['port'] );
|
||||||
|
else
|
||||||
|
$this->status[$server_id] = $this->connection->connect ( $server['host'] , $server['port'] );
|
||||||
|
|
||||||
|
$this->log ( $server_id . __translate__(" added, persistent mode: ", self::plugin_constant ) . $this->options['persistent'] );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* backend is now alive */
|
||||||
|
$this->alive = true;
|
||||||
|
$this->memcache_status();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* check current backend alive status for Memcached
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private function memcache_status () {
|
||||||
|
/* server status will be calculated by getting server stats */
|
||||||
|
$this->log ( __translate__("checking server statuses", self::plugin_constant ));
|
||||||
|
/* get servers statistic from connection */
|
||||||
|
foreach ( $this->options['servers'] as $server_id => $server ) {
|
||||||
|
$this->status[$server_id] = $this->connection->getServerStatus( $server['host'], $server['port'] );
|
||||||
|
if ( $this->status[$server_id] == 0 )
|
||||||
|
$this->log ( $server_id . __translate__(" server is down", self::plugin_constant ));
|
||||||
|
else
|
||||||
|
$this->log ( $server_id . __translate__(" server is up & running", self::plugin_constant ));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get function for Memcached backend
|
||||||
|
*
|
||||||
|
* @param string $key Key to get values for
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private function memcache_get ( &$key ) {
|
||||||
|
return $this->connection->get($key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set function for Memcached backend
|
||||||
|
*
|
||||||
|
* @param string $key Key to set with
|
||||||
|
* @param mixed $data Data to set
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private function memcache_set ( &$key, &$data ) {
|
||||||
|
$result = $this->connection->set ( $key, $data , 0 , $this->options['expire'] );
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Flush memcached entries
|
||||||
|
*/
|
||||||
|
private function memcache_flush ( ) {
|
||||||
|
return $this->connection->flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 ) {
|
||||||
|
/* make an array if only one string is present, easier processing */
|
||||||
|
if ( !is_array ( $keys ) )
|
||||||
|
$keys = array ( $keys );
|
||||||
|
|
||||||
|
foreach ( $keys as $key ) {
|
||||||
|
$kresult = $this->connection->delete( $key );
|
||||||
|
|
||||||
|
if ( $kresult === false )
|
||||||
|
{
|
||||||
|
$this->log ( __translate__('unable to delete entry ', self::plugin_constant ) . $key );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$this->log ( __translate__( 'entry deleted: ', self::plugin_constant ) . $key );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************** END MEMCACHE FUNCTIONS ***********************/
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
663
wp-ffpc-class.php
Normal file
663
wp-ffpc-class.php
Normal file
|
@ -0,0 +1,663 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* main class for WordPress plugin WP-FFPC
|
||||||
|
*
|
||||||
|
* supported storages:
|
||||||
|
* - APC
|
||||||
|
* - Memcached
|
||||||
|
* - Memcache
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
if ( ! class_exists( 'WP_FFPC' ) ) {
|
||||||
|
|
||||||
|
/* get the plugin abstract class*/
|
||||||
|
include_once ( 'wp-ffpc-abstract.php');
|
||||||
|
/* get the common functions class*/
|
||||||
|
include_once ( 'wp-ffpc-backend.php');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* main wp-ffpc class
|
||||||
|
*
|
||||||
|
* @var string $acache_config Configuration storage file location
|
||||||
|
* @var string $acache_worker The advanced cache worker file location
|
||||||
|
* @var string $acache The WordPress standard advanced cache location
|
||||||
|
* @var array $select_cache_type Possible cache types array
|
||||||
|
* @var array $select_invalidation_method Possible invalidation methods array
|
||||||
|
* @var string $nginx_sample Nginx example config file location
|
||||||
|
* @var array $select_cache_type Cache types string array
|
||||||
|
* @var array $select_invalidation_method Invalidation methods string array
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class WP_FFPC extends WP_Plugins_Abstract {
|
||||||
|
const host_separator = ',';
|
||||||
|
const port_separator = ':';
|
||||||
|
const donation_id_key = 'hosted_button_id=';
|
||||||
|
const global_config_var = '$wp_ffpc_config';
|
||||||
|
const slug_flush = '&flushed=true';
|
||||||
|
private $global_option = '';
|
||||||
|
private $global_config_key = '';
|
||||||
|
private $global_config = array();
|
||||||
|
private $global_saved = false;
|
||||||
|
private $acache_worker = '';
|
||||||
|
private $acache = '';
|
||||||
|
private $nginx_sample = '';
|
||||||
|
private $acache_backend = '';
|
||||||
|
private $button_flush;
|
||||||
|
protected $select_cache_type = array ();
|
||||||
|
protected $select_invalidation_method = array ();
|
||||||
|
protected $valid_cache_type = array ();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* init hook function runs before admin panel hook, themeing and options read
|
||||||
|
*/
|
||||||
|
public function plugin_init() {
|
||||||
|
/* advanced cache "worker" file */
|
||||||
|
$this->acache_worker = $this->plugin_dir . $this->plugin_constant . '-acache.php';
|
||||||
|
/* WordPress advanced-cache.php file location */
|
||||||
|
$this->acache = WP_CONTENT_DIR . '/advanced-cache.php';
|
||||||
|
/* nginx sample config file */
|
||||||
|
$this->nginx_sample = $this->plugin_dir . $this->plugin_constant . '-nginx-sample.conf';
|
||||||
|
/* backend driver file */
|
||||||
|
$this->acache_backend = $this->plugin_dir . $this->plugin_constant . '-backend.php';
|
||||||
|
/* flush button identifier */
|
||||||
|
$this->button_flush = $this->plugin_constant . '-flush';
|
||||||
|
/* global options identifier */
|
||||||
|
$this->global_option = $this->plugin_constant . '-global';
|
||||||
|
|
||||||
|
/* set global config key; here, because it's needed for migration */
|
||||||
|
if ( $this->network )
|
||||||
|
$this->global_config_key = 'network';
|
||||||
|
else
|
||||||
|
$this->global_config_key = $_SERVER['HTTP_HOST'];
|
||||||
|
|
||||||
|
/* cache type possible values array */
|
||||||
|
$this->select_cache_type = array (
|
||||||
|
'apc' => __( 'APC' , $this->plugin_constant ),
|
||||||
|
'memcache' => __( 'PHP Memcache' , $this->plugin_constant ),
|
||||||
|
'memcached' => __( 'PHP Memcached' , $this->plugin_constant ),
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->valid_cache_type = array (
|
||||||
|
'apc' => function_exists( 'apc_sma_info' ) ? true : false,
|
||||||
|
'memcache' => class_exists ( 'Memcache') ? true : false,
|
||||||
|
'memcached' => class_exists ( 'Memcached') ? true : false,
|
||||||
|
);
|
||||||
|
|
||||||
|
/* invalidation method possible values array */
|
||||||
|
$this->select_invalidation_method = array (
|
||||||
|
0 => __( 'flush cache' , $this->plugin_constant ),
|
||||||
|
1 => __( 'only modified post' , $this->plugin_constant ),
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* additional init, steps that needs the plugin options
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function plugin_setup () {
|
||||||
|
|
||||||
|
/* initiate backend */
|
||||||
|
$this->backend = new WP_FFPC_Backend ( $this->options );
|
||||||
|
|
||||||
|
/* 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 );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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 filter for catching canonical redirects */
|
||||||
|
add_filter('redirect_canonical', 'wp_ffpc_redirect_callback', 10, 2);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* activation hook function, to be extended
|
||||||
|
*/
|
||||||
|
public function plugin_activate() {
|
||||||
|
/* we leave this empty to avoid not detecting WP network correctly */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* deactivation hook function, to be extended
|
||||||
|
*/
|
||||||
|
public function plugin_deactivate () {
|
||||||
|
/* remove current site config from global config */
|
||||||
|
$this->update_global_config( true );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* uninstall hook function, to be extended
|
||||||
|
*/
|
||||||
|
public function plugin_uninstall( $delete_options = true ) {
|
||||||
|
/* delete advanced-cache.php file */
|
||||||
|
unlink ( $this->acache );
|
||||||
|
|
||||||
|
/* delete site settings */
|
||||||
|
if ( $delete_options ) {
|
||||||
|
$this->plugin_options_delete ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* admin panel, the admin page displayed for plugin settings
|
||||||
|
*/
|
||||||
|
public function plugin_admin_panel() {
|
||||||
|
/**
|
||||||
|
* security, if somehow we're running without WordPress security functions
|
||||||
|
*/
|
||||||
|
if( ! function_exists( 'current_user_can' ) || ! current_user_can( 'manage_options' ) ){
|
||||||
|
die( );
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
|
||||||
|
<div class="wrap">
|
||||||
|
|
||||||
|
<script>
|
||||||
|
jQuery(document).ready(function($) {
|
||||||
|
jQuery( "#<?php echo $this->plugin_constant ?>-settings" ).tabs();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<?php
|
||||||
|
|
||||||
|
$this->plugin_donation_form();
|
||||||
|
/**
|
||||||
|
* if options were saved, display saved message
|
||||||
|
*/
|
||||||
|
if ( ! empty( $this->broadcast_message ) ) : ?>
|
||||||
|
<div class="updated"><?php echo $this->broadcast_message; ?></div>
|
||||||
|
<?php endif;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* if options were saved, display saved message
|
||||||
|
*/
|
||||||
|
if ($_GET['saved']=='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) : ?>
|
||||||
|
<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) : ?>
|
||||||
|
<div class='updated settings-error'><p><strong><?php _e( "Cache flushed." , $this->plugin_constant ); ?></strong></p></div>
|
||||||
|
<?php endif;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* the admin panel itself
|
||||||
|
*/
|
||||||
|
?>
|
||||||
|
|
||||||
|
<h2><?php echo $this->plugin_name ; _e( ' settings', $this->plugin_constant ) ; ?></h2>
|
||||||
|
|
||||||
|
<?php if ( ! WP_CACHE ) : ?>
|
||||||
|
<div class="error"><p><?php _e("WP_CACHE is disabled, plugin will not work that way. Please add define `( 'WP_CACHE', true );` in wp-config.php", $this->plugin_constant ); ?></p></div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<?php if ( ! $this->global_saved ) : ?>
|
||||||
|
<div class="error"><p><?php _e("WARNING: plugin settings are not yet saved for the site, please save settings!", $this->plugin_constant); ?></p><p><?php _e( "Technical information: the configuration array is not present in the global configuration." , $this->plugin_constant ) ?></p></div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<?php if ( ! file_exists ( $this->acache ) ) : ?>
|
||||||
|
<div class="error"><p><?php _e("WARNING: advanced cache file is yet to be generated, please save settings!", $this->plugin_constant); ?></p><p><?php _e( "Technical information: please check if location is writable: " . $this->acache , $this->plugin_constant ) ?></p></div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<?php if ( $this->options['cache_type'] == 'memcached' && !class_exists('Memcached') ) : ?>
|
||||||
|
<div class="error"><p><?php _e('ERROR: Memcached cache backend activated but no PHP memcached extension was found.', $this->plugin_constant); ?></p></div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<?php if ( $this->options['cache_type'] == 'memcache' && !class_exists('Memcache') ) : ?>
|
||||||
|
<div class="error"><p><?php _e('ERROR: Memcache cache backend activated but no PHP memcache extension was found.', $this->plugin_constant); ?></p></div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<?php
|
||||||
|
/* get the current runtime configuration for memcache in PHP because Memcache in binary mode is really problematic */
|
||||||
|
if ( extension_loaded ( 'memcache' ) )
|
||||||
|
{
|
||||||
|
$memcache_settings = ini_get_all( 'memcache' );
|
||||||
|
if ( !empty ( $memcache_settings ) && $this->options['cache_type'] == 'memcache' )
|
||||||
|
{
|
||||||
|
$memcache_protocol = strtolower($memcache_settings['memcache.protocol']['local_value']);
|
||||||
|
if ( $memcached_protocol == 'binary' ) :
|
||||||
|
?>
|
||||||
|
<div class="error"><p><?php _e('WARNING: Memcache extension is configured to use binary mode. This is very buggy and the plugin will most probably not work correctly. <br />Please consider to change either to ASCII mode or to Memcached extension.', $this->plugin_constant ); ?></p></div>
|
||||||
|
<?php
|
||||||
|
endif;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
<div class="updated">
|
||||||
|
<p><strong><?php _e ( 'Driver: ' , $this->plugin_constant); echo $this->options['cache_type']; ?></strong></p>
|
||||||
|
<?php
|
||||||
|
/* only display backend status if memcache-like extension is running */
|
||||||
|
if ( strstr ( $this->options['cache_type'], 'memcache') ) :
|
||||||
|
?><p><?php
|
||||||
|
_e( '<strong>Backend status:</strong><br />', $this->plugin_constant );
|
||||||
|
|
||||||
|
/* we need to go through all servers */
|
||||||
|
$servers = $this->backend->status();
|
||||||
|
foreach ( $servers as $server_string => $status ) {
|
||||||
|
echo $server_string ." => ";
|
||||||
|
|
||||||
|
if ( $status == 0 )
|
||||||
|
_e ( '<span class="error-msg">down</span><br />', $this->plugin_constant );
|
||||||
|
elseif ( $status == 1 )
|
||||||
|
_e ( '<span class="ok-msg">up & running</span><br />', $this->plugin_constant );
|
||||||
|
else
|
||||||
|
_e ( '<span class="error-msg">unknown, please try re-saving settings!</span><br />', $this->plugin_constant );
|
||||||
|
}
|
||||||
|
|
||||||
|
?></p><?php
|
||||||
|
endif;
|
||||||
|
?>
|
||||||
|
</div>
|
||||||
|
<form method="post" action="#" id="<?php echo $this->plugin_constant ?>-settings" class="plugin-admin">
|
||||||
|
|
||||||
|
<ul class="tabs">
|
||||||
|
<li><a href="#<?php echo $this->plugin_constant ?>-type" class="wp-switch-editor"><?php _e( 'Cache type', $this->plugin_constant ); ?></a></li>
|
||||||
|
<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>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<fieldset id="<?php echo $this->plugin_constant ?>-type">
|
||||||
|
<legend><?php _e( 'Set cache type', $this->plugin_constant ); ?></legend>
|
||||||
|
<dl>
|
||||||
|
<dt>
|
||||||
|
<label for="cache_type"><?php _e('Select backend', $this->plugin_constant); ?></label>
|
||||||
|
</dt>
|
||||||
|
<dd>
|
||||||
|
<select name="cache_type" id="cache_type">
|
||||||
|
<?php $this->print_select_options ( $this->select_cache_type , $this->options['cache_type'], $this->valid_cache_type ) ?>
|
||||||
|
</select>
|
||||||
|
<span class="description"><?php _e('Select backend storage driver', $this->plugin_constant); ?></span>
|
||||||
|
<span class="default"><?php $this->print_default ( 'cache_type' ); ?></span>
|
||||||
|
</dd>
|
||||||
|
|
||||||
|
<dt>
|
||||||
|
<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="default"><?php $this->print_default ( 'expire' ); ?></span>
|
||||||
|
</dd>
|
||||||
|
|
||||||
|
<dt>
|
||||||
|
<label for="charset"><?php _e('Charset', $this->plugin_constant); ?></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.', $this->plugin_constant); ?></span>
|
||||||
|
<span class="default"><?php $this->print_default ( 'charset' ); ?></span>
|
||||||
|
</dd>
|
||||||
|
|
||||||
|
<dt>
|
||||||
|
<label for="invalidation_method"><?php _e('Cache invalidation method', $this->plugin_constant); ?></label>
|
||||||
|
</dt>
|
||||||
|
<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="default"><?php $this->print_default ( 'invalidation_method' ); ?></span>
|
||||||
|
</dd>
|
||||||
|
|
||||||
|
<dt>
|
||||||
|
<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="default"><?php $this->print_default ( 'prefix_data' ); ?></span>
|
||||||
|
</dd>
|
||||||
|
|
||||||
|
<dt>
|
||||||
|
<label for="prefix_meta"><?php _e('Meta prefix', $this->plugin_constant); ?></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.', $this->plugin_constant); ?></span>
|
||||||
|
<span class="default"><?php $this->print_default ( 'prefix_meta' ); ?></span>
|
||||||
|
</dd>
|
||||||
|
</dl>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
<fieldset id="<?php echo $this->plugin_constant ?>-debug">
|
||||||
|
<legend><?php _e( 'Debug & in-depth settings', $this->plugin_constant ); ?></legend>
|
||||||
|
<dl>
|
||||||
|
<dt>
|
||||||
|
<label for="log"><?php _e("Enable logging", $this->plugin_constant); ?></label>
|
||||||
|
</dt>
|
||||||
|
<dd>
|
||||||
|
<input type="checkbox" name="log" id="log" value="1" <?php checked($this->options['log'],true); ?> />
|
||||||
|
<span class="description"><?php _e('Enables ERROR and WARNING level syslog messages. Requires PHP syslog function.', $this->plugin_constant); ?></span>
|
||||||
|
<span class="default"><?php $this->print_default ( 'log' ); ?></span>
|
||||||
|
</dd>
|
||||||
|
|
||||||
|
<dt>
|
||||||
|
<label for="log_info"><?php _e("Enable information log", $this->plugin_constant); ?></label>
|
||||||
|
</dt>
|
||||||
|
<dd>
|
||||||
|
<input type="checkbox" name="log_info" id="log_info" value="1" <?php checked($this->options['log_info'],true); ?> />
|
||||||
|
<span class="description"><?php _e('Enables INFO level messages; carefull, plugin is really talkative. Requires PHP syslog function.', $this->plugin_constant); ?></span>
|
||||||
|
<span class="default"><?php $this->print_default ( 'log_info' ); ?></span>
|
||||||
|
</dd>
|
||||||
|
|
||||||
|
<dt>
|
||||||
|
<label for="response_header"><?php _e("Add X-Cache-Engine header", $this->plugin_constant); ?></label>
|
||||||
|
</dt>
|
||||||
|
<dd>
|
||||||
|
<input type="checkbox" name="response_header" id="response_header" value="1" <?php checked($this->options['response_header'],true); ?> />
|
||||||
|
<span class="description"><?php _e('Add X-Cache-Engine HTTP header to HTTP responses.', $this->plugin_constant); ?></span>
|
||||||
|
<span class="default"><?php $this->print_default ( 'response_header' ); ?></span>
|
||||||
|
</dd>
|
||||||
|
|
||||||
|
<dt>
|
||||||
|
<label for="sync_protocols"><?php _e("Enable sync protocolls", $this->plugin_constant); ?></label>
|
||||||
|
</dt>
|
||||||
|
<dd>
|
||||||
|
<input type="checkbox" name="sync_protocols" id="sync_protocols" value="1" <?php checked($this->options['sync_protocols'],true); ?> />
|
||||||
|
<span class="description"><?php _e('Enable to replace every protocol to the same as in the request for site\'s domain', $this->plugin_constant); ?></span>
|
||||||
|
<span class="default"><?php $this->print_default ( 'sync_protocols' ); ?></span>
|
||||||
|
</dd>
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
<fieldset id="<?php echo $this->plugin_constant ?>-exceptions">
|
||||||
|
<legend><?php _e( 'Set cache additions/excepions', $this->plugin_constant ); ?></legend>
|
||||||
|
<dl>
|
||||||
|
<dt>
|
||||||
|
<label for="cache_loggedin"><?php _e('Enable cache for logged in users', $this->plugin_constant); ?></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.', $this->plugin_constant); ?></span>
|
||||||
|
<span class="default"><?php $this->print_default ( 'cache_loggedin' ); ?></span>
|
||||||
|
</dd>
|
||||||
|
|
||||||
|
<dt>
|
||||||
|
<label for="nocache_home"><?php _e("Don't cache home", $this->plugin_constant); ?></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', $this->plugin_constant); ?></span>
|
||||||
|
<span class="default"><?php $this->print_default ( 'nocache_home' ); ?></span>
|
||||||
|
</dd>
|
||||||
|
|
||||||
|
<dt>
|
||||||
|
<label for="nocache_feed"><?php _e("Don't cache feeds", $this->plugin_constant); ?></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.', $this->plugin_constant); ?></span>
|
||||||
|
<span class="default"><?php $this->print_default ( 'nocache_feed' ); ?></span>
|
||||||
|
</dd>
|
||||||
|
|
||||||
|
<dt>
|
||||||
|
<label for="nocache_archive"><?php _e("Don't cache archives", $this->plugin_constant); ?></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.', $this->plugin_constant); ?></span>
|
||||||
|
<span class="default"><?php $this->print_default ( 'nocache_archive' ); ?></span>
|
||||||
|
</dd>
|
||||||
|
|
||||||
|
<dt>
|
||||||
|
<label for="nocache_single"><?php _e("Don't cache posts (and single-type entries)", $this->plugin_constant); ?></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.', $this->plugin_constant); ?></span>
|
||||||
|
<span class="default"><?php $this->print_default ( 'nocache_single' ); ?></span>
|
||||||
|
</dd>
|
||||||
|
|
||||||
|
<dt>
|
||||||
|
<label for="nocache_page"><?php _e("Don't cache pages", $this->plugin_constant); ?></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.', $this->plugin_constant); ?></span>
|
||||||
|
<span class="default"><?php $this->print_default ( 'nocache_page' ); ?></span>
|
||||||
|
</dd>
|
||||||
|
</dl>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
<fieldset id="<?php echo $this->plugin_constant ?>-memcached">
|
||||||
|
<legend><?php _e('Settings for memcached backend', $this->plugin_constant); ?></legend>
|
||||||
|
<dl>
|
||||||
|
<dt>
|
||||||
|
<label for="hosts"><?php _e('Hosts', $this->plugin_constant); ?></label>
|
||||||
|
</dt>
|
||||||
|
<dd>
|
||||||
|
<input type="text" name="hosts" id="hosts" value="<?php echo $this->options['hosts']; ?>" />
|
||||||
|
<span class="description"><?php _e('List all valid like host:port,host:port,... <br />No spaces are allowed, please stick to use ":" for separating host and port and "," for separating entries. Do not add trailing ",".', $this->plugin_constant); ?></span>
|
||||||
|
<span class="default"><?php $this->print_default ( 'hosts' ); ?></span>
|
||||||
|
</dd>
|
||||||
|
<dt>
|
||||||
|
<label for="persistent"><?php _e('Persistent memcache connections', $this->plugin_constant); ?></label>
|
||||||
|
</dt>
|
||||||
|
<dd>
|
||||||
|
<input type="checkbox" name="persistent" id="persistent" value="1" <?php checked($this->options['persistent'],true); ?> />
|
||||||
|
<span class="description"><?php _e('Make all memcache(d) connections persistent. Be carefull with this setting, always test the outcome.', $this->plugin_constant); ?></span>
|
||||||
|
<span class="default"><?php $this->print_default ( 'persistent' ); ?></span>
|
||||||
|
</dd>
|
||||||
|
</dl>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
<fieldset id="<?php echo $this->plugin_constant ?>-nginx">
|
||||||
|
<legend><?php _e('Sample config for nginx to utilize the data entries', $this->plugin_constant); ?></legend>
|
||||||
|
<pre><?php echo $this->nginx_example(); ?></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>
|
||||||
|
</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 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* extending options_save
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function plugin_hook_options_save( $activating ) {
|
||||||
|
|
||||||
|
/* flush the cache when news options are saved, not needed on activation */
|
||||||
|
if ( !$activating )
|
||||||
|
$this->backend->clear();
|
||||||
|
|
||||||
|
/* create the to-be-included configuration for advanced-cache.php */
|
||||||
|
$this->update_global_config();
|
||||||
|
|
||||||
|
/* create advanced cache file, needed only once or on activation, because there could be lefover advanced-cache.php from different plugins */
|
||||||
|
if ( !$activating )
|
||||||
|
$this->deploy_acache();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* read hook; needs to be implemented
|
||||||
|
*/
|
||||||
|
public function plugin_hook_options_read( &$options ) {
|
||||||
|
/* read the global options, network compatibility */
|
||||||
|
$this->global_config = get_site_option( $this->global_option );
|
||||||
|
|
||||||
|
/* check if current site present in global config */
|
||||||
|
if ( !empty ( $this->global_config[ $this->global_config_key ] ) )
|
||||||
|
$this->global_saved = true;
|
||||||
|
|
||||||
|
$this->global_config[ $this->global_config_key ] = $options;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* options delete hook; needs to be implemented
|
||||||
|
*/
|
||||||
|
public function plugin_hook_options_delete( ) {
|
||||||
|
delete_site_option ( $this->global_option );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* need to do migrations from previous versions of the plugin
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function plugin_hook_options_migrate( &$options ) {
|
||||||
|
|
||||||
|
if ( $options['version'] != $this->plugin_version || !isset ( $options['version'] ) ) {
|
||||||
|
|
||||||
|
/* cleanup possible leftover files from previous versions */
|
||||||
|
$check = array ( 'advanced-cache.php', 'nginx-sample.conf', 'wp-ffpc.admin.css', 'wp-ffpc-common.php' );
|
||||||
|
foreach ( $check as $fname ) {
|
||||||
|
$fname = $this->plugin_dir . $fname;
|
||||||
|
if ( file_exists ( $fname ) )
|
||||||
|
unlink ( $fname );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* updating from version 0.4.x */
|
||||||
|
if ( !empty ( $options['host'] ) ) {
|
||||||
|
$options['hosts'] = $options['host'] . ':' . $options['port'];
|
||||||
|
}
|
||||||
|
/* migrating from version 0.6.x */
|
||||||
|
elseif ( is_array ( $options ) && array_key_exists ( $this->global_config_key , $options ) ) {
|
||||||
|
$options = $options[ $this->global_config_key ];
|
||||||
|
}
|
||||||
|
/* migrating from something, drop previous config */
|
||||||
|
else {
|
||||||
|
$options = array();
|
||||||
|
}
|
||||||
|
/* renamed options */
|
||||||
|
$options['log'] = $options['syslog'];
|
||||||
|
$options['response_header'] = $options['debug'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* advanced-cache.php creator function
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private function deploy_acache( ) {
|
||||||
|
|
||||||
|
/* in case advanced-cache.php was already there, remove it */
|
||||||
|
if ( @file_exists( $this->acache ))
|
||||||
|
unlink ($this->acache);
|
||||||
|
|
||||||
|
/* is deletion was unsuccessful, die, we have no rights to do that, fail */
|
||||||
|
if ( @file_exists( $this->acache ))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* if no active site left no need for advanced cache :( */
|
||||||
|
if ( empty ( $this->global_config ) )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* add the required includes and generate the needed code */
|
||||||
|
$string[] = "<?php";
|
||||||
|
$string[] = self::global_config_var . ' = ' . var_export ( $this->global_config, true ) . ';' ;
|
||||||
|
$string[] = "include_once ('" . $this->acache_backend . "');";
|
||||||
|
$string[] = "include_once ('" . $this->acache_worker . "');";
|
||||||
|
$string[] = "?>";
|
||||||
|
|
||||||
|
/* write the file and start caching from this point */
|
||||||
|
return file_put_contents( $this->acache, join( "\n" , $string ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* function to generate working example from the nginx sample file
|
||||||
|
*
|
||||||
|
* @return string nginx config file
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private function nginx_example () {
|
||||||
|
/* read the sample file */
|
||||||
|
$nginx = file_get_contents ( $this->nginx_sample );
|
||||||
|
|
||||||
|
/* this part is not used when the cache is turned on for logged in users */
|
||||||
|
$loggedin = '# avoid cache for logged in users
|
||||||
|
if ($http_cookie ~* "comment_author_|wordpressuser_|wp-postpass_" ) {
|
||||||
|
set $memcached_request 0;
|
||||||
|
}';
|
||||||
|
|
||||||
|
/* replace the data prefix with the configured one */
|
||||||
|
$nginx = str_replace ( 'DATAPREFIX' , $this->options['prefix_data'] , $nginx );
|
||||||
|
|
||||||
|
/* set upstream servers from configured servers, best to get from the actual backend */
|
||||||
|
$servers = $this->backend->get_servers();
|
||||||
|
foreach ( array_keys( $servers ) as $server ) {
|
||||||
|
$nginx_servers .= " server ". $server .";\n";
|
||||||
|
}
|
||||||
|
$nginx = str_replace ( 'MEMCACHED_SERVERS' , $nginx_servers , $nginx );
|
||||||
|
|
||||||
|
/* add logged in cache, if valid */
|
||||||
|
if ( ! $this->options['cache_loggedin'])
|
||||||
|
$nginx = str_replace ( 'LOGGEDIN_EXCEPTION' , $loggedin , $nginx );
|
||||||
|
else
|
||||||
|
$nginx = str_replace ( 'LOGGEDIN_EXCEPTION' , '' , $nginx );
|
||||||
|
|
||||||
|
return $nginx;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* function to update global configuration
|
||||||
|
*
|
||||||
|
* @param boolean $remove_site Bool to remove or add current config to global
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private function update_global_config ( $remove_site = false ) {
|
||||||
|
|
||||||
|
/* remove or add current config to global config */
|
||||||
|
if ( $remove_site ) {
|
||||||
|
unset ( $this->global_config[ $this->global_config_key ] );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$this->global_config[ $this->global_config_key ] = $this->options;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* deploy advanced-cache.php */
|
||||||
|
$this->deploy_acache ();
|
||||||
|
|
||||||
|
/* save options to database */
|
||||||
|
update_site_option( $this->global_option , $this->global_config );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
51
wp-ffpc-nginx-sample.conf
Normal file
51
wp-ffpc-nginx-sample.conf
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
http {
|
||||||
|
...
|
||||||
|
upstream memcached-servers {
|
||||||
|
MEMCACHED_SERVERS
|
||||||
|
}
|
||||||
|
...
|
||||||
|
server {
|
||||||
|
...
|
||||||
|
|
||||||
|
# try to get result from memcached
|
||||||
|
location @memcached {
|
||||||
|
default_type text/html;
|
||||||
|
set $memcached_key DATAPREFIX$scheme://$host$request_uri;
|
||||||
|
set $memcached_request 1;
|
||||||
|
|
||||||
|
# exceptions
|
||||||
|
# avoid cache serve of POST requests
|
||||||
|
if ($request_method = POST ) {
|
||||||
|
set $memcached_request 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
# avoid cache serve of wp-admin-like pages, starting with "wp-"
|
||||||
|
if ( $uri ~ "/wp-" ) {
|
||||||
|
set $memcached_request 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOGGEDIN_EXCEPTION
|
||||||
|
|
||||||
|
if ( $memcached_request = 1) {
|
||||||
|
memcached_pass memcached-servers;
|
||||||
|
error_page 404 = @rewrites;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( $memcached_request = 0) {
|
||||||
|
rewrite ^ /index.php$request_uri last;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
## rewrite rules
|
||||||
|
location @rewrites {
|
||||||
|
rewrite ^ /index.php$request_uri last;
|
||||||
|
}
|
||||||
|
|
||||||
|
location / {
|
||||||
|
try_files $uri $uri/ @memcached;
|
||||||
|
}
|
||||||
|
|
||||||
|
...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
...
|
Loading…
Reference in a new issue