Handling jQuery Component Collision

In plugin development, what is the best practice to prevent jQuery component collision on the front end?

For instance, let’s say I include the jQuery Apprise dialog in a plugin that loads this on the front-end for something, yet another plugin may do the same. Because this gets loaded and declared twice, or perhaps one is forked and customized while mine is not, we get Javascript errors on the frontend (I assume).

Read More

(Note that I’m doing the best practice of using the wp_register_script() and wp_enqueue_script() strategy via a wp_head() action event in order to load a jQuery component on the frontend.)

Related posts

Leave a Reply

3 comments

  1. My suggestion would be to use a mix of code isolation in an anonymous function and checking if jquery is already present.

    Here’s an example:

    (function() {
    
    var jQuery;  // your jquery variable
    
    // check if jquery is present and if it has the version you want
    if (window.jQuery === undefined || window.jQuery.fn.jquery !== '1.8.3') {
    
        // load jquery lib from google hosted libraries
        var script_tag = document.createElement('script');
        script_tag.setAttribute("type","text/javascript");
        script_tag.setAttribute("src","http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js");
    
        // wait for jquery lib to load
        if (script_tag.readyState) {
          script_tag.onreadystatechange = function () { // old versions of IE
              if (this.readyState == 'complete' || this.readyState == 'loaded') {
                  jqueryLoadHandler();
              }
          };
        } else { // for other browsers
          script_tag.onload = jqueryLoadHandler;
        }
    
        // Try to find the head, otherwise default to the documentElement
        (document.getElementsByTagName("head")[0] || document.documentElement).appendChild(script_tag);
    
    } else {
    
        // The current site is already using the jquery you want, so just point your variable to that jquery
        jQuery = window.jQuery;
        main();
    }
    
    // as soons as jquery is loaded
    function jqueryLoadHandler() {
        // Restore $ and window.jQuery to their previous values and store the
        // new jQuery in our local jQuery variable
        jQuery = window.jQuery.noConflict(true);
    
        // Call plugin main function
        main(); 
    }
    
    // plugin main function
    function main() { 
        jQuery(document).ready(function($) { 
            // Here you can use the $ without any problems
        });
    }
    
    })(); // We call our anonymous function immediately
    

    This way you can use jQuery without problems in your plugin, even if other plugins used jquery without wp_enqueue_script.
    Every variables and functions you use inside this anonymous function won’t interfere with the rest of the page.

    Maybe this could work even better if it was integrated with wp_enqueue_script.

    You can read more about this approach of loading jquery inside an anonoymous function in http://alexmarandon.com/articles/web_widget_jquery/

  2. The best practice to enqueue or registering scripts is to use wp_register_script and wp_enqueue_script. Plugins and themes which do not use this functions to add their scripts, should not be used.

    The reason is simple: with wp_register_script() we are able to retrieve a lot of informations about registered scripts. Especially if a given source is already registered or not.

    I wrote a simple class to test if a source is already registered. The class can deregister the script and register the new script or skip the new script. This class should be a starting point for your own development. It is not for production enviroment!

    How do the class work?

    The class retrieve an array with the scripts that should be registered. Than it compare the filenames (and only the filenames) of each registered script with the filenames of the scripts that should be registered. If the script/filename isn’t already registered, it’s handle will be added to an array and will be registered at a later point.

    The class can be extended to compare the full path of the script or the version or whatever is needed to decide if the script should be registered or not.

    A simple example

        $my_scripts = array(
    
                'foo' => array(
                        'src' => 'external/ressource/foo.js',
                        'deps' => array( 'jquery' ),
                        'version' => false,
                        'in_footer' => true
                        ),
    
                'bar' => array(
                        'src' => home_url( '/wp-admin/js/common.min.js' ),
                        'deps' => false,
                        'version' => false,
                        'in_footer' => true
                        ),
    
                'jquery' => array(
                        'src' => '//ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js',
                        'deps' => false,
                        'version' => '1.8.3',
                        'in_footer' => true
                        ),
    
        );
    
        $safe_register = new Safe_Registering_Scripts( $my_scripts, true );
    
        global $wp_scripts;
    
        var_dump( $wp_scripts->registered['jquery'] );
    

    At first we define an array with all our scripts to be registered. The class will walk over our scripts and compare if the source is already registered.

    • the foo script will be always registered because the source isn’t registered.
    • the bar script will never be registered because it’s source is already registered.
    • the jquery script is a special case. There is already a handle called jquery but the second parameter in the class call says that this script source have to be replaced with the new source.

    As you can see in the var_dump(), the source of the jquery script was replaced by the class. So if you extend the class and adjust the test (source, js filename, version, enqueued scripts, etc.), it could help to minimize js collisions.

  3. Problem with jQuery core is very common and many plugins have a lot of ways to prevent it.

    When we talk about plugins for jQuery there is another problem but you can remove it in simillar way.

    In your sittuation I prefer common solution to add include switch on settings page of your plugin – I think this is very popular for plugins with jQuery core, but you can use it for jQuery plugins too.

    Another solution is write a script in js to check if jQuery extra method (from plugin) is defined, when it is not you can include plugin in your script. This solution will only work if you add a hook for scripts with a very low priorty. It will run after other plugins and this condition will work.