Продвинутая оптимизация WordPress. Часть 2: динамическое кэширование с помощью плагина WP Supercache

В продолжение предыдущей статьи цикла о продвинутой оптимизации 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 варианта реализации динамических блоков:

  1. Через функцию dynamic_cache_test_init(), которая добавит нужный код, используя стандартный хук Вордпресса wp_footer. То есть выведет в подвале сайта.
  2. Через 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-cache-test.php и найдем 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, фасетного поиска и оптимизации кода темы да и не только. Следите за обновлениями!