В продолжение предыдущей статьи цикла о продвинутой оптимизации WordPress я расскажу о реализации динамических блоков для не авторизованных пользователей в кэширующем плагине WP Supercache.

Иногда отдельные блоки просто невозможно отдавать в закэшированном виде. Я столкнулся с подобной проблемой в интернет-магазине при реализации выбора города и отображении пунктов выдачи на карте. Дело в том, что выбор и определение города происходили на бэкенде по IP-адресу, а при изменении локации необходимо было менять еще и координаты карты, которая располагается на очень большом количестве страниц. При этом я применил для решения этой задачи оба доступных в плагине метода. Об этом и расскажу.
Артём Зайцев
Evilmarketer
Что имеем
— Плагин определения и выбора города “WT geotargeting pro” с шорткодом вывода локации.
[wt_contacts get="region"][/wt_contacts]
— Карты Yandex maps. В принципе, метод подойдет и для Google maps, с той лишь оговоркой, что различаться будет JS код для центрирования карты. Поэтому читайте их документацию.
<script src="https://api-maps.yandex.ru/2.1/?lang=ru_RU&coordorder=longlat" type="text/javascript"></script>
— Для разметки пунктов выдачи используется JSON-файл.
Пример JSON файла в официальной документации
— Для центрирования карты я добавил небольшой JS код и поставил его в Footer.php шаблона:
ymaps.ready() .done(function (ym) { var myMap = new ym.Map('YMapsID', { center: [coordinatesArrayLng, coordinatesArrayLat], zoom: zoomSelectForPickupLocations }, { searchControlProvider: 'yandex#search' }); jQuery.getJSON('/yamaps.json', function (json) { var geoObjects = ym.geoQuery(json) .addToMap(myMap); }); });
— Переменные coordinatesArrayLng и coordinatesArrayLat у нас будут динамические, поэтому я их задал в шаблоне чуть повыше, но в том же footer.php. Для удобства пока что задам им нулевые значения:
var coordinatesArrayLat = 0; var coordinatesArrayLng = 0;
Картина на данном этапе должна выглядеть примерно так:

— Для вывода текущего города посетителя и вызова попапа с выбором локации я использую такой код:
<div class="header-location pull-left"> <i class="gmw-location-icon fa fa-map-marker"></i> <a class="navbar-link primer-header-region" data-toggle="popover" data-placement="bottom" data-title="Ваш регион <?php echo do_shortcode('[wt_contacts get="region"][/wt_contacts]'); ?>?" onclick="modalRegionSelectionShow()"> <?php echo do_shortcode('[wt_contacts get="region"][/wt_contacts]'); ?> </a> </div>
Шорткоды идут стандартные из плагина определения города.
Реализуем динамически блоки вывода города посетителя и координат для карты
Итак, прежде чем приступить к реализации, понадобится включить динамический кэш в настройках плагина.

И активировать позднюю инициализацию. Если её не включить, увидите либо белый экран, либо 500 ошибку.

