WordPress Plugin Asset Loading

SkillAI & models

Register and enqueue WordPress plugin scripts/styles with

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the WordPress Plugin Asset Loading skill

What this skill tells your AI

The instructions your AI receives, as published by lonsdale201/wp-agent-skills in plugin-scaffold/wp-plugin-assets-loading/SKILL.md and read by ahel’s review.

Use this skill when adding or reviewing plugin JS/CSS enqueue code. The goal is to load the right asset on the right screen, with a correct dependency graph and modern loading hints.

This skill avoids Gutenberg-specific editor development. It covers general WordPress frontend/admin assets.

When to use this skill

Trigger when ANY of the following is true:

  • Code calls wp_enqueue_script(), wp_register_script(), wp_enqueue_style(), wp_script_add_data(), wp_style_add_data(), wp_register_script_module(), or wp_enqueue_script_module().
  • A plugin loads assets on every admin page or every frontend request without checking context.
  • The task mentions defer, async, fetchpriority, script modules, module translations, module_dependencies, inline CSS, asset bloat, or frontend performance.
  • Code uses legacy IE conditional comments or wp_style_add_data( $handle, 'conditional', ... ).

Runtime placement

ContextHook
Frontend scripts/styleswp_enqueue_scripts
Admin scripts/stylesadmin_enqueue_scripts
Login page assetslogin_enqueue_scripts
Specific plugin settings pageCheck $hook_suffix in admin_enqueue_scripts

Do not enqueue admin assets globally unless the UI appears globally.

add_action( 'admin_enqueue_scripts', static function ( string $hook_suffix ): void {
    if ( 'settings_page_myplugin' !== $hook_suffix ) {
        return;
    }

    wp_enqueue_script(
        'myplugin-admin',
        plugins_url( 'assets/admin.js', MYPLUGIN_FILE ),
        array( 'wp-api-fetch' ),
        MYPLUGIN_VERSION,
        array(
            'in_footer'     => true,
            'strategy'      => 'defer',
            'fetchpriority' => 'low',
        )
    );
} );

Script loading args

Since WP 6.3, the fifth wp_enqueue_script() parameter can be an args array. Since WP 6.9, it also accepts fetchpriority. Since WP 7.0, it also accepts module_dependencies so a classic script can dynamically import registered script modules.

wp_enqueue_script(
    'myplugin-frontend',
    plugins_url( 'assets/frontend.js', MYPLUGIN_FILE ),
    array(),
    MYPLUGIN_VERSION,
    array(
        'in_footer'     => true,
        'strategy'      => 'defer',
        'fetchpriority' => 'low', // 'auto', 'low', or 'high'.
    )
);

Guidance:

  • Use in_footer => true for non-critical frontend behavior.
  • Use strategy => 'defer' for scripts that can run after parsing and preserve dependency order.
  • Use strategy => 'async' only for independent scripts that do not depend on execution order.
  • Use fetchpriority => 'high' rarely, only for scripts that are genuinely critical to initial rendering.
  • Use fetchpriority => 'low' for behavior that should not compete with LCP resources.
  • If a classic script uses module_dependencies, it must either set in_footer => true or strategy => 'defer'; otherwise it can run before the import map exists.
wp_enqueue_script(
    'myplugin-admin',
    plugins_url( 'assets/admin.js', MYPLUGIN_FILE ),
    array( 'wp-api-fetch' ),
    MYPLUGIN_VERSION,
    array(
        'in_footer'           => true,
        'module_dependencies' => array(
            '@wordpress/abilities',
        ),
    )
);

Script modules

For ES modules, use the Script Modules API on WP 6.5+:

wp_enqueue_script_module(
    'myplugin/frontend',
    plugins_url( 'assets/frontend.js', MYPLUGIN_FILE ),
    array(),
    MYPLUGIN_VERSION,
    array(
        'in_footer'     => true,
        'fetchpriority' => 'low',
    )
);

In WP 6.9, wp_register_script_module() and wp_enqueue_script_module() accept an $args array with in_footer and fetchpriority. Feature-detect if supporting older WP:

if ( function_exists( 'wp_enqueue_script_module' ) ) {
    wp_enqueue_script_module( 'myplugin/frontend', $src, array(), MYPLUGIN_VERSION );
} else {
    wp_enqueue_script( 'myplugin-frontend', $fallback_src, array(), MYPLUGIN_VERSION, array( 'in_footer' => true ) );
}

In WP 7.0, registered script modules can have translations:

wp_register_script_module(
    'myplugin/admin',
    plugins_url( 'assets/admin.js', MYPLUGIN_FILE ),
    array(),
    MYPLUGIN_VERSION
);

wp_set_script_module_translations(
    'myplugin/admin',
    'myplugin',
    plugin_dir_path( MYPLUGIN_FILE ) . 'languages'
);

wp_enqueue_script_module( 'myplugin/admin' );

Call wp_set_script_module_translations() after the module is registered. Use wp_set_script_translations() for classic scripts and wp_set_script_module_translations() for script modules.

WordPress 7.1 admin design-system assets

