Opens in a new tab
  1. Home
  2. Guides
  3. System
System guide

wp_enqueue_scripts explained

Learn how WordPress uses wp_enqueue_scripts to manage JavaScript and CSS, including handles, dependencies, versions, loading strategies, conditional assets and frontend performance.

  • Updated September 2, 2026
  • 22 min read
  • WordPress guide

wp_enqueue_scripts is the main WordPress action hook used to load JavaScript and CSS assets on the public-facing frontend of a website.

Instead of manually inserting <script> and <link> tags into theme templates, WordPress provides a dependency-aware asset system built around functions such as:

  • wp_enqueue_script();
  • wp_enqueue_style();
  • wp_register_script();
  • wp_register_style().

The typical pattern is:

add_action(
    'wp_enqueue_scripts',
    'mytheme_enqueue_assets'
);

function mytheme_enqueue_assets() {

    wp_enqueue_style(
        'mytheme-style',
        get_stylesheet_uri()
    );

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

This looks simple, but WordPress’s asset-loading system solves several important problems at once:

  • preventing unnecessary duplicate assets;
  • managing JavaScript dependencies;
  • controlling load order;
  • adding versions for cache busting;
  • deciding whether scripts appear in the document head or footer;
  • supporting modern loading strategies such as defer and async;
  • allowing themes and plugins to interact with the same dependency system;
  • conditionally loading assets only where they are needed.

This guide explains how wp_enqueue_scripts works, how it differs from wp_enqueue_script(), how handles and dependencies work, how to load CSS and JavaScript correctly, and how to build a maintainable WordPress frontend asset architecture.

What is wp_enqueue_scripts?

wp_enqueue_scripts is an action hook.

It is not the function that actually prints a JavaScript file.

That distinction is important.

The hook

wp_enqueue_scripts

provides a point in the WordPress frontend lifecycle where themes and plugins can register or enqueue assets.

The functions

wp_enqueue_script()
wp_enqueue_style()

tell WordPress which individual JavaScript or CSS resources should be loaded.

The relationship is:

WordPress reaches
wp_enqueue_scripts
↓
your callback runs
↓
callback calls
wp_enqueue_script()
and/or
wp_enqueue_style()
↓
WordPress records assets
↓
assets are printed later

The official wp_enqueue_scripts documentation describes it as the proper hook for enqueueing scripts and styles that should appear on the frontend.

Why WordPress uses an enqueue system

A basic HTML website could load JavaScript directly:

<script src="/assets/app.js"></script>

and CSS with:

<link
    rel="stylesheet"
    href="/assets/style.css"
>

WordPress websites are different because multiple independent components may need assets at the same time.

A single page can involve:

  • WordPress Core;
  • the active theme;
  • a child theme;
  • several plugins;
  • blocks;
  • widgets;
  • third-party libraries.

If every component manually inserted its own tags, coordination would become difficult.

For example:

Theme
→ loads library.js

Plugin A
→ loads library.js

Plugin B
→ loads another library.js

Now the browser may receive multiple copies of the same dependency.

The enqueue system provides a shared registry so WordPress can reason about resources by their handles and dependencies.

A basic wp_enqueue_scripts example

A standard theme implementation might look like this:

function mytheme_enqueue_assets() {

    wp_enqueue_style(
        'mytheme-style',
        get_stylesheet_uri(),
        array(),
        '1.0.0'
    );

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

add_action(
    'wp_enqueue_scripts',
    'mytheme_enqueue_assets'
);

What happens here?

First:

add_action()

connects:

mytheme_enqueue_assets()

to:

wp_enqueue_scripts

When WordPress reaches that action, the callback executes.

The callback then asks WordPress to load:

mytheme-style
+
mytheme-app

Understanding wp_enqueue_script()

The current wp_enqueue_script() documentation defines the function approximately as:

wp_enqueue_script(
    $handle,
    $src,
    $deps,
    $ver,
    $args
);

Each parameter has a separate purpose.

$handle

The handle is WordPress’s internal identifier for the script.

'mytheme-app'

Handles are central to the dependency system.

They let other code refer to the script without needing to know its URL.

$src

The source is the JavaScript URL.

get_theme_file_uri(
    '/assets/js/app.js'
)

It can also be a full external URL where appropriate.

$deps

The dependencies array contains handles of scripts that must be available before this script.

array(
    'jquery'
)

means:

my script
depends on
jQuery

$ver

The version is commonly used for cache busting.

'1.2.0'

can result in a URL similar to:

app.js?ver=1.2.0

$args

Modern WordPress supports an arguments array that can control properties including:

in_footer
strategy

For example:

array(
    'in_footer' => true,
    'strategy'  => 'defer',
)

What is a script handle?

A handle is not a filename.

It is a unique logical identifier.

For example:

wp_enqueue_script(
    'mytheme-slider',
    get_theme_file_uri(
        '/assets/js/slider.js'
    )
);

The handle is:

mytheme-slider

The filename is:

slider.js

Why handles matter

Other scripts can declare:

array(
    'mytheme-slider'
)

as a dependency.

Plugins can also check whether an asset is:

  • registered;
  • enqueued;
  • already printed.

Use descriptive unique handles

Prefer:

theonewp-gsap
mytheme-navigation
myplugin-gallery

over extremely generic handles such as:

script
main
custom

Prefixing handles reduces collisions between unrelated themes and plugins.

How JavaScript dependencies work

Suppose your animation file requires GSAP.

You can register GSAP:

wp_enqueue_script(
    'mytheme-gsap',
    get_theme_file_uri(
        '/assets/js/gsap.min.js'
    ),
    array(),
    '3.13.0',
    array(
        'in_footer' => true,
    )
);

Then enqueue your own script:

wp_enqueue_script(
    'mytheme-animations',
    get_theme_file_uri(
        '/assets/js/animations.js'
    ),
    array(
        'mytheme-gsap'
    ),
    '1.0.0',
    array(
        'in_footer' => true,
    )
);

The dependency graph becomes:

mytheme-gsap
↓
mytheme-animations

WordPress knows that:

animations.js

must not be executed before its required GSAP dependency.

This exact pattern is useful when integrating libraries such as GSAP. See GSAP in WordPress: getting started for a complete implementation.

Dependencies can have dependencies

Suppose:

app
depends on
slider

slider
depends on
utility

The dependency graph becomes:

utility
↓
slider
↓
app

WordPress’s script dependency manager can resolve the order from the registered handles.

wp_enqueue_script() vs wp_register_script()

These functions are closely related but not identical.

wp_register_script()

The official wp_register_script() documentation describes it as registering a script so it can be enqueued later.

Example:

wp_register_script(
    'my-library',
    get_theme_file_uri(
        '/assets/js/library.js'
    ),
    array(),
    '2.0.0',
    array(
        'in_footer' => true,
    )
);

This makes WordPress aware of the resource.

It does not necessarily mean it will be printed on the page.

Then enqueue it

wp_enqueue_script(
    'my-library'
);

wp_enqueue_script() can register and enqueue at the same time

This:

wp_enqueue_script(
    'my-library',
    get_theme_file_uri(
        '/assets/js/library.js'
    ),
    array(),
    '2.0.0',
    array(
        'in_footer' => true,
    )
);

does both operations in one call when the script has not already been registered.

When separate registration is useful

Separate registration can help when:

  • several components may need the same library;
  • you want centralized dependency definitions;
  • the script should be conditionally enqueued later;
  • other plugins or modules need to reference the handle.

Loading CSS with wp_enqueue_style()

The same general architecture applies to stylesheets.

A typical example:

wp_enqueue_style(
    'mytheme-main',
    get_theme_file_uri(
        '/assets/css/main.css'
    ),
    array(),
    '1.0.0'
);

Style dependencies also exist

Suppose:

components.css

expects variables or base rules from:

base.css

You can write:

wp_enqueue_style(
    'mytheme-base',
    get_theme_file_uri(
        '/assets/css/base.css'
    ),
    array(),
    '1.0.0'
);

wp_enqueue_style(
    'mytheme-components',
    get_theme_file_uri(
        '/assets/css/components.css'
    ),
    array(
        'mytheme-base'
    ),
    '1.0.0'
);

The resulting relationship is:

base.css
↓
components.css

Versioning and cache busting

The version argument is more important than it may initially appear.

Browsers and CDNs cache static files.

Suppose visitors already have:

app.js?ver=1.0.0

cached.

You deploy new JavaScript but leave the URL unchanged.

Some visitors may continue receiving the old version until their cache expires or revalidates.

Change the version when the file changes

'1.0.0'

becomes:

'1.1.0'

and the URL can become:

app.js?ver=1.1.0

This gives the resource a different cache identity.

Using file modification time

During active development, developers sometimes use:

filemtime()

to automatically derive the version from the file’s modification timestamp.

For example:

$path = get_theme_file_path(
    '/assets/js/app.js'
);

wp_enqueue_script(
    'mytheme-app',
    get_theme_file_uri(
        '/assets/js/app.js'
    ),
    array(),
    filemtime( $path ),
    array(
        'in_footer' => true,
    )
);

Every file modification produces a different version value.

Use filemtime() carefully

The file path must exist locally.

A safer production implementation checks first:

$path = get_theme_file_path(
    '/assets/js/app.js'
);

$version = file_exists( $path )
    ? filemtime( $path )
    : '1.0.0';

For the broader relationship between asset URLs, cache headers and CDN caching, see CDN vs. self-hosted assets in WordPress.

Loading scripts in the footer

Historically, the final argument of wp_enqueue_script() was commonly a boolean:

true

meaning:

print this script
in the footer

Modern WordPress also supports the clearer arguments-array syntax:

array(
    'in_footer' => true,
)

Example

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

Why footer placement can help

A blocking JavaScript file placed high in the document can interfere with HTML parsing while the browser downloads and executes it.

Moving non-critical scripts later can reduce the amount of work required before the document becomes visible and usable.

However, footer placement and deferred loading are related but separate concepts.

Using defer and async in modern WordPress

Since WordPress 6.3, the Scripts API supports loading strategies directly.

The supported strategies include:

  • defer;
  • async.

If no strategy is supplied, the script uses the normal blocking behavior appropriate to its placement.

Using defer

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

A deferred script downloads without blocking HTML parsing and executes after the document has been parsed.

Deferred scripts preserve execution order relative to other deferred scripts.

Using async

wp_enqueue_script(
    'analytics-example',
    'https://example.com/analytics.js',
    array(),
    '1.0.0',
    array(
        'strategy' => 'async',
    )
);

An asynchronous script executes as soon as its download finishes.

Execution order between independent async scripts is not guaranteed.

defer is usually easier for dependency chains

Suppose:

library.js
↓
plugin.js
↓
app.js

The application expects a strict execution order.

defer is generally easier to reason about for this type of chain.

async is more appropriate for genuinely independent scripts that do not need a predictable position in an execution sequence.

WordPress calculates an eligible loading strategy

An important detail is that the strategy you request is an intended strategy.

WordPress’s Scripts API analyzes dependencies and dependents before determining what can safely be printed.

For example:

library
↓
app

If changing the library to asynchronous execution would break the dependency relationship, WordPress should not blindly output a configuration that destroys execution order.

The current Core implementation accounts for the dependency tree when calculating the eligible strategy.

This is why the native API is preferable to manually filtering script tags

Older WordPress implementations often used:

script_loader_tag

to manually insert:

defer

or:

async

into generated HTML.

That can still be useful for specialized cases, but for standard loading strategies the native Scripts API has a significant advantage:

WordPress knows
the dependency graph

A string replacement on a generated script tag does not.

Conditional asset loading

One of the most useful features of wp_enqueue_scripts is the ability to decide whether an asset is needed before enqueueing it.

Suppose a slider library is used only on the homepage.

Do not automatically load it on:

  • every blog post;
  • every archive;
  • every search page;
  • every WooCommerce page;
  • every static page.

Homepage example

function mytheme_enqueue_assets() {

    if ( ! is_front_page() ) {
        return;
    }

    wp_enqueue_script(
        'mytheme-home',
        get_theme_file_uri(
            '/assets/js/home.js'
        ),
        array(),
        '1.0.0',
        array(
            'in_footer' => true,
        )
    );
}

add_action(
    'wp_enqueue_scripts',
    'mytheme_enqueue_assets'
);

Other useful conditional functions

Depending on the project, you can use:

is_front_page()
is_home()
is_page()
is_single()
is_singular()
is_archive()
is_category()
is_search()
is_404()
is_page_template()

Example for a specific page template

if (
    is_page_template(
        'templates/landing.php'
    )
) {

    wp_enqueue_script(
        'mytheme-landing',
        get_theme_file_uri(
            '/assets/js/landing.js'
        ),
        array(),
        '1.0.0',
        array(
            'in_footer' => true,
        )
    );
}

This can substantially reduce unnecessary frontend JavaScript.

Loading an asset only when a dependency is actually needed

Another useful architecture is:

register globally
↓
enqueue conditionally

Register first

function mytheme_register_assets() {

    wp_register_script(
        'mytheme-gallery',
        get_theme_file_uri(
            '/assets/js/gallery.js'
        ),
        array(),
        '1.0.0',
        array(
            'in_footer' => true,
        )
    );
}

add_action(
    'wp_enqueue_scripts',
    'mytheme_register_assets'
);

Then enqueue where needed

if ( is_page( 'portfolio' ) ) {
    wp_enqueue_script(
        'mytheme-gallery'
    );
}

This pattern is useful when a shared library may be requested by several separate components.

Frontend, admin and editor hooks are not the same

wp_enqueue_scripts is primarily for the frontend.

WordPress exposes different hooks for different application surfaces.

Frontend

wp_enqueue_scripts

Use for public-facing theme and plugin assets.

WordPress admin

admin_enqueue_scripts

Use when loading assets in wp-admin.

Block editor interface

Editor-related assets can involve hooks such as:

enqueue_block_editor_assets

and:

enqueue_block_assets

depending on whether the asset belongs to the editor interface or block content.

This distinction matters particularly in modern versions of the Block Editor. See WordPress block editor CSS, explained for the dedicated architecture.

Do not use admin_enqueue_scripts for the frontend

This:

add_action(
    'admin_enqueue_scripts',
    'my_frontend_script'
);

does not mean:

load script for administrators
on the public site

It means:

load script inside
WordPress administration screens

User role and application surface are separate concepts.

How jQuery dependencies work

WordPress registers a number of scripts internally, including jQuery-related handles.

If your script requires WordPress’s registered jQuery dependency, declare:

array(
    'jquery'
)

Example

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

You generally do not need to manually include another jQuery file simply because your script needs jQuery.

Avoid loading duplicate library copies

A page that contains:

WordPress jQuery
+
theme jQuery
+
CDN jQuery

has unnecessary duplication and greater potential for compatibility problems.

The same principle applies to many other shared frontend libraries.

Local vs external script URLs

wp_enqueue_script() can load both local and remote assets.

Local theme asset

wp_enqueue_script(
    'mytheme-app',
    get_theme_file_uri(
        '/assets/js/app.js'
    )
);

Remote asset

wp_enqueue_script(
    'external-library',
    'https://cdn.example.com/library.js',
    array(),
    '2.0.0'
);

The enqueue API does not decide whether a public CDN is the right architecture.

That is a separate decision involving:

  • privacy;
  • availability;
  • performance;
  • version control;
  • licensing;
  • deployment requirements.

See CDN vs. self-hosted assets in WordPress for that comparison.

Passing PHP data to JavaScript

Sometimes JavaScript needs information generated by WordPress or PHP.

Examples include:

  • REST API URLs;
  • nonce values;
  • plugin settings;
  • localized strings;
  • dynamic configuration.

Do not create an entirely separate global inline script manually when WordPress already provides APIs for attaching data to registered scripts.

wp_localize_script()

The function is historically associated with localization but is also commonly encountered when passing structured PHP data to JavaScript.

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

wp_localize_script(
    'mytheme-app',
    'MyThemeData',
    array(
        'restUrl' => rest_url(),
    )
);

JavaScript can then access:

MyThemeData.restUrl

Use the most appropriate API for arbitrary data

wp_localize_script() was designed primarily for localization data.

For arbitrary JavaScript initialization or configuration, WordPress also provides tools such as:

wp_add_inline_script()

depending on the use case.

Adding inline JavaScript correctly

You can attach inline JavaScript to a registered or enqueued script handle.

Example:

wp_add_inline_script(
    'mytheme-app',
    'window.myThemeReady = true;',
    'before'
);

or:

wp_add_inline_script(
    'mytheme-app',
    'console.log("Loaded");',
    'after'
);

Why attaching inline code to a handle is useful

WordPress understands the relationship:

inline configuration
↓
mytheme-app

instead of having unrelated JavaScript scattered throughout PHP templates.

Inline scripts can also affect which script loading strategies are safe, which is another reason to let the Scripts API manage the relationship.

Adding inline CSS

WordPress provides the equivalent concept for styles:

wp_add_inline_style()

For example:

wp_enqueue_style(
    'mytheme-style',
    get_stylesheet_uri()
);

wp_add_inline_style(
    'mytheme-style',
    '.site-header { background: #111; }'
);

The inline CSS is associated with the registered stylesheet handle.

Loading only one copy of an asset

Handles help WordPress avoid printing the same registered resource repeatedly.

For example, if several pieces of code call:

wp_enqueue_script(
    'my-library'
);

WordPress can treat them as requests for the same registered dependency rather than blindly printing identical script tags each time.

This depends on shared handles

If Plugin A registers:

library-a

and Plugin B independently registers the exact same physical library as:

library-b

WordPress cannot necessarily infer that the URLs represent the same conceptual package.

Good dependency coordination still requires sensible ecosystem conventions.

Changing enqueue priority

WordPress hooks support priorities.

The default priority is:

10

You can run earlier:

add_action(
    'wp_enqueue_scripts',
    'mytheme_assets',
    5
);

or later:

add_action(
    'wp_enqueue_scripts',
    'mytheme_assets',
    20
);

Priority is not the same as dependency order

This is important.

Do not rely on hook priority alone to express:

script B depends on script A

Declare:

array(
    'script-a'
)

as the dependency.

Hook priority controls when callbacks execute.

The dependency array expresses the actual relationship between assets.

Dequeueing and deregistering assets

WordPress also provides functions including:

wp_dequeue_script()
wp_deregister_script()
wp_dequeue_style()
wp_deregister_style()

Dequeue

removes a resource from the current enqueue queue.

Deregister

removes its registration from the dependency registry.

Use these carefully

If another plugin depends on the resource you remove, functionality may break.

Do not remove a library simply because a performance scanner says:

unused JavaScript detected

without determining:

  • who registered it;
  • who depends on it;
  • whether it is conditionally used;
  • whether removal changes functionality.

Parent themes and child themes

Stylesheet and theme directory functions deserve attention when working with child themes.

get_template_directory_uri()

refers to the parent theme directory.

get_stylesheet_directory_uri()

refers to the active stylesheet directory, which can be the child theme.

get_theme_file_uri()

is often convenient because WordPress can resolve a requested theme file while accounting for child-theme overrides.

Choosing the correct path function prevents assets from unexpectedly loading from the wrong theme directory.

Do not hardcode your theme URL

Avoid:

https://example.com/wp-content/themes/mytheme/js/app.js

inside reusable code.

WordPress installations can use:

  • different domains;
  • different content directories;
  • multisite;
  • different environments;
  • CDN rewriting.

Use WordPress URL helpers instead.

A clean production asset architecture

A straightforward theme structure could be:

my-theme/
│
├── functions.php
│
└── assets/
    ├── css/
    │   ├── main.css
    │   └── components.css
    │
    └── js/
        ├── app.js
        ├── navigation.js
        └── animations.js

Your enqueue function can then describe the relationships explicitly.

function mytheme_enqueue_assets() {

    $main_css =
        get_theme_file_path(
            '/assets/css/main.css'
        );

    $app_js =
        get_theme_file_path(
            '/assets/js/app.js'
        );

    wp_enqueue_style(
        'mytheme-main',
        get_theme_file_uri(
            '/assets/css/main.css'
        ),
        array(),
        file_exists( $main_css )
            ? filemtime( $main_css )
            : '1.0.0'
    );

    wp_enqueue_script(
        'mytheme-app',
        get_theme_file_uri(
            '/assets/js/app.js'
        ),
        array(),
        file_exists( $app_js )
            ? filemtime( $app_js )
            : '1.0.0',
        array(
            'strategy'  => 'defer',
            'in_footer' => true,
        )
    );
}

add_action(
    'wp_enqueue_scripts',
    'mytheme_enqueue_assets'
);

This gives you:

WordPress-managed URLs
+
explicit handles
+
automatic development versioning
+
modern script loading
+
central asset management

Using a build tool with wp_enqueue_scripts

Modern WordPress development may involve:

  • Vite;
  • webpack;
  • Rollup;
  • esbuild;
  • PostCSS;
  • Sass.

The build tool might transform:

src/main.js

into:

dist/main.a82f91.js

WordPress’s job is still the same:

build system
↓
creates browser asset
↓
WordPress
↓
enqueues browser asset

Content-hashed filenames

A build system may produce a filename whose hash changes whenever the content changes.

app.72ab14.js

becomes:

app.91cd82.js

This is an effective cache-busting strategy because the URL changes with the content itself.

Performance: do not enqueue everything everywhere

A correctly written enqueue function can still produce a slow frontend if it loads unnecessary assets globally.

Suppose a site contains:

slider.js
gallery.js
maps.js
animations.js
checkout.js
charts.js

Loading all six on every page is easy.

It is not necessarily sensible.

Map asset ownership to page requirements

Homepage
→ animations.js

Portfolio
→ gallery.js

Store checkout
→ checkout.js

Analytics dashboard
→ charts.js

Conditional enqueueing can reduce:

  • network requests;
  • JavaScript parsing;
  • JavaScript execution;
  • memory usage;
  • third-party connections.

Using TheOneWP Library Importer

TheOneWP Library Importer provides a visual alternative for managing many common frontend libraries without manually writing every enqueue declaration.

The module supports a catalog of frontend libraries and can manage different delivery methods, including:

  • the configured CDN source;
  • a downloaded local static copy;
  • inline loading.

The underlying architectural concepts remain the same:

library
↓
loading location
↓
execution position
↓
dependency relationships
↓
frontend behavior

Understanding wp_enqueue_scripts is therefore useful even when a management tool handles some of the repetitive implementation work.

Common wp_enqueue_scripts mistakes

Confusing the hook with the function

wp_enqueue_scripts is an action hook.

wp_enqueue_script() is a function.

Putting script tags directly in header.php

This bypasses WordPress’s dependency registry and makes asset coordination harder.

Putting stylesheet tags directly in templates

Use wp_enqueue_style() where possible.

Using generic handles

Use project-specific prefixes to reduce collisions.

Ignoring dependencies

If one script requires another, declare the dependency explicitly.

Using hook priority as a dependency system

Callback execution order is not a substitute for script dependencies.

Loading every script globally

Conditionally load large or specialized assets when possible.

Using async for dependent scripts

Async execution order is not guaranteed.

Manually injecting defer when the native API is sufficient

Modern WordPress can calculate loading strategies while considering the dependency tree.

Forgetting versioning

Visitors may continue using stale cached resources.

Using filemtime() without checking the file

A missing file can cause PHP warnings.

Hardcoding wp-content URLs

Use WordPress path and URL helpers.

Loading frontend assets with admin_enqueue_scripts

The admin hook is for administration screens.

Using wp_enqueue_scripts for every editor asset

The block editor has its own asset-loading architecture.

Loading multiple copies of the same library

Inspect what themes and plugins already register before adding another copy.

Deregistering Core or plugin scripts without checking dependents

Removing one dependency can break several downstream components.

Loading third-party scripts without evaluating the external request

Remote scripts affect performance, privacy and availability. See WordPress privacy and third-party requests for the broader analysis.

wp_enqueue_scripts checklist

  • Use wp_enqueue_scripts for public frontend assets.
  • Use admin_enqueue_scripts for WordPress admin assets.
  • Use the appropriate block editor hooks for editor-specific assets.
  • Load JavaScript with wp_enqueue_script().
  • Load CSS with wp_enqueue_style().
  • Use unique descriptive handles.
  • Declare JavaScript dependencies explicitly.
  • Declare stylesheet dependencies where needed.
  • Use WordPress URL helpers instead of hardcoded theme paths.
  • Version assets for cache busting.
  • Consider file modification timestamps during development.
  • Check that files exist before calling filemtime().
  • Use in_footer where appropriate.
  • Use WordPress’s native defer and async strategies on supported versions.
  • Prefer predictable dependency-aware loading for dependent scripts.
  • Use async only for suitable independent resources.
  • Conditionally load assets where possible.
  • Avoid duplicate third-party libraries.
  • Register shared libraries centrally when multiple components may need them.
  • Use wp_add_inline_script() for related inline JavaScript when appropriate.
  • Use wp_add_inline_style() for CSS associated with an enqueued stylesheet.
  • Do not use hook priority as a replacement for dependency declarations.
  • Review third-party asset privacy and reliability.
  • Do not dequeue scripts without checking their dependents.
  • Keep asset management centralized and predictable.

Related WordPress development guides

Continue with these related guides and tools:

Final thoughts

wp_enqueue_scripts is one of the foundations of professional WordPress frontend development.

The central idea is simple:

do not print assets manually
↓
describe them to WordPress

Give WordPress:

a handle
+
a URL
+
dependencies
+
a version
+
loading instructions

and let its dependency system coordinate the final output.

A well-structured implementation separates three concerns.

First:

when should the asset
be requested?

That is where hooks and conditional loading matter.

Second:

what does the asset
depend on?

That is where handles and dependency arrays matter.

Third:

how should the browser
receive and execute it?

That is where placement, versioning, caching and loading strategies such as defer and async matter.

Once those concepts are understood, integrations such as GSAP, sliders, frontend frameworks, analytics libraries and custom theme scripts become much easier to manage.

The goal is not merely to make a script appear on the page. It is to make the relationship between every frontend asset explicit, predictable and maintainable.

Simplify your WordPress stack

A modular WordPress toolkit. 104 focused tools.

Ultimately, you can build cleaner workflows, maintain fewer plugins and enable only the features each website actually needs.