Все эти опции находятся в секции расширенных настроек WP Supercache.
Далее нужно найти файл /wp-content/plugins/wp-super-cache/plugins/dynamic-cache-test.php
У плагина есть 2 варианта реализации динамических блоков:
- Через функцию
dynamic_cache_test_init()
, которая добавит нужный код, используя стандартный хук Вордпрессаwp_footer
. То есть выведет в подвале сайта. - Через
OUTPUT_BUFFER_TAG
. Этот метод позволит создать специальный тэг. Увидев его в шаблоне, плагин будет исполнять нужный нам код и не кэшировать.
Первый вариант я буду использовать как раз для генерации JS кода с координатами (помните переменные coordinatesArrayLat и coordinatesArrayLng выше?). Второй вариант я применю для вывода города посетителя.
Генерируем JS с координатами
Для начала придумаем наш secret placeholder tag:
define( 'DYNAMIC_CACHE_TEST_TAG', 'YOURSECRETTAG' );
Затем напишем функцию, которая будет возвращать координаты пункта выдачи. Их мы возьмем из текущего города пользователя через стандартный объект плагина WT Geotargeting.
Чтобы брать не координаты города, а позиционировать карту по пункту выдачи, я добавил плагин Marty Geocoder. А дальше я уже из объекта нахожу значения нужных мне метаполей и использую. В моем случае этоWT::$obj->contacts->items["martygeocoderlatlng"].
function user_js_geodata_func2(){ //Get current user's geodata for yandex maps and transform it to array $get_coordinates = WT::$obj->contacts->items["martygeocoderlatlng"]??null; $clean_coordinates = str_replace(array(')','('),array('',''),$get_coordinates); $coordinates_array = explode(",", $clean_coordinates); //Sometimes somebody could forget to set the pickup locations coordinates, so in this case I use the default city’s coordinates. And even if there’s no city coordinates I set coordinates strictly. if (isset($get_coordinates)) { $coordinates_array_lat = floatval($coordinates_array[0]); $coordinates_array_lng = floatval($coordinates_array[1]); $zoom_select_for_pickup_locations = 16; } elseif(!isset($get_coordinates) && do_shortcode('[wt_geotargeting get="lng"]') && do_shortcode('[wt_geotargeting get="lat"]')){ $coordinates_array_lat = do_shortcode('[wt_geotargeting get="lat"]'); $coordinates_array_lng = do_shortcode('[wt_geotargeting get="lng"]'); $zoom_select_for_pickup_locations = 12; } else{ $coordinates_array_lat = 56.8575; $coordinates_array_lng = 60.6125; $zoom_select_for_pickup_locations = 10; } return "\n<script type='text/javascript'>\n". "var zoomSelectForPickupLocations = ".$zoom_select_for_pickup_locations.";\n". "var coordinatesArrayLat = ".$coordinates_array_lat.";\n". "var coordinatesArrayLng = ".$coordinates_array_lng.";\n". "</script>\n"; }
Наша функция готова, осталось её правильно инициализировать.
if ( '' !== DYNAMIC_CACHE_TEST_TAG ) { function dynamic_cache_test_safety( $safety ) { return 1; } add_cacheaction( 'wpsc_cachedata_safety', 'dynamic_cache_test_safety' ); //adding our function “user_js_geodata_func2” to DYNAMIC_CACHE_TEST_TAG function dynamic_cache_test_filter( $cachedata ) { return str_replace( DYNAMIC_CACHE_TEST_TAG, user_js_geodata_func2(), $cachedata ); } add_cacheaction( 'wpsc_cachedata', 'dynamic_cache_test_filter' ); function dynamic_cache_test_template_tag() { echo DYNAMIC_CACHE_TEST_TAG; // This is the template tag. } //adding action for outputting our coordinates function dynamic_cache_test_init() { add_action( 'wp_footer', 'dynamic_cache_test_template_tag' ); } add_cacheaction( 'add_cacheaction', 'dynamic_cache_test_init' ); }
Все готово, можно включить кэширование и проверить, что в футере отображается нужный JS код.

Отобразились верные координаты.
Выводим город посетителя
Чтобы вывести город, обратимся его коду в шаблоне. Я его размещал выше, для наглядности еще раз продублирую
<div class="header-location pull-left"> <i class="gmw-location-icon fa fa-map-marker"></i> <a class="navbar-link primer-header-region" data-toggle="popover" data-placement="bottom" data-title="Ваш регион <?php echo do_shortcode('[wt_contacts get="region"][/wt_contacts]'); ?>?" onclick="modalRegionSelectionShow()"> <?php echo do_shortcode('[wt_contacts get="region"][/wt_contacts]'); ?> </a> </div>
[wt_contacts get="region"][/wt_contacts]
? Здесь мы и выведем результат его выполнения через созданный специальный тэг.DYNAMIC_OUTPUT_BUFFER_TAG
. Здесь нужно придумать название тэга. Очень рекомендую в целях безопасности его нигде не светить 🙂define( 'DYNAMIC_OUTPUT_BUFFER_TAG', 'YOUROUTPUTBUFFERTAG' );
dynamic_output_buffer_test()
между ob_start();
и ob_end_clean();
вместо строки с echo
.До

После

Дальше воспользуемся нашим тэгом, для этого заменим в шаблоне шорткод на него.
<div class="header-location pull-left"> <i class="gmw-location-icon fa fa-map-marker"></i> <a class="navbar-link primer-header-region" data-toggle="popover" data-placement="bottom" data-title="Ваш регион <?php if ( function_exists( 'dynamic_output_buffer_test' ) ) dynamic_output_buffer_test(); ?>YOUROUTPUTBUFFERTAG?" onclick="modalRegionSelectionShow()"> YOUROUTPUTBUFFERTAG </a> </div>
dynamic_output_buffer_test()
, иначе работать не будет.Почти готово. Но есть нюанс. Если по какой-то причине вы выключите кэширование, то вместо города показываться будет тэг, а этого нам не надо. Поэтому финальным штрихом добавим проверку на работу кэша в нашем коде.
<div class="header-location pull-left"> <i class="gmw-location-icon fa fa-map-marker"></i> <a class="navbar-link primer-header-region" data-toggle="popover" data-placement="bottom" data-title="Ваш регион <?php if ($cache_enabled){ if ( function_exists( 'dynamic_output_buffer_test' ) ) dynamic_output_buffer_test(); ?> YOUROUTPUTBUFFERTAG <?php } else { echo do_shortcode('[wt_contacts get="region"][/wt_contacts]'); } ?>?" onclick="modalRegionSelectionShow()"> <?php if ($cache_enabled){ ?> YOUROUTPUTBUFFERTAG <?php } else { echo do_shortcode('[wt_contacts get="region"][/wt_contacts]'); } ?> </a> </div>
Вот теперь готово.
В заключение
С помощью приведенного мной примера из практики, немного осмыслив и заменив нужные куски на собственные, вы с легкостью примените динамический кэш.
А на сегодня все. В следующий статьях расскажу о применении Elasticsearch, фасетного поиска и оптимизации кода темы да и не только. Следите за обновлениями!