WordPress 7.1 registers wp-theme as both a stylesheet handle and a classic script handle. They are independent assets that happen to share a handle name in their respective registries:

  • depend on the wp-theme style to use the --wpds-* semantic design tokens in wp-admin CSS;
  • depend on the wp-theme script when code uses the @wordpress/theme package and its ThemeProvider component;
  • prefer WordPress UI components over styling directly against low-level tokens when an appropriate component exists.
wp_enqueue_style(
    'myplugin-admin',
    plugins_url( 'assets/admin.css', MYPLUGIN_FILE ),
    array( 'wp-theme' ),
    MYPLUGIN_VERSION
);

wp_enqueue_script(
    'myplugin-admin',
    plugins_url( 'assets/admin.js', MYPLUGIN_FILE ),
    array( 'wp-element', 'wp-theme' ),
    MYPLUGIN_VERSION,
    array( 'in_footer' => true )
);

Do not enqueue either asset solely because it exists, and do not assume the stylesheet loads with the script. A ThemeProvider can alter color, roundness, and control-cursor tokens for its subtree. Render at most one root provider per document, and still verify contrast for custom seed colors.

Styles and legacy conditionals

WP 6.9 removed support for legacy conditional asset loading for Internet Explorer. Do not use wp_style_add_data( $handle, 'conditional', 'IE' ); in WP 6.9, a stylesheet with conditional data is ignored.

// WRONG on WP 6.9+.
wp_style_add_data( 'myplugin-ie', 'conditional', 'IE' );

// RIGHT - drop legacy IE-only styles, or serve a normal stylesheet if still required.
wp_enqueue_style( 'myplugin-admin', plugins_url( 'assets/admin.css', MYPLUGIN_FILE ), array(), MYPLUGIN_VERSION );

Use the path style data only when the stylesheet is registered and the file path is absolute:

wp_register_style( 'myplugin-small', plugins_url( 'assets/small.css', MYPLUGIN_FILE ), array(), MYPLUGIN_VERSION );
wp_style_add_data( 'myplugin-small', 'path', plugin_dir_path( MYPLUGIN_FILE ) . 'assets/small.css' );
wp_enqueue_style( 'myplugin-small' );

Inline data

Use wp_add_inline_script() for boot data and wp_set_script_translations() for translations. Do not use wp_localize_script() as a generic JSON dump.

wp_add_inline_script(
    'myplugin-admin',
    'window.mypluginSettings = ' . wp_json_encode( $settings ) . ';',
    'before'
);

Critical rules

  • Register/enqueue on the correct hook for frontend, admin, or login.
  • Gate admin assets by screen using $hook_suffix or get_current_screen().
  • Use script args arrays, not the old boolean-only fifth parameter, when setting strategy/footer/fetchpriority.
  • Do not use async on dependency-sensitive scripts.
  • For classic scripts with module_dependencies, use footer placement or defer.
  • Use the matching translation API: wp_set_script_translations() for classic scripts, wp_set_script_module_translations() for modules.
  • Declare wp-theme in the correct registry when using WordPress 7.1 design tokens or ThemeProvider; the style and script do not imply each other.
  • Do not use legacy IE conditional data on styles in WP 6.9+.
  • Do not put <script> tags inside wp_add_inline_script().
  • Prefer dependencies over manual load ordering.

Common mistakes

// WRONG - loads everywhere in wp-admin.
add_action( 'admin_enqueue_scripts', static function (): void {
    wp_enqueue_script( 'myplugin-admin', plugins_url( 'admin.js', __FILE__ ) );
} );

// RIGHT - load only where the screen exists.
add_action( 'admin_enqueue_scripts', static function ( string $hook_suffix ): void {
    if ( 'settings_page_myplugin' !== $hook_suffix ) {
        return;
    }

    wp_enqueue_script(
        'myplugin-admin',
        plugins_url( 'admin.js', __FILE__ ),
        array( 'wp-api-fetch' ),
        '1.0.0',
        array( 'in_footer' => true, 'strategy' => 'defer', 'fetchpriority' => 'low' )
    );
} );

// WRONG - dependency-sensitive code with async.
wp_enqueue_script( 'myplugin-app', $src, array( 'jquery' ), '1.0.0', array( 'strategy' => 'async' ) );

// RIGHT
wp_enqueue_script( 'myplugin-app', $src, array( 'jquery' ), '1.0.0', array( 'strategy' => 'defer' ) );

Cross-references

  • Run wp-plugin-architecture for broader placement of enqueue code inside plugin services.
  • Run wp-i18n-audit when scripts need translations.
  • Run wp-security-audit when inline boot data contains user/admin-controlled values.
  • Run wp-block-editor-iframe-compatibility for assets that must load inside the editor canvas.
  • Run wp-interactivity-api when viewScriptModule implements reactive block behavior.

What this skill does NOT cover

  • Gutenberg/block editor component development.
  • Build tooling such as Vite, webpack, or @wordpress/scripts.
  • CDN/page-cache strategy.

References

Signals

GitHub stars
22
Forks
2
Last commit
Sep 2026
Advanced
Catalog kind
skill
Gateway key
wp-plugin-assets-loading
Source
github.com/lonsdale201/wp-agent-skills