Skip to the content.

WordPress Assets

WordPress provides registration and enqueue APIs to load JavaScript and CSS that allow programatic and conditional interaction with static assets.

These APIs allow for dependency management, version-based busting of browser-cached assets and hooks for printing data from PHP for JavaScript to read from the global window object.

Never directly enqueue assets

*with the exception of scripts where the source is extra-sensitive or local development assets that should be wrapped in conditional logic such that they’re not registered in production environments.

Never directly call wp_enqueue_script() or wp_enqueue_style() without first using wp_register_script() or wp_register_style() – this allows for programmatic override and substitution by other codebases.

Registering globally even when enqueues are conditionally-scoped helps detect and prevents race conditions of assets sharing the same handle in our products or third-party developers trying to debug their products while ours are running.

Break each parameter for wp_register_script() and wp_register_style() onto new lines

Benefits:

// ❌ Don't put every parameter on a single line
\wp_register_script( 'web-admin-widget', WEB_BUILD_URL . '/index.js', apply_filters('nfd_web_admin_widget_dependencies', array('wp-element', 'wp-components', 'wp-dom-ready', 'wp-data')), $version, true );

// ✅ Break each onto a new line
$dependencies = apply_filters('nfd_web_admin_widget_dependencies', array('wp-element', 'wp-components', 'wp-dom-ready', 'wp-data'));

\wp_register_script( 
    'web-admin-widget', 
    WEB_BUILD_URL . '/index.js', 
    $dependencies, 
    $version, 
    true 
);

Naming dependency handle slugs

Supply WordPress filter hooks for dependency assets

For the array of dependencies provided to registration functions, please wrap all arrays – even empty ones – with apply_filters() and a snake-case equivalent of the kebab-case slug and a postfix of _dependencies – this allows other codebases to extend dependencies that get loaded with an asset (i.e. a brand-specific stylesheet whenever a brand-agnostic module asset is loaded)

First preference is given to 3rd-party vendor assets shipped in WordPress Core

In general, we prefer the use of assets that ship with WordPress instead of bundling other equivalents to reduce cumulative disk space and leverage assets already browser-cached by users.

Use environment-aware asset loading and configuration

Using wp_get_environment_type() to scope registrations and enqueue declarations for local, staging and production. Passing the value of wp_get_environment_type() through to scripts during runtime is also a great way to use one value across PHP and JavaScript.

Examples

Beware bundled dependencies in other codebases

WordPress does little to prevent the collision of assets. Please prefix third-party vendor code with nfd to avoid conflicts.

Instead of react-router-dom, use nfd-react-router-dom.

Provide a version string for caching

All mission-critical assets should be tied to the codebase’s semver version, busting on every release.

Vendor code and more static assets can be locked to a specific version.

Note: the use of filetime() is not considered a reliable way to cache-bust assets.

Pass data to script at runtime

In addition to making API calls in JavaScript, it’s easy to pass data directly into the DOM for a script to take advantage of. Sometimes a new API endpoint is overkill, it’s undesirable to have a public endpoint for a sensitive operation or you want the response to an endpoint available immediately.

WordPress uses wp_add_inline_script to print inline scripts before or after the <script> tag for an enqueued asset.

wp_add_inline_script(
    'web-admin-widget',
    'console.log("web-admin-widget is running", window.web)',
    'before'
);

However, this is a great opportunity to pass data through to the application.

wp_add_inline_script(
    'web-admin-widget',
    'var Newfold =' . wp_json_encode( array( 'adminUrl' => admin_url(), 'userId' => get_current_user_id() ) ) . ';';
    'before'
);

Finally, this is a good time to point out that you can interact with Core and Custom REST Endpoints in PHP.

$request    = new WP_REST_Request( 'GET', '/web/v1/widget' );
$response   = rest_do_request( $request );
$server     = rest_get_server();
$data       = $server->response_to_data( $response, false );
wp_add_inline_script(
    'web-admin-widget',
    'var Newfold.apiResponse =' . wp_json_encode( $data ) . ';';
    'before'
);

Conditional checks and debugging

wp_script_is() and wp_style_is() are great for scoping logic and local development debugging for checking for registration or whether an asset is enqueued.

Query Monitor also lists actions firing where scripts and styles are enqueued, but also a complete reference of enqueued scripts and styles, their dependencies and the origin codebase where it was enqueued.