Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

The reliable WordPress method is to enqueue assets with wp_enqueue_style() and wp_enqueue_script() from the hook that matches where they are needed. This lets WordPress, themes and plugins resolve dependencies, control loading order and avoid duplicate or hard-coded tags in templates.

Use the enqueue system instead of hard-coding tags

Do not normally paste <link> or <script> tags into header.php or a template file. Enqueue each file with a unique handle, its URL, dependencies and a version. WordPress then prints the appropriate tags when the page is generated.

Asset Function Typical hook
CSS stylesheet wp_enqueue_style() wp_enqueue_scripts
Classic JavaScript wp_enqueue_script() wp_enqueue_scripts
Admin CSS or JavaScript The same enqueue functions admin_enqueue_scripts
JavaScript module wp_enqueue_script_module() Use the appropriate front-end or admin enqueue flow

Registration and enqueueing are different: wp_register_script() or wp_register_style() records an asset for later use, but registration alone does not put it in the page output.

Enqueue theme CSS and JavaScript

For front-end theme files, attach one callback to wp_enqueue_scripts. The following example assumes the files are stored in assets/css/main.css and assets/js/main.js.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
<?php
function example_theme_assets() {
    wp_enqueue_style(
        'example-theme-main',
        get_theme_file_uri( 'assets/css/main.css' ),
        array(),
        '1.0.0'
    );

    wp_enqueue_script(
        'example-theme-main',
        get_theme_file_uri( 'assets/js/main.js' ),
        array(),
        '1.0.0',
        array( 'in_footer' => true )
    );
}
add_action( 'wp_enqueue_scripts', 'example_theme_assets' );

Replace the handles, paths and version with values for your project. Handles must be unique within the WordPress installation; prefixing them with a theme or company name helps prevent collisions.

Where to put the code

Put theme-specific enqueue code in the theme’s PHP code, commonly functions.php or an included file. A child theme should enqueue its own files from the child theme rather than editing the parent theme. The theme’s style.css remains the required stylesheet containing theme metadata; additional styles should still be managed through the enqueue API.

Add dependencies and preserve order

The third argument is an array of dependency handles. If your script uses WordPress’s registered jQuery handle, for example, declare it instead of loading a second copy:

wp_enqueue_script(
    'example-interactions',
    get_theme_file_uri( 'assets/js/interactions.js' ),
    array( 'jquery' ),
    '1.0.0',
    array( 'in_footer' => true )
);

WordPress uses the dependency graph to determine order. A dependency handle that has not been registered cannot be loaded for the dependent script, so check the handle name and ensure the dependency is available.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Enqueue plugin assets correctly

A plugin should use its own front-end callback and build the URL from the plugin location rather than assuming a theme path.

<?php
function example_plugin_assets() {
    wp_enqueue_style(
        'example-plugin-public',
        plugins_url( 'assets/css/public.css', __FILE__ ),
        array(),
        '1.0.0'
    );

    wp_enqueue_script(
        'example-plugin-public',
        plugins_url( 'assets/js/public.js', __FILE__ ),
        array(),
        '1.0.0',
        array( 'in_footer' => true )
    );
}
add_action( 'wp_enqueue_scripts', 'example_plugin_assets' );

If the plugin file is in a different directory, adjust the path passed to plugins_url() so it resolves to the real asset location. Keep plugin assets separate from theme assets because a plugin can remain active when the site’s theme changes.

Load CSS and JavaScript only in the admin

Use admin_enqueue_scripts for dashboard screens. Its callback receives the current screen hook suffix, which lets you avoid loading files on every admin page.

<?php
function example_plugin_admin_assets( $hook_suffix ) {
    if ( 'settings_page_example-plugin' !== $hook_suffix ) {
        return;
    }

    wp_enqueue_style(
        'example-plugin-admin',
        plugins_url( 'assets/css/admin.css', __FILE__ ),
        array(),
        '1.0.0'
    );

    wp_enqueue_script(
        'example-plugin-admin',
        plugins_url( 'assets/js/admin.js', __FILE__ ),
        array(),
        '1.0.0',
        array( 'in_footer' => true )
    );
}
add_action( 'admin_enqueue_scripts', 'example_plugin_admin_assets' );

Use the actual screen hook for your page. Conditional loading reduces unnecessary requests and prevents admin code from affecting unrelated screens.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Choose a version and cache-busting method

The version argument is appended to the asset URL as a version query value. Set it to your release or build version so browsers can fetch a changed file after deployment. Avoid leaving a changing development timestamp in production unless you deliberately accept a cache miss on every request.

