fix: address Phase 1 code review findings

- Serve cache via template_redirect so feeds/404/REST are excluded and
  query conditionals work
- Bypass cache on query strings; key files by md5(host+path) to avoid
  collisions and support multisite
- Write wp-content/wp-recache-cache.php drop-in server and set WP_CACHE
  in wp-config.php so advanced-cache.php actually runs
- Only remove advanced-cache.php on deactivation when it is ours
- Respect DONOTCACHEPAGE, non-200 responses; bots read but never warm
  cache
- Fix comment purge (comment_post_ID) and heartbeat purge ($data arg)
- Fix exclude URLs textarea parsing; purge all when exclusions change
- Enqueue admin purge script on every admin-bar page, not just settings
- Sync tests, add TESTING.md manual test guide
This commit is contained in:
2026-09-13 13:44:30 +02:00
parent 33099591f5
commit d2be239c3f
12 changed files with 309 additions and 78 deletions
+65
View File
@@ -0,0 +1,65 @@
# Testing WP Recache (manual)
Environment: Docker (`docker-compose up -d`), or any WP ≥ 5.8 + PHP ≥ 7.4 install with the plugin symlinked into `wp-content/plugins/`.
## Activation
1. Activate the plugin.
2. Check `wp-config.php` contains `define('WP_CACHE', true); // Added by WP Recache.`
3. Check these files exist:
- `wp-content/advanced-cache.php`
- `wp-content/wp-recache-cache.php`
- `wp-content/cache/wp-recache/.htaccess` + `index.php`
## Core cache (issue #1 stories 1, 11, 12)
4. Anonymous visit (incognito) to a page twice:
- 1st: response header `X-WP-Recache: MISS`, file `md5(host + path) . '.html'` appears in `wp-content/cache/wp-recache/`.
- 2nd: `X-WP-Recache: HIT` (via WP) or `X-WP-Recache-Dropin: 1` (served before WP loaded).
5. Same URL with `?utm_source=test`: always MISS, no new cache file (query strings bypass).
6. Define `DONOTCACHEPAGE` on a page (e.g. in a must-use plugin): page never cached.
7. Logged-in visit: no `X-WP-Recache` headers, nothing cached (logged-in cookie also bypasses the drop-in).
## Exclusions (stories 46)
8. Settings → Cache → Exclude URLs: add `/about`, save, visit `/about` twice → never cached.
9. Default exclusions: `/cart`, `/checkout`, `/my-account` never cached.
10. Feeds (`/feed/`) and 404 pages: no `X-WP-Recache` MISS header, no cache file.
## Purge (stories 2, 3)
11. Edit a published post → its cache file and the homepage file are deleted.
12. Add a comment to a post → that post's cache file is deleted (not the comment ID's).
13. Admin bar → WP Recache → Purge All Cache (works on every admin page AND on the front-end admin bar, not just the settings page) → cache dir emptied.
14. Settings → Advanced → Purge All Cache button → same result.
15. Heartbeat purge: `wp.heartbeat.send('wp_recache_purge', 1)` in browser console on an admin page → next heartbeat tick purges all (check response `wp_recache_purged`).
## Mobile (story 7)
16. Enable "Separate Mobile Cache", visit once with a mobile UA (`curl -A "iPhone"`), once desktop → two files: `*-mobile.html`, `*-desktop.html`.
17. With mobile cache ON, the drop-in does not serve (falls through to WP path) — expected.
## Stats (story 9)
18. Settings → Cache → Cache Statistics shows file count and size matching `wp-content/cache/wp-recache/`.
## Multisite (story 10)
19. On a network: same path on two sites produces two different files (host+path in key). Purge on one site must not touch the other.
## Deactivation / uninstall
20. Deactivate: `advanced-cache.php`, `wp-recache-cache.php` removed, `WP_CACHE` marker line removed from `wp-config.php`.
21. If another plugin's `advanced-cache.php` exists (no "WP Recache" marker), deactivation must NOT delete it.
22. Uninstall: options deleted, `wp-content/cache/wp-recache/` removed.
## Automated
- `composer test` (PHPUnit, needs WP test suite via docker-compose).
- `composer phpstan`, `composer lint`.
## Known ceilings
- Drop-in ignores `cache_duration` TTL (no WP available to read the option); freshness relies on purge-on-update. Files are never served stale for edited content, only for TTL-based expiry.
- Preload toggle (story 8) has no crawler implementation yet.
- Purge on publish clears only the post + homepage; archives/taxonomy pages expire via TTL.
+23
View File
@@ -0,0 +1,23 @@
/**
* WP Recache admin-bar / settings actions.
*
* @package WP_Recache
*/
function wpRecachePurgeAll() {
if (!confirm('Are you sure you want to purge all cache?')) {
return;
}
jQuery.post(wpRecache.ajaxUrl, {
action: 'wp_recache_purge_all',
nonce: wpRecache.nonce
}, function (response) {
if (response.success) {
alert('Cache purged successfully');
location.reload();
} else {
alert('Error: ' + response.data);
}
});
}
+81 -1
View File
@@ -15,7 +15,9 @@ class WP_Recache_Activator {
public static function activate() { public static function activate() {
self::create_cache_directory(); self::create_cache_directory();
self::set_default_options(); self::set_default_options();
self::create_cache_server();
self::create_advanced_cache(); self::create_advanced_cache();
self::set_wp_cache_constant(true);
self::flush_rewrite_rules(); self::flush_rewrite_rules();
} }
@@ -29,7 +31,7 @@ class WP_Recache_Activator {
$htaccess = WP_RECACHE_CACHE_PATH . '.htaccess'; $htaccess = WP_RECACHE_CACHE_PATH . '.htaccess';
if (!file_exists($htaccess)) { if (!file_exists($htaccess)) {
file_put_contents($htaccess, "Deny from all\n"); file_put_contents($htaccess, "<IfModule mod_authz_core.c>\nRequire all denied\n</IfModule>\n<IfModule !mod_authz_core.c>\nDeny from all\n</IfModule>\n");
} }
$index = WP_RECACHE_CACHE_PATH . 'index.php'; $index = WP_RECACHE_CACHE_PATH . 'index.php';
@@ -59,6 +61,50 @@ class WP_Recache_Activator {
} }
} }
/**
* Write the standalone cache server required by the advanced-cache.php
* drop-in. Must run without WordPress loaded.
*/
private static function create_cache_server() {
$content = '<?php
/**
* WP Recache early cache serving.
*
* This file is automatically generated by WP Recache.
* Do not edit this file manually.
*/
if (($_SERVER[\'REQUEST_METHOD\'] ?? \'GET\') !== \'GET\') {
return;
}
if (!empty($_SERVER[\'QUERY_STRING\'])) {
return;
}
foreach ($_COOKIE as $name => $value) {
if (strpos($name, \'wordpress_logged_in\') === 0) {
return;
}
}
$uri = isset($_SERVER[\'REQUEST_URI\']) ? (string) parse_url($_SERVER[\'REQUEST_URI\'], PHP_URL_PATH) : \'/\';
$host = $_SERVER[\'HTTP_HOST\'] ?? \'\';
$file = WP_CONTENT_DIR . \'/cache/wp-recache/\' . md5($host . $uri) . \'.html\';
// With separate mobile cache enabled, files carry a -desktop/-mobile suffix,
// so the plain file never exists and serving falls through to WordPress.
if (file_exists($file)) {
header(\'X-WP-Recache: HIT\');
header(\'X-WP-Recache-Dropin: 1\');
readfile($file);
exit;
}
';
file_put_contents(WP_CONTENT_DIR . '/wp-recache-cache.php', $content);
}
/** /**
* Create advanced-cache.php drop-in. * Create advanced-cache.php drop-in.
*/ */
@@ -87,6 +133,40 @@ if (file_exists(WP_CONTENT_DIR . \'/wp-recache-cache.php\')) {
file_put_contents($advanced_cache, $content); file_put_contents($advanced_cache, $content);
} }
/**
* Add or remove the WP_CACHE constant in wp-config.php.
*
* Without it, WordPress never loads advanced-cache.php.
*
* @param bool $enable True to add the constant, false to remove it.
*/
public static function set_wp_cache_constant($enable) {
$marker = "define('WP_CACHE', true); // Added by WP Recache.\n";
$config_path = ABSPATH . 'wp-config.php';
if (!file_exists($config_path)) {
$config_path = dirname(ABSPATH) . '/wp-config.php';
}
if (!file_exists($config_path) || !is_writable($config_path)) {
return;
}
$content = file_get_contents($config_path);
if ($enable) {
if (strpos($content, $marker) !== false || preg_match("/define\s*\(\s*['\"]WP_CACHE['\"]\s*,\s*true\s*\)/", $content)) {
return;
}
$content = preg_replace('/^<\?php/', "<?php\n" . $marker, $content, 1);
} else {
$content = str_replace($marker, '', $content);
}
file_put_contents($config_path, $content);
}
/** /**
* Flush rewrite rules. * Flush rewrite rules.
*/ */
+12 -8
View File
@@ -19,11 +19,9 @@ class WP_Recache_Admin {
add_action('wp_ajax_wp_recache_purge_all', [$this, 'ajax_purge_all']); add_action('wp_ajax_wp_recache_purge_all', [$this, 'ajax_purge_all']);
add_action('wp_ajax_wp_recache_purge_url', [$this, 'ajax_purge_url']); add_action('wp_ajax_wp_recache_purge_url', [$this, 'ajax_purge_url']);
add_action('admin_notices', [$this, 'admin_notices']); add_action('admin_notices', [$this, 'admin_notices']);
add_action('admin_enqueue_scripts', 'wp_recache_enqueue_admin_bar_script');
wp_localize_script('jquery', 'wpRecache', [ // New exclusions must not leave stale files that the drop-in would still serve.
'ajaxUrl' => admin_url('admin-ajax.php'), add_action('update_option_wp_recache_exclude_urls', 'wp_recache_delete_all_cache');
'nonce' => wp_create_nonce('wp_recache_nonce'),
]);
} }
/** /**
@@ -93,11 +91,13 @@ class WP_Recache_Admin {
* @return array Sanitized URLs. * @return array Sanitized URLs.
*/ */
public function sanitize_exclude_urls($input) { public function sanitize_exclude_urls($input) {
if (!is_array($input)) { if (is_array($input)) {
return []; $input = implode("\n", $input);
} }
return array_map('sanitize_text_field', $input); $lines = array_filter(array_map('trim', explode("\n", (string) $input)));
return array_map('sanitize_text_field', $lines);
} }
/** /**
@@ -110,6 +110,10 @@ class WP_Recache_Admin {
$active_tab = isset($_GET['tab']) ? sanitize_text_field($_GET['tab']) : 'cache'; $active_tab = isset($_GET['tab']) ? sanitize_text_field($_GET['tab']) : 'cache';
if (!in_array($active_tab, ['cache', 'optimize', 'advanced'], true)) {
$active_tab = 'cache';
}
include WP_RECACHE_INC_PATH . 'Admin/views/settings.php'; include WP_RECACHE_INC_PATH . 'Admin/views/settings.php';
} }
+1 -21
View File
@@ -48,7 +48,7 @@ $stats = WP_Recache_Admin::get_cache_stats();
<tr> <tr>
<th scope="row">Exclude URLs</th> <th scope="row">Exclude URLs</th>
<td> <td>
<textarea name="wp_recache_exclude_urls[]" rows="5" cols="50" class="large-text"><?php echo esc_textarea(implode("\n", get_option('wp_recache_exclude_urls', ['/cart', '/checkout', '/my-account']))); ?></textarea> <textarea name="wp_recache_exclude_urls" rows="5" cols="50" class="large-text"><?php echo esc_textarea(implode("\n", get_option('wp_recache_exclude_urls', ['/cart', '/checkout', '/my-account']))); ?></textarea>
<p class="description">One URL per line. These pages will not be cached.</p> <p class="description">One URL per line. These pages will not be cached.</p>
</td> </td>
</tr> </tr>
@@ -131,23 +131,3 @@ $stats = WP_Recache_Admin::get_cache_stats();
<?php submit_button('Save Settings'); ?> <?php submit_button('Save Settings'); ?>
</form> </form>
</div> </div>
<script>
function wpRecachePurgeAll() {
if (!confirm('Are you sure you want to purge all cache?')) {
return;
}
jQuery.post(wpRecache.ajaxUrl, {
action: 'wp_recache_purge_all',
nonce: wpRecache.nonce
}, function(response) {
if (response.success) {
alert('Cache purged successfully');
location.reload();
} else {
alert('Error: ' + response.data);
}
});
}
</script>
+52 -8
View File
@@ -9,17 +9,26 @@ defined('ABSPATH') || exit;
class WP_Recache_WPCache { class WP_Recache_WPCache {
/**
* Whether this request started our output buffer.
*
* @var bool
*/
private $buffer_started = false;
/** /**
* Initialize cache hooks. * Initialize cache hooks.
*/ */
public function init() { public function init() {
add_action('init', [$this, 'start_output_buffering']); // template_redirect: query conditionals (is_feed/is_404/is_preview) are
// available here, and REST/AJAX requests never reach it.
add_action('template_redirect', [$this, 'start_output_buffering'], 0);
add_action('shutdown', [$this, 'end_output_buffering']); add_action('shutdown', [$this, 'end_output_buffering']);
add_action('save_post', [$this, 'purge_post_cache']); add_action('save_post', [$this, 'purge_post_cache']);
add_action('wp_insert_comment', [$this, 'purge_post_cache']); add_action('wp_insert_comment', [$this, 'purge_comment_cache']);
add_filter('heartbeat_received', [$this, 'purge_cache_onheartbeat']); add_filter('heartbeat_received', [$this, 'purge_cache_onheartbeat'], 10, 2);
} }
/** /**
@@ -54,8 +63,14 @@ class WP_Recache_WPCache {
} }
} }
// Bots get served warm cache but never warm it themselves.
if (wp_recache_is_robots()) {
return;
}
header('X-WP-Recache: MISS'); header('X-WP-Recache: MISS');
ob_start([$this, 'cache_output']); ob_start([$this, 'cache_output']);
$this->buffer_started = true;
} }
/** /**
@@ -69,6 +84,20 @@ class WP_Recache_WPCache {
return $output; return $output;
} }
// Respect opt-outs from WordPress and third-party plugins.
if (defined('DONOTCACHEPAGE') && DONOTCACHEPAGE) {
return $output;
}
$status = http_response_code();
if ($status !== false && $status !== 200) {
return $output;
}
if (wp_recache_is_robots()) {
return $output;
}
$url = $this->get_current_url(); $url = $this->get_current_url();
$cache_path = wp_recache_get_cache_path_with_device($url); $cache_path = wp_recache_get_cache_path_with_device($url);
$cache_dir = dirname($cache_path); $cache_dir = dirname($cache_path);
@@ -86,7 +115,7 @@ class WP_Recache_WPCache {
* End output buffering. * End output buffering.
*/ */
public function end_output_buffering() { public function end_output_buffering() {
if (ob_get_level()) { if ($this->buffer_started && ob_get_level()) {
ob_end_flush(); ob_end_flush();
} }
} }
@@ -106,15 +135,30 @@ class WP_Recache_WPCache {
wp_recache_delete_cache(home_url('/')); wp_recache_delete_cache(home_url('/'));
} }
/**
* Purge cache for the post a comment belongs to.
*
* @param int $comment_id Comment ID.
*/
public function purge_comment_cache($comment_id) {
$comment = get_comment($comment_id);
if ($comment) {
$this->purge_post_cache($comment->comment_post_ID);
}
}
/** /**
* Purge cache on heartbeat. * Purge cache on heartbeat.
* *
* @param array $response Heartbeat response. * @param array $response Heartbeat response.
* @param array $data Data sent with the heartbeat request.
* @return array Modified response. * @return array Modified response.
*/ */
public function purge_cache_onheartbeat($response) { public function purge_cache_onheartbeat($response, $data) {
if (isset($response['wp_recache_purge'])) { if (isset($data['wp_recache_purge'])) {
wp_recache_delete_all_cache(); wp_recache_delete_all_cache();
$response['wp_recache_purged'] = true;
} }
return $response; return $response;
@@ -127,8 +171,8 @@ class WP_Recache_WPCache {
*/ */
private function get_current_url() { private function get_current_url() {
$protocol = is_ssl() ? 'https' : 'http'; $protocol = is_ssl() ? 'https' : 'http';
$host = $_SERVER['HTTP_HOST']; $host = $_SERVER['HTTP_HOST'] ?? '';
$uri = $_SERVER['REQUEST_URI']; $uri = $_SERVER['REQUEST_URI'] ?? '/';
return $protocol . '://' . $host . $uri; return $protocol . '://' . $host . $uri;
} }
+25 -27
View File
@@ -58,11 +58,12 @@ function wp_recache_should_exclude() {
return true; return true;
} }
if (wp_recache_is_robots()) { // Dynamic query-string requests are never cached (story 11).
if (!empty($_SERVER['QUERY_STRING'])) {
return true; return true;
} }
if (is_preview()) { if (is_preview() || is_feed() || is_404()) {
return true; return true;
} }
@@ -93,40 +94,22 @@ function wp_recache_is_robots() {
* Check if request is a POST action. * Check if request is a POST action.
*/ */
function wp_recache_is_post_action() { function wp_recache_is_post_action() {
return $_SERVER['REQUEST_METHOD'] === 'POST'; return ($_SERVER['REQUEST_METHOD'] ?? 'GET') === 'POST';
} }
/** /**
* Get cache file path for URL. * Get cache file path for URL.
* *
* @param string $url URL to cache. * Keyed by md5(host + path) so nested paths, hosts and multisite
*/ * sub-directories never collide. Query strings are bypassed upstream.
function wp_recache_get_cache_path($url) {
$path = wp_parse_url($url, PHP_URL_PATH);
$path = trim($path, '/');
if (empty($path)) {
$path = 'index';
}
$path = sanitize_file_name($path);
return WP_RECACHE_CACHE_PATH . $path . '.html';
}
/**
* Get cache key for URL.
* *
* @param string $url URL to cache. * @param string $url URL to cache.
*/ */
function wp_recache_get_cache_key($url) { function wp_recache_get_cache_path($url) {
$key = wp_parse_url($url, PHP_URL_PATH); $host = (string) wp_parse_url($url, PHP_URL_HOST);
$path = (string) wp_parse_url($url, PHP_URL_PATH);
if (empty($key)) { return WP_RECACHE_CACHE_PATH . md5($host . $path) . '.html';
$key = '/';
}
return md5($key);
} }
/** /**
@@ -214,3 +197,18 @@ function wp_recache_get_cache_path_with_device($url) {
return $path; return $path;
} }
/**
* Enqueue the admin-bar purge script (admin and front-end admin bar).
*/
function wp_recache_enqueue_admin_bar_script() {
if (!is_admin_bar_showing() || !current_user_can('manage_options')) {
return;
}
wp_enqueue_script('wp-recache-admin', WP_RECACHE_URL . 'assets/admin.js', ['jquery'], WP_RECACHE_VERSION, true);
wp_localize_script('wp-recache-admin', 'wpRecache', [
'ajaxUrl' => admin_url('admin-ajax.php'),
'nonce' => wp_create_nonce('wp_recache_nonce'),
]);
}
+20 -2
View File
@@ -14,20 +14,38 @@ class WP_Recache_Deactivator {
*/ */
public static function deactivate() { public static function deactivate() {
self::remove_advanced_cache(); self::remove_advanced_cache();
self::remove_cache_server();
WP_Recache_Activator::set_wp_cache_constant(false);
self::flush_rewrite_rules(); self::flush_rewrite_rules();
} }
/** /**
* Remove advanced-cache.php drop-in. * Remove advanced-cache.php drop-in, but only if it is ours.
*/ */
private static function remove_advanced_cache() { private static function remove_advanced_cache() {
$advanced_cache = WP_CONTENT_DIR . '/advanced-cache.php'; $advanced_cache = WP_CONTENT_DIR . '/advanced-cache.php';
if (file_exists($advanced_cache)) { if (!file_exists($advanced_cache)) {
return;
}
$content = file_get_contents($advanced_cache);
if (strpos($content, 'WP Recache') !== false) {
unlink($advanced_cache); unlink($advanced_cache);
} }
} }
/**
* Remove the standalone cache server.
*/
private static function remove_cache_server() {
$server = WP_CONTENT_DIR . '/wp-recache-cache.php';
if (file_exists($server)) {
unlink($server);
}
}
/** /**
* Flush rewrite rules. * Flush rewrite rules.
*/ */
+10
View File
@@ -10,6 +10,11 @@ class WP_Recache_WPCache_Test extends WP_UnitTestCase {
public function test_cache_creates_file_on_first_request() { public function test_cache_creates_file_on_first_request() {
$cache = new WP_Recache_WPCache(); $cache = new WP_Recache_WPCache();
$_SERVER['HTTP_HOST'] = 'example.com';
$_SERVER['REQUEST_URI'] = '/test-page/';
$_SERVER['HTTPS'] = 'off';
unset($_SERVER['HTTP_USER_AGENT']);
$url = 'https://example.com/test-page/'; $url = 'https://example.com/test-page/';
$path = wp_recache_get_cache_path($url); $path = wp_recache_get_cache_path($url);
@@ -59,6 +64,11 @@ class WP_Recache_WPCache_Test extends WP_UnitTestCase {
public function test_cache_file_is_created_with_correct_permissions() { public function test_cache_file_is_created_with_correct_permissions() {
$cache = new WP_Recache_WPCache(); $cache = new WP_Recache_WPCache();
$_SERVER['HTTP_HOST'] = 'example.com';
$_SERVER['REQUEST_URI'] = '/test-page/';
$_SERVER['HTTPS'] = 'off';
unset($_SERVER['HTTP_USER_AGENT']);
$url = 'https://example.com/test-page/'; $url = 'https://example.com/test-page/';
$path = wp_recache_get_cache_path($url); $path = wp_recache_get_cache_path($url);
+10 -10
View File
@@ -34,26 +34,26 @@ class WP_Recache_Helpers_Test extends WP_UnitTestCase {
public function test_wp_recache_get_cache_path_returns_correct_path() { public function test_wp_recache_get_cache_path_returns_correct_path() {
$url = 'https://example.com/test-page/'; $url = 'https://example.com/test-page/';
$expected = WP_RECACHE_CACHE_PATH . 'test-page.html'; $expected = WP_RECACHE_CACHE_PATH . md5('example.com/test-page/') . '.html';
$this->assertEquals($expected, wp_recache_get_cache_path($url)); $this->assertEquals($expected, wp_recache_get_cache_path($url));
} }
public function test_wp_recache_get_cache_path_handles_root_url() { public function test_wp_recache_get_cache_path_handles_root_url() {
$url = 'https://example.com/'; $url = 'https://example.com/';
$expected = WP_RECACHE_CACHE_PATH . 'index.html'; $expected = WP_RECACHE_CACHE_PATH . md5('example.com/') . '.html';
$this->assertEquals($expected, wp_recache_get_cache_path($url)); $this->assertEquals($expected, wp_recache_get_cache_path($url));
} }
public function test_wp_recache_get_cache_key_returns_md5_hash() { public function test_wp_recache_get_cache_path_no_collision_between_nested_urls() {
$url = 'https://example.com/test-page/'; $a = wp_recache_get_cache_path('https://example.com/a/b/');
$expected = md5('/test-page/'); $b = wp_recache_get_cache_path('https://example.com/ab/');
$this->assertEquals($expected, wp_recache_get_cache_key($url)); $this->assertNotEquals($a, $b);
} }
public function test_wp_recache_get_cache_key_handles_root_url() { public function test_wp_recache_get_cache_path_no_collision_between_hosts() {
$url = 'https://example.com/'; $a = wp_recache_get_cache_path('https://site1.example.com/');
$expected = md5('/'); $b = wp_recache_get_cache_path('https://site2.example.com/');
$this->assertEquals($expected, wp_recache_get_cache_key($url)); $this->assertNotEquals($a, $b);
} }
public function test_wp_recache_is_mobile_returns_false_for_desktop_user_agent() { public function test_wp_recache_is_mobile_returns_false_for_desktop_user_agent() {
+6
View File
@@ -49,3 +49,9 @@ if (file_exists($advanced_cache)) {
unlink($advanced_cache); unlink($advanced_cache);
} }
} }
// Remove the standalone cache server.
$cache_server = WP_CONTENT_DIR . '/wp-recache-cache.php';
if (file_exists($cache_server)) {
unlink($cache_server);
}
+4 -1
View File
@@ -34,11 +34,13 @@ function wp_recache_init() {
$admin->init(); $admin->init();
} }
if (WP_RECACHE_CACHE_ENABLED) { if (wp_recache_is_cache_enabled()) {
require_once WP_RECACHE_INC_PATH . 'Cache/WPCache.php'; require_once WP_RECACHE_INC_PATH . 'Cache/WPCache.php';
$cache = new WP_Recache_WPCache(); $cache = new WP_Recache_WPCache();
$cache->init(); $cache->init();
} }
add_action('wp_enqueue_scripts', 'wp_recache_enqueue_admin_bar_script');
} }
/** /**
@@ -54,6 +56,7 @@ register_activation_hook(__FILE__, 'wp_recache_activate');
* Plugin deactivation. * Plugin deactivation.
*/ */
function wp_recache_deactivate() { function wp_recache_deactivate() {
require_once WP_RECACHE_INC_PATH . 'Activator.php';
require_once WP_RECACHE_INC_PATH . 'Deactivator.php'; require_once WP_RECACHE_INC_PATH . 'Deactivator.php';
WP_Recache_Deactivator::deactivate(); WP_Recache_Deactivator::deactivate();
} }