I’ll build this as a reusable performance/prerender.php module for your RX theme: safe defaults, filters for future extension, resource hints, preload/prefetch/prerender, and modern Speculation Rules support.
Below is an advanced performance/prerender.php file for your rx-theme. It includes DNS prefetch, preconnect, preload, prefetch, prerender-safe URL handling, modern Speculation Rules API, link headers, featured-image preload, font preload, stylesheet/script preload, safe exclusions, and many filters for future expansion.
Create this file:
mkdir -p performance
touch performance/prerender.php
Then paste this code:
<?php
/**
* RX Theme Performance: Preload, Prefetch, Preconnect, Prerender
*
* File: /performance/prerender.php
*
* Features:
* - DNS prefetch
* - Preconnect
* - Preload fonts, CSS, JS, featured images, custom assets
* - Prefetch likely next pages
* - Safe prerender candidates
* - Modern Speculation Rules API
* - HTTP Link headers
* - WooCommerce/cart/admin/search/login safe exclusions
* - Developer filters for future extension
*
* @package RX_Theme
*/
defined( 'ABSPATH' ) || exit;
if ( ! class_exists( 'RX_Theme_Prerender_Performance' ) ) :
final class RX_Theme_Prerender_Performance {
/**
* Version.
*/
const VERSION = '1.0.0';
/**
* Singleton instance.
*
* @var self|null
*/
private static $instance = null;
/**
* Whether module is enabled for this request.
*
* @var bool|null
*/
private $enabled = null;
/**
* Get singleton instance.
*
* @return self
*/
public static function instance() {
if ( null === self::$instance ) {
self::$instance = new self();
}
return self::$instance;
}
/**
* Constructor.
*/
private function __construct() {
add_filter( 'wp_resource_hints', array( $this, 'resource_hints' ), 10, 2 );
add_action( 'send_headers', array( $this, 'send_link_headers' ), 20 );
add_action( 'wp_head', array( $this, 'print_early_resource_links' ), 1 );
add_action( 'wp_head', array( $this, 'print_prefetch_links' ), 3 );
add_action( 'wp_head', array( $this, 'print_prerender_links' ), 4 );
add_action( 'wp_head', array( $this, 'print_speculation_rules' ), 5 );
add_filter( 'script_loader_tag', array( $this, 'optimize_script_loader_tag' ), 10, 3 );
add_filter( 'style_loader_tag', array( $this, 'optimize_style_loader_tag' ), 10, 4 );
}
/**
* Check whether performance hints should run.
*
* @return bool
*/
public function is_enabled() {
if ( null !== $this->enabled ) {
return $this->enabled;
}
$enabled = true;
if ( is_admin() || wp_doing_ajax() || wp_doing_cron() || is_feed() || is_robots() ) {
$enabled = false;
}
if ( is_preview() || is_customize_preview() ) {
$enabled = false;
}
if ( is_user_logged_in() && current_user_can( 'edit_posts' ) ) {
$enabled = false;
}
if ( isset( $_GET['rx_no_prerender'] ) ) {
$enabled = false;
}
if ( function_exists( 'is_cart' ) && ( is_cart() || is_checkout() || is_account_page() ) ) {
$enabled = false;
}
/**
* Enable or disable RX prerender performance module.
*
* @param bool $enabled
*/
$this->enabled = (bool) apply_filters( 'rx_prerender_enabled', $enabled );
return $this->enabled;
}
/**
* Add WordPress resource hints.
*
* @param array $urls URLs.
* @param string $relation_type Relation type.
*
* @return array
*/
public function resource_hints( $urls, $relation_type ) {
if ( ! $this->is_enabled() ) {
return $urls;
}
if ( 'dns-prefetch' === $relation_type ) {
foreach ( $this->get_dns_prefetch_urls() as $url ) {
$urls[] = $url;
}
}
if ( 'preconnect' === $relation_type ) {
foreach ( $this->get_preconnect_urls() as $url ) {
$urls[] = array(
'href' => $url,
'crossorigin' => 'anonymous',
);
}
}
return array_values( array_unique( $urls, SORT_REGULAR ) );
}
/**
* Print early resource links in head.
*
* @return void
*/
public function print_early_resource_links() {
if ( ! $this->is_enabled() ) {
return;
}
$this->print_dns_prefetch();
$this->print_preconnect();
$this->print_preload_links();
}
/**
* Print DNS prefetch manually.
*
* @return void
*/
private function print_dns_prefetch() {
$urls = $this->get_dns_prefetch_urls();
foreach ( $urls as $url ) {
printf(
"<link rel=\"dns-prefetch\" href=\"%s\">\n",
esc_url( $url )
);
}
}
/**
* Print preconnect manually.
*
* @return void
*/
private function print_preconnect() {
$urls = $this->get_preconnect_urls();
foreach ( $urls as $url ) {
printf(
"<link rel=\"preconnect\" href=\"%s\" crossorigin>\n",
esc_url( $url )
);
}
}
/**
* Print preload links.
*
* @return void
*/
private function print_preload_links() {
$items = $this->get_preload_items();
foreach ( $items as $item ) {
$item = wp_parse_args(
$item,
array(
'href' => '',
'as' => '',
'type' => '',
'media' => '',
'crossorigin' => '',
'fetchpriority' => '',
)
);
if ( empty( $item['href'] ) || empty( $item['as'] ) ) {
continue;
}
$attrs = array(
'rel' => 'preload',
'href' => esc_url( $item['href'] ),
'as' => esc_attr( $item['as'] ),
);
if ( ! empty( $item['type'] ) ) {
$attrs['type'] = esc_attr( $item['type'] );
}
if ( ! empty( $item['media'] ) ) {
$attrs['media'] = esc_attr( $item['media'] );
}
if ( ! empty( $item['crossorigin'] ) ) {
$attrs['crossorigin'] = esc_attr( $item['crossorigin'] );
}
if ( ! empty( $item['fetchpriority'] ) ) {
$attrs['fetchpriority'] = esc_attr( $item['fetchpriority'] );
}
echo '<link ' . $this->build_html_attributes( $attrs ) . ">\n";
}
}
/**
* Print prefetch links.
*
* @return void
*/
public function print_prefetch_links() {
if ( ! $this->is_enabled() ) {
return;
}
$urls = $this->get_prefetch_urls();
foreach ( $urls as $url ) {
if ( ! $this->is_safe_url( $url ) ) {
continue;
}
printf(
"<link rel=\"prefetch\" href=\"%s\" as=\"document\">\n",
esc_url( $url )
);
}
}
/**
* Print old-style prerender links.
*
* Conservative by default.
*
* @return void
*/
public function print_prerender_links() {
if ( ! $this->is_enabled() ) {
return;
}
$allow_old_prerender = (bool) apply_filters( 'rx_allow_legacy_prerender_link', false );
if ( ! $allow_old_prerender ) {
return;
}
$urls = $this->get_prerender_urls();
foreach ( $urls as $url ) {
if ( ! $this->is_safe_url( $url ) ) {
continue;
}
printf(
"<link rel=\"prerender\" href=\"%s\">\n",
esc_url( $url )
);
}
}
/**
* Print modern Speculation Rules API.
*
* @return void
*/
public function print_speculation_rules() {
if ( ! $this->is_enabled() ) {
return;
}
$enabled = (bool) apply_filters( 'rx_enable_speculation_rules', true );
if ( ! $enabled ) {
return;
}
$prefetch_urls = array_values( array_filter( $this->get_prefetch_urls(), array( $this, 'is_safe_url' ) ) );
$prerender_urls = array_values( array_filter( $this->get_prerender_urls(), array( $this, 'is_safe_url' ) ) );
$rules = array(
'prefetch' => array(
array(
'source' => 'document',
'eagerness' => 'moderate',
'where' => array(
'and' => array(
array(
'href_matches' => '/*',
),
array(
'not' => array(
'href_matches' => array(
'/wp-admin/*',
'/wp-login.php*',
'*/cart*',
'*/checkout*',
'*/my-account*',
'*/account*',
'*/?s=*',
'*/search/*',
'*/feed/*',
'*/comments/*',
'*add-to-cart=*',
'*preview=true*',
'*customize_changeset_uuid=*',
),
),
),
),
),
),
),
'prerender' => array(
array(
'source' => 'list',
'eagerness' => 'conservative',
'urls' => $prerender_urls,
),
),
);
if ( ! empty( $prefetch_urls ) ) {
$rules['prefetch'][] = array(
'source' => 'list',
'eagerness' => 'moderate',
'urls' => $prefetch_urls,
);
}
/**
* Filter Speculation Rules JSON.
*
* @param array $rules
*/
$rules = apply_filters( 'rx_speculation_rules', $rules );
if ( empty( $rules ) || ! is_array( $rules ) ) {
return;
}
echo '<script type="speculationrules">' . "\n";
echo wp_json_encode( $rules, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT );
echo "\n" . '</script>' . "\n";
}
/**
* Send HTTP Link headers.
*
* @return void
*/
public function send_link_headers() {
if ( headers_sent() || ! $this->is_enabled() ) {
return;
}
$enabled = (bool) apply_filters( 'rx_enable_link_headers', true );
if ( ! $enabled ) {
return;
}
$headers = array();
foreach ( $this->get_preconnect_urls() as $url ) {
$headers[] = sprintf(
'<%s>; rel=preconnect; crossorigin',
esc_url_raw( $url )
);
}
foreach ( $this->get_preload_items() as $item ) {
if ( empty( $item['href'] ) || empty( $item['as'] ) ) {
continue;
}
$header = sprintf(
'<%s>; rel=preload; as=%s',
esc_url_raw( $item['href'] ),
sanitize_key( $item['as'] )
);
if ( ! empty( $item['type'] ) ) {
$header .= '; type=' . sanitize_text_field( $item['type'] );
}
if ( ! empty( $item['crossorigin'] ) ) {
$header .= '; crossorigin';
}
$headers[] = $header;
}
$headers = array_slice( array_unique( $headers ), 0, 15 );
foreach ( $headers as $header ) {
header( 'Link: ' . $header, false );
}
}
/**
* Get DNS-prefetch URLs.
*
* @return array
*/
private function get_dns_prefetch_urls() {
$urls = array(
'//fonts.googleapis.com',
'//fonts.gstatic.com',
'//www.googletagmanager.com',
'//www.google-analytics.com',
'//pagead2.googlesyndication.com',
'//securepubads.g.doubleclick.net',
'//static.cloudflareinsights.com',
);
$theme_cdn = $this->get_theme_cdn_origin();
if ( $theme_cdn ) {
$urls[] = $theme_cdn;
}
/**
* Filter DNS prefetch URLs.
*
* Example:
* add_filter('rx_dns_prefetch_urls', function($urls) {
* $urls[] = '//cdn.example.com';
* return $urls;
* });
*/
$urls = apply_filters( 'rx_dns_prefetch_urls', $urls );
return $this->clean_url_list( $urls );
}
/**
* Get preconnect URLs.
*
* @return array
*/
private function get_preconnect_urls() {
$urls = array(
'https://fonts.gstatic.com',
);
$theme_cdn = $this->get_theme_cdn_origin();
if ( $theme_cdn ) {
$urls[] = $theme_cdn;
}
/**
* Filter preconnect URLs.
*/
$urls = apply_filters( 'rx_preconnect_urls', $urls );
return $this->clean_url_list( $urls );
}
/**
* Get preload items.
*
* @return array
*/
private function get_preload_items() {
$items = array();
$main_css = get_stylesheet_uri();
if ( $main_css ) {
$items[] = array(
'href' => $main_css,
'as' => 'style',
);
}
$featured_image = $this->get_featured_image_url();
if ( $featured_image ) {
$items[] = array(
'href' => $featured_image,
'as' => 'image',
'fetchpriority' => 'high',
);
}
foreach ( $this->get_font_preloads() as $font ) {
$items[] = $font;
}
foreach ( $this->get_custom_asset_preloads() as $asset ) {
$items[] = $asset;
}
/**
* Filter preload items.
*
* Item example:
* array(
* 'href' => 'https://example.com/font.woff2',
* 'as' => 'font',
* 'type' => 'font/woff2',
* 'crossorigin' => 'anonymous',
* )
*/
$items = apply_filters( 'rx_preload_items', $items );
return $this->clean_preload_items( $items );
}
/**
* Get font preload items.
*
* @return array
*/
private function get_font_preloads() {
$fonts = array();
/**
* Put your local theme fonts here.
*
* Example folder:
* /assets/fonts/inter-var.woff2
*/
$possible_fonts = array(
'/assets/fonts/inter-var.woff2',
'/assets/fonts/roboto-regular.woff2',
'/assets/fonts/roboto-bold.woff2',
);
foreach ( $possible_fonts as $font_path ) {
$file_path = get_stylesheet_directory() . $font_path;
if ( file_exists( $file_path ) ) {
$fonts[] = array(
'href' => get_stylesheet_directory_uri() . $font_path,
'as' => 'font',
'type' => 'font/woff2',
'crossorigin' => 'anonymous',
);
}
}
/**
* Filter font preloads.
*/
return apply_filters( 'rx_font_preload_items', $fonts );
}
/**
* Get custom asset preloads.
*
* @return array
*/
private function get_custom_asset_preloads() {
$assets = array();
$theme_assets = array(
array(
'path' => '/assets/css/critical.css',
'as' => 'style',
),
array(
'path' => '/assets/js/app.js',
'as' => 'script',
),
array(
'path' => '/assets/js/main.js',
'as' => 'script',
),
);
foreach ( $theme_assets as $asset ) {
$file_path = get_stylesheet_directory() . $asset['path'];
if ( file_exists( $file_path ) ) {
$assets[] = array(
'href' => get_stylesheet_directory_uri() . $asset['path'],
'as' => $asset['as'],
);
}
}
/**
* Filter custom asset preloads.
*/
return apply_filters( 'rx_custom_asset_preloads', $assets );
}
/**
* Get prefetch URLs.
*
* @return array
*/
private function get_prefetch_urls() {
$urls = array();
if ( is_singular( 'post' ) ) {
$next_post = get_next_post();
if ( $next_post instanceof WP_Post ) {
$urls[] = get_permalink( $next_post );
}
$prev_post = get_previous_post();
if ( $prev_post instanceof WP_Post ) {
$urls[] = get_permalink( $prev_post );
}
}
if ( is_home() || is_front_page() ) {
$recent_posts = get_posts(
array(
'numberposts' => 3,
'post_status' => 'publish',
'ignore_sticky_posts' => true,
'no_found_rows' => true,
)
);
foreach ( $recent_posts as $post ) {
$urls[] = get_permalink( $post );
}
}
if ( is_category() || is_tag() || is_tax() ) {
$queried = get_queried_object();
if ( $queried && ! is_wp_error( $queried ) ) {
$urls[] = get_term_link( $queried );
}
}
$urls[] = home_url( '/' );
/**
* Filter prefetch URLs.
*/
$urls = apply_filters( 'rx_prefetch_urls', $urls );
return $this->clean_document_urls( $urls );
}
/**
* Get prerender URLs.
*
* Conservative list.
*
* @return array
*/
private function get_prerender_urls() {
$urls = array();
if ( is_singular( 'post' ) ) {
$next_post = get_next_post();
if ( $next_post instanceof WP_Post ) {
$urls[] = get_permalink( $next_post );
}
}
if ( is_front_page() || is_home() ) {
$posts = get_posts(
array(
'numberposts' => 1,
'post_status' => 'publish',
'ignore_sticky_posts' => true,
'no_found_rows' => true,
)
);
if ( ! empty( $posts[0] ) ) {
$urls[] = get_permalink( $posts[0] );
}
}
/**
* Filter prerender URLs.
*/
$urls = apply_filters( 'rx_prerender_urls', $urls );
return array_slice( $this->clean_document_urls( $urls ), 0, 3 );
}
/**
* Optimize script tag.
*
* @param string $tag Script tag.
* @param string $handle Script handle.
* @param string $src Script source.
*
* @return string
*/
public function optimize_script_loader_tag( $tag, $handle, $src ) {
if ( ! $this->is_enabled() || empty( $src ) ) {
return $tag;
}
$defer_handles = apply_filters(
'rx_defer_script_handles',
array(
'rx-app',
'rx-main',
'rx-theme',
)
);
$async_handles = apply_filters(
'rx_async_script_handles',
array()
);
if ( in_array( $handle, $async_handles, true ) && false === strpos( $tag, ' async' ) ) {
$tag = str_replace( '<script ', '<script async ', $tag );
}
if ( in_array( $handle, $defer_handles, true ) && false === strpos( $tag, ' defer' ) ) {
$tag = str_replace( '<script ', '<script defer ', $tag );
}
return $tag;
}
/**
* Optimize style tag.
*
* @param string $html Style tag.
* @param string $handle Style handle.
* @param string $href Style href.
* @param string $media Style media.
*
* @return string
*/
public function optimize_style_loader_tag( $html, $handle, $href, $media ) {
if ( ! $this->is_enabled() || empty( $href ) ) {
return $html;
}
$preload_style_handles = apply_filters(
'rx_preload_style_handles',
array()
);
if ( ! in_array( $handle, $preload_style_handles, true ) ) {
return $html;
}
$html = '<link rel="preload" href="' . esc_url( $href ) . '" as="style" onload="this.onload=null;this.rel=\'stylesheet\'"';
$html .= ! empty( $media ) ? ' media="' . esc_attr( $media ) . '"' : '';
$html .= ">\n";
$html .= '<noscript><link rel="stylesheet" href="' . esc_url( $href ) . '"';
$html .= ! empty( $media ) ? ' media="' . esc_attr( $media ) . '"' : '';
$html .= "></noscript>\n";
return $html;
}
/**
* Get featured image URL for preload.
*
* @return string
*/
private function get_featured_image_url() {
if ( ! is_singular() ) {
return '';
}
$post_id = get_queried_object_id();
if ( ! $post_id || ! has_post_thumbnail( $post_id ) ) {
return '';
}
$image = wp_get_attachment_image_src( get_post_thumbnail_id( $post_id ), 'full' );
if ( empty( $image[0] ) ) {
return '';
}
return esc_url_raw( $image[0] );
}
/**
* Get CDN origin from theme mod.
*
* @return string
*/
private function get_theme_cdn_origin() {
$cdn = get_theme_mod( 'rx_theme_cdn_origin', '' );
if ( empty( $cdn ) ) {
return '';
}
$cdn = untrailingslashit( esc_url_raw( $cdn ) );
return $cdn;
}
/**
* Check safe URL.
*
* @param string $url URL.
*
* @return bool
*/
public function is_safe_url( $url ) {
if ( empty( $url ) || ! is_string( $url ) ) {
return false;
}
$url = esc_url_raw( $url );
if ( empty( $url ) ) {
return false;
}
$home_host = wp_parse_url( home_url(), PHP_URL_HOST );
$url_host = wp_parse_url( $url, PHP_URL_HOST );
if ( empty( $home_host ) || empty( $url_host ) || $home_host !== $url_host ) {
return false;
}
$blocked_patterns = array(
'/wp-admin',
'/wp-login.php',
'/cart',
'/checkout',
'/my-account',
'/account',
'/feed',
'/comments',
'add-to-cart=',
'preview=true',
'customize_changeset_uuid=',
'_wpnonce=',
'wc-ajax=',
's=',
);
foreach ( $blocked_patterns as $pattern ) {
if ( false !== stripos( $url, $pattern ) ) {
return false;
}
}
/**
* Filter safe prerender/prefetch URL decision.
*/
return (bool) apply_filters( 'rx_is_safe_prerender_url', true, $url );
}
/**
* Clean document URLs.
*
* @param array $urls URLs.
*
* @return array
*/
private function clean_document_urls( $urls ) {
$clean = array();
foreach ( (array) $urls as $url ) {
if ( is_wp_error( $url ) || empty( $url ) ) {
continue;
}
$url = esc_url_raw( $url );
if ( $this->is_safe_url( $url ) ) {
$clean[] = $url;
}
}
$clean = array_values( array_unique( $clean ) );
return array_slice( $clean, 0, 10 );
}
/**
* Clean URL list.
*
* @param array $urls URLs.
*
* @return array
*/
private function clean_url_list( $urls ) {
$clean = array();
foreach ( (array) $urls as $url ) {
if ( empty( $url ) || ! is_string( $url ) ) {
continue;
}
$url = trim( $url );
if ( 0 === strpos( $url, '//' ) || 0 === strpos( $url, 'https://' ) || 0 === strpos( $url, 'http://' ) ) {
$clean[] = $url;
}
}
return array_values( array_unique( $clean ) );
}
/**
* Clean preload items.
*
* @param array $items Items.
*
* @return array
*/
private function clean_preload_items( $items ) {
$clean = array();
foreach ( (array) $items as $item ) {
if ( empty( $item['href'] ) || empty( $item['as'] ) ) {
continue;
}
$href = esc_url_raw( $item['href'] );
if ( empty( $href ) ) {
continue;
}
$clean[] = array(
'href' => $href,
'as' => sanitize_key( $item['as'] ),
'type' => isset( $item['type'] ) ? sanitize_text_field( $item['type'] ) : '',
'media' => isset( $item['media'] ) ? sanitize_text_field( $item['media'] ) : '',
'crossorigin' => isset( $item['crossorigin'] ) ? sanitize_text_field( $item['crossorigin'] ) : '',
'fetchpriority' => isset( $item['fetchpriority'] ) ? sanitize_text_field( $item['fetchpriority'] ) : '',
);
}
return array_slice( $clean, 0, 20 );
}
/**
* Build HTML attributes.
*
* @param array $attrs Attributes.
*
* @return string
*/
private function build_html_attributes( $attrs ) {
$html = array();
foreach ( $attrs as $key => $value ) {
if ( '' === $value || null === $value || false === $value ) {
continue;
}
$html[] = sprintf(
'%s="%s"',
esc_attr( $key ),
esc_attr( $value )
);
}
return implode( ' ', $html );
}
}
endif;
/**
* Start RX prerender performance module.
*/
function rx_theme_prerender_performance() {
return RX_Theme_Prerender_Performance::instance();
}
rx_theme_prerender_performance();
Now include it in your functions.php:
/**
* RX Theme Performance Files.
*/
$rx_prerender_file = get_template_directory() . '/performance/prerender.php';
if ( file_exists( $rx_prerender_file ) ) {
require_once $rx_prerender_file;
}
Optional: Add your CDN origin
Add this to functions.php or your theme setup file:
add_filter( 'rx_preconnect_urls', function ( $urls ) {
$urls[] = 'https://static-assets-cdnrx.rxharun.com';
return $urls;
} );
add_filter( 'rx_dns_prefetch_urls', function ( $urls ) {
$urls[] = '//static-assets-cdnrx.rxharun.com';
return $urls;
} );
Optional: Add your chunk/app files for preload
add_filter( 'rx_preload_items', function ( $items ) {
$items[] = array(
'href' => 'https://static-assets-cdnrx.rxharun.com/_next/static/chunks/02c3irf6-c0dr.js',
'as' => 'script',
);
$items[] = array(
'href' => 'https://static-assets-cdnrx.rxharun.com/assets/app.css',
'as' => 'style',
);
return $items;
} );
Optional: Defer your RX scripts
add_filter( 'rx_defer_script_handles', function ( $handles ) {
$handles[] = 'rx-app-js';
$handles[] = 'rx-main-js';
$handles[] = 'rx-header-js';
return $handles;
} );
This file is safe because it avoids prerendering sensitive pages like wp-admin, login, cart, checkout, account, search, feed, preview, nonce URLs, and WooCommerce AJAX URLs.