Кэш объектов в WordPress: способы реализации на PHP
Объектное кэширование в WordPress: настройка и варианты
Объектный кэш (object cache) в WordPress хранит результаты часто выполняемых запросов к базе данных, чтобы снизить нагрузку на сервер и ускорить загрузку страниц. По умолчанию WordPress использует встроенный кэш в оперативной памяти PHP, который теряется после каждого запроса. Для постоянного кэширования требуется внешнее хранилище, такое как Redis, Memcached или APCu. В этой статье рассмотрено несколько подходов с подробными примерами кода.
Как организовать постоянный объектный кэш с помощью Redis?
Основное и наиболее производительное решение для большинства проектов – использование Redis через drop-in файл object-cache.php. Для этого потребуется сервер с установленным Redis и PHP-расширение PhpRedis (или Predis).
- Установка Redis на сервер (например, Ubuntu):
sudo apt update && sudo apt install redis-serverCache php id (кэширование по id в php)
- Установка расширения PhpRedis:
sudo apt install php-redisPhp http cache (http-кэширование в php)
После установки перезапустите веб-сервер. - Скачайте файл object-cache.php из репозитория WP Redis (https://github.com/WordPress/wp-redis) или используйте плагин WP Redis. Поместите файл в wp-content/object-cache.php.
- Настройте подключение, добавив в wp-config.php:
define('WP_REDIS_HOST', '127.0.0.1');
define('WP_REDIS_PORT', 6379);
define('WP_REDIS_DATABASE', 0);Cache index php (кэширование индекса в php)
- Проверьте работу:
$value = wp_cache_get('key', 'group');
if (false === $value) {
$value = 'cached data';
wp_cache_set('key', $value, 'group');
}
echo $value;Wp content object cache php (кэш объектов в wp-content (wordpress))
Типичные ошибки:
- Файл object-cache.php не распознаётся из-за неправильных прав доступа (должен быть 644).
- Redis не запущен – проверьте командой
redis-cli pingCache html php (кэширование html в php)
. - Ошибка подключения из-за неверных параметров WP_REDIS_HOST или порта.
- Конфликт с другими плагинами кэширования – отключайте их при использовании объектного кэша.
Как использовать Memcached для объектного кэша?
Memcached – альтернатива Redis. Требует установки расширения memcached в PHP и демона memcached. Drop-in файл object-cache.php для Memcached доступен в плагине Memcached Object Cache. Настройка похожа на Redis:
define('WP_CACHE_KEY_SALT', 'mysite_');
define('WP_MEMCACHED_SERVERS', array(
array('127.0.0.1', 11211)
));Bitrix php cache (кэширование в bitrix (php))
Важно: Memcached не поддерживает персистентность данных (данные теряются при перезапуске), поэтому не подходит для длительного хранения. Частая проблема – неверное указание серверов в многосерверной конфигурации.
Когда достаточно APCu (оперативного кэша в памяти PHP)?
APCu подходит для односерверных сайтов с низкой нагрузкой. Кэш хранится в общей памяти PHP, но не распространяется между разными серверами. Для включения достаточно установить расширение APCu и активировать плагин APCu Object Cache или написать свой object-cache.php на основе apcu_store() и apcu_fetch().
function apcu_cache_store($key, $data, $group, $expire) {
return apcu_store($group . ':' . $key, $data, $expire);
}APCu не синхронизируется между серверами, поэтому на балансировщиках нагрузки возникнет различие в данных. Также APCu имеет ограничение по размеру памяти (обычно 32–128 МБ).
Как организовать файловый кэш без внешних сервисов?
Файловый кэш сохраняет данные в файлы внутри wp-content/cache/. Он медленнее Redis, но не требует дополнительных служб. Можно использовать плагин File-Based Object Cache или написать собственный:
$file = WP_CONTENT_DIR . '/cache/obj_cache_' . md5($key . $group) . '.txt';
if (file_exists($file) && (time() - filemtime($file) < 3600)) {
return unserialize(file_get_contents($file));
} else {
$value = compute_data();
file_put_contents($file, serialize($value));
return $value;
}Проблемы: рост числа файлов, медленная работа на больших объёмах, конфликты блокировок при одновременной записи. Не подходит для высоконагруженных проектов.
Зачем использовать транзиенты (transients) для временного кэширования?
Транзиенты – встроенный механизм WordPress для хранения данных с TTL. Они реализованы через опции, но объектный кэш может ускорить их получение. Пример:
$data = get_transient('my_featured_posts');
if (false === $data) {
$data = new WP_Query(array('posts_per_page' => 5));
set_transient('my_featured_posts', $data, 12 * HOUR_IN_SECONDS);
}
// $data содержит объект WP_QueryТранзиенты не используют собственный TTL при использовании внешнего объектного кэша – срок действия управляется через ключ. Ошибка: путаница между set_transient и set_site_transient для мультисайтов.
Как создать собственный object-cache.php с гибкой инвалидацией?
Можно написать свой drop-in файл, который, например, группирует данные и сбрасывает всю группу по команде. Пример использования wp_cache_* функций с групповой поддержкой:
// object-cache.php (фрагмент)
function wp_cache_add($key, $data, $group = '', $expire = 0) {
global $custom_cache;
if (isset($custom_cache[$group][$key])) return false;
$custom_cache[$group][$key] = $data;
// дополнительно сохраняем в Redis
return true;
}Главная сложность – синхронизация групповых инвалидаций между серверами при использовании распределённого кэша. Требуется продуманная логика ключей.
Расширенные примеры кода для объектного кэша WordPress
Пример 1: Пакетное чтение и запись с wp_cache_get_multiple и wp_cache_set_multiple
Начиная с WordPress 6.0 доступны функции для работы с несколькими ключами. Пример:
$keys = array('post_1', 'post_2', 'post_3');
$group = 'posts';
$cached = wp_cache_get_multiple($keys, $group);
// $cached = array('post_1' => false, 'post_2' => 'data2', 'post_3' => false);
foreach ($cached as $key => $value) {
if ($value === false) {
$value = get_post($key);
wp_cache_set($key, $value, $group);
}
}Если Redis не поддерживает пакетные операции, функция decomposes в цикл – это медленнее.
Пример 2: Использование wp_cache_flush_group для сброса одной группы (только Redis)
Redis позволяет сбрасывать ключи по шаблону. Пример с group flushing:
// При сохранении поста сбрасываем кэш группы 'post_meta' для этого поста
add_action('updated_post_meta', function($meta_id, $post_id) {
wp_cache_delete($post_id, 'post_meta');
// или если нужен сброс всей группы
wp_cache_flush_group('post_meta'); // только если объектный кэш поддерживает
}, 10, 2);Не все реализации поддерживают wp_cache_flush_group – проверяйте документацию вашего object-cache.php.
Пример 3: Мониторинг кэша через Redis CLI
Подключитесь к Redis и выполните:
redis-cli
KEYS *wordpress* # список всех ключей, содержащих 'wordpress'
MEMORY USAGE wp:options:alloptions # размер конкретного ключа
INFO keyspace # статистика по базамВывод: множество ключей, например: "wp:posts:1", "wp:options:alloptions", размер в байтах.
Пример 4: Настройка кластера Redis для WordPress Multisite
Для мультисайтовой сети нужно указывать префикс для каждого сайта. В wp-config.php:
define('WP_REDIS_CLIENT', 'phpredis');
define('WP_REDIS_SERVERS', serialize(array('
'tcp://192.168.1.1:6379',
'tcp://192.168.1.2:6379'
)));
define('WP_CACHE_KEY_SALT', 'network_'); // префикс для всей сети
// Для индивидуальных префиксов используйте фильтр 'wp_cache_key_prefix'Важно: кластер Redis не поддерживает транзакции и сброс всех ключей через FLUSHDB – используйте ключи с шаблонами.
Пример 5: Собственный object-cache.php с поддержкой истечения по группам
Код:
function wp_cache_set($key, $data, $group = '', $expire = 0) {
$redis = get_redis_connection();
$redis_key = $group . ':' . $key;
$result = $redis->set($redis_key, serialize($data));
if ($expire > 0) {
$redis->expire($redis_key, $expire);
}
// храним список ключей группы для быстрой очистки
$redis->sAdd('group:' . $group, $redis_key);
return $result;
}
function wp_cache_flush_group($group) {
$redis = get_redis_connection();
$keys = $redis->sMembers('group:' . $group);
foreach ($keys as $key) {
$redis->del($key);
}
$redis->del('group:' . $group);
}При сбросе группы все ключи этой группы будут удалены, но если в процессе создаются новые – может потребоваться блокировка.
Пример 6: Использование транзиентов с объектным кэшем для сложных запросов
$transient_key = 'category_posts_' . $cat_id;
$cached = get_transient($transient_key);
if (false === $cached) {
$query = new WP_Query(array('cat' => $cat_id, 'posts_per_page' => 10));
$cached = array('posts' => $query->posts, 'total' => $query->found_posts);
set_transient($transient_key, $cached, HOUR_IN_SECONDS);
}
foreach ($cached['posts'] as $post) {
setup_postdata($post);
// вывод поста
}
wp_reset_postdata();Транзиенты автоматически синхронизируются с объектным кэшем, если включён drop-in, иначе сохраняются в таблице wp_options.
Пример 7: Настройка времени жизни разных групп кэша
В object-cache.php можно задавать разное TTL для разных групп:
$ttl_config = array(
'posts' => 3600, // 1 час
'comments' => 600, // 10 минут
'options' => 86400, // сутки
);
function get_group_ttl($group) {
global $ttl_config;
return isset($ttl_config[$group]) ? $ttl_config[$group] : 0;
}После добавления проверьте, что значения TTL корректно передаются в Redis (через EXPIRE).