33

I have this in my functions.php file and I can't get jQuery to load in the footer. The includes file loads in the footer fine, though. What else do I need to do?

function starter_scripts() {
    wp_enqueue_style( 'starter-style', get_stylesheet_uri() );

    wp_enqueue_script( 'jquery', '', '', '', true );

    wp_enqueue_script( 'includes', get_template_directory_uri() . '/js/min/includes.min.js', '', '', true );
}
add_action( 'wp_enqueue_scripts', 'starter_scripts' );
2

6 Answers 6

29

To do that you will first have to deregister your jQuery script and then register again. If you use jQuery comes with WordPress then following is the function your are looking for.

function starter_scripts() {
    wp_deregister_script( 'jquery' );
    wp_register_script( 'jquery', includes_url( '/js/jquery/jquery.js' ), false, NULL, true );
    wp_enqueue_script( 'jquery' );

    wp_enqueue_style( 'starter-style', get_stylesheet_uri() );
    wp_enqueue_script( 'includes', get_template_directory_uri() . '/js/min/includes.min.js', '', '', true );
}
add_action( 'wp_enqueue_scripts', 'starter_scripts' );

If you use Google CDN hosted version of jQuery then let me know I will modify this code for Google CDN URL.

8
  • 6
    What do you mean? The solution is about moving jQuery to footer.
    – Robert hue
    Sep 3, 2015 at 10:58
  • 2
    You might also need to check is_admin() to avoid making changes to the backend jQuery, after all we only really need to optimise the frontend of our sites :)
    – Tim Malone
    Oct 20, 2016 at 22:10
  • 2
    @TimMalone - actually, you don't - wp_enqueue_scripts is used only on front end while admin_enqueue_scripts is used for back end
    – dev_masta
    Mar 4, 2017 at 17:18
  • 1
    I think this solution is actually horrible. Are the version tags are removed with this. What is this starter-style and that is this includes.min.js and what has it to do with jQuery. Jul 31, 2017 at 9:09
  • 2
    @redanimalwar starter-style and includes files are directly from the question.
    – tehlivi
    Jan 16, 2018 at 18:43
60

Here's another option which avoids having to de-register and re-register:

/**
 * Move jQuery to the footer. 
 */
function wpse_173601_enqueue_scripts() {
    wp_scripts()->add_data( 'jquery', 'group', 1 );
    wp_scripts()->add_data( 'jquery-core', 'group', 1 );
    wp_scripts()->add_data( 'jquery-migrate', 'group', 1 );
}
add_action( 'wp_enqueue_scripts', 'wpse_173601_enqueue_scripts' );

