Jump to Navigation Jump to Main Content Jump to Footer
Home » Docs » Features » Automated assets registration and enqueueing

Automated assets registration and enqueueing

Chisel automatically registers and enqueues scripts and styles for frontend, admin, editor, and login contexts. Assets are defined via simple array configurations, then filtered, registered on init, and enqueued at the appropriate hooks. The system handles versioning, dependencies, localization, inline code, and conditional loading—all through a unified API.

Webpack generates .asset.php files alongside compiled CSS and JS, providing automatic dependency tracking and cache-busting versions. The theme prefixes all handles with chisel- to avoid conflicts, and appends -fast-refresh in development mode for hot module replacement.

Performance optimizations include style preloading, script deferral, and development-only fast refresh scripts that enable CSS hot-reloading without page refreshes. Add custom assets via filters without touching core files, and conditionally load assets based on page context using boolean or callable conditions.

Overview

Core class

File: core/WP/Assets.php

The Assets class centralizes all asset registration and enqueueing logic:

  • Maintains separate asset arrays for each context (frontend, admin, editor, login)
  • Registers assets on init hook
  • Enqueues assets on context-specific hooks (wp_enqueue_scriptsadmin_enqueue_scripts, etc.)
  • Applies filters before registration and before enqueueing for maximum flexibility
  • Handles inline styles/scripts, localization, and script translations

Helper class

File: core/Helpers/AssetsHelpers.php

Provides utility methods for asset handling:

  • get_final_handle( string $handle ): string
    • Prefixes handle with chisel-
    • Appends -fast-refresh suffix in development mode
    • Example: 'app' becomes 'chisel-app' (production) or 'chisel-app-fast-refresh' (development)

Asset contexts and hooks

Context buckets

File: core/WP/Assets.php

The class maintains separate arrays for each context:

ContextStyles arrayScripts arrayEnqueue hook
Frontend$frontend_styles$frontend_scriptswp_enqueue_scripts (priority 99)
Frontend footer$frontend_footer_stylesn/awp_footer (priority 11)
Admin$admin_styles$admin_scriptsadmin_enqueue_scripts (priority 11)
Editor$editor_styles$editor_scriptsenqueue_block_editor_assets
Login$login_styles$login_scriptslogin_enqueue_scripts (priority 99)

Hook execution order

Registration phase (init hook):

  1. set_properties() seeds default assets
  2. Apply filters: chisel_frontend_styleschisel_frontend_scripts, etc.
  3. Call register_style() or register_script() for each asset
  4. wp_register_style() / wp_register_script() called internally

Enqueue phase (context-specific hooks):

  1. Apply pre-enqueue filters: chisel_pre_enqueue_frontend_styles, etc.
  2. Apply per-asset filters: chisel_enqueue_frontend_style, etc.
  3. Call enqueue_style() or enqueue_script()
  4. Apply inline code and localization
  5. Set script translations (if wp-i18n dependency detected)

File structure and naming

Build directory structure

Scripts:

  • Compiled file: build/scripts/{name}.js
  • Metadata file: build/scripts/{name}.asset.php (optional)

Styles:

  • Compiled file: build/styles/{name}.css
  • Metadata file: build/styles/{name}.asset.php (optional)
  • Dev refresh script: build/styles/{name}.js (development only)

Asset metadata file

Format: {name}.asset.php

<?php
return array(
    'dependencies' => array( 'wp-i18n', 'jquery' ),
    'version'      => '1.2.3-abc123',
);
PHP

Generated automatically by Webpack’s @wordpress/dependency-extraction-webpack-plugin.

Fallback: If .asset.php doesn’t exist, version defaults to ThemeHelpers::get_theme_version()


Default assets

Frontend assets

File: core/WP/Assets.php → set_properties()

Styles:

  • main → build/styles/main.css

Scripts:

  • runtime → build/runtime.js (development only, for React Refresh)
  • app → build/scripts/app.js with localization:
    • chiselScripts.ajax.url → REST API base URL
    • chiselScripts.ajax.nonce → WordPress REST nonce

Admin assets

