Advanced WordPress optimization. Part 2: dynamic caching with WP Supercache

Following on the previous article in the series on advanced WordPress optimization, I’ll talk about implementing dynamic blocks for unauthorized users in the WP Supercache caching plugin.

Sometimes it is simply impossible to cache certain blocks. I faced such a problem in the e-commerce project when implementing the selection of the city and displaying the pickup locations on the map. The fact is that the selection and detection of the users’ city processed by the backend, and when you changed the location it was necessary to change the coordinates of the map, which were on a very large number of pages. Another fact is that I used both methods available in the plugin to solve this task. And I going to tell you what I did.

Artyom Zaytsev

Evilmarketer

What we have

— Plugin for detection and selection of the city  “WT geotargeting pro” with a shortcode of location output.

[wt_contacts get="region"][/wt_contacts]

— Yandex maps. In theory, the method is suitable for Google maps, with the only clarification that JS code for centering the map will be different. So read their documentation.

<script src="https://api-maps.yandex.ru/2.1/?lang=ru_RU&coordorder=longlat" type="text/javascript"></script>

— For marking pickup locations points I used a special JSON-file.

JSON example in official docs

— To center the map, I added a small JS code and put it in the Footer.php:

ymaps.ready()

           .done(function (ym) {

               var myMap = new ym.Map('YMapsID', {

                   center: [coordinatesArrayLng, coordinatesArrayLat],

                   zoom: zoomSelectForPickupLocations

               }, {

                   searchControlProvider: 'yandex#search'

               });

               jQuery.getJSON('<?php echo get_site_url(); ?>/yamaps.json', function (json) {

                   var geoObjects = ym.geoQuery(json)

                           .addToMap(myMap);

               });

           });

— coordinatesArrayLng and coordinatesArrayLat variables will be dynamic, so I added them a little bit higher, but in the same footer.php. For convenience, so far I will set their values to null:

var coordinatesArrayLat = 0;
var coordinatesArrayLng = 0;

The picture at this stage should look like this:

— To display the current visitor’s city and pop-up link with the list of different cities, I use this code:

<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="Your region: <?php echo do_shortcode('[wt_contacts get="region"][/wt_contacts]'); ?>?"
	   	onclick="modalRegionSelectionShow()">
	   	<?php echo do_shortcode('[wt_contacts get="region"][/wt_contacts]'); ?>
	</a>
</div>

Adding dynamic blocks for visitor’s city detection and coordinates for the map

So, before you start the implementation, you will need to enable dynamic caching in the plugin settings

and activate late init. If you don’t turn it on, you’ll see either a white screen or a 500 error.

All these options are in the advanced settings section of WP Supercache.

Next you find the file /wp-content/plugins/wp-super-cache/plugins/dynamic-cache-test.php

The plugin has 2 solutions for dynamic blocks implementation:

  1. Via dynamic_cache_test_init() function, which uses a WordPress hook wp_footer and will display the result in the footer.
  2. Via OUTPUT_BUFFER_TAG. This method allows you to create a special tag for the template. The plugin will replace it with the result the code execution.

The first option I’ll use for generating JS code with coordinates (remember variables coordinatesArrayLat and coordinatesArrayLng above?). The second option I’ll use to display the city.

Generate JS with coordinates

First of all, we will come up with our secret placeholder tag:

define( 'DYNAMIC_CACHE_TEST_TAG', 'YOURSECRETTAG' );

Then we’ll write a function that will return the coordinates of the pickup location. We will take them from the user’s current city out of the standard plugin’s object.

To not take the coordinates of the city, and to center the map at the pickup location I added a plugin called Marty Geocoder. And then I got the needed values from meta out of the object. In my case it was 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";
}

Our function is ready, it remains to init it.

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' );
}

Ready, you can enable caching and check that the footer displays the desired JS code.

The correct coordinates are displayed.

Get the city of the visitor

To display the city, we should refer to its code in the template. I posted it above. For clarity, I show it again here:

<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="Your region <?php echo do_shortcode('[wt_contacts get="region"][/wt_contacts]'); ?>?"
	   	onclick="modalRegionSelectionShow()">
	   	<?php echo do_shortcode('[wt_contacts get="region"][/wt_contacts]'); ?>
	</a>
</div>
Have you seen the shortcode [wt_contacts get= "region"] [/wt_contacts]? Here we will output the result of its execution through the created special tag.
Let’s return to the dynamic-cache-test.php and find DYNAMIC_OUTPUT_BUFFER_TAG. You should specify the name of your tag. Highly recommend you not to show it anywhere for security reasons  🙂
define( 'DYNAMIC_OUTPUT_BUFFER_TAG', 'YOUROUTPUTBUFFERTAG' );
To execute the shortcode you must specify it inside the function dynamic_output_buffer_test() between ob_start(); and ob_end_clean(); instead of echo line.

Before

After

Then we may use our tag. To do this we should replace the shortcode in the template with it.

<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="Your region: <?php if ( function_exists( 'dynamic_output_buffer_test' ) ) dynamic_output_buffer_test(); ?>YOUROUTPUTBUFFERTAG?"
	   	onclick="modalRegionSelectionShow()">
	   	YOUROUTPUTBUFFERTAG
	</a>
</div>

Be sure to call the dynamic_output_buffer_test() function inside the template file where you use the tag, otherwise, it will not work.

Almost ready. But there is a moment: if you turn off caching for some reason, the tag will be displayed instead of the city, and we don’t need it. Therefore, the final touch will be adding one more condition for checking a working caching.

<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="Your region: 
								   	<?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>

Ready.

In conclusion

Having comprehended a little and having replaced the necessary pieces with your own, you will apply a dynamic cache with ease.

That is all for today. In the next articles, we will talk about the use of Elasticsearch, faceted search and optimization of the template code etc. Stay tuned for updates!