Next Page Caching: A Whole New Way to Speed Up Your Site

If you’ve created or maintained a website before, chances are you’re aware how challenging optimizing page load speed is. The job increases in difficulty especially if you’re using WordPress and dealing with plugins that add their own files.

Caching is one of the many effective ways to speed up your website: you can install caching plugins like WP Rocket or W3 Total Cache. While those do the job well, there’s a relatively new method of further speeding up your site – we like to call this method “next page caching”.

It isn’t just caching; It’s next page caching

The concept of next page caching works differently from regular web page caching. Next page caching concentrates on speeding up the transition to the next predicted page your site visitors will be navigating to.

How does this work?

Next Page Caching is a relatively new method of further speeding up your site.

You can cache the next page by utilizing a relatively new feature of browsers called Resource Hints.

Basically, Resource Hints give us with a few methods to prompt the browser to do some special things. When these methods are used together, we can prompt the loading of the next page (and its succeeding pages) to load faster.

Preload Hint

Preload prioritizes loading files that are on the current page. You can use this to prompt the browser to load files that are crucial, like an article’s featured image or theme styles.

Prefetch Hint

Prefetch fetches files when the browser has finished loading the current web page. You can use this to load the the critical scripts and styles of the next page. This way, the content of the next page load will start to load while the user is still busy reading or scrolling through the current page.

Preconnect Hint

This preemptively connects to a domain to speed up future loading of files that originate from it. You can use this to preconnect to a domain if your page uses multiple files from it. Use this for CDN domains or Google Fonts.

Introducing: The Next Page Caching Plugin

With this concept in mind, we’ve created a plugin that bears the same name: Next Page Caching. By using the three Resource Hints above, you can probably expect a loading time decrease to the next page anywhere from 100ms to 500ms depending on the situation.

Technically, the plugin doesn’t exactly lessen the loading time. Instead, it works with page interactivity time, making the next page feel faster since the critical parts prioritized during loading and the visitor can interact with the page sooner.

This is opposed to the visitor waiting on a white screen while waiting for the page, featured image, or Google Fonts to finish loading.

Here are the kinds of caching that the Next Page Caching plugin can do:

  • The plugin prefetches the main HTML of the chosen next page, as well as the critical files specified.
  • Prefetches the first post when viewing a blog list or archive page.
  • Preloads the post’s chosen critical files to prioritize them.
  • Preloads the theme stylesheet so that it gets loaded first.
  • Preloads the featured image of a blog post or page when needed (and if it’s large) so that it shows up faster.
  • Preconnects to the Google Fonts domain for faster font downloading when needed.

Since next page caching essentially loads parts of the next page WHILE you browse the current page, normal speed testing tools like YSlow, Pingdom Tools or GTMetrix will not show much difference – those only test the speed of the current page you’re at. What you need is to test the speed from transitioning between one page to the next.

You can open an incognito window, disable caching and check the network tab while navigating through your site.

The Next Page Caching plugin is available for free in the WordPress Plugin Directory.

Get Free Plugin Here

How to Perform an Action Only Once in WordPress

The add_action function is the main function to use when creating WordPress plugins. You mainly use it for executing code at various run time points within WordPress. With this function, you can create shortcodes, enqueue scripts, styles, modify post titles and contents and lots more.

How does this work? If you explode the core code of WordPress, it is littered with do_action calls all over. Every time WordPress does a do_action, all function passed to matching add_action calls get executed. This is very helpful in the creation of modular and maintainable code, and it’s great.

So if you perform 2 add_action calls to an action named wp_head, this means that when WordPress calls a do_action( 'wp_head' ), your 2 functions in your add_actions get called.

The Problem

In Titan Framework, we have a lot of add_action calls. But since we designed Titan Framework to be object oriented (OOP), some of our actions were getting called multiple times when we only intended for it to run once. How is that? Check this brief example of what a color option class might look like:

class TitanFrameworkColorOption {

