How to use rel=preload for critical scripts from PHP in WordPress

Contents

Overview — Why rel=preload for critical scripts in WordPress

rel=preload is an early-fetch hint that tells the browser to start fetching a resource (CSS, fonts, scripts, etc.) as soon as possible, before the browser discovers it in the normal document flow. For critical JavaScript that you need available earlier than normal discovery allows (for example, above-the-fold feature controls, inline bootstrapping, or critical third-party scripts), preloading can reduce the time-to-execute and improve perceived performance.

In WordPress you must still output the ltscriptgt tag (or enqueue the script) to execute the script. Preload only starts the fetch it does not run the script. A correct setup ensures the browser fetches the script early (preload) and then reuses that downloaded resource when the normal ltscript src=…gt is parsed or injected.

Important concepts and rules

  • as=script — always include as=script on the preload link. If as doesnt match the resource type, the browser may ignore the preload or treat it differently.
  • Keep the script tag — preload is a fetch hint the script must still be present for execution (unless you programmatically inject one client‑side, but that is still a script tag in the end).
  • crossorigin and integrity — if your script uses CORS (cross-origin) or SRI (integrity), include matching crossorigin and integrity on the preload link as well.
  • Order execution — preloading does not change execution order by itself. If you rely on execution order among scripts, do not use async prefer defer or normal script tags and use preload purely to accelerate fetch.
  • Compatibility — rel=preload is widely supported by modern browsers. Older browsers ignore it harmlessly. Always keep the script tag as a fallback.
  • Avoid double-download pitfalls — most modern browsers avoid double downloads when a preload and subsequent script tag reference the exact same URL and attributes (same CORS/integrity). Mismatches in URL, query strings, or CORS settings can cause duplicate fetches.

Where to add preloads in WordPress

There are commonly two places to add preload hints in WordPress:

  1. Output ltlink rel=preload …gt tags in the head (commonly via the wp_head action).
  2. Send HTTP Link headers (rel=preload) from PHP on the server response (via send_headers action or server config). Browsers accept Link headers as preload hints too.

Which is preferable?

Either method is valid. HTTP Link headers can be preferred because they are seen earlier (before HTML parsing) which can improve effectiveness slightly, but adding link tags to the head is simple and reliable within themes/plugins and works well for most sites.

Basic strategy patterns

  • Enqueue the script through WordPress as normal for proper dependency handling and versioning.
  • Emit a matching ltlink rel=preload as=script href=…gt in the document head while ensuring the URL, crossorigin and integrity values match the script tag.
  • Optionally add defer on the script tag preload will have already fetched it so execution will happen quickly at the right time.

Common pitfalls to avoid

  • Using preload with an incorrect as type (for instance forgetting as=script).
  • Mismatched URLs (for example, adding a version query on the script tag but not on the preload link) — leads to duplicate fetches.
  • Missing or mismatched crossorigin/integrity attributes — may force a second fetch or fail SRI checks.
  • Preloading everything — preload should be reserved for a very small set of truly critical resources.

Practical WordPress examples

Below are several complete examples you can drop into a themes functions.php or a plugin file. Each example follows best-practice: enqueue the script normally and add a matching preload link in the head. Use conditional checks to limit preloads to only the pages you need.

1) Minimal example — preload a theme script

This demonstrates enqueueing a script and outputting a corresponding preload link in the head. The code uses WordPress globals to read the registered script information and prints a safe preload link. It ensures the URL includes versioning if provided so the browser sees the exact same resource URL.

registered[ handle ] ) ) {
        return
    }

    script = wp_scripts->registered[ handle ]
    src = script->src
    ver = script->ver

    // Ensure full URL if WordPress stored relative src
    if ( strpos( src, :// ) === false  substr( src, 0, 1 ) === / ) {
        src = site_url( src )
    } elseif ( strpos( src, :// ) === false ) {
        src = site_url( / . ltrim( src, / ) )
    }

    // Append version query string if present and not already in URL
    if ( ver  false === strpos( src, ver= ) ) {
        src = add_query_arg( ver, ver, src )
    }

    // Output preload link. Use esc_url for safety.
    echo n
}
?>

2) Preload a third-party CDN script with SRI and crossorigin

If you load a CDN script with Subresource Integrity (SRI) and CORS, the preload link should include the same integrity and crossorigin attributes so the browser can reuse the fetch for the script tag without a separate request.

n
}

// Add the integrity and crossorigin attributes to the script tag when WordPress prints it
add_filter( script_loader_tag, plugin_add_sri_and_crossorigin, 10, 3 )
function plugin_add_sri_and_crossorigin( tag, handle, src ) {
    if ( thirdparty-lib === handle ) {
        integrity = sha384-abc123...
        crossorigin = anonymous
        // Rebuild the script tag with matching attributes
        tag = n
    }
    return tag
}
?>

3) Use defer preload — fetch early, execute later but keep order

Common pattern: preload a critical script, but keep it defer so execution happens after parsing while preserving relative order with other deferred scripts. Preload ensures the file is already fetched when the parser reaches the deferred script tag so execution is quick and synchronous order among deferred scripts is still preserved.

registered[ handle ] ) ) {
        return
    }
    src = wp_scripts->registered[ handle ]->src
    ver = wp_scripts->registered[ handle ]->ver
    if ( ver  false === strpos( src, ver= ) ) {
        src = add_query_arg( ver, ver, src )
    }
    echo n
}

// Add defer attribute to the script tag when WordPress prints it
add_filter( script_loader_tag, deferred_add_attribute, 10, 3 )
function deferred_add_attribute( tag, handle, src ) {
    if ( critical-deferred === handle ) {
        return n
    }
    return tag
}
?>

4) Using HTTP Link header preload (server-side header)

Preload via an HTTP Link header can be emitted very early. Here is an example that sends a header for a critical script on singular posts. Be careful: headers must be sent before output begins, and close attention is required when using caching layers or CDNs.

 rel=preload as=script )
    }
}
?>

Advanced topics and nuances

Match attributes exactly

If your script tag includes crossorigin or integrity, add the exact same attributes to the preload link. Browsers treat these attributes as part of the fetch identity mismatches can lead to duplicate fetches.

Absolute vs relative URLs

Preload links can be relative or absolute. Make sure the preload link URL exactly matches the script URL the browser will request. A difference as small as a trailing slash, different domain alias, or missing query string can negate the reuse.

Modules (type=module)

For ES modules, the link still uses as=script but the script tag should be type=module. Example:



When enqueuing module scripts in WordPress you need to add the type attribute to the script tag using the script_loader_tag filter (or print a manual script tag). Preload the same URL the script will use.

When preload might not help

  • If the script is not discovered until very late (for instance printed by JavaScript after load) the preload may not start early enough to matter.
  • If you preload many large resources you may hurt performance by competing with more critical downloads (HTML, fonts, above-the-fold CSS).
  • On some HTTP/2 servers a preload link and a subsequent script tag with different attributes could result in two HTTP/2 streams and potential duplication — attribute matching avoids this.

Troubleshooting checklist

  1. Verify both the preload link and the script tag point to the exact same final URL (including query string/version).
  2. Ensure as=script is present on the preload link.
  3. If using SRI, add integrity and crossorigin to both preload link and script tag.
  4. Use browser devtools Network tab to look for duplicate downloads.
  5. Test with Lighthouse or WebPageTest to see improvements (or regressions).

Testing and metrics

To measure the effect of preloading critical scripts, use:

  • Lighthouse (measure overall performance score and script impact)
  • WebPageTest (waterfall view shows when the browser fetched and executed the script)
  • Chrome DevTools Network panel — confirm that the preload request is issued early and the subsequent script uses the cached response (or does not re-download).

Security and maintenance notes

  • Keep preloads minimal — only for scripts truly needed early.
  • Keep SRI values updated when you update script contents.
  • If your site uses caching layers or a CDN, ensure the link header/preload URL is reachable and stable from the public edge.
  • Regularly audit preloaded resources with performance tools to ensure they still provide benefit as the site evolves.

Summary — best practice checklist

  1. Enqueue scripts via wp_enqueue_script for proper dependency and version handling.
  2. Add a matching ltlink rel=preload as=script href=…/gt in the head early (wp_head with priority 1 is a good place).
  3. Make sure the URLs and attributes (crossorigin, integrity) match exactly to avoid duplicate downloads.
  4. Prefer preload only for a small set of truly critical scripts measure with Lighthouse / WebPageTest.
  5. Consider sending Link headers when you need preload hints earlier than HTML parsing.


Acepto donaciones de BAT's mediante el navegador Brave 🙂



Leave a Reply

Your email address will not be published. Required fields are marked *