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.phpfiles 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
The Assets class centralizes all asset registration and enqueueing logic:
- Maintains separate asset arrays for each context (frontend, admin, editor, login)
- Registers assets on
inithook - Enqueues assets on context-specific hooks (
wp_enqueue_scripts,admin_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-refreshsuffix in development mode - Example:
'app'becomes'chisel-app'(production) or'chisel-app-fast-refresh'(development)
- Prefixes handle with
Asset contexts and hooks
Context buckets
The class maintains separate arrays for each context:
| Context | Styles array | Scripts array | Enqueue hook |
|---|---|---|---|
| Frontend | $frontend_styles | $frontend_scripts | wp_enqueue_scripts (priority 99) |
| Frontend footer | $frontend_footer_styles | n/a | wp_footer (priority 11) |
| Admin | $admin_styles | $admin_scripts | admin_enqueue_scripts (priority 11) |
| Editor | $editor_styles | $editor_scripts | enqueue_block_editor_assets |
| Login | $login_styles | $login_scripts | login_enqueue_scripts (priority 99) |
Hook execution order
Registration phase (init hook):
set_properties()seeds default assets- Apply filters:
chisel_frontend_styles,chisel_frontend_scripts, etc. - Call
register_style()orregister_script()for each asset wp_register_style()/wp_register_script()called internally
Enqueue phase (context-specific hooks):
- Apply pre-enqueue filters:
chisel_pre_enqueue_frontend_styles, etc. - Apply per-asset filters:
chisel_enqueue_frontend_style, etc. - Call
enqueue_style()orenqueue_script() - Apply inline code and localization
- Set script translations (if
wp-i18ndependency detected)
File structure and naming
Build directory structure
- Compiled file:
build/scripts/{name}.js - Metadata file:
build/scripts/{name}.asset.php(optional)
- 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',
);PHPGenerated 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.jswith localization:chiselScripts.ajax.url→ REST API base URLchiselScripts.ajax.nonce→ WordPress REST nonce
Admin assets
Styles:
admin→build/styles/admin.css
Scripts:
Editor assets
Styles:
editor→build/styles/editor.css
Scripts:
editor→build/scripts/editor.jswith localization:
Login assets
Styles:
Scripts:
runtime→ Development onlylogin→build/scripts/login.jswith localization:chiselScripts.logoData→ Login logo data
Asset configuration options
Style configuration
Available keys:
| Key | Type | Description |
|---|---|---|
src | string | URL to stylesheet (defaults to build/styles/{name}.css) |
deps | array | Style dependencies (merged with .asset.php deps) |
ver | string | Version (defaults to .asset.php version or theme version) |
media | string | Media query (default: 'all') |
condition | bool|callable | Whether to register (evaluated at registration) |
inline | array | Inline CSS: ['data' => 'css code'] |
Script configuration
Available keys:
| Key | Type | Description |
|---|---|---|
src | string | URL to script (defaults to build/scripts/{name}.js) |
deps | array | Script dependencies (merged with .asset.php deps) |
ver | string | Version (defaults to .asset.php version or theme version) |
strategy | array|bool | Loading strategy (see below) |
condition | bool|callable | Whether to register (evaluated at registration) |
localize | array | Localization: ['name' => 'varName', 'data' => [...]] |
inline | array | Inline JS: ['data' => 'js code', 'position' => 'before'|'after'] |
Strategy options:
Default:
array(
'in_footer' => true,
'strategy' => 'defer',
)PHPCan be false to load in <head> without defer/async, or array with:
in_footer→trueorfalsestrategy→'defer'or'async'
Filters for adding assets
Registration filters
Apply during init hook, before registration:
chisel_frontend_styleschisel_frontend_footer_styleschisel_frontend_scriptschisel_admin_styleschisel_admin_scriptschisel_editor_styleschisel_editor_scriptschisel_login_styleschisel_login_scripts
Pre-enqueue filters
Apply during enqueue hooks, before individual assets are enqueued:
chisel_pre_enqueue_frontend_styleschisel_pre_enqueue_frontend_footer_styleschisel_pre_enqueue_frontend_scriptschisel_pre_enqueue_admin_styleschisel_pre_enqueue_admin_scriptschisel_pre_enqueue_editor_styleschisel_pre_enqueue_editor_scriptschisel_pre_enqueue_login_styleschisel_pre_enqueue_login_scripts
Per-asset filters
Apply during enqueue, for each asset individually:
chisel_enqueue_frontend_stylechisel_enqueue_frontend_footer_stylechisel_enqueue_frontend_scriptchisel_enqueue_admin_stylechisel_enqueue_admin_scriptchisel_enqueue_editor_stylechisel_enqueue_editor_scriptchisel_enqueue_login_stylechisel_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;
}PHPAccessed in JS as:
console.log(window.myFeature.apiKey);JavaScriptFrontend 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;
}PHPConditional 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;
}PHPEditor 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;
}PHPAdmin 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;
}PHPCustom 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;
}PHPInline 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;
}PHPDevelopment features
Fast refresh (Hot Module Replacement)
Condition: ThemeHelpers::is_fast_refresh() returns true
WP_DEBUGistrueANDSCRIPT_DEBUGistrueANDWP_ENVIRONMENT_TYPEis'development'
- Runtime script:
build/runtime.jsis registered and enqueued- Depends on
wp-react-refresh-runtime - Required for React Fast Refresh functionality
- Depends on
- 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
- Example:
- Handle suffix: All handles get
-fast-refreshappended- Example:
chisel-appbecomeschisel-app-fast-refresh
- Example:
Performance optimizations
Style preloading
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"' />HTMLScript deferral
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
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()
When a script has wp-i18n in its dependencies, translations are automatically loaded:
wp_set_script_translations( $handle, 'chisel', get_template_directory() . '/languages' );PHPTranslation 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(),
);PHPPre-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;
}PHPPer-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;
}PHPTroubleshooting
Asset not loading
- Check handle registration:
global $wp_scripts;
var_dump( wp_script_is( 'chisel-my-script', 'registered' ) );PHP- Verify file exists:
- Script:
build/scripts/my-script.js - Style:
build/styles/my-style.css
- Script:
- Check condition evaluation:
- If using
conditionparameter, ensure it returnstrueat registration time
- If using
- Inspect console for errors:
- 404 errors indicate wrong path or missing build
- Syntax errors indicate compilation issues
Fast refresh not working
- Verify environment settings:
define( 'WP_DEBUG', true );
define( 'SCRIPT_DEBUG', true );
define( 'WP_ENVIRONMENT_TYPE', 'development' );PHP- Check
runtime.jsis enqueued:
global $wp_scripts;
var_dump( wp_script_is( 'chisel-runtime-fast-refresh', 'enqueued' ) );PHP- Ensure webpack dev server is running:
npm run devBashDependencies not loading
- Check
.asset.phpfile exists:build/scripts/{name}.asset.phpbuild/styles/{name}.asset.php
- Verify dependencies array:
$asset = include get_template_directory() . '/build/scripts/app.asset.php';
var_dump( $asset['dependencies'] );PHP- 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;
}PHPLocalized data not available
- Check script is enqueued before accessing:
if ( typeof window.chiselScripts !== 'undefined' ) {
console.log( window.chiselScripts );
}JavaScript- Verify localize config:
'localize' => array(
'name' => 'chiselScripts', // Global variable name
'data' => array( 'key' => 'value' ), // Data object
),PHP- 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.phpdirectly—use filters incustom/appdirectory in custom classes - Leverage conditions: Use
conditionparameter to avoid enqueueing unnecessary assets - Minimize dependencies: Only include required dependencies to reduce bundle size
- Use
.asset.phpfiles: 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