- Auto-detect: Memcached (class Memcache/Memcached + port 11211), Redis (Predis + port 6379), or none - WP-CLI commands: wp dekart cache-flush, wp dekart cache-memcached - cache-memcached checks PHP extension before copying drop-in - Removed Redis-specific constants (handled by redis-cache plugin) - Handle activation conflict: Memcached drop-in copied manually, not via plugin activation (prevents wp_cache_add fatal error)
178 lines
5.4 KiB
PHP
178 lines
5.4 KiB
PHP
<?php
|
||
/**
|
||
* MU-Plugin: Object Cache Bootstrap
|
||
*
|
||
* Автоопределение backend кеширования + versioned cache + автоинвалидация.
|
||
* Dev → Redis (через redis-cache plugin).
|
||
* Prod → Memcached (через Memcached Object Cache plugin).
|
||
* Работает с любым active drop-in (object-cache.php).
|
||
*
|
||
* @package Dekart
|
||
* @version 2.0
|
||
*/
|
||
|
||
// ============================================================
|
||
// 1. КОНСТАНТЫ ДЛЯ ПЛАГИНОВ (выполняется до загрузки WP)
|
||
// ============================================================
|
||
|
||
// Redis: константы для redis-cache plugin
|
||
if ( ! defined( 'WP_REDIS_HOST' ) ) {
|
||
define( 'WP_REDIS_HOST', '127.0.0.1' );
|
||
}
|
||
if ( ! defined( 'WP_REDIS_PORT' ) ) {
|
||
define( 'WP_REDIS_PORT', 6379 );
|
||
}
|
||
if ( ! defined( 'WP_REDIS_DATABASE' ) ) {
|
||
define( 'WP_REDIS_DATABASE', 0 );
|
||
}
|
||
|
||
// ============================================================
|
||
// 2. АВТООПРЕДЕЛЕНИЕ BACKEND
|
||
// ============================================================
|
||
|
||
/**
|
||
* Определить активный backend object cache.
|
||
*
|
||
* @return string 'memcached' | 'redis' | 'none'
|
||
*/
|
||
function dekart_detect_cache_backend(): string {
|
||
// 1. По active drop-in: Memcached Object Cache
|
||
if ( class_exists( 'Memcache' ) || class_exists( 'Memcached' ) ) {
|
||
$mc_sock = @fsockopen( '127.0.0.1', 11211, $errno, $errstr, 0.5 );
|
||
if ( $mc_sock ) {
|
||
fclose( $mc_sock );
|
||
return 'memcached';
|
||
}
|
||
}
|
||
|
||
// 2. По active drop-in: Redis (через Predis от redis-cache)
|
||
if ( class_exists( 'Predis\Client' ) ) {
|
||
$r_sock = @fsockopen( '127.0.0.1', 6379, $errno, $errstr, 0.5 );
|
||
if ( $r_sock ) {
|
||
fclose( $r_sock );
|
||
return 'redis';
|
||
}
|
||
}
|
||
|
||
// 3. Есть object-cache.php, но сервис не отвечает
|
||
if ( file_exists( WP_CONTENT_DIR . '/object-cache.php' ) ) {
|
||
return 'dropin-no-connection';
|
||
}
|
||
|
||
return 'none';
|
||
}
|
||
|
||
// ============================================================
|
||
// 3. VERSIONED CACHE KEY
|
||
// ============================================================
|
||
|
||
/**
|
||
* Текущая версия кеша.
|
||
*/
|
||
function my_cache_version(): int {
|
||
return (int) get_option( 'my_cache_version', 1 );
|
||
}
|
||
|
||
/**
|
||
* Обернуть ключ с префиксом версии.
|
||
* Инвалидация: достаточно изменить версию.
|
||
*
|
||
* @param string $key Исходный ключ.
|
||
* @return string
|
||
*/
|
||
function my_cache_key( string $key ): string {
|
||
return 'v:' . my_cache_version() . ':' . $key;
|
||
}
|
||
|
||
// ============================================================
|
||
// 4. ИНВАЛИДАЦИЯ КЕША (version bump + flush)
|
||
// ============================================================
|
||
|
||
/**
|
||
* Сбросить object cache + увеличить версию.
|
||
* Безопасно от рекурсии — static guard.
|
||
*/
|
||
function my_cache_bump_version(): void {
|
||
static $running = false;
|
||
if ( $running ) {
|
||
return;
|
||
}
|
||
$running = true;
|
||
|
||
wp_cache_flush();
|
||
$v = my_cache_version();
|
||
update_option( 'my_cache_version', $v + 1, false );
|
||
|
||
$running = false;
|
||
}
|
||
|
||
// branch_* опции → сброс кеша (настройки филиала)
|
||
add_action( 'update_option', function ( $option ) {
|
||
if ( str_starts_with( $option, 'branch_' ) ) {
|
||
my_cache_bump_version();
|
||
}
|
||
}, 10, 1 );
|
||
|
||
// Посты (включая Carbon Fields)
|
||
add_action( 'save_post', 'my_cache_bump_version' );
|
||
add_action( 'carbon_fields_post_meta_container_saved', 'my_cache_bump_version' );
|
||
|
||
// ============================================================
|
||
// 5. WP-CLI: установка/сброс кеша
|
||
// ============================================================
|
||
|
||
if ( defined( 'WP_CLI' ) && WP_CLI ) {
|
||
|
||
/**
|
||
* Сброс версии кеша.
|
||
*/
|
||
WP_CLI::add_command( 'dekart cache-flush', function () {
|
||
my_cache_bump_version();
|
||
WP_CLI::success( 'Cache flushed + version bumped.' );
|
||
} );
|
||
|
||
/**
|
||
* Установить drop-in Memcached Object Cache.
|
||
*
|
||
* Копирует object-cache.php из плагина memcached в wp-content/.
|
||
* Использовать ПОСЛЕ удаления Redis-плагина.
|
||
*/
|
||
WP_CLI::add_command( 'dekart cache-memcached', function () {
|
||
$source = WP_CONTENT_DIR . '/plugins/memcached/object-cache.php';
|
||
$target = WP_CONTENT_DIR . '/object-cache.php';
|
||
|
||
if ( ! file_exists( $source ) ) {
|
||
WP_CLI::error( 'Memcached Object Cache plugin not installed. Run: wp plugin install memcached' );
|
||
return;
|
||
}
|
||
|
||
if ( ! class_exists( 'Memcache' ) && ! class_exists( 'Memcached' ) ) {
|
||
WP_CLI::warning( 'PHP memcache/memcached extension not found.' );
|
||
WP_CLI::line( 'Install it on your server first, then run this command again.' );
|
||
WP_CLI::line( 'Debian/Ubuntu: sudo apt install php-memcache' );
|
||
WP_CLI::line( 'After install, copy the drop-in manually:' );
|
||
WP_CLI::line( " cp {$source} {$target}" );
|
||
return;
|
||
}
|
||
|
||
if ( copy( $source, $target ) ) {
|
||
WP_CLI::success( 'Memcached drop-in installed to wp-content/object-cache.php' );
|
||
} else {
|
||
WP_CLI::error( 'Failed to copy drop-in. Check file permissions.' );
|
||
}
|
||
} );
|
||
}
|
||
|
||
// ============================================================
|
||
// 6. ЛОГИРОВАНИЕ (dev only)
|
||
// ============================================================
|
||
|
||
if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
|
||
add_action( 'init', function () {
|
||
$b = dekart_detect_cache_backend();
|
||
if ( 'none' === $b ) {
|
||
error_log( '[Object Cache] WARNING: No cache backend available.' );
|
||
}
|
||
}, 0 );
|
||
}
|