Speculative Loading is coming to WordPress 6.8. The Speculation Rules API enables browsers to prefetch or prerender URLs so that pages can load much faster for users. Prefetching can reduce your TTFB to zero, and prerendering can reduce your LCP to zero: instant navigation! As explained in Prerender pages in Chrome for instant page navigations, these speculative loads can be done with different degrees of eagerness:
- Conservative: Load when the user starts to click on a link.
- Moderate: Load when the user hovers over a link.
- Eager: Load as soon as possible without user interaction.
In WordPress 6.8, the default configuration is to use the conservative eagerness to speculatively load with prefetch. This gives a tiny head start to loading the page. The intention is to switch from conservative to moderate eagerness in a future WordPress version once we’ve tested the impact in the initial release. When using the Speculative Loading plugin (which the core feature was based on), the default is to prerender with moderate eagerness, which enables the possibility for instant page loads. However, these instant page loads are primarily experienced on desktop because the moderate eagerness depends on there being a mouse/pointer hovering over a link to initiate the speculative load, and hovering isn’t typically something available on a touch device.
So, how can visitors on mobile get an instant loading experience without eagerly loading all links on a page? We can eagerly load the specific link we determine the user is most likely to go to next. While we could use analytics to inform precisely what the user journeys will be, on my site I’m confident that eager speculative loads should be done for two scenarios:
- The link to the first post listed on my index pages (e.g. homepage, archives).
- The link to the homepage on my singular posts and pages.
I’ve implemented these here on my site, so try clicking my name in the header to see how fast it is to navigate to the homepage. Then try clicking the link for the first blog post to see what should be an equally fast navigation, compared with clicking on the link to the second blog post. (Either try clicking the link very quickly without hovering over for long, or try on mobile where the moderate eagerness won’t result in prerendering.)
It was pretty easy to implement speculative loading for these scenarios with the extensibility provided in the new WordPress API.
In my colleague Felix Arntzʼs post linked to above, he documents how to include additional speculation rules beyond what is added by the default in WordPress. There is a wp_load_speculation_rules
action that is passed a WP_Speculation_Rules
object on which you can call the add_rule()
method to add additional speculation rules. Here’s how you could use that to prerender the homepage whenever viewing a blog post:
add_action(
'wp_load_speculation_rules',
function ( WP_Speculation_Rules $rules ): void {
if ( ! is_singular() ) {
return;
}
$rules->add_rule(
'prerender',
'prerender-homepage-from-singular-template',
array(
'source' => 'list',
'urls' => array( home_url( '/' ) ),
'eagerness' => 'eager',
)
);
}
);
Code language: PHP (php)
While this will work most of the time, there are a few scenarios where it will cause the homepage to be wastefully prerendered:
- A plugin adds query parameters to links while the template is rendered (e.g. via some WP filter in PHP).
- Some JavaScript adds query parameters to links after the page has loaded.
- The template omits the header (and the contained homepage link) for some reason.
In these three cases, prerendering the home_url('/')
would be a waste because there’s no way the user could navigate to that specific URL via a link on the page. Therefore, an alternative to the above which accounts for this is to use a document
source as opposed to a list
source. This ensures that the URL being prerendered actually exists in the page.
All of the bundled themes in WordPress Core use the Rel-Home Microformat to annotate homepage links (which is also common across all themes in the dotorg directory), so the selector a[rel="home"]
can be used to match the link to prerender:
add_action(
'wp_load_speculation_rules',
function ( WP_Speculation_Rules $rules ): void {
if ( ! is_singular() ) {
return;
}
$rules->add_rule(
'prerender',
'prerender-homepage-from-singular-template',
array(
'source' => 'document',
'where' => array(
'selector_matches' => 'a[rel="home"]',
),
'eagerness' => 'eager',
)
);
}
);
Code language: PHP (php)
Prerendering the URL for the first post in The Loop on an index page requires a bit more work because there are more conditions for an index page and the CSS selector is a bit more complicated:
add_action(
'wp_load_speculation_rules',
function ( WP_Speculation_Rules $rules ): void {
if ( ! ( is_archive() || is_home() || is_search() ) ) {
return;
}
global $wp_query;
$rules->add_rule(
'prerender',
'prerender-first-post-in-archive-loop',
array(
'source' => 'document',
'where' => array(
'selector_matches' => sprintf(
'.hentry.post-%d :is(h1, h2, h3) a[href]',
$wp_query->posts[0]->ID
),
),
'eagerness' => 'eager',
)
);
}
);
Code language: PHP (php)
This depends on themes using the post_class()
function on the wrapper element for the posts in The Loop (which all core themes do) in order for the hentry
and post-{id}
classes to be added. It obtains the first post in the $wp_query
global in order to determine the ID of the first post. (An alternative would be to use .hentry:first-child
which would potentially eliminate the need for including the post ID in the selector, but this would cause multiple posts to be prerendered if there were multiple post loops on the page.) All the core themes then display the permalink to the post inside of a heading, but they may use different heading levels (e.g. H1
vs H2
). So for example, if the first post in the main loop has an ID of 1, then the selector used for prerendering that post from the homepage would be:
.hentry.post-1 :is(h1, h2, h3) a[href]
Code language: plaintext (plaintext)
I tested this successfully in each of the core themes.
I put these examples together in a couple Gist mini plugins which you’re welcome to adapt for your needs:
- Speculative Loading: Eagerly Prerender First Post in Archive Loop
- Speculative Loading: Eagerly Prerender Homepage from Singular Template
I’ve also included backwards-compatibility for WordPress versions prior to 6.8.
If you want to learn about more techniques for customizing speculative loading on your site, check out Barry Pollardʼs just-published guide to implementing speculation rules for more complex sites.
I posted this on the following platforms if you want to boost:
Featured image generated by AI via Google’s Imagen 3 in ImageFX.
Leave a Reply