Skip to main content

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

ConceptWhat it meansWhere it lives
EnqueueRegister/load assets through WordPresswp_enqueue_scripts hook
Dependency orderParent CSS first, child CSS secondwp_enqueue_style( ..., array( 'parent-handle' ) )
Cache bustingVersion string changes when file changesfilemtime()
Conditional loadingLoad JS only when neededis_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

PracticeWhy
Keep JS minimalTheme JS runs everywhere
Use filemtime() in stagingFaster iteration and fewer cache bugs
Group CSS by intentEasier maintenance
Document asset handlesPrevent collisions

Troubleshooting

SymptomCauseFix
Child CSS not overridingWrong enqueue orderEnsure child style depends on parent
CSS changes not visibleCachePurge LSCache and verify version strings
404 on assetsWrong file pathConfirm file exists and URL is correct

Hands-On

  1. Create assets/css/custom.css and assets/js/custom.js.
  2. Enqueue them using filemtime().
  3. 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