5

I will like to implement a few of the boilerplate template features in one of my instance WordPress.

I am trying to figure out how to exchange the regular jquery calls below

<script type='text/javascript' src='http:/.../wp-includes/js/jquery/jquery.js?ver=1.4.4'></script>
<script type='text/javascript' src='http://.../wp-includes/js/jquery/ui.core.js?ver=1.8.9'></script>

to this:

<!-- Grab Google CDN's jQuery, with a protocol relative URL; fall back to local if necessary -->
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.js"></script>
<script>window.jQuery || document.write("<script src='js/libs/jquery-1.5.1.min.js'>\x3C/script>")</script>
15

You should be loading jQuery with wp_enqueue_script('jquery') - that way, you won't end up with multiple instances if plugins try to load it too.

To use Google CDN, place this in your functions.php;

wp_deregister_script( 'jquery' );
wp_register_script(
    'jquery',
    'https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js', 
    null, // Dependencies - none
    null  // Version - use null to prevent WP adding version argument "?ver" in URL
);

Update: Personally, and I know this sounds like a cop-out, but I wouldn't bother checking the CDN. Google is just so damn reliable, and it's more than likely it's already in the user's browser cache anyway (so many sites use Google's CDN).

However, in my duty to answer, you have one of two options;

  1. Check server side with a remote get, and if it fails, serve the local copy (expensive and not recommended)
  2. Run a script client-side that checks for jQuery, and prints the fallback if necessary

The trouble with 2) is that you need to inject this script right after jQuery, and before any other plugins that depend on it fire their scripts. The only way I know you can do this is to 'listen' for jQuery, then output the JavaScript on the next call.

The magic? Drop this in your functions.php;

/**
 * Print fallback script right after jQuery is printed from queue.
 *
 * @param   string $src
 * @return  string
 */
function wpse_12448_fallback_jquery( $src, $handle = null ) {
    static $run_next = false;

    if ( $run_next ) {
        // Defaults to WP bundled jQuery, but you should use your own that
        // matches the version loaded via CDN.
        $local = includes_url( 'js/jquery/jquery.js' );

        echo <<<JS
<script>window.jQuery || document.write( '<script src="$local"></script>' );</script>

JS;
        $run_next = false;
    }

    if ( $handle === 'jquery' )
        $run_next = true;

    return $src;
}

add_action( 'wp_head', 'wpse_12448_fallback_jquery', 2 );
if ( ! is_admin() )
    add_filter( 'script_loader_src', 'wpse_12448_fallback_jquery', 10, 2 );

For those in the know, this is also hooked to wp_head right after wp_print_scripts would have fired, in case there were no more scripts to print after jquery (the function does it's work on the next call, rather than the instance it is called with jQuery).

  • just noticed this nice little hack has been folded into the wordpress Roots theme - sweet github.com/retlehs/roots/blob/master/lib/scripts.php – orionrush Feb 8 '13 at 16:50
  • This answer is REALLY bad. It hardcodes the version of jQuery, so it is never going to update when WordPress updates. For example, current version is 1.12.4, this hardcodes 1.11.3. Also, by removing jQuery from WordPress' dependency management other plugins can't control it. – JPollock Feb 22 '17 at 2:11
  • @JPollock Valid points, but the question was how to use jQuery from a CDN with a fallback, and so I answered. IMO it varies - if you're building a theme for release, then yes, this can pose a hazard. But if you're building bespoke for yourself/clients, then I like the idea of using an explicit version of jQuery coupled with the benefits of a CDN. I think saying this answer is "REALLY bad" is a bit inflammatory and doesn't address the other side of the coin (relying on bundled jQuery leaves your theme's JS exposed to breaking in future updates). – TheDeadMedic Feb 22 '17 at 10:15
  • I do think the answer is really bad. to be more specific it is really bad for forward compatibility with plugins that expect the version of jQuery to be the version that WordPress core bundles. Even on client sites, things get updated, often times years later, by people without an understanding of what might be the difference between jQuery versions. – JPollock Feb 24 '17 at 17:09
  • I've built and maintained (for years) an awful lot of WordPress themes using hardcoded jQuery CDNs, and have never had a problem. If I did the same in a publicly released theme? Maybe not the same story. And whilst I accept your point about forward compatibility, you seem to disregard the counter point that relying on bundled still leaves you exposed. Point is it depends, and I don't think you'll convince me otherwise. But I appreciate the feedback, as always. – TheDeadMedic Feb 24 '17 at 17:37
2

Two things to keep in mind about this answer:

  • Never do this in a plugin or theme for release.
  • WordPress plugins rely on the correct version of jQuery being provided, that's why I'm not using jQuery 3 and not hardcoding version numbers. Instead I'm letting WordPress set the version number for the version loaded form the CDN.

```

add_action( 'init', function(){
    //Only act if in admin
    if (  ! is_admin()) {
        //set protocol dynamically
        if( is_ssl() ){
            $protocol = 'https';
        }else {
            $protocol = 'http';
        }

        /** @var WP_Scripts $wp_scripts */
        global  $wp_scripts;
        /** @var _WP_Dependency $core */
        $core = $wp_scripts->registered[ 'jquery-core' ];
        $core_version = $core->ver;
        $core->src = "$protocol://ajax.googleapis.com/ajax/libs/jquery/$core_version/jquery.min.js";

        ///Use jQuery migrate if WP_DEBUG
        if ( WP_DEBUG ) {
            /** @var _WP_Dependency $migrate */
            $migrate         = $wp_scripts->registered[ 'jquery-migrate' ];
            $migrate_version = $migrate->ver;
            $migrate->src    = "$protocol://cdn.jsdelivr.net/jquery.migrate/$migrate_version/jquery-migrate.min.js";
        }else{
            /** @var _WP_Dependency $jquery */
            $jquery = $wp_scripts->registered[ 'jquery' ];
            $jquery->deps = [ 'jquery-core' ];
        }

    }


}, 11 );

```

Notice that I'm still using WordPress' dependency management system. Also, sets HTTPS vs HTTP using is_ssl() to avoid mixed content errors, and lets WordPress dictate version number.

2

For Wordpress 4.5.0 + : wp_add_inline_script() #

function jquery_enqueue_with_fallback() {
    wp_deregister_script( 'jquery' );
    wp_register_script( 'jquery' , '//ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js', false, '3.1.1', true );
    wp_add_inline_script( 'jquery', 'window.jQuery||document.write(\'<script src="'.esc_url(get_template_directory_uri()).'/libs/js/jquery.js"><\/script>\')' );
    wp_enqueue_script( 'jquery' );
}
add_action( 'wp_enqueue_scripts' , 'jquery_enqueue_with_fallback' );

Note : Change the version and your own local jQuery source.

  • I had to use 'window.jQuery||document.write("<script src='.esc_url(includes_url('/js/jquery/jquery.js')).'><\/script>");' because wordpress was rewriting my quotes, and I use the core bundled as a fallback. – WraithKenny Sep 29 '16 at 18:09

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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