Styles:

  • admin → build/styles/admin.css

Scripts:

  • runtime → Development only
  • admin → build/scripts/admin.js with localization:
    • chiselAdminScripts.acfColorPickerPalette → ACF color picker palette

Editor assets

Styles:

  • editor → build/styles/editor.css

Scripts:

  • editor → build/scripts/editor.js with localization:
    • chiselEditorScripts.icons → Icon labels for blocks

Login assets

Styles:

  • login → build/styles/login.css
  • Includes inline global styles from theme.json

Scripts:

  • runtime → Development only
  • login → build/scripts/login.js with localization:
    • chiselScripts.logoData → Login logo data

Asset configuration options

Style configuration

Available keys:

KeyTypeDescription
srcstringURL to stylesheet (defaults to build/styles/{name}.css)
depsarrayStyle dependencies (merged with .asset.php deps)
verstringVersion (defaults to .asset.php version or theme version)
mediastringMedia query (default: 'all')
conditionbool|callableWhether to register (evaluated at registration)
inlinearrayInline CSS: ['data' => 'css code']

Script configuration

Available keys:

KeyTypeDescription
srcstringURL to script (defaults to build/scripts/{name}.js)
depsarrayScript dependencies (merged with .asset.php deps)
verstringVersion (defaults to .asset.php version or theme version)
strategyarray|boolLoading strategy (see below)
conditionbool|callableWhether to register (evaluated at registration)
localizearrayLocalization: ['name' => 'varName', 'data' => [...]]
inlinearrayInline JS: ['data' => 'js code', 'position' => 'before'|'after']

Strategy options:

Default:

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

Can be false to load in <head> without defer/async, or array with:

  • in_footer → true or false
  • strategy → 'defer' or 'async'

Filters for adding assets

Registration filters

Apply during init hook, before registration:

  • chisel_frontend_styles
  • chisel_frontend_footer_styles
  • chisel_frontend_scripts
  • chisel_admin_styles
  • chisel_admin_scripts
  • chisel_editor_styles
  • chisel_editor_scripts
  • chisel_login_styles
  • chisel_login_scripts

Pre-enqueue filters

Apply during enqueue hooks, before individual assets are enqueued:

  • chisel_pre_enqueue_frontend_styles
  • chisel_pre_enqueue_frontend_footer_styles
  • chisel_pre_enqueue_frontend_scripts
  • chisel_pre_enqueue_admin_styles
  • chisel_pre_enqueue_admin_scripts
  • chisel_pre_enqueue_editor_styles
  • chisel_pre_enqueue_editor_scripts
  • chisel_pre_enqueue_login_styles
  • chisel_pre_enqueue_login_scripts

Per-asset filters

Apply during enqueue, for each asset individually:

  • chisel_enqueue_frontend_style
  • chisel_enqueue_frontend_footer_style
  • chisel_enqueue_frontend_script
  • chisel_enqueue_admin_style
  • chisel_enqueue_admin_script
  • chisel_enqueue_editor_style
  • chisel_enqueue_editor_script
  • chisel_enqueue_login_style
  • chisel_enqueue_login_script

Adding custom assets

Frontend script with localization

add_filter( 'chisel_frontend_scripts', array( $this, 'custom_frontend_scripts' ) );

public function custom_frontend_scripts( array $scripts ): array {
    $scripts['my-feature'] = array(
        'deps'      => array( 'wp-i18n', 'jquery' ),
        'strategy'  => array(
            'in_footer' => true,
            'strategy'  => 'defer',
        ),
        'localize'  => array(
            'name' => 'myFeature',
            'data' => array(
                'apiKey' => get_option( 'my_api_key' ),
                'enabled' => true,
            ),
        ),
    );
    
    return $scripts;
}
PHP

Accessed in JS as:

console.log(window.myFeature.apiKey);
JavaScript

Frontend style with inline CSS

add_filter( 'chisel_frontend_styles', array( $this, 'custom_frontend_styles' ) );

