Assets, Enqueue, and Build
Free themeHow BuddyX registers, conditionally loads, and builds its CSS and JavaScript, and how to add your own child-theme assets after the parent.
BuddyX drives every front-end stylesheet and script through two manifest classes rather than scattered wp_enqueue_*() calls. Per the theme audit manifest, BuddyX can emit 37 CSS handles and 21 JS handles, most of them loaded conditionally. This page covers where the manifests live, how handles are named, when each loads, where source vs. built assets sit, the build commands, and the correct way to enqueue after BuddyX.
Requires PHP 8.0+.
The two manifest classes
| Concern | Class file | Core array | Filter |
|---|---|---|---|
| Stylesheets | inc/Styles/Component.php |
$css_files (in get_css_files()) |
buddyx_css_files |
| Scripts | inc/Scripts/Component.php |
$js_files (in get_js_files()) |
buddyx_js_files |
Both hook wp_enqueue_scripts. Styles\Component additionally hooks wp_head (preload emission), after_setup_theme (editor styles), and style_loader_tag (critical-CSS preload). Handle names are stable across releases, so any wp_dequeue_*() you write keeps working after an update.
CSS handle structure
Core manifest handles
These nine are declared in get_css_files() and are the filterable base set. global handles enqueue on every request; the rest are registered and emitted only when their preload_callback returns true (or unconditionally when preloading is disabled).
| Handle | File (assets/css/) |
Loads when |
|---|---|---|
buddyx-global |
global.min.css |
Always (global) |
buddyx-tokens-applied |
bx-tokens-applied.css |
Always (global), depends on buddyx-global |
buddyx-site-loader |
loaders.min.css |
Always (global) |
buddyx-load-fontawesome |
fontawesome.min.css |
Always (global) |
buddyx-comments |
comments.min.css |
Singular view with comments open or present |
buddyx-content |
content.min.css |
Registered only (opt-in via print_styles()) |
buddyx-sidebar |
sidebar.min.css |
On demand |
buddyx-widgets |
widgets.min.css |
On demand |
buddyx-front-page |
front-page.min.css |
When the active template is front-page.php |
Conditional integration handles
The remainder of the 37 are enqueued directly inside action_enqueue_styles() (and three integration methods that run at priority 99), each guarded by a class_exists() / function_exists() / defined() check. A representative set:
| Handle | Guard |
|---|---|
buddyx-buddypress |
BuddyPress active and Youzify not active |
buddyx-bbpress |
is_bbpress() / BuddyBoss Platform |
buddyx-platform |
BuddyBoss Platform |
buddyx-woocommerce |
WooCommerce |
buddyx-wc-vendor |
WC_Vendors |
multivendorx |
MVX |
buddyx-learnpress / buddyx-lifterlms / buddyx-learndash |
LearnPress / LifterLMS / SFWD_LMS |
buddyx-eventscalendar |
Tribe__Events__Main (priority 99) |
buddyx-dokan |
WeDevs_Dokan (priority 99) |
buddyx-surecart / buddyx-fluentcart |
SURECART_PLUGIN_FILE / FLUENTCART_PLUGIN_FILE_PATH |
buddyx-better-messages / buddyx-gamipress / buddyx-rtmedia / buddyx-bp-verified-member |
Respective plugin class present |
buddyx-slick |
Always (carousel library) |
buddyx-dark-mode |
Always (dark token overrides) |
buddyx-rtl |
is_rtl() |
buddyx-amp |
AMP endpoint |
Non-critical stylesheets (buddyx-slick, buddyx-eventscalendar, buddyx-dokan, buddyx-youzify, buddyx-wpjobmanager, multivendorx) are rewritten by add_preload_for_critical_css() on style_loader_tag to load with media="print" onload="this.media='all'" plus a <noscript> fallback, so they never block first paint.
CSS manifest entry shape
Each core entry is normalized to these keys:
'buddyx-front-page' => array(
'file' => 'front-page.min.css', // relative to assets/css/
'global' => false, // true = enqueue on every request
'preload_callback' => function () { // decides per-request when global is false
global $template;
return $template && 'front-page.php' === basename( $template );
},
'media' => 'all',
'deps' => array( 'buddyx-global' ),
),
| Key | Meaning |
|---|---|
file |
Path under assets/css/. Manifest references the built .min.css |
global |
true enqueues immediately; false registers for conditional/on-demand use |
preload_callback |
Callable deciding emission when global is false (e.g. is_singular(), class_exists()) |
media |
Media attribute, default all |
deps |
Other handles loaded first |
Versions are computed per file via buddyx()->get_asset_version() for cache busting, so you never hand-maintain a version string. Preloading itself can be toggled with the buddyx_preloading_styles_enabled filter (it is disabled automatically under AMP).
JS handle structure
get_js_files() declares seven base handles, all global, footer-loaded, and dependent on jquery:
| Handle | File (assets/js/) |
Loading | Notes |
|---|---|---|---|
buddyx-superfish |
superfish.min.js |
defer |
Menu behaviour |
buddyx-isotope-pkgd |
isotope.pkgd.min.js |
defer |
Masonry/grid layout |
buddyx-fitvids |
fitvids.min.js |
defer |
Responsive video |
buddyx-sticky-kit |
sticky-kit.min.js |
defer |
Sticky sidebar |
buddyx-jquery-cookie |
jquery-cookie.min.js |
defer |
Cookie helper |
buddyx-slick |
slick.min.js |
defer |
Carousels |
buddyx-custom |
custom.min.js |
normal | Main theme JS; localizes buddyx_ajax (nonce, ajaxurl) |
Conditional handles are appended when their integration is active:
| Handle | Guard |
|---|---|
buddyx-gamipress |
GamiPress |
buddyx-buddypress |
BuddyPress |
buddyx-learndash |
SFWD_LMS |
loading maps to wp_script_add_data() (async or defer); footer controls in-footer output; localize feeds wp_localize_script(). The buddyx_js_files filter lets you disable, replace, or add entries the same way as CSS.
Source vs. built assets
Source files are authored under src/; the build tools compile them to minified siblings one level up, which is what the manifests enqueue.
| Type | Source | Built output | Compiler |
|---|---|---|---|
| CSS | assets/css/src/*.css |
assets/css/*.min.css |
lightningcss |
| JS | assets/js/src/*.{js,tsx} |
assets/js/*.min.js |
esbuild |
| JS vendor | assets/js/src/**/*.cjs |
copied to assets/js/*.min.js |
copied as-is (UMD bundles) |
| Editor CSS | assets/css/src/… |
assets/css/editor/editor-styles.min.css |
lightningcss (added via add_editor_style()) |
The CSS build resolves @import statements manually and prepends the theme's @custom-media breakpoint definitions (--narrow-menu-query, --wide-menu-query, --content-query, --sidebar-query) before minifying, so partials such as _header.css and _typography.css collapse into single output files.
Edit the src/ files, never the .min output. A rebuild overwrites anything you change in the built files.
Build commands
Defined in package.json (scripts). Node >=20.13.1, npm >=10.5.2.
| Command | Runs | Purpose |
|---|---|---|
npm run build:css |
node scripts/build-css.js |
Compile + minify all CSS (lightningcss) |
npm run build:js |
node scripts/build-js.js |
Bundle + minify all JS (esbuild) |
npm run dev:css |
build-css.js --dev |
Unminified CSS for debugging |
npm run dev:js |
build-js.js --dev |
Unminified JS for debugging |
npm run build |
node scripts/cli.js build |
Full build (CSS + JS + assets) |
npm run dev |
node scripts/cli.js dev |
Watch mode with BrowserSync |
npm run build:blocks |
node scripts/build-all-blocks.js |
Build bundled block assets |
npm run lint:css / lint:js |
stylelint / eslint on src/ |
Lint before building |
Typical loop:
npm install # first time
npm run dev # watch + live reload while editing src/
npm run build # produce final .min.css / .min.js before commit
The pre-commit hook (lint-staged) auto-fixes staged assets/css/src/** with stylelint and assets/js/src/** with eslint, so keep edits in src/.
Enqueue your own child-theme assets after BuddyX
BuddyX loads templates with standard get_template_part(), and its handles are stable, so child-theme assets follow the normal WordPress pattern: hook wp_enqueue_scripts at a priority above 10 (BuddyX enqueues at the default 10) and declare a BuddyX handle as a dependency so your file loads last.
Child-theme stylesheet after the parent
add_action( 'wp_enqueue_scripts', function () {
wp_enqueue_style(
'buddyx-child',
get_stylesheet_uri(), // child theme style.css
array( 'buddyx-global' ), // load after BuddyX core CSS
wp_get_theme()->get( 'Version' )
);
}, 20 );
Child-theme script depending on theme JS
add_action( 'wp_enqueue_scripts', function () {
wp_enqueue_script(
'buddyx-child-scripts',
get_stylesheet_directory_uri() . '/assets/js/child.js',
array( 'jquery', 'buddyx-custom' ), // after BuddyX main JS
wp_get_theme()->get( 'Version' ),
true // in footer
);
}, 20 );
Remove a BuddyX asset you do not want
Because handles are stable, dequeue the WordPress-native way at priority 20 (after BuddyX's 10):
add_action( 'wp_enqueue_scripts', function () {
wp_dequeue_style( 'buddyx-slick' ); // e.g. you are not using carousels
}, 20 );
Extend the manifest instead (theme-level / plugin authors)
For conditional orchestration rather than an unconditional enqueue, filter the manifest so your entry inherits BuddyX's preload and dependency handling:
add_filter( 'buddyx_css_files', function ( $css_files ) {
$css_files['my-feature'] = array(
'file' => 'my-feature.min.css', // under assets/css/
'global' => false,
'preload_callback' => function () { return is_page( 'pricing' ); },
'media' => 'all',
'deps' => array( 'buddyx-global' ),
);
return $css_files;
} );
Use the manifest filter when your asset lives inside the theme's assets/css/ (or assets/js/) tree and you want BuddyX's conditional loading. Use plain wp_enqueue_*() at priority 20 for child-theme files that live in the child theme directory. Both approaches respect the stable handle names.
Debugging what loads
To confirm which handles fire on a page:
add_action( 'wp_print_styles', function () {
global $wp_styles;
error_log( 'Enqueued styles: ' . implode( ', ', $wp_styles->queue ) );
} );
Or open the browser Network tab and filter by .css / .js: BuddyX handle names are encoded in the built paths (for example buddypress.min.css, custom.min.js).
Related
- Developer docs index
- Child theme
- Action hooks
- Filter hooks
- Template structure and overrides
- Design tokens