diff --git a/.codeclimate.yml b/.codeclimate.yml new file mode 100644 index 0000000..2d62ef2 --- /dev/null +++ b/.codeclimate.yml @@ -0,0 +1,66 @@ +--- +engines: + csslint: + enabled: true + duplication: + enabled: true + config: + languages: + - javascript + - php + fixme: + enabled: true + phpcodesniffer: + enabled: true + config: + standard: "WordPress-Core,WordPress-Docs,WordPress-Extra" + phpmd: + enabled: true + checks: + Controversial/CamelCaseParameterName: + enabled: false + Controversial/CamelCaseMethodName: + enabled: false + Controversial/CamelCasePropertyName: + enabled: false + Controversial/CamelCaseVariableName: + enabled: false + CleanCode/ElseExpression: + enabled: false + eslint: + enabled: true + scss-lint: + enabled: true + markdownlint: + enabled: true +ratings: + paths: + - "**.scss" + - "**.inc" + - "**.js" + - "**.jsx" + - "**.module" + - "**.php" + - "**.md" + - "**.py" + - "**.rb" +exclude_paths: + - "**.png" + - "**.jpg" + - "**.gif" + - "**.css" + - "**.map" + - "gulpfile.js" + - "config.codekit" + - "composer.lock" + - "phpcs.xml" + - "**.json" + - "**.pot" + - "**.txt" + - "**-min.js" + - "**-min.css" + - "**.dist" + - "**.sh" + - "**.gif" + - "**.jpg" + - "**.jpeg" \ No newline at end of file diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..c951f00 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,21 @@ +# This file is for unifying the coding style for different editors and IDEs +# editorconfig.org + +# WordPress Coding Standards +# https://make.wordpress.org/core/handbook/coding-standards/ + +root = true + +[*] +charset = utf-8 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true +indent_style = tab + +[{.jshintrc,*.json,*.yml}] +indent_style = space +indent_size = 2 + +[{*.txt,wp-config-sample.php}] +end_of_line = crlf \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..208a599 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +vendor/* \ No newline at end of file diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..b3b6744 --- /dev/null +++ b/composer.json @@ -0,0 +1,5 @@ +{ + "require-dev": { + "stevegrunwell/wp-enforcer": "^0.5.0" + } +} diff --git a/composer.lock b/composer.lock new file mode 100644 index 0000000..443546b --- /dev/null +++ b/composer.lock @@ -0,0 +1,195 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", + "This file is @generated automatically" + ], + "content-hash": "30d16e2aef30b09fea6c6c062175bcb2", + "packages": [], + "packages-dev": [ + { + "name": "squizlabs/php_codesniffer", + "version": "3.0.2", + "source": { + "type": "git", + "url": "https://github.com/squizlabs/PHP_CodeSniffer.git", + "reference": "c7594a88ae75401e8f8d0bd4deb8431b39045c51" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/c7594a88ae75401e8f8d0bd4deb8431b39045c51", + "reference": "c7594a88ae75401e8f8d0bd4deb8431b39045c51", + "shasum": "" + }, + "require": { + "ext-simplexml": "*", + "ext-tokenizer": "*", + "ext-xmlwriter": "*", + "php": ">=5.4.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.0" + }, + "bin": [ + "bin/phpcs", + "bin/phpcbf" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Greg Sherwood", + "role": "lead" + } + ], + "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.", + "homepage": "http://www.squizlabs.com/php-codesniffer", + "keywords": [ + "phpcs", + "standards" + ], + "time": "2017-07-18T01:12:32+00:00" + }, + { + "name": "stevegrunwell/wp-enforcer", + "version": "v0.5.0", + "source": { + "type": "git", + "url": "https://github.com/stevegrunwell/wp-enforcer.git", + "reference": "6d583588d06346982b5819066f14675ddc8004d7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/stevegrunwell/wp-enforcer/zipball/6d583588d06346982b5819066f14675ddc8004d7", + "reference": "6d583588d06346982b5819066f14675ddc8004d7", + "shasum": "" + }, + "require": { + "wp-coding-standards/wpcs": "*" + }, + "bin": [ + "bin/wp-enforcer" + ], + "type": "library", + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Steve Grunwell", + "email": "steve@stevegrunwell.com", + "homepage": "https://stevegrunwell.com" + } + ], + "description": "Git hooks to encourage well-written WordPress.", + "keywords": [ + "PHP_CodeSniffer", + "coding standards", + "git hooks", + "wordpress" + ], + "time": "2017-05-28T18:44:13+00:00" + }, + { + "name": "wp-coding-standards/wpcs", + "version": "0.13.1", + "source": { + "type": "git", + "url": "https://github.com/WordPress-Coding-Standards/WordPress-Coding-Standards.git", + "reference": "1f64b1a0b5b789822d0303436ee4e30e0135e4dc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/WordPress-Coding-Standards/WordPress-Coding-Standards/zipball/1f64b1a0b5b789822d0303436ee4e30e0135e4dc", + "reference": "1f64b1a0b5b789822d0303436ee4e30e0135e4dc", + "shasum": "" + }, + "require": { + "php": ">=5.3", + "squizlabs/php_codesniffer": "^2.9.0 || ^3.0.2" + }, + "suggest": { + "dealerdirect/phpcodesniffer-composer-installer": "^0.4.1" + }, + "type": "phpcodesniffer-standard", + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Contributors", + "homepage": "https://github.com/WordPress-Coding-Standards/WordPress-Coding-Standards/graphs/contributors" + } + ], + "description": "PHP_CodeSniffer rules (sniffs) to enforce WordPress coding conventions", + "keywords": [ + "phpcs", + "standards", + "wordpress" + ], + "time": "2017-08-05T16:08:58+00:00" + }, + { + "name": "wpreadme2markdown/wpreadme2markdown", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/wpreadme2markdown/wp-readme-to-markdown.git", + "reference": "50c4a56503cd26b48c28fad19be281b948b8c2e0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/wpreadme2markdown/wp-readme-to-markdown/zipball/50c4a56503cd26b48c28fad19be281b948b8c2e0", + "reference": "50c4a56503cd26b48c28fad19be281b948b8c2e0", + "shasum": "" + }, + "require": { + "php": ">= 5.3.3" + }, + "type": "library", + "autoload": { + "psr-4": { + "WPReadme2Markdown\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Benjamin J. Balter" + }, + { + "name": "Christian Archer", + "email": "sunchaser@sunchaser.info" + } + ], + "description": "Convert WordPress Plugin readme.txt to Markdown", + "keywords": [ + "converter", + "markdown", + "readme", + "wordpress" + ], + "time": "2017-08-06T04:42:13+00:00" + } + ], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": [], + "platform-dev": [] +} diff --git a/object-cache.php b/object-cache.php index b7eca42..388321b 100644 --- a/object-cache.php +++ b/object-cache.php @@ -1,75 +1,159 @@ add( $key, $data, $group, $expire ); } +/** + * WP Cache Incr + * + * @access public + * @param mixed $key Key. + * @param int $n (default: 1) N. + * @param string $group (default: '') Group. + */ function wp_cache_incr( $key, $n = 1, $group = '' ) { global $wp_object_cache; return $wp_object_cache->incr( $key, $n, $group ); } +/** + * WP Cache Decr + * + * @access public + * @param mixed $key Key. + * @param int $n (default: 1) N. + * @param string $group (default: '') Group. + */ function wp_cache_decr( $key, $n = 1, $group = '' ) { global $wp_object_cache; return $wp_object_cache->decr( $key, $n, $group ); } +/** + * WP Cache Close + * + * @access public + */ function wp_cache_close() { global $wp_object_cache; return $wp_object_cache->close(); } +/** + * WP Cache Delete. + * + * @access public + * @param mixed $key Key. + * @param string $group (default: '') Group. + */ function wp_cache_delete( $key, $group = '' ) { global $wp_object_cache; return $wp_object_cache->delete( $key, $group ); } +/** + * WP Cache Flush. + * + * @access public + */ function wp_cache_flush() { global $wp_object_cache; return $wp_object_cache->flush(); } +/** + * WP Cache Get. + * + * @access public + * @param mixed $key Key. + * @param string $group (default: '') Group. + * @param bool $force (default: false) Force. + */ function wp_cache_get( $key, $group = '', $force = false ) { global $wp_object_cache; return $wp_object_cache->get( $key, $group, $force ); } +/** + * WP Cache Init. + * + * @access public + */ function wp_cache_init() { global $wp_object_cache; $wp_object_cache = new WP_Object_Cache(); } +/** + * WP Cache Replace. + * + * @access public + * @param mixed $key Key. + * @param mixed $data Data. + * @param string $group (default: '') Group. + * @param int $expire (default: 0) Expire. + */ function wp_cache_replace( $key, $data, $group = '', $expire = 0 ) { global $wp_object_cache; return $wp_object_cache->replace( $key, $data, $group, $expire ); } +/** + * Wp Chace Set. + * + * @access public + * @param mixed $key Key. + * @param mixed $data Data. + * @param string $group (default: '') Group. + * @param int $expire (default: 0) Expire. + */ function wp_cache_set( $key, $data, $group = '', $expire = 0 ) { global $wp_object_cache; @@ -80,45 +164,186 @@ function wp_cache_set( $key, $data, $group = '', $expire = 0 ) { } } +/** + * WP Cache Switch to Blog. + * + * @access public + * @param mixed $blog_id Blog ID. + */ function wp_cache_switch_to_blog( $blog_id ) { global $wp_object_cache; return $wp_object_cache->switch_to_blog( $blog_id ); } +/** + * WP Cache Add Global Groups. + * + * @access public + * @param mixed $groups Groups. + */ function wp_cache_add_global_groups( $groups ) { global $wp_object_cache; $wp_object_cache->add_global_groups( $groups ); } +/** + * Wp Cahce Add Non Persistent Groups. + * + * @access public + * @param mixed $groups Groups. + */ function wp_cache_add_non_persistent_groups( $groups ) { global $wp_object_cache; $wp_object_cache->add_non_persistent_groups( $groups ); } +/** + * WP_Object_Cache class. + */ class WP_Object_Cache { + + /** + * Global Groups. + * + * (default value: array( 'WP_Object_Cache_global' )) + * + * @var string + * @access public + */ var $global_groups = array( 'WP_Object_Cache_global' ); + /** + * NO MC Groups. + * + * (default value: array()) + * + * @var array + * @access public + */ var $no_mc_groups = array(); - var $cache = array(); - var $mc = array(); - var $stats = array(); + /** + * Cache + * + * (default value: array()) + * + * @var array + * @access public + */ + var $cache = array(); + + /** + * MC + * + * (default value: array()) + * + * @var array + * @access public + */ + var $mc = array(); + + /** + * Stats + * + * (default value: array()) + * + * @var array + * @access public + */ + var $stats = array(); + + /** + * Group Ops. + * + * (default value: array()) + * + * @var array + * @access public + */ var $group_ops = array(); - var $flush_number = array(); + /** + * Flush Number. + * + * (default value: array()) + * + * @var array + * @access public + */ + var $flush_number = array(); + + /** + * Global Flush Number. + * + * (default value: null) + * + * @var mixed + * @access public + */ var $global_flush_number = null; - var $cache_enabled = true; + /** + * Cache Enabled. + * + * (default value: true) + * + * @var bool + * @access public + */ + var $cache_enabled = true; + + /** + * Default Expiration. + * + * (default value: 0) + * + * @var int + * @access public + */ var $default_expiration = 0; - var $max_expiration = 2592000; // 30 days + /** + * Max Expiration. + * + * (default value: 2592000) + * + * @var int + * @access public + */ + var $max_expiration = 2592000; // 30 days + + /** + * Stats Callback. + * + * (default value: null) + * + * @var mixed + * @access public + */ var $stats_callback = null; + /** + * Connection Errors. + * + * (default value: array()) + * + * @var array + * @access public + */ var $connection_errors = array(); + /** + * Add. + * + * @access public + * @param mixed $id ID. + * @param mixed $data Data. + * @param string $group (default: 'default') Group. + * @param int $expire (default: 0) Expire. + */ function add( $id, $data, $group = 'default', $expire = 0 ) { $key = $this->key( $id, $group ); @@ -148,18 +373,24 @@ function add( $id, $data, $group = 'default', $expire = 0 ) { $this->group_ops[ $group ][] = "add $id"; $this->cache[ $key ] = $data; - } else if ( false === $result && true === isset( $this->cache[$key] ) && false === $this->cache[$key] ) { + } elseif ( false === $result && true === isset( $this->cache[ $key ] ) && false === $this->cache[ $key ] ) { /* * Here we unset local cache if remote add failed and local cache value is equal to `false` in order * to update the local cache anytime we get a new information from remote server. This way, the next * cache get will go to remote server and will fetch recent data. */ - unset( $this->cache[$key] ); + unset( $this->cache[ $key ] ); } return $result; } + /** + * Add Global Groups. + * + * @access public + * @param mixed $groups Groups. + */ function add_global_groups( $groups ) { if ( ! is_array( $groups ) ) { $groups = (array) $groups; @@ -169,6 +400,12 @@ function add_global_groups( $groups ) { $this->global_groups = array_unique( $this->global_groups ); } + /** + * Add Non Persistent Groups. + * + * @access public + * @param mixed $groups Groups. + */ function add_non_persistent_groups( $groups ) { if ( ! is_array( $groups ) ) { $groups = (array) $groups; @@ -178,6 +415,14 @@ function add_non_persistent_groups( $groups ) { $this->no_mc_groups = array_unique( $this->no_mc_groups ); } + /** + * Increment. + * + * @access public + * @param mixed $id ID. + * @param int $n (default: 1) Numeric. + * @param string $group (default: 'default') Group. + */ function incr( $id, $n = 1, $group = 'default' ) { $key = $this->key( $id, $group ); $mc =& $this->get_mc( $group ); @@ -187,6 +432,14 @@ function incr( $id, $n = 1, $group = 'default' ) { return $this->cache[ $key ]; } + /** + * Decr. + * + * @access public + * @param mixed $id ID. + * @param int $n (default: 1) Numeric. + * @param string $group (default: 'default') Group. + */ function decr( $id, $n = 1, $group = 'default' ) { $key = $this->key( $id, $group ); $mc =& $this->get_mc( $group ); @@ -196,12 +449,24 @@ function decr( $id, $n = 1, $group = 'default' ) { return $this->cache[ $key ]; } + /** + * Close. + * + * @access public + */ function close() { foreach ( $this->mc as $bucket => $mc ) { $mc->close(); } } + /** + * Delete. + * + * @access public + * @param mixed $id ID. + * @param string $group (default: 'default') Group. + */ function delete( $id, $group = 'default' ) { $key = $this->key( $id, $group ); @@ -226,6 +491,11 @@ function delete( $id, $group = 'default' ) { return $result; } + /** + * Flush. + * + * @access public + */ function flush() { // Do not use the memcached flush method. It acts on an // entire memcached server, affecting all sites. @@ -241,18 +511,36 @@ function flush() { } } + /** + * Rotate Site Keys. + * + * @access public + */ function rotate_site_keys() { $this->add( 'flush_number', intval( microtime( true ) * 1e6 ), 'WP_Object_Cache' ); $this->flush_number[ $this->blog_prefix ] = $this->incr( 'flush_number', 1, 'WP_Object_Cache' ); } + /** + * Rotate Global Keys. + * + * @access public + */ function rotate_global_keys() { $this->add( 'flush_number', intval( microtime( true ) * 1e6 ), 'WP_Object_Cache_global' ); $this->global_flush_number = $this->incr( 'flush_number', 1, 'WP_Object_Cache_global' ); } + /** + * Get. + * + * @access public + * @param mixed $id ID. + * @param string $group (default: 'default') Group. + * @param bool $force (default: false) Force. + */ function get( $id, $group = 'default', $force = false ) { $key = $this->key( $id, $group ); $mc =& $this->get_mc( $group ); @@ -263,7 +551,7 @@ function get( $id, $group = 'default', $force = false ) { } else { $value = $this->cache[ $key ]; } - } else if ( in_array( $group, $this->no_mc_groups ) ) { + } elseif ( in_array( $group, $this->no_mc_groups ) ) { $this->cache[ $key ] = $value = false; } else { $value = $mc->get( $key ); @@ -288,9 +576,15 @@ function get( $id, $group = 'default', $force = false ) { return $value; } + /** + * Get Mulit. + * + * @access public + * @param mixed $groups Groups. + */ function get_multi( $groups ) { /* - format: $get['group-name'] = array( 'key1', 'key2' ); + Format: $get['group-name'] = array( 'key1', 'key2' ); */ $return = array(); @@ -308,7 +602,7 @@ function get_multi( $groups ) { } continue; - } else if ( in_array( $group, $this->no_mc_groups ) ) { + } elseif ( in_array( $group, $this->no_mc_groups ) ) { $return[ $key ] = false; continue; @@ -333,6 +627,12 @@ function get_multi( $groups ) { return $return; } + /** + * Flush Prefix. + * + * @access public + * @param mixed $group Group. + */ function flush_prefix( $group ) { if ( 'WP_Object_Cache' === $group || 'WP_Object_Cache_global' === $group ) { // Never flush the flush numbers. @@ -362,6 +662,13 @@ function flush_prefix( $group ) { return $number . ':'; } + /** + * Key. + * + * @access public + * @param mixed $key Key. + * @param mixed $group Group. + */ function key( $key, $group ) { if ( empty( $group ) ) { $group = 'default'; @@ -380,6 +687,15 @@ function key( $key, $group ) { return preg_replace( '/\s+/', '', "$prefix:$group:$key" ); } + /** + * Replace. + * + * @access public + * @param mixed $id ID. + * @param mixed $data Data. + * @param string $group (default: 'default') Group. + * @param int $expire (default: 0) Expire. + */ function replace( $id, $data, $group = 'default', $expire = 0 ) { $key = $this->key( $id, $group ); @@ -403,6 +719,15 @@ function replace( $id, $data, $group = 'default', $expire = 0 ) { return $result; } + /** + * Set. + * + * @access public + * @param mixed $id ID. + * @param mixed $data Data. + * @param string $group (default: 'default') Group. + * @param int $expire (default: 0) Expire. + */ function set( $id, $data, $group = 'default', $expire = 0 ) { $key = $this->key( $id, $group ); @@ -428,12 +753,18 @@ function set( $id, $data, $group = 'default', $expire = 0 ) { $mc =& $this->get_mc( $group ); $result = $mc->set( $key, $data, false, $expire ); - ++$this->stats[ 'set' ]; - $this->group_ops[$group][] = "set $id"; + ++$this->stats['set']; + $this->group_ops[ $group ][] = "set $id"; return $result; } + /** + * Switch to Blog. + * + * @access public + * @param mixed $blog_id Blog ID. + */ function switch_to_blog( $blog_id ) { global $table_prefix; @@ -442,6 +773,12 @@ function switch_to_blog( $blog_id ) { $this->blog_prefix = ( is_multisite() ? $blog_id : $table_prefix ); } + /** + * Colorize Debug Line. + * + * @access public + * @param mixed $line Line. + */ function colorize_debug_line( $line ) { $colors = array( 'get' => 'green', @@ -457,6 +794,11 @@ function colorize_debug_line( $line ) { return $cmd2 . substr( $line, strlen( $cmd ) ) . "\n"; } + /** + * Stats. + * + * @access public + */ function stats() { if ( $this->stats_callback && is_callable( $this->stats_callback ) ) { return call_user_func( $this->stats_callback ); @@ -493,6 +835,12 @@ function stats() { } } + /** + * Get MC. + * + * @access public + * @param mixed $group Group. + */ function &get_mc( $group ) { if ( isset( $this->mc[ $group ] ) ) { return $this->mc[ $group ]; @@ -501,6 +849,13 @@ function &get_mc( $group ) { return $this->mc['default']; } + /** + * Failure. + * + * @access public + * @param mixed $host Host. + * @param mixed $port Port. + */ function failure_callback( $host, $port ) { $this->connection_errors[] = array( 'host' => $host, @@ -508,6 +863,12 @@ function failure_callback( $host, $port ) { ); } + /** + * Salt Keys. + * + * @access public + * @param mixed $key_salt Key Salt. + */ function salt_keys( $key_salt ) { if ( strlen( $key_salt ) ) { $this->key_salt = $key_salt . ':'; @@ -516,6 +877,11 @@ function salt_keys( $key_salt ) { } } + /** + * __construct function. + * + * @access public + */ function __construct() { $this->stats = array( 'get' => 0, @@ -536,13 +902,15 @@ function __construct() { reset( $buckets ); if ( is_int( key( $buckets ) ) ) { - $buckets = array( 'default' => $buckets ); + $buckets = array( + 'default' => $buckets, + ); } foreach ( $buckets as $bucket => $servers ) { $this->mc[ $bucket ] = new Memcache(); - foreach ( $servers as $server ) { + foreach ( $servers as $server ) { if ( 'unix://' == substr( $server, 0, 7 ) ) { $node = $server; $port = 0; diff --git a/phpcs.xml b/phpcs.xml new file mode 100644 index 0000000..dbb6871 --- /dev/null +++ b/phpcs.xml @@ -0,0 +1,24 @@ + + + + Coding standards from WP Enforcer. + + + phpcs.xml + */tests/* + */vendor/* + + + + 0 + + + + + \ No newline at end of file diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..6be82f1 --- /dev/null +++ b/readme.md @@ -0,0 +1,97 @@ +# Memcached Object Cache + +Use memcached and the PECL memcache extension to provide a backing store for the WordPress object cache. + +## Description +Memcached Object Cache provides a persistent backend for the WordPress object cache. A memcached server and the PECL memcache extension are required. + +## Installation +1. Install [memcached](http://danga.com/memcached) on at least one server. Note the connection info. The default is `127.0.0.1:11211`. + +1. Install the [PECL memcache extension](http://pecl.php.net/package/memcache) + +1. Copy object-cache.php to wp-content + +## Frequently Asked Questions + +### How can I manually specify the memcached server(s)? = + +Add something similar to the following to wp-config.php above `/* That's all, stop editing! Happy blogging. */`: + +``` +$memcached_servers = array( + 'default' => array( + '10.10.10.20:11211', + '10.10.10.30:11211' + ) +); +``` + +The top level array keys, are cache groups, where 'default' corresponds to any cache group that is not explicitly defined. This allows for specifying memcached servers that only handle certain cache groups. The most common use is only specifying 'default'. + +Possible cache groups are: + +``` +{$taxonomy}_relationships +{$meta_type}_meta +{$taxonomy}_relationships +blog-details +blog-id-cache +blog-lookup +bookmark +calendar +category +comment +counts +general +global-posts +options +plugins +post_ancestors +post_meta +posts +rss +site-lookup +site-options +site-transient +terms +themes +timeinfo +transient +user_meta +useremail +userlogins +usermeta +users +userslugs +widget +``` + +## Changelog + +### 3.0.1 +* Fix key generation error in switch_to_blog() + +### 3.0.0 +* Flush site cache by rotating keys +* Flush global cache when flushing main site + +### 2.0.6 +* Flush the local cache on wp_cache_flush() + +### 2.0.5 +* Fix missing global in switch_to_blog + +### 2.0.4 +* Remove deprecated constructor + +### 2.0.3 +* Support for unix sockets + +### 2.0.2 +* Break references by cloning objects +* Keep local cache in sync with memcached when using incr and decr +* Handle limited environments where is_multisite() is not defined +* Fix setting and getting 0 +* PHP 5.2.4 is now required +* Use the WP_CACHE_KEY_SALT constant if available to gaurantee uniqueness of keys