This solution mimics WordPress core by setting the group to 1, which is how WordPress determines if a script should be in the footer or not (I'm not aware of the reasoning for 1, as @jgraup noted in the comments it seems a bit arbitrary).

16
  • 1
    Interesting. It looks like wp_register_script uses add_data( $handle, 'group', 1 ) to move scripts into the footer. core.trac.wordpress.org/browser/tags/4.5/src/wp-includes/… - Could you expand on why that is? Glancing at your code, 'group' seems a bit arbitrary. But I can see in core.trac.wordpress.org/browser/tags/4.5/src/wp-includes/… how it's used in WP_Scripts->do_item later. Either way, this would seem to be the least destructive answer.
    – jgraup
    May 7, 2016 at 18:37
  • 2
    I hope someone can comment further on these three upvoted answers. All are different and require some knowledge of WP. Because google requires these scripts to be below the fold, this is an important topic.
    – ssaltman
    May 18, 2016 at 13:32
  • 3
    Best answer! Note: it works since WordPress 4.2.0 and use it in functions.php in hook 'wp_enqueue_scripts' callback
    – realmag777
    Jul 1, 2016 at 18:22
  • Hi I tried the above approach, but it didn't worked. Can anyone help?
    – iSaumya
    Aug 31, 2016 at 12:13
  • 1
    This is so good! Thank you so much. But, worth noting is as @tehlivi states - WP uses an old version of jQuery - consider deregistering and registering a newer version.
    – skolind
    Mar 8, 2018 at 9:24
24

A better solution:

add_action( 'wp_default_scripts', 'move_jquery_into_footer' );

function move_jquery_into_footer( $wp_scripts ) {

    if( is_admin() ) {
        return;
    }

    $wp_scripts->add_data( 'jquery', 'group', 1 );
    $wp_scripts->add_data( 'jquery-core', 'group', 1 );
    $wp_scripts->add_data( 'jquery-migrate', 'group', 1 );
}

Why its better then the accepted answer IMO

  1. Changes it at the very core not at a later stage where other things might already messed with it.
  2. The version string it kept in place and not removed!
  3. It does not unregister and reregister a script but it just sets the group value that is essentially the same as if the script would be registered with $footer = true.

About not doing this to the admin

If plugins add inline jquery to the wp_head it will fail when jquery is not loaded at that point, so I suggest you avoid that until you have millions editing your site and you try to performance optimize your admin. This is true for frontend as well so you should watch out for bad coded themes or plugins that assume jquery in the head by using inline jQuery code. WP and plugins register other scripts to the admin head with jquery in deps so it would not work anyway I think.

About it not working

You need to be aware that if any other script is loaded to the head that has jQuery in its dependencies, it will also make jQuery load in the head right before itself. And this is good and expected, the reason the wp_enqueue system exists. This means you will learn soon if you use a few plugins that one of them will require cause jquery to the head. It the the default for enqueued scripts, sadly.

Radical Solution

I think it will brake any inline JS that assumes jquery but should that should be rare. This will force all scripts to the footer regardless of how they are enqueued.

add_action( 'wp_enqueue_scripts', 'js_to_footer' );

function js_to_footer() {
  remove_action( 'wp_head', 'wp_print_scripts' );
  remove_action( 'wp_head', 'wp_print_head_scripts', 9 );
  remove_action( 'wp_head', 'wp_enqueue_scripts', 1 );
}
7
  • 2
    While this may answer the question and has some good points to chew on there's too much noise (fluff?) in the answer and is very similar to the previously posted answers with minor code improvements. It may be more well received if it were edited and slimmed down into a more informational version. There's also no real need to call out specific users or answers ( as they may not exist for whatever reason in the future ).
    – Howdy_McGee
    Oct 21, 2016 at 20:38
  • You call a completely unmentioned and probably better then anything mentioned in other answers "minor code improvements". Well thats simply untrue. Also I did not "call out" anyone, I just mentioned facts that I know to improve coding style and educate readers about it to make them write better code. Seriously I did take quite some time to write the best answer here to far and this is what I get for it. Oct 21, 2016 at 20:58
  • 4
    The other answers mention nothing about others scripts forcing the jQuery to the head, in fact my answer takes the confusion away from people who don't know why its not working. None of the others answers mention the potential risks ... Oct 21, 2016 at 21:03
  • This code (as the code of the answer above) returned me a 500 error. I have WordPress 4.9.9 Jan 8, 2019 at 9:19
  • Hard to believe that this code is causing a 500, you probably have made a mistake in implementing this in your code. This is not really the right place to ask and your outdated WP version is hardly enough information. Jan 9, 2019 at 18:19
2

I have developed a plugin for this specific problem. This plugin doesn't mess with WordPress jQuery as it is only loaded in the front-end. See: jQuery Manager for WordPress

Why yet another jQuery Updater / Manager / Developer / Debugging tool?

Because none of the developer tools lets you select a specific version of jQuery and/or jQuery Migrate. Providing both the compressed minified / production and the uncompressed / development version. See features below!

✅ Only executed in the front-end, doesn't interfere with WordPress admin/backend and WP customizer (for compatibility reasons) See: https://core.trac.wordpress.org/ticket/45130 and https://core.trac.wordpress.org/ticket/37110

Turn on/off jQuery and/or jQuery Migrate

✅ Activate a specific version of jQuery and/or jQuery Migrate

And much more! The code is open source, so you could study it, learn from it and contribute.


Almost everybody uses the incorrect handle

WordPress actually uses the jquery-core handle, not jquery:

https://github.com/WordPress/WordPress/blob/f84ab5e19f0038a3abec71821c9b8f47a4272942/wp-includes/script-loader.php#L1017

// jQuery
$scripts->add( 'jquery', false, array( 'jquery-core', 'jquery-migrate' ), '1.12.4-wp' );
$scripts->add( 'jquery-core', '/wp-includes/js/jquery/jquery.js', array(), '1.12.4-wp' );
$scripts->add( 'jquery-migrate', "/wp-includes/js/jquery/jquery-migrate$suffix.js", array(), '1.4.1' );

The jquery handle is just an alias to load jquery-core with jquery-migrate

See more info about aliases: wp_register_script multiple identifiers?

The correct way to do it

In my example below I use the official jQuery CDN at https://code.jquery.com I also use script_loader_tag so that I could add some CDN attributes.
You could use the following code:

// Front-end not excuted in the wp admin and the wp customizer (for compatibility reasons)
// See: https://core.trac.wordpress.org/ticket/45130 and https://core.trac.wordpress.org/ticket/37110
function wp_jquery_manager_plugin_front_end_scripts() {
    $wp_admin = is_admin();
    $wp_customizer = is_customize_preview();

    // jQuery
    if ( $wp_admin || $wp_customizer ) {
        // echo 'We are in the WP Admin or in the WP Customizer';
        return;
    }
    else {
        // Deregister WP core jQuery, see https://github.com/Remzi1993/wp-jquery-manager/issues/2 and https://github.com/WordPress/WordPress/blob/91da29d9afaa664eb84e1261ebb916b18a362aa9/wp-includes/script-loader.php#L226
        wp_deregister_script( 'jquery' ); // the jquery handle is just an alias to load jquery-core with jquery-migrate
        // Deregister WP jQuery
        wp_deregister_script( 'jquery-core' );
        // Deregister WP jQuery Migrate
        wp_deregister_script( 'jquery-migrate' );

        // Register jQuery in the head
        wp_register_script( 'jquery-core', 'https://code.jquery.com/jquery-3.3.1.min.js', array(), null, false );

        /**
         * Register jquery using jquery-core as a dependency, so other scripts could use the jquery handle
         * see https://wordpress.stackexchange.com/questions/283828/wp-register-script-multiple-identifiers
         * We first register the script and afther that we enqueue it, see why:
         * https://wordpress.stackexchange.com/questions/82490/when-should-i-use-wp-register-script-with-wp-enqueue-script-vs-just-wp-enque
         * https://stackoverflow.com/questions/39653993/what-is-diffrence-between-wp-enqueue-script-and-wp-register-script
         */
        wp_register_script( 'jquery', false, array( 'jquery-core' ), null, false );
        wp_enqueue_script( 'jquery' );
    }
}
add_action( 'wp_enqueue_scripts', 'wp_jquery_manager_plugin_front_end_scripts' );


function add_jquery_attributes( $tag, $handle ) {
    if ( 'jquery-core' === $handle ) {
        return str_replace( "type='text/javascript'", "type='text/javascript' integrity='sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=' crossorigin='anonymous'", $tag );
    }
    return $tag;
}
add_filter( 'script_loader_tag', 'add_jquery_attributes', 10, 2 );
1
  • 1
    This places jQuery in the head (as per your own inline comment) and is not an answer for OP.
    – Pim Schaaf
    Jan 30, 2020 at 17:58
0
add_action("wp_enqueue_scripts", "myscripts");

function myscripts() { 
   wp_enqueue_script( 'jquery' , '', array(), true); //true for footer
   wp_enqueue_script( 'someScript-js', 'https://domain.com/someScript.js' , '', '', true );
}
-3

Hey only change your code to like this

function starter_scripts() {
        wp_enqueue_style( 'starter-style', get_stylesheet_uri() );
        wp_enqueue_script('jquery');
        wp_enqueue_script( 'includes', get_template_directory_uri() . '/js/min/includes.min.js', array( 'jquery' ) );
    }
    add_action( 'wp_enqueue_scripts', 'starter_scripts' );

i think it work fine

add this lines into your functions.php file

remove_action('wp_head', 'wp_enqueue_scripts', 1);
add_action('wp_footer', 'wp_enqueue_scripts', 5);

then it add script into footer

4
  • This puts jQuery in the head. I need it in the footer.
    – Desi
    Dec 30, 2014 at 20:06
  • Hey Desi please check the edited answer I think it help you Dec 30, 2014 at 20:13
  • 6
    I'm pretty sure this is a terrible idea -- you've effectively prevented anything from loading scripts in the header, not just jQuery, and might be double-enqueuing scripts (haven't looked that deeply). In fact, you probably only need the remove_action / add_action part if you're going to do it this way.
    – drzaus
    Jan 26, 2016 at 20:34
  • 1
    Indeed terrible idea, don't do this! Sep 26, 2016 at 20:50

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.