    function __construct() {
        add_action( 'admin_enqueue_scripts', array( $this, 'enqueueScripts' ) );

    public function enqueueScripts() {
        wp_enqueue_script( 'wp-color-picker' );
        wp_enqueue_style( 'wp-color-picker' );

This is a very stripped-to-the-basics class of the option (in reality it’s much more code than this). With the code above, when you create a color option TitanFrameworkColorOption, we enqueue the script and styles of WordPress’ built-in color picker.

The problem here is that when two color options are created via new TitanFrameworkColorOption(), that means that the add_action function is called twice, and therefore the enqueueScripts function is ran twice. This might not be much of a problem with the example code above since WordPress doesn’t enqueue the same thing multiple times. But if you have a more elaborate code in there, then those would get executed twice. That could lead to more memory and CPU usage for your server, and slower loading times.

The solution then is to create a checker so that we only run enqueueScripts once. Let’s add that in:

class TitanFrameworkColorOption {

    public static $alreadyEnqueued = false;

    function __construct() {
        add_action( 'admin_enqueue_scripts', array( $this, 'enqueueScripts' ) );

    public function enqueueScripts() {
        if ( ! self::$alreadyEnqueued ) {
            wp_enqueue_script( 'wp-color-picker' );
            wp_enqueue_style( 'wp-color-picker' );
        self::$alreadyEnqueued = true;

This now works fine. The bad side is that you now have added 4 new lines of code. If you have a large codebase, this can scale up fast and your code slowly becomes a little bit harder to read.

The Solution

 * Performs an add_filter only once. Helpful for factory constructors where an action only
 * needs to be added once. Because of this, there will be no need to do a static variable that
 * will be set to true after the first run, ala $firstLoad
 * @since 1.9
 * @param string   $tag             The name of the filter to hook the $function_to_add callback to.
 * @param callback $function_to_add The callback to be run when the filter is applied.
 * @param int      $priority        Optional. Used to specify the order in which the functions
 *                                  associated with a particular action are executed. Default 10.
 *                                  Lower numbers correspond with earlier execution,
 *                                  and functions with the same priority are executed
 *                                  in the order in which they were added to the action.
 * @param int      $accepted_args   Optional. The number of arguments the function accepts. Default 1.
 * @return true
function add_filter_once( $tag, $function_to_add, $priority = 10, $accepted_args = 1 ) {
	global $_gambitFiltersRan;

	if ( ! isset( $_gambitFiltersRan ) ) {
		$_gambitFiltersRan = array();

	// Since references to $this produces a unique id, just use the class for identification purposes
	$idxFunc = $function_to_add;
	if ( is_array( $function_to_add ) ) {
		$idxFunc[0] = get_class( $function_to_add[0] );
	$idx = _wp_filter_build_unique_id( $tag, $idxFunc, $priority );

	if ( ! in_array( $idx, $_gambitFiltersRan ) ) {
		add_filter( $tag, $function_to_add, $priority, $accepted_args );

	$_gambitFiltersRan[] = $idx;

	return true;

The solution is this new function called add_filter_once. This runs similar to add_action except that it only executes the function passed to it once, even if it is called multiple times.

If we implement this to our class, we end up with a much more elegant code that’s still very much readable:

class TitanFrameworkColorOption {

    function __construct() {
        add_action_once( 'admin_enqueue_scripts', array( $this, 'enqueueScripts' ) );

    public function enqueueScripts() {
        wp_enqueue_script( 'wp-color-picker' );
        wp_enqueue_style( 'wp-color-picker' );

PHPUnit Installer Script that Works in Travis CI and Locally for VVV

Travis CI is great and we’re using a very (VERY) simple singular test that just checks whether or not Titan Framework encounters any activation errors. As of the moment we haven’t wrote any other detailed tests for Titan, and that simple activation test soon will no longer cut it.

Ideally, testing would be done both remotely and locally during development so that you can catch errors quickly.. probably with a Gulp watch running the tests, but that would be for another article. I did some research on running PHPUnit tests locally and found Pippin’s 4-part blog post on Unit Testing for WordPress Plugins really helpful (read it if you haven’t yet). We’re using that as our guide to adding unit tests for Titan.

As of the moment we’re using VVV as our development environment, and it’s good that it already has WP-CLI and PHPUnit pre-installed so we can quickly jump into trying out unit testing locally. Titan already has a bin/ so we don’t need to do a wp scaffold. We tried initializing the testing environment using this command inside VVV:

$ bash bin/ wordpress_unit_tests root 'root' localhost latest

Surprise, the command failed. It works when Travis CI uses it, but it fails inside VVV. Why? Because Travis CI runs it’s tests on an empty environment, while VVV already has a bunch of development stuff inside it like a development copy of WordPress.

Not only that, the normal installer script would take a long time to finish since it downloads the WordPress installer, unzips it and uses that one as the testing environment. IF we performed testing across all our plugins, that would take up precious time.

So we modified the to only download stuff only when necessary and so skip cloning of the dev copy of WordPress if it already exists. Now, the script works locally inside VVV and it still works great also in Travis CI.

Here’s the copy of the install script that Titan Framework uses if anyone finds it useful:

For newly scaffolded projects, here’s the modified one:

Using IDs or query_vars instead of slug names in get_post_types

Here’s one that had my head scratching for a while.

We are currently developing a much-sought-after update for Carousel Anything, and it involves enumerating post types, taxonomies and terms. On a routine testing en route to being a candidate build, our testing team found out it wasn’t working with the custom post types by Meet The Team.

Several comparative var dumps later, I learned it wasn’t returning the correct post type variable!

Then I was reminded I implemented a feature previously in Meet The Team where I could change the slug name to something far more frendlier. It was friendly for readers in SEO, but not for the devs.

Or so I thought.

This meant slugs can’t be used for internal queries because it could be modified midway and wasn’t reliable, until I scoured a var dump of get_post_types() and found what I needed.

The query_vars key.

At last, this was the id that identified each post type reliably. And most slugs take up its name! No wonder why some post types worked and some did not!

That’s one piece of code definitely going to the snippets.

Here is what was wrong before.

$posttypes['slug'][] = $post_type->rewrite['slug'];
$posttypes['name'][ $post_type->rewrite['slug'] ] = $post_type->labels->name;

And here’s the code that set things right.

$posttypes['slug'][] = $post_type->query_var;
$posttypes['name'][ $post_type->query_var ] = $post_type->labels->name;

Converting Relative URLs to Absolute URLs in PHP

We needed to convert relative URLs to absolute URLs inside CSS files for our upcoming plugin Combinator.

There are a lot of code floating online that partially worked. The one that was closest was from Here’s the reworked version that works great in PHP 5.3+

function rel2abs( $rel, $base ) {

	// parse base URL  and convert to local variables: $scheme, $host,  $path
	extract( parse_url( $base ) );

	if ( strpos( $rel,"//" ) === 0 ) {
		return $scheme . ':' . $rel;

	// return if already absolute URL
	if ( parse_url( $rel, PHP_URL_SCHEME ) != '' ) {
		return $rel;

	// queries and anchors
	if ( $rel[0] == '#' || $rel[0] == '?' ) {
		return $base . $rel;

	// remove non-directory element from path
	$path = preg_replace( '#/[^/]*$#', '', $path );

	// destroy path if relative url points to root
	if ( $rel[0] ==  '/' ) {
		$path = '';

	// dirty absolute URL
	$abs = $host . $path . "/" . $rel;

	// replace '//' or  '/./' or '/foo/../' with '/'
	$abs = preg_replace( "/(\/\.?\/)/", "/", $abs );
	$abs = preg_replace( "/\/(?!\.\.)[^\/]+\/\.\.\//", "/", $abs );

	// absolute URL is ready!
	return $scheme . '://' . $abs;


rel2abs( '../images/image.jpg', '' );
// Outputs

How to Use the Javascript YouTube API Across Multiple Plugins

When using the YouTube API, you are required to create the function onYouTubePlayerAPIReady. There is a huge problem with this.

If you have multiple WordPress plugins that use the YouTube API, that means that you have multiple declarations of onYouTubePlayerAPIReady. Multiple declarations in Javascript mean that previous onYouTubePlayerAPIReady functions get overwritten and will never be called. So if you are using 2 WordPress plugins that both use the YouTube API, 1 of them will for sure stop working.

The workaround for this is before creating your own onYouTubePlayerAPIReady function, you should check first for previous declarations and keep a reference to those previous functions. Then inside your own onYouTubePlayerAPIReady function, after you perform the tasks you want, call the function references you kept.

The New onYouTubePlayerAPIReady

Instead of doing simply this:

function onYouTubePlayerAPIReady() {

    // Initialize YT.Player and do stuff here


Use this instead:

setTimeout( function() {
    if ( typeof window.onYouTubePlayerAPIReady !== 'undefined' ) {
        if ( typeof window.gambitOtherYTAPIReady === 'undefined' ) {
            window.gambitOtherYTAPIReady = [];
        window.gambitOtherYTAPIReady.push( window.onYouTubePlayerAPIReady );
    window.onYouTubePlayerAPIReady = function() {
        // Initialize YT.Player and do stuff here
        if ( typeof window.gambitOtherYTAPIReady !== 'undefined' ) {
            if ( window.gambitOtherYTAPIReady.length ) {
}, 2);


Important parts of the code:

  1. setTimeout – We wait a small bit until other Javascript have run and if other code elsewhere have defined a function onYouTubePlayerAPIReady, then we can detect that,
  2. window.gambitOtherYTAPIReady – We create a global array/stack that we will use to store the existing onYouTubePlayerAPIReady functions,
  3. window.onYouTubePlayerAPIReady – We then create our own onYouTubePlayerAPIReady where we do what we need,
  4. window.gambitOtherYTAPIReady.pop()() – Before the ready function ends, we call the other stored function, which in turn will call another one, and so on until they are all complete.

Tip: Detecting a Mobile Browser with Javascript

There are a lot of existing ways to detect whether the browser is being used in a mobile device. You can use Modernizr to check for Touch support, check for whether Touch events are supported by the browser, or check the width of the screen. We previously used a combination of these, but they only worked most of the time.

Mozilla has recommended a better and shorter way to detect a mobile device and it is much more stable and reliable so far:

In summary, we recommend looking for the string “Mobi” anywhere in the User Agent to detect a mobile device.

if ( navigator.userAgent.match(/Mobi/) ) {
    // We are in a mobile device

Image Dimensions Get Lost when JetPack’s Photon is Activated

Jetpack issue submitted:

If you do this:

$attachmentImage = wp_get_attachment_image_src( 1234, 'full' );
$url = $attachmentImage[0];
$width = $attachmentImage[1];
$height = $attachmentImage[2];

$width and $height should give out the image dimensions, but when Photon is activated, both don’t get returned.

The workaround for this is discussed here:

The workaround is to get the dimensions without Photon, then get the image URL normally:

add_filter( 'jetpack_photon_override_image_downsize', '__return_true' );
$imageInfo = wp_get_attachment_image_src( 1234, 'full' );
remove_filter( 'jetpack_photon_override_image_downsize', '__return_true' );

$attachmentImage = wp_get_attachment_image_src( 1234, 'full' );
$url = $attachmentImage[0];
$width = $imageInfo[1];
$height = $imageInfo[2];