How to split JS by pages with conditional wp_enqueue_script in WordPress

Contents

Why split JavaScript by pages?

Performance: delivering only the code that a page needs reduces payload, lowers TTFB and time-to-interactive, and reduces render-blocking. Maintainability: smaller modules are easier to reason about and test. Caching and versions: targeted files change less often, so caches stay valid longer.

How WordPress script loading works (quick fundamentals)

  • Use wp_register_script() to register a script handle and path, then wp_enqueue_script() to add it to the page.
  • Hook your enqueue logic into the correct action: wp_enqueue_scripts for frontend, admin_enqueue_scripts for admin, login_enqueue_scripts for the login page, enqueue_block_editor_assets for the block editor.
  • Conditional template tags (is_page, is_single, is_singular, is_post_type_archive, is_page_template, is_front_page, etc.) only work reliably after the main query is set — i.e. inside the wp_enqueue_scripts hook (or later).
  • Provide dependencies (array) and a version number to avoid broken ordering and caching issues. Use filemtime() for automatic cache-busting during development.
  • Use the in_footer argument to avoid render-blocking where possible (set true to print before lt/bodygt).

General pattern: register once, enqueue conditionally

The simplest and safest pattern: register all scripts (or at least the common/global ones), then call wp_enqueue_script() only when the conditions match a given page or context.

Basic example: register and conditionally enqueue by slug, template, CPT


Common page conditions and examples

Condition When to use
is_page( slug_or_id ) Specific static pages by slug or ID
is_page_template( template.php ) When pages use a particular page template
is_singular( cpt ) Single post of a custom post type
is_post_type_archive( cpt ) Archive page for a CPT
is_front_page() / is_home() Homepage or posts page
is_category() / is_tag() / is_tax() Taxonomy archive pages
is_search() / is_404() Search or 404 pages

Example: conditionals for taxonomy, archives, and search


Admin, login, block editor and customizer contexts

  • Admin: use admin_enqueue_scripts and check hook to limit to particular screens.
  • Block editor: use enqueue_block_editor_assets for editor-only scripts (blocks), or enqueue_block_assets for both editor frontend blocks.
  • Customizer: use customize_controls_enqueue_scripts and customize_preview_init appropriately.
  • Login page: use login_enqueue_scripts for custom login page assets.

Admin example: load only on a plugin settings page


Advanced: asset manifests and hashed/compiled builds

Modern build tools (Webpack, Vite, Rollup) produce hashed filenames. Keep a simple manifest.json and a PHP helper to map logical names to hashed filenames. This ensures you can change chunk names without changing PHP code.

Sample manifest helper and usage


Client-side dynamic imports vs server-side conditional enqueuing

Server-side conditional enqueuing is the canonical approach for WordPress: only output ltscriptgt tags for the pages that need them. However, you can combine that with client-side dynamic imports for even finer-grained lazy-loading inside a page (e.g., loading a heavy modal or chart library only when a user interacts).

Example: JS dynamic import for an on-demand feature

// This script can be enqueued on pages that MIGHT open a modal.
// Actual heavy modal code is dynamically loaded only on interaction.
document.querySelectorAll([data-open-modal]).forEach(btn => {
  btn.addEventListener(click, function () {
    import(./modal.js).then(module => {
      module.openModal()
    }).catch(err => {
      console.error(Failed to load modal:, err)
    })
  })
})

Adding async or defer attributes

WordPress provides helpers to flag scripts as async or defer. Use wp_script_add_data() after registering or enqueuing.


Passing server values to conditional scripts

Use wp_localize_script() or wp_add_inline_script() to pass configuration or URLs to your JS modules (ajax url, nonce, localized strings). Always attach localization to the script handle that will be enqueued conditionally.

 admin_url( admin-ajax.php ),
        nonce   => wp_create_nonce( contact_nonce ),
        strings => array( submit => __( Send message, mytheme ) ),
    ) )
}
?>