Build systems can provide dependency and version metadata alongside compiled files. Use that generated metadata when available rather than manually maintaining a dependency list that can become stale.

Control script execution with footer, defer and async

Passing array( 'in_footer' => true ) asks WordPress to print a classic script in the footer location. It does not by itself make the script asynchronous.

Since WordPress 6.3, wp_enqueue_script() also accepts a strategy value of defer or async:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
wp_enqueue_script(
    'example-deferred',
    get_theme_file_uri( 'assets/js/deferred.js' ),
    array(),
    '1.0.0',
    array(
        'in_footer' => true,
        'strategy'   => 'defer',
    )
);
Strategy Execution behavior Use when
defer Downloads without blocking parsing, then executes after parsing while preserving document order. The script depends on another script or on the parsed document.
async Executes as soon as downloading finishes; order relative to other asynchronous scripts is not guaranteed. A self-contained script has no ordering requirement.

WordPress evaluates the dependency tree when applying a requested strategy and may choose a more conservative result to protect dependencies. Do not use async for code that must run after another asset or that assumes the DOM is ready.

Use JavaScript modules when the project requires them

For module-based builds, WordPress 6.5 identifies wp_enqueue_script_module() as the preferred module-enqueue function. This is a specialized path; ordinary browser scripts should continue to use wp_enqueue_script(). Confirm that the project’s minimum WordPress version supports the API before adopting it.

Add small inline configuration safely

For a short configuration value or snippet that belongs to an enqueued file, enqueue the file first and attach the inline code to its handle:

wp_enqueue_script(
    'example-app',
    get_theme_file_uri( 'assets/js/app.js' ),
    array(),
    '1.0.0',
    array( 'in_footer' => true )
);

wp_add_inline_script(
    'example-app',
    'window.exampleSettings = ' . wp_json_encode( array(
        'mode' => 'production',
    ) ) . ';',
    'before'
);

Use wp_add_inline_style() for CSS associated with an already enqueued stylesheet:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
wp_enqueue_style(
    'example-theme-main',
    get_theme_file_uri( 'assets/css/main.css' ),
    array(),
    '1.0.0'
);

wp_add_inline_style(
    'example-theme-main',
    '.notice { margin-block: 1rem; }'
);

These helpers keep inline code attached to a declared asset. They are better suited to small, generated or page-specific additions than placing reusable files directly in template output.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Load assets conditionally when their scope is limited

Global assets are appropriate for code used throughout the site. For a page, block or feature used only in some contexts, wrap the enqueue call in a condition such as a page check, post-type check or screen check. Block themes and block-based builds can enqueue block-specific styles selectively, avoiding a site-wide stylesheet for a single block.

Keep the condition next to the enqueue logic and test both the condition’s true and false paths. A misplaced conditional is a common reason for a script appearing on every page or not appearing where it is needed.

Common failures and fixes

  • Nothing appears in the page source: confirm that the callback is attached to the correct hook and that you called an enqueue function, not only a register function.
  • The browser reports a 404: inspect the generated URL and correct the theme or plugin path passed to get_theme_file_uri() or plugins_url().
  • A dependency runs too late or is missing: use the dependency’s registered handle and verify that it is registered before the dependent asset is resolved.
  • Changes do not show: increment the asset version or use the build-generated version so caches recognize the new file.
  • Code breaks after adding async: remove the asynchronous strategy or switch to defer when execution order matters.
  • Admin styles affect the public site: move admin-only code to admin_enqueue_scripts; move public assets to wp_enqueue_scripts.

A practical decision checklist

  1. Identify whether the file belongs to a theme, a plugin, the public front end or an admin screen.
  2. Choose a unique handle and the correct WordPress hook.
  3. Build the URL from the asset’s real theme or plugin location.
  4. Declare every registered dependency and choose a meaningful version.
  5. Decide whether the asset is global, conditional or block-specific.
  6. Use footer placement, defer or async only when its execution behavior matches the code’s requirements.
  7. Attach small inline code with wp_add_inline_script() or wp_add_inline_style() after enqueueing the parent asset.
  8. Test the generated URL, browser console, dependency order and cache behavior in both logged-in and logged-out contexts.

Bottom line

Proper WordPress asset loading means declaring CSS and JavaScript through the enqueue APIs, using the hook that matches the execution context, naming dependencies explicitly and selecting loading strategies deliberately. This approach works with WordPress’s asset manager instead of competing with it, while keeping theme, plugin and admin code maintainable.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.