- Использует DB_NAME как соль для ключей кеша - Предотвращает коллизию когда schelkovo и pushkino используют один Memcached/Redis на сервере - Без соли siteurl/home из кеша одного сайта читаются другим
233 lines
8.3 KiB
PHP
233 lines
8.3 KiB
PHP
<?php
|
||
/**
|
||
* MU-Plugin: Object Cache Bootstrap
|
||
*
|
||
* Автоопределение backend кеширования + versioned cache + автоинвалидация.
|
||
* Работает с любым active drop-in (object-cache.php).
|
||
*
|
||
* УСТАНОВКА MEMCACHED НА ПРОДЕ:
|
||
* 1. Установить PHP-расширение: sudo apt install php-memcache
|
||
* 2. wp plugin install memcached
|
||
* 3. Скопировать drop-in:
|
||
* cp wp-content/plugins/memcached/object-cache.php wp-content/object-cache.php
|
||
* 4. Плагин НЕ активировать.
|
||
*
|
||
* @package Dekart
|
||
* @version 2.2
|
||
*/
|
||
|
||
// ============================================================
|
||
// 1. КОНСТАНТЫ ДЛЯ ПЛАГИНОВ
|
||
// ============================================================
|
||
|
||
// Уникальная соль для ключей кеша — на основе DB_NAME (разная для каждого сайта).
|
||
// Предотвращает коллизию когда несколько WP-сайтов используют один Memcached/Redis.
|
||
if ( ! defined( 'WP_CACHE_KEY_SALT' ) && defined( 'DB_NAME' ) ) {
|
||
define( 'WP_CACHE_KEY_SALT', DB_NAME );
|
||
}
|
||
|
||
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
|
||
// ============================================================
|
||
|
||
function dekart_detect_cache_backend(): string {
|
||
if ( class_exists( 'Memcache' ) || class_exists( 'Memcached' ) ) {
|
||
$sock = @fsockopen( '127.0.0.1', 11211, $errno, $errstr, 0.5 );
|
||
if ( $sock ) {
|
||
fclose( $sock );
|
||
return 'memcached';
|
||
}
|
||
}
|
||
|
||
if ( class_exists( 'Predis\Client' ) ) {
|
||
$sock = @fsockopen( '127.0.0.1', 6379, $errno, $errstr, 0.5 );
|
||
if ( $sock ) {
|
||
fclose( $sock );
|
||
return 'redis';
|
||
}
|
||
}
|
||
|
||
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 );
|
||
}
|
||
|
||
function my_cache_key( string $key ): string {
|
||
return 'v:' . my_cache_version() . ':' . $key;
|
||
}
|
||
|
||
// ============================================================
|
||
// 4. ИНВАЛИДАЦИЯ КЕША
|
||
// ============================================================
|
||
|
||
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;
|
||
}
|
||
|
||
add_action( 'update_option', function ( $option ) {
|
||
if ( str_starts_with( $option, 'branch_' ) ) {
|
||
my_cache_bump_version();
|
||
}
|
||
}, 10, 1 );
|
||
|
||
add_action( 'save_post', 'my_cache_bump_version' );
|
||
add_action( 'carbon_fields_post_meta_container_saved', 'my_cache_bump_version' );
|
||
|
||
// ============================================================
|
||
// 5. АДМИН-НОТИС + БЛОКИРОВКА АКТИВАЦИИ MEMCACHED
|
||
// ============================================================
|
||
|
||
/**
|
||
* Убрать ссылку "Активировать" у плагина Memcached Object Cache.
|
||
* Плагин — только источник object-cache.php, активация вызывает фатальную ошибку.
|
||
*/
|
||
add_filter( 'plugin_action_links_memcached/object-cache.php', function ( $actions ) {
|
||
unset( $actions['activate'] );
|
||
$actions['info'] = '<span style="color:#999">⚠ установите вручную</span>';
|
||
return $actions;
|
||
} );
|
||
|
||
// ============================================================
|
||
// 6. АДМИН-НОТИС + БЛОКИРОВКА АКТИВАЦИИ MEMCACHED PLUGIN
|
||
// ============================================================
|
||
|
||
/**
|
||
* Убрать ссылку "Активировать" у плагина Memcached Object Cache —
|
||
* он содержит только object-cache.php, активация вызывает фатальную ошибку.
|
||
* Файл копируется автоматически через dekart_try_install_memcached_dropin().
|
||
*/
|
||
add_filter( 'plugin_action_links_memcached/object-cache.php', function ( $actions ) {
|
||
unset( $actions['activate'] );
|
||
$actions['info'] = '<span style="color:#999">drop-in (копируется автоматически)</span>';
|
||
return $actions;
|
||
} );
|
||
|
||
add_action( 'admin_notices', function () {
|
||
if ( ! current_user_can( 'manage_options' ) ) {
|
||
return;
|
||
}
|
||
|
||
$source = WP_CONTENT_DIR . '/plugins/memcached/object-cache.php';
|
||
$target = WP_CONTENT_DIR . '/object-cache.php';
|
||
|
||
if ( ! file_exists( $source ) ) {
|
||
return; // плагин не установлен
|
||
}
|
||
if ( file_exists( $target ) ) {
|
||
return; // drop-in уже стоит
|
||
}
|
||
|
||
if ( class_exists( 'Memcache' ) || class_exists( 'Memcached' ) ) {
|
||
$conn = @fsockopen( '127.0.0.1', 11211, $errno, $errstr, 0.5 );
|
||
if ( $conn ) {
|
||
fclose( $conn );
|
||
// Всё готово — можно установить вручную
|
||
printf(
|
||
'<div class="notice notice-info is-dismissible"><p>%s</p></div>',
|
||
'<strong>Кеширование:</strong> Memcached доступен. Установите drop-in командой:
|
||
<code>cp ' . esc_html( str_replace( ABSPATH, '', $source ) ) . ' ' . esc_html( str_replace( ABSPATH, '', $target ) ) . '</code>
|
||
или через WP-CLI: <code>wp dekart cache-memcached</code>'
|
||
);
|
||
return;
|
||
}
|
||
// Есть расширение, но сервер не отвечает
|
||
printf(
|
||
'<div class="notice notice-warning is-dismissible"><p>%s</p></div>',
|
||
'<strong>Кеширование:</strong> PHP-расширение Memcache установлено, но сервер Memcached (127.0.0.1:11211) не отвечает.
|
||
Запустите Memcached на сервере или обратитесь в хостинг.'
|
||
);
|
||
return;
|
||
}
|
||
|
||
printf(
|
||
'<div class="notice notice-warning is-dismissible"><p>%s</p></div>',
|
||
'<strong>Кеширование:</strong> Плагин Memcached Object Cache установлен, но PHP-расширение <code>memcache</code> не найдено.
|
||
Установите его на сервере (через панель хостинга: PHP → Расширения → memcache).
|
||
<strong>Не активируйте плагин</strong> — это вызовет фатальную ошибку. Он работает как drop-in.'
|
||
);
|
||
} );
|
||
|
||
// ============================================================
|
||
// 7. 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.' );
|
||
} );
|
||
|
||
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 ( file_exists( $target ) ) {
|
||
WP_CLI::success( 'Drop-in already exists at wp-content/object-cache.php' );
|
||
return;
|
||
}
|
||
|
||
if ( ! class_exists( 'Memcache' ) && ! class_exists( 'Memcached' ) ) {
|
||
WP_CLI::warning( 'PHP memcache extension not found. Install it:' );
|
||
WP_CLI::line( ' sudo apt install php-memcache' );
|
||
WP_CLI::line( ' sudo systemctl restart php8.3-fpm' );
|
||
WP_CLI::line( 'Then run this command again.' );
|
||
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 permissions.' );
|
||
}
|
||
} );
|
||
}
|
||
|
||
// ============================================================
|
||
// 8. ЛОГИРОВАНИЕ
|
||
// ============================================================
|
||
|
||
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 );
|
||
}
|