public function custom_frontend_styles( array $styles ): array {
    $styles['my-style'] = array(
        'inline' => array(
            'data' => ':root { --primary-color: #ff6600; }',
        ),
    );
    
    return $styles;
}
PHP

Conditional asset loading

add_filter( 'chisel_frontend_scripts', array( $this, 'custom_frontend_scripts' ) );

public function custom_frontend_scripts( array $scripts ): array {
    // Boolean condition
    $scripts['map'] = array(
        'condition' => is_page_template( 'templates/page-map.php' ),
    );
    
    // Callable condition
    $scripts['checkout'] = array(
        'condition' => function(): bool {
            return function_exists( 'is_checkout' ) && is_checkout();
        },
    );
    
    return $scripts;
}
PHP

Editor stylesheet

add_filter( 'chisel_editor_styles', array( $this, 'custom_editor_styles' ) );

public function custom_editor_styles( array $styles ): array {
    $styles['editor-custom'] = array(
        'deps' => array( 'wp-edit-blocks' ),
    );
    
    return $styles;
}
PHP

Admin script with dependencies

add_filter( 'chisel_admin_scripts', array( $this, 'custom_admin_scripts' ) );

public function custom_admin_scripts( array $scripts ): array {
    $scripts['admin-dashboard'] = array(
        'deps'     => array( 'jquery', 'wp-api' ),
        'localize' => array(
            'name' => 'adminDashboard',
            'data' => array(
                'nonce' => wp_create_nonce( 'admin_dashboard' ),
            ),
        ),
    );
    
    return $scripts;
}
PHP

Custom source path

add_filter( 'chisel_frontend_scripts', array( $this, 'custom_frontend_scripts' ) );

public function custom_frontend_scripts( array $scripts ): array {
    $scripts['external-lib'] = array(
        'src'      => 'https://cdn.example.com/library.js',
        'deps'     => array(),
        'ver'      => '2.0.0',
        'strategy' => false, // Load in head without defer
    );
    
    return $scripts;
}
PHP

Inline script

add_filter( 'chisel_frontend_scripts', array( $this, 'custom_frontend_scripts' ) );

public function custom_frontend_scripts( array $scripts ): array {
    $scripts['analytics'] = array(
        'inline' => array(
            'data'     => "console.log('Analytics initialized');",
            'position' => 'after', // 'before' or 'after'
        ),
    );
    
    return $scripts;
}
PHP

Development features

Fast refresh (Hot Module Replacement)

Condition: ThemeHelpers::is_fast_refresh() returns true

Enabled when:

  • WP_DEBUG is true AND
  • SCRIPT_DEBUG is true AND
  • WP_ENVIRONMENT_TYPE is 'development'

Behavior:

  1. Runtime script:build/runtime.js is registered and enqueued
    • Depends on wp-react-refresh-runtime
    • Required for React Fast Refresh functionality
  2. Style refresh scripts: For each registered stylesheet, a companion JS file is created:
    • Example: build/styles/main.css → build/styles/main.js
    • Enqueued automatically when stylesheet is enqueued
    • Enables CSS hot-reloading without page refresh
  3. Handle suffix: All handles get -fast-refresh appended
    • Example: chisel-app becomes chisel-app-fast-refresh

Performance optimizations

Style preloading

Method: preload_styles()

Filter: style_loader_tag

Preloads specific stylesheets to improve paint times:

Preloaded handles:

  • wp-block-library
  • Any handle starting with gform_
  • Any handle starting with block

Output transformation:

<!-- Original -->
<link rel='stylesheet' href='...' media='all' />

<!-- Preloaded -->
<link rel='preload' as='style' href='...' />
<link rel='stylesheet' href='...' media='print' onload='this.media="all"' />
HTML

Script deferral

Method: defer_script()

Filter: script_loader_tag

Defers all scripts by default (controlled via strategy parameter in asset config).

Note: Method exists but currently returns empty array—all deferral handled via strategy parameter.

Async loading

Method: async_script()

Filter: script_loader_tag

Allows selective async loading of specific script handles.

Note: Method exists but currently returns empty array—extend if needed.


Script translations

Method: set_script_translations()

