From 2deb14c7369dd3024257fc5d503ce8142d595aca Mon Sep 17 00:00:00 2001 From: Dekart Deploy Bot Date: Fri, 17 Jul 2026 16:49:56 +0000 Subject: [PATCH] fix: auto-install memcached drop-in + block plugin activation - dekart_try_install_memcached_dropin(): auto-copy object-cache.php from memcached plugin to wp-content/ on plugins_loaded - Remove 'Activate' link for memcached plugin (prevents fatal error) - Admin notice with instructions when PHP extension is missing - WP-CLI command: wp dekart cache-memcached --- .../mu-plugins/object-cache-bootstrap.php | 152 ++++++++++++------ 1 file changed, 99 insertions(+), 53 deletions(-) diff --git a/wp-content/mu-plugins/object-cache-bootstrap.php b/wp-content/mu-plugins/object-cache-bootstrap.php index a8f4f48..dfd8d07 100644 --- a/wp-content/mu-plugins/object-cache-bootstrap.php +++ b/wp-content/mu-plugins/object-cache-bootstrap.php @@ -3,19 +3,23 @@ * 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). * + * УСТАНОВКА 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.0 + * @version 2.1 */ // ============================================================ -// 1. КОНСТАНТЫ ДЛЯ ПЛАГИНОВ (выполняется до загрузки WP) +// 1. КОНСТАНТЫ ДЛЯ ПЛАГИНОВ // ============================================================ -// Redis: константы для redis-cache plugin if ( ! defined( 'WP_REDIS_HOST' ) ) { define( 'WP_REDIS_HOST', '127.0.0.1' ); } @@ -30,31 +34,23 @@ if ( ! defined( 'WP_REDIS_DATABASE' ) ) { // 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 ); + $sock = @fsockopen( '127.0.0.1', 11211, $errno, $errstr, 0.5 ); + if ( $sock ) { + fclose( $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 ); + $sock = @fsockopen( '127.0.0.1', 6379, $errno, $errstr, 0.5 ); + if ( $sock ) { + fclose( $sock ); return 'redis'; } } - // 3. Есть object-cache.php, но сервис не отвечает if ( file_exists( WP_CONTENT_DIR . '/object-cache.php' ) ) { return 'dropin-no-connection'; } @@ -66,32 +62,18 @@ function dekart_detect_cache_backend(): string { // 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) +// 4. ИНВАЛИДАЦИЯ КЕША // ============================================================ -/** - * Сбросить object cache + увеличить версию. - * Безопасно от рекурсии — static guard. - */ function my_cache_bump_version(): void { static $running = false; if ( $running ) { @@ -106,37 +88,97 @@ function my_cache_bump_version(): void { $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: установка/сброс кеша +// 5. АВТОУСТАНОВКА DROP-IN MEMCACHED (для прода) +// ============================================================ + +/** + * Попробовать установить drop-in Memcached, если: + * - плагин memcached установлен, + * - object-cache.php ещё нет, + * - PHP-расширение Memcache доступно. + */ +function dekart_try_install_memcached_dropin(): void { + $target = WP_CONTENT_DIR . '/object-cache.php'; + if ( file_exists( $target ) ) { + return; // drop-in уже есть + } + + $source = WP_CONTENT_DIR . '/plugins/memcached/object-cache.php'; + if ( ! file_exists( $source ) ) { + return; // плагин не установлен + } + + if ( ! class_exists( 'Memcache' ) && ! class_exists( 'Memcached' ) ) { + return; // нет PHP-расширения + } + + copy( $source, $target ); +} + +add_action( 'plugins_loaded', 'dekart_try_install_memcached_dropin', 0 ); + +// ============================================================ +// 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'] = 'drop-in (копируется автоматически)'; + 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; + } + if ( class_exists( 'Memcache' ) || class_exists( 'Memcached' ) ) { + return; + } + + printf( + '

%s

', + 'Настройка кеширования: Плагин Memcached Object Cache установлен, но PHP-расширение memcache не найдено. + Установите его на сервере (sudo apt install php-memcache), после чего drop-in скопируется автоматически. + Не активируйте плагин — это вызовет фатальную ошибку. Он работает как 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.' ); } ); - /** - * Установить 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'; @@ -146,25 +188,29 @@ if ( defined( 'WP_CLI' ) && WP_CLI ) { 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/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}" ); + 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 file permissions.' ); + WP_CLI::error( 'Failed to copy drop-in. Check permissions.' ); } } ); } // ============================================================ -// 6. ЛОГИРОВАНИЕ (dev only) +// 8. ЛОГИРОВАНИЕ // ============================================================ if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {