Loading Styles & Scripts
warning
Do not enqueue large JS bundles "just because". Theme JS affects every page and can regress INP.
Loading Styles & Scripts Explained
| Concept | What it means | Where it lives |
|---|---|---|
| Enqueue | Register/load assets through WordPress | wp_enqueue_scripts hook |
| Dependency order | Parent CSS first, child CSS second | wp_enqueue_style( ..., array( 'parent-handle' ) ) |
| Cache busting | Version string changes when file changes | filemtime() |
| Conditional loading | Load JS only when needed | is_page(), is_singular() checks |
Why It Matters
- Correct enqueue order prevents "why are my overrides ignored" issues.
- Versioning prevents stale CSS under LSCache.
- Conditional loading prevents performance regressions.
How It Works
WordPress runs wp_enqueue_scripts during page render. Your child theme registers CSS/JS, and the browser downloads those assets. Cache behavior depends on version strings and server caching.
Practical Walkthrough
Step 1: Create Asset Folders
create-child-asset-folders.sh
cd /var/www/html
mkdir -p wp-content/themes/generatepress-child/assets/css
mkdir -p wp-content/themes/generatepress-child/assets/js
Step 2: Create Minimal Asset Files
create-minimal-assets.sh
cat > wp-content/themes/generatepress-child/assets/css/custom.css <<'EOF'
.gp-child-proof { border: 2px dashed #1e3a8a; padding: 8px; }
EOF
cat > wp-content/themes/generatepress-child/assets/js/custom.js <<'EOF'
// Custom JS (keep minimal)
console.log('generatepress-child custom.js loaded');
EOF
Step 3: Enqueue Assets with filemtime() Versioning
wp-content/themes/generatepress-child/functions.php
<?php
add_action( 'wp_enqueue_scripts', function() {
wp_enqueue_style(
'generatepress-parent',
get_template_directory_uri() . '/style.css'
);
wp_enqueue_style(
'generatepress-child',
get_stylesheet_directory_uri() . '/style.css',
array( 'generatepress-parent' ),
filemtime( get_stylesheet_directory() . '/style.css' )
);
wp_enqueue_style(
'generatepress-child-custom',
get_stylesheet_directory_uri() . '/assets/css/custom.css',
array( 'generatepress-child' ),
filemtime( get_stylesheet_directory() . '/assets/css/custom.css' )
);
wp_enqueue_script(
'generatepress-child-custom',
get_stylesheet_directory_uri() . '/assets/js/custom.js',
array(),
filemtime( get_stylesheet_directory() . '/assets/js/custom.js' ),
true
);
} );
caution
If your site uses aggressive cache/minify plugins, they may override versioning. Test with those plugins disabled on staging when debugging.
Step 4: Verify Files Exist from the CLI
verify-assets-exist.sh
cd /var/www/html
ls -lah wp-content/themes/generatepress-child/assets/css
ls -lah wp-content/themes/generatepress-child/assets/js
Practical Examples
Example 1: Conditional Script Loading
wp-content/themes/generatepress-child/functions.php
<?php
add_action( 'wp_enqueue_scripts', function() {
if ( is_page( 'contact' ) ) {
wp_enqueue_script( 'contact-page', get_stylesheet_directory_uri() . '/assets/js/contact.js', array(), '1.0.0', true );
}
} );
Example 2: Add defer (Advanced)
If you need defer, use script_loader_tag and scope it to your handle.
Best Practices
| Practice | Why |
|---|---|
| Keep JS minimal | Theme JS runs everywhere |
Use filemtime() in staging | Faster iteration and fewer cache bugs |
| Group CSS by intent | Easier maintenance |
| Document asset handles | Prevent collisions |
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
| Child CSS not overriding | Wrong enqueue order | Ensure child style depends on parent |
| CSS changes not visible | Cache | Purge LSCache and verify version strings |
| 404 on assets | Wrong file path | Confirm file exists and URL is correct |
Hands-On
- Create
assets/css/custom.cssandassets/js/custom.js. - Enqueue them using
filemtime(). - Confirm changes appear after a cache purge.
Quick Reference
enqueue-cheatsheet.sh
cd /var/www/html
ls wp-content/themes/generatepress-child/assets/css
ls wp-content/themes/generatepress-child/assets/js
What's Next
- Next: Recommended functions.php Patterns
- Related: Customizer Essentials