Automatic behavior:

When a script has wp-i18n in its dependencies, translations are automatically loaded:

wp_set_script_translations( $handle, 'chisel', get_template_directory() . '/languages' );
PHP

Translation file location: languages/chisel-{locale}-{hash}.json


Conditional enqueueing

Per-asset conditional

During registration (via condition key in config):

$scripts['my-script'] = array(
    'condition' => is_front_page(),
);
PHP

Pre-enqueue filter

During enqueue phase (modify entire array):

add_filter( 'chisel_pre_enqueue_frontend_scripts', array( $this, 'custom_pre_enqueue_frontend_scripts' ) );

public function custom_pre_enqueue_frontend_scripts( array $scripts ): array {
    if ( ! is_user_logged_in() ) {
        unset( $scripts['admin-bar-tweaks'] );
    }
    
    return $scripts;
}
PHP

Per-asset enqueue filter

During enqueue phase (per individual asset):

add_filter( 'chisel_enqueue_frontend_script', array( $this, 'custom_enqueue_frontend_scripts' ), 10, 3 );

public function custom_enqueue_frontend_scripts( bool $enqueue, string $handle, array $args ): bool {
    if ( $handle === 'map' && ! is_page_template( 'templates/page-map.php' ) ) {
        return false;
    }
    
    return $enqueue;
}
PHP

Troubleshooting

Asset not loading

  1. Check handle registration:
global $wp_scripts;
var_dump( wp_script_is( 'chisel-my-script', 'registered' ) );
PHP
  1. Verify file exists:
    • Script: build/scripts/my-script.js
    • Style: build/styles/my-style.css
  2. Check condition evaluation:
    • If using condition parameter, ensure it returns true at registration time
  3. Inspect console for errors:
    • 404 errors indicate wrong path or missing build
    • Syntax errors indicate compilation issues

Fast refresh not working

  1. Verify environment settings:
define( 'WP_DEBUG', true );
define( 'SCRIPT_DEBUG', true );
define( 'WP_ENVIRONMENT_TYPE', 'development' );
PHP
  1. Check runtime.js is enqueued:
global $wp_scripts;
var_dump( wp_script_is( 'chisel-runtime-fast-refresh', 'enqueued' ) );
PHP
  1. Ensure webpack dev server is running:
npm run dev
Bash

Dependencies not loading

  1. Check .asset.php file exists:
    • build/scripts/{name}.asset.php
    • build/styles/{name}.asset.php
  2. Verify dependencies array:
$asset = include get_template_directory() . '/build/scripts/app.asset.php';
var_dump( $asset['dependencies'] );
PHP
  1. Manual override if needed:
add_filter( 'chisel_frontend_scripts', array( $this, 'custom_frontend_scripts' ) );

public function custom_enqueue_frontend_scripts( $scripts ) {
    $scripts['app']['deps'] = array( 'jquery', 'wp-i18n' );
    return $scripts;
}
PHP

Localized data not available

  1. Check script is enqueued before accessing:
if ( typeof window.chiselScripts !== 'undefined' ) {
    console.log( window.chiselScripts );
}
JavaScript
  1. Verify localize config:
'localize' => array(
    'name' => 'chiselScripts', // Global variable name
    'data' => array( 'key' => 'value' ), // Data object
),
PHP
  1. Ensure script is not deferred/async if accessing inline:
    • Localized data is printed inline before the script tag
    • Deferred/async scripts may load after DOM ready

Best practices

  • Use filters for custom assets: Never modify core/WP/Assets.php directly—use filters in custom/app directory in custom classes
  • Leverage conditions: Use condition parameter to avoid enqueueing unnecessary assets
  • Minimize dependencies: Only include required dependencies to reduce bundle size
  • Use .asset.php files: Let Webpack handle dependency extraction automatically
  • Prefix custom handles: Although handled automatically, be aware all handles are prefixed with chisel-
  • Test in production mode: Verify assets work without fast refresh enabled
  • Use inline code sparingly: Prefer separate files for maintainability

Do you like Chisel?

Give it a star on GitHub!