Многие на нагруженных проектах на WordPress используют плагин WP Super Cache чтобы снизить нагрузку на сервер. Плагин создает статичные html странички и отдает их пользователю без обращения к php. Можно настроить и отдачу этих статичных страничек через nginx.

Как работает WP SuperCache

Статичные страницы имеет задаваемые параметры в виде срока жизни страницы (Cache Timeout ) и времени сбора мусора (Scheduler ). Процедура выглядит таким образом – при первом обращении пользователя к странице она собирается с помощью php, сегенеренная страница отдается пользователю и сохраняется, а следующий пользователь получает её уже из кеша WP Super Cache. Страница в кеше обновляется в зависимости от параметров срока жизни страницы (Cache Timeout ) / времени сбора мусора (Scheduler ). Так же можно настроить, что страница поста будет обновляться при добавлении комментария.

P.S. В версии WP Super Cache 1.0 на WordPress 3.x.x бывает что страница не обновляется при добавлении комментария. Автор баг признал, порекомендовал скачать девелоперскую версию, ну и в следующей версии баг обещал исправить. В девелоперской версии все работает.

И всё бы хорошо. Задавай сроки жизни страниц подольше, обновляй кеш с настройкой «Clear all cache files when a post or page is published or updated». Если стоят какие то виджеты – задавай нужные параметры обновления. Но неожиданная проблема обнаружилась с плагином рейтингов WP Postratings.

Суть проблемы связки WP SuperCache и WP PostRatings

Допустим заходит пользователь на страницу которой ещё нет в кеше, на ней установлен вывод значений WP Postratings. Если это страница поста, то блок WP Postratings 1 штука, если индексная страница архива, категории или тому подобное, то этих блоков может быть несколько ( или не быть вообще, тут уж как кто любит ). Так вот допустим человек зашел, проголосовал, обновил страницу, а его голос не засчитался. Человек жмет проголосовать ещё раз, а postratings ему говорит что вы уже проголосовали. Человек в недоумении. Причем заметьте с случае с комментированием такого не происходит. Если человек оставил коммент и обновил страницу, то он увидит сраницу уже со своим комментом. Что же не так.

Когда человек зашел впервые на страницу, страница была собрана и сохранена в кеше. Тогда он ещё не проголосовал в postratings. Страница сохранена без учета его оценки. Когда он нажал на звездочки postratings – его голос через javascript был учтен. Но страница в кеше обновлена не была. Поэтому обновив страницу он получит её из кеша, когда он её ещё не оценил.


Почем такого не происходит когда человек оставляет коммент?
Потому что WP Super Cache отлавливает событие комментирования и удаляет пост из кеша. Следующий пользователь при обращении генерит новый кеш страницы с новым комментарием.

Так что же нам делать со связкой WP Super Cache и WP Postratings, как заставить их работать вместе.

В сети есть один вариант. В принципе он одобрен автором WP Super Cache. Обсуждали его здесь . Идея этой модификации в том что оценка получается не при генерации странице, а через AJAX. То есть пользователь при обращении к странице с модулем WP Postratings получает кеш страницы из WP SuperCache, а оценку получает через AJAX, который в свою очередь обращается к wp-postraings.php, который в свою очередь обращается к базе за оценкой этого поста. Таким образом, если у человека включен JavaScript то он всегда будет получать актуальную оценку. Всё вроде бы хорошо и работает. Но!
Предположим главную страницу блога, блок со звездочками WP PostRatings выводится под каждым анонсом статьи ( это довольно эффективно, поверьте ), допустим их 10 штук. Каждый такой модуль получает через AJAX свою оценку, таким образом за одно обращение к главной странице ( не зависимо в кеше SuperCache она или нет ), мы получаем 10 обращений к MySQL, PHP. Предположим, что главную посещают 10000 хостов. Итого 10 000 обращений к MySQL, PHP. По статистике CTR WP Postratings порядка 2-5%, то есть 95 000 обращений в холостую. 95% посетителей не нужен AJAX в WP PostRatings, 95% хостов были бы вполне удовлетворены страничкой из кеша WP SuperCache. Так зачем напрягать сервак, зачем заставлять юзеров ждать прогрузки оценок. Давайте будем людям отдавать статичные странички из WP SuperCache. И обновлять их при новой оценке.

Как же это сделать. Если без заморочек – легко.

Отлавливаем событие добавления новой оценки. Обновляем страничку данного поста в кеше, и страничку, откуда была произведена оценка.
При нажатии на звездочку AJAX обращается к файлу плагина wp-postratings.php , к функции
[cc lang=”php”]### Function: Process Ratings
process_ratings();
function process_ratings()[/cc]
, в ней оценивается правомочность оценки пользователем статьи. Давайте после строки
[cc lang=”php”]// Output AJAX Result
echo the_ratings_results($post_id, $post_ratings_users, $post_ratings_score, $post_ratings_average);[/cc]
добавим нашу функцию
[cc lang=”php”]azz_post_rated($post_id, $_SERVER[‘HTTP_REFERER’]);[/cc]
Собственно ID оцениваемого поста и адрес странички с которого была произведена оценка. А в файлики functions.php нашей темы создадим две функции:
[cc lang=”php”]//**************************************************
function azz_post_rated($post_id, $referer){
// С помощью функции WP SuperCache получаем директорию где лежит кеш поста
$dir_post = get_current_url_supercache_dir( $post_id );
// Функция аналогична предыдущей, только директорию мы получаем по реферу
$dir_referer = azz_get_supercache_dir_by_referer($referer).’index.html';
// Удаляем кеш по реферу
if(is_file($dir_referer)){
unlink($dir_referer);
}
// Обновляем кеш поста, куски кода просто выдраны из WP SuperCache
prune_super_cache( $dir_post, true, true );
do_action( ‘gc_cache’, ‘prune’, $dir_post );

}

function azz_get_supercache_dir_by_referer( $referer ) {
// Обновляем кеш поста, куски кода просто выдраны из WP SuperCache
// и доработано напильником
global $cached_direct_pages, $cache_path;
$uri = strtolower( $referer );
// https://azzrael.ru – не забудьте заменить на url вашего сайта
$uri = str_replace(‘https://azzrael.ru, ”, $uri );
$uri = preg_replace(‘/[ <>\’\”\r\n\t\(\)]/’, ”, str_replace( ‘/index.php’, ‘/’, str_replace( ‘..’, ”, preg_replace(“/(\?.*)?$/”, ”, $uri ) ) ) );
$uri = str_replace( ‘\\’, ”, $uri );
$dir = preg_replace( ‘/:.*$/’, ”, $_SERVER[“HTTP_HOST”] ) . $uri; // To avoid XSS attacks
/*
if ( function_exists( “apply_filters” ) ) {
$dir = apply_filters( ‘supercache_dir’, $dir );
} else {
$dir = do_cacheaction( ‘supercache_dir’, $dir );
}
*/
$dir = $cache_path . ‘supercache/’ . $dir . ‘/';
if( is_array( $cached_direct_pages ) && in_array( $_SERVER[ ‘REQUEST_URI’ ], $cached_direct_pages ) ) {
$dir = ABSPATH . $uri . ‘/';
}
$dir = str_replace( ‘//’, ‘/’, $dir );
return $dir;
}

//**************************************************[/cc]
Как то так. Код очень сырой. Но работает. Кому надо сам допилит. У меня в таком виде работает. При обновлении оценки WP PostRatings удаляется кеш страницы оцениваемого поста и кеш странички откуда была произведена оценка.
Вообще автору WP SuperCache не помешало бы прикрутить хук к плагину, который бы работал вместо этого костыля. А через хук можно было бы обновлять кеш полностью или частично в других плагинах.

15 февраля 2012 |

2 Комментариев к “Как заставить работать вместе WP SuperCache и WP PostRatings”

  1. Сергей 16 июня, 2012

    Плагин WP SuperCache хорош, но сколько раз я его уже настраивал по-разному! Приходится делать выбор, либо большое время жизни кэшированных страниц и меньшая нагрузка на сервер, либо частое обновление кэша и большая нагрузка на сервер! Не все так просто…

  2. Azzrael 5 июля, 2012

    Мммм ваш коммент как то совсем не в тему статьи. Но все же отвечу. Поставьте обновлять кеш по выходу новой статьи и при добавлении нового комментария, выставьте время жизни кеша сто тыщ секунд и забудьте о нагрузке. Суперкеш он не хорош, он великолепен. На сателитах у меня кеш живет по полгода, я его в ручную обновляю. А на белых проектах SuperCache с костылями + nginx + vds за тыщу рублей держат до 200К просмотров в день. Отключение суперкеша убивает вдс в момент. Лучше, возможно, только макскеш, но он платен.

Есть что сказать по теме статьи? Пожалуйста - пишите!