How to Enqueue Scripts and Styles Correctly in WordPress

WordPress has its own asset loading system built around wp_enqueue_script() and wp_enqueue_style(). Using it — instead of hardcoded <script> and <link> tags in the theme header — ensures correct dependency ordering, deduplication, and compatibility with plugins that may need the same assets.

Problem: How do you correctly load CSS and JavaScript files in WordPress without conflicts or duplicate loads?

Solution: Use wp_enqueue_style() and wp_enqueue_script() inside a wp_enqueue_scripts action hook, declaring handles and dependencies so WordPress resolves the load order automatically.

A complete example enqueuing a stylesheet and two scripts (one of which depends on jQuery):

add_action( 'wp_enqueue_scripts', 'mytheme_enqueue_assets' );

function mytheme_enqueue_assets() {
    $ver = wp_get_theme()->get( 'Version' );

    // Main stylesheet
    wp_enqueue_style(
        'mytheme-style',
        get_stylesheet_uri(),
        [],
        $ver
    );

    // A plugin-style CSS file
    wp_enqueue_style(
        'mytheme-slick',
        get_template_directory_uri() . '/vendor/slick/slick.css',
        [],
        '1.8.1'
    );

    // jQuery is already registered by WordPress — just enqueue it
    wp_enqueue_script( 'jquery' );

    // Custom script depending on jQuery, loaded in the footer
    wp_enqueue_script(
        'mytheme-main',
        get_template_directory_uri() . '/js/main.js',
        [ 'jquery' ],
        $ver,
        true  // true = load in footer
    );

    // Pass PHP data to JavaScript
    wp_localize_script( 'mytheme-main', 'siteData', [
        'ajaxUrl' => admin_url( 'admin-ajax.php' ),
        'nonce'   => wp_create_nonce( 'mytheme_nonce' ),
        'siteUrl' => home_url( '/' ),
    ] );
}

To load assets only on specific pages:

add_action( 'wp_enqueue_scripts', 'mytheme_conditional_assets' );

function mytheme_conditional_assets() {
    if ( is_page( 'contact' ) ) {
        wp_enqueue_script( 'google-maps',
            'https://maps.googleapis.com/maps/api/js?key=YOUR_KEY',
            [],
            null,
            true
        );
    }
}

NOTE: Always load scripts in the footer (true as the fifth argument) unless they must run before the page renders. Use null as the version for external scripts with their own cache-busting — passing a version appends a ?ver= query string that can conflict.