Tips, gotchas and best practices (exhaustive)

  • Hook timing: use wp_enqueue_scripts. Conditional template tags will not work if you hook too early (e.g., plugins_loaded or init without a global query).
  • Check admin vs frontend: avoid loading frontend scripts in admin and vice versa. Use is_admin() and proper enqueue action hooks.
  • Use filemtime() for development: automatic cache-busting while editing. For production hashed filenames or build manifests are better.
  • Use dependencies: ensure ordering by listing handles your script needs WordPress will print them in the proper order.
  • Load in footer: pass true to wp_enqueue_script to reduce render-blocking.
  • Avoid printing too many small files: splitting is good but creating dozens of tiny requests can be counterproductive. Balance splitting and HTTP overhead (HTTP/2 mitigates this).
  • Be careful with jQuery: dont deregister core jQuery unless you understand consequences many plugins rely on it.
  • Use wp_script_add_data to add defer or async where appropriate.
  • Dont use conditional tags in plugins hooked on init to decide frontend enqueueing: use wp_enqueue_scripts or template_redirect for accurate conditions.
  • Test plugin/theme interactions: other plugins may expect global scripts document dependencies or include safe fallbacks.
  • Security: always pass nonces for AJAX endpoints and escape/sanitize any data passed to script output.
  • Editor vs frontend: block editor assets must be enqueued via enqueue_block_editor_assets (or enqueue_block_assets), not wp_enqueue_scripts.

Real-world progressive strategy (step-by-step)

  1. Audit current pages and identify heavy scripts and features used per page type.
  2. Group JavaScript into logical bundles: global/common, page-specific, component-specific (modal, charts), editor/admin.
  3. Update functions.php or plugin code: register global bundle and register page/component bundles.
  4. Use conditional checks in wp_enqueue_scripts and admin_enqueue_scripts to enqueue only the bundles needed for each context.
  5. Introduce filemtime() or a manifest for build outputs to handle versioning.
  6. Test on staging with tools (Lighthouse) and check network tab for unwanted files being loaded.
  7. Consider client-side dynamic imports for very rarely used, large modules to further shave initial payload.
  8. Monitor and iterate based on real user metrics (RUM) or analytics for perceived performance improvements.

Example: comprehensive functions.php snippet tying multiple concepts together

 admin_url( admin-ajax.php ),
            nonce => wp_create_nonce( contact ),
        ) )

        wp_script_add_data( theme-contact, defer, true )
    }

    // Product pages: single product
    if ( is_singular( product ) ) {
        wp_enqueue_script( theme-product, mytheme_asset_manifest_path( product.js ), array( theme-base ), null, true )
    }

    // Events archive - maybe needs maps
    if ( is_post_type_archive( events ) ) {
        wp_enqueue_script( events-archive, mytheme_asset_manifest_path( events.js ), array( theme-base ), null, true )
    }
}
add_action( wp_enqueue_scripts, mytheme_register_and_conditional_enqueue )
?>

Debugging tips

  • Check the page source (view-source) for generated ltscriptgt tags and verify paths/versions.
  • Open the network panel and filter by JS to see loaded chunks and their sizes and initiation types (defer/async).
  • If a conditional branch isnt firing, ensure your hook is attached at an appropriate time — template tags rely on the query.
  • Enable SCRIPT_DEBUG in wp-config.php to avoid minified builds when debugging: define( SCRIPT_DEBUG, true )
  • Look for 404s in the network tab — wrong get_template_directory_uri() vs get_stylesheet_directory_uri() mistakes are common.

Checklist before shipping

  • All page-specific scripts are enqueued only on pages that need them.
  • Common dependencies are properly registered and not duplicated by plugins.
  • Versioning is handled (hashed filenames or filemtime during deploy process).
  • Scripts are loaded in footer or marked defer/async where safe.
  • Localization and nonces are passed only to scripts that need them.
  • Editor/admin pages are not loading unnecessary frontend bundles.

Useful links

Final note

Splitting JS by pages in WordPress is a combination of careful registration, correct use of conditional template tags inside the proper hooks, and a build/distribution strategy (filemtime or manifest) for versioning. Follow the patterns above, test thoroughly across pages and devices, and iterate — usually a few targeted splits produce the most worthwhile performance wins without overcomplicating the asset pipeline.



Acepto donaciones de BAT's mediante el navegador Brave 🙂



Leave a Reply

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