6
JavaScript

In the first edition of this book, we wrote that JavaScript is “principally a language used to code plain‐text script executed on the client side, that is, the browser.” Since then, JavaScript has exploded into one of the world's most popular programming languages, and that statement is no longer completely accurate.

JavaScript can be used to power a web server using Node, and the web is now full of rich and powerful tooling that is pushing the boundaries of what is possible in‐browser. Even the bulk of the latest and greatest block‐based content editor is coded using nearly nothing but JavaScript.

This chapter covers best practices for getting your JavaScript files registered and enqueued inside WordPress. It will educate you on what JavaScript comes bundled with WordPress, including some oldies but goodies. It will help prepare you for the next chapter, which will put everything you've learned across multiple chapters to work using Gutenberg, the block‐based editing experience included in the latest versions of WordPress.

When it comes to JavaScript in WordPress, remember this:

  • Always register. Conditionally enqueue.

REGISTERING SCRIPTS

WordPress expects all JavaScript files to be registered. Registering prevents multiple plugins from including duplicates of the same JavaScript libraries multiple times and also just generally helps you keep track of all the JavaScript you are packaging inside your WordPress plugins (which can sometimes be a lot!).

Registering is simply announcing that some unique JavaScript file exists so that it can be easily included in the correct order later. Many things in WordPress are registered before they are used. Things like Post Types and Taxonomies are good examples of things we've already touched on in this book, and JavaScript is no different.

At the time of this writing, the official WordPress documentation considers registering your JavaScript files as optional, but we strongly recommend you consider it a requirement for everything you do. Even if you decide to skip this step and jump ahead to enqueueing, if you enqueue something that isn't registered, it does the registration just‐in‐time for you anyway. Do it yourself, and you'll be glad you did.

You can register your custom JavaScript files anytime in your loading or bootstrapping process. We recommend doing this relatively early, like on the plugins_loaded or init action hook, because if they are registered too late, it makes it difficult for other plugins to use your JavaScript reliably.

Register your JavaScript via the wp_register_script() function, like so:

/**
 * Register a script
 */
function pdev_register_scripts() {
       wp_register_script(
             'pdev-your-script-id',                    // Unique name
             plugin_dir_url( __FILE__ ) . 'your.js',   // URL to the file
             array(),                                  // Dependencies
             '1.0.0',                                  // Version
             true                                      // Output in Footer
       );
}
add_action( 'init', 'pdev_register_scripts' );

You can also similarly deregister a script if you need to:

/**
 * Deregister a script
 */
function pdev_deregister_scripts() {
       wp_deregister_script( 'pdev-your-script-id' );
}
add_action( 'init', 'pdev_deregister_scripts' );

We recommend registering each of your unique JavaScript files (and to avoid using the JavaScript @import approach) because it will always be better for WordPress to be aware of your JavaScript intentions, plus it helps you better organize all of the JavaScript you will likely be writing and working with in your professional plugins going forward.

It is still possible to write inline JavaScript, but it is highly recommended you avoid going this route in your professional plugins and stick to registering them. If you're considering just dumping some <script> tags into your post content or <head>, please reconsider refactoring your code so that your JavaScript fits into individual files that can be registered; you will be glad you did!

ENQUEUEING SCRIPTS

Now that you've registered your JavaScript files, it's time to enqueue them. Enqueueing is the way that WordPress manages what will end up being a somewhat complex tree of relationships between different scripts, the files they depend on, and the files that depend on them. Under the hood, it uses the WP_Dependencies API, which is exactly what is used when registering and enqueueing CSS.

This is also how you tell WordPress that your intention is to interact with (or include) what JavaScript on which available pages. Thanks to having registered all of your JavaScript earlier, the dependency tree will be completely managed for you!

You will typically want to enqueue your JavaScript on one of two different WordPress action hooks: admin_enqueue_scripts or wp_enqueue_scripts. The former is for admin area JavaScript, and the latter is for theme‐side JavaScript.

There are other atypical reasons and ways to enqueue your JavaScript, but we recommend avoiding them as much as you can. The added code complexity is difficult to maintain over time and will cause confusion and misunderstandings when it comes time to share your code with colleagues and with the rest of the world.

You will enqueue your registered JavaScript like this:

/**
 * Enqueue a script
 */
function pdev_enqueue_scripts() {
       wp_enqueue_script( 'pdev-your-script-id' );
}
add_action( 'wp_enqueue_scripts', 'pdev_enqueue_scripts' );

You may also similarly dequeue a previously enqueued script.

/**
 * Dequeue a script
 */
function pdev_dequeue_scripts() {
       wp_dequeue_script( 'pdev-your-script-id' );
}
add_action( 'wp_enqueue_scripts', 'pdev_dequeue_scripts' );

LIMITING SCOPE

Now that you know how to register and enqueue your JavaScript, the next thing you'll want to do is tune it so that you are enqueueing only on the WordPress pages where it is necessary for that JavaScript to be.

This is always going to be different based on the needs of your application, but by using your best judgment and a bit of trial and error, you will find it is possible to narrow down the scope based on just about any criteria you can imagine.

WordPress includes many helper functions for identifying what kind of page is being loaded. Functions like is_singular(), is_archive(), and more can be used to tell WordPress whether your custom JavaScript should be included.

In this example, you are looking for single pages with gallery shortcodes only:

/**
 * Enqueue only on single pages using Gallery shortcodes
 */
function pdev_enqueue_gallery_scripts() {
       if ( is_singular() && has_shortcode( get_the_content(), 'gallery' ) {
             wp_enqueue_script( 'pdev-your-script-id' );
       }
}
add_action( 'wp_enqueue_scripts', 'pdev_enqueue_gallery_scripts' );

LOCALIZING SCRIPTS

When you want to take something out of PHP and make it available within your JavaScript, you need to localize it. This API gets its name from the idea that all languages (not just coding ones) are restricted to their particular fixed area, but sometimes it's necessary to translate something from one language to another.

In the normal world, the act of translating words between languages is called localization, so why would that be any different in the coding world? Just because you know something in PHP doesn't mean you shouldn't know it in your JavaScript too, right? Right!

Localizing allows you to bridge the gap between what variable content you can ask WordPress for in PHP and translate it into your custom JavaScript for later reuse. In this section, you will take a PHP array of keys and values and turn it into a JavaScript object of keys and values instead. Magic!

In this example, we are localizing some strings and the time into our JavaScript:

/**
 * Enqueue only on single pages using Gallery shortcodes
 */
function pdev_localize_scripts() {
       wp_localize_script(
             'pdev-your-script-id',            // Script handle from previous
             'pdevScript',                     // Name of JavaScript object
             array(                            // Array of properties for JS object
                    'greeting' => __( 'Hello' )
                    'repeat'   => __( 'Hello, again' ),
                    'time'     => time()
             )
       );
}
add_action( 'wp_enqueue_scripts', 'pdev_localize_scripts' );

You can include anything you need to in your array, but you'll need to remember that localization applies only to the registered and enqueued JavaScript referenced in the script handle and only by using the name of the JavaScript object as you've named it. If you have more than one file you need to localize, simply make multiple calls to wp_localize_script(), one for each file.

INLINE SCRIPTS

If you must include inline scripts to accomplish your goals, you should use the wp_add_inline_script() function to do so. This allows you to output JavaScript directly before or after a registered JavaScript file is rendered to the page, allowing you to sneak ahead of or behind it right away, rather than needing to worry about the dependency tree of multiple JavaScript files.

In many ways, you can probably get by without using this approach, but it is useful for the times when you do need to do this. A good example of this in WordPress is the wp_localize_jquery_ui_datepicker() function. Its job is to make sure that anytime the jQuery UI Datepicker is initialized, the date and time abbreviations for the currently selected language are set in JavaScript.

/**
 * Localizes the jQuery UI datepicker.
 *
 * @since 4.6.0
 *
 * @link https://api.jqueryui.com/datepicker/#options
 *
 * @global WP_Locale $wp_locale WordPress date and time locale object.
 */
function wp_localize_jquery_ui_datepicker() {
       global $wp_locale;
 
       if ( ! wp_script_is( 'jquery-ui-datepicker', 'enqueued' ) ) {
             return;
       }
 
       // Convert the PHP date format into jQuery UI's format.
       $datepicker_date_format = str_replace(
             array(
                    'd',
                    'j',
                    'l',
                    'z', // Day.
                    'F',
                    'M',
                    'n',
                    'm', // Month.
                    'Y',
                    'y', // Year.
             ),
             array(
                    'dd',
                    'd',
                    'DD',
                    'o',
                    'MM',
                    'M',
                    'm',
                    'mm',
                    'yy',
                    'y',
             ),
             get_option( 'date_format' )
       );
 
       $datepicker_defaults = wp_json_encode(
             array(
                  'closeText'       => __( 'Close' ),
                  'currentText'     => __( 'Today' ),
                  'monthNames'      => array_values( $wp_locale->month ),
                  'monthNamesShort' => array_values( $wp_locale->month_abbrev ),
                  'nextText'        => __( 'Next' ),
                  'prevText'        => __( 'Previous' ),
                  'dayNames'        => array_values( $wp_locale->weekday ),
                  'dayNamesShort'   => array_values( $wp_locale->weekday_abbrev ),
                  'dayNamesMin'     => array_values( $wp_locale->weekday_initial ),
                  'dateFormat'      => $datepicker_date_format,
                  'firstDay'        => absint( get_option( 'start_of_week' ) ),
                  'isRTL'           => $wp_locale->is_rtl(),
             )
       );
 
       wp_add_inline_script( 'jquery-ui-datepicker', 
       "jQuery(document).ready(function(jQuery){jQuery.datepicker.
       setDefaults({$datepicker_defaults});});" );
}

As you can see, wp_add_inline_script() is particularly useful here in making sure that no matter when or why you are using the jQuery UI Datepicker library, it will always be invoked with the correct strings and settings for the chosen language.

At the time of this writing, you should consider using this in your own plugins relatively sparingly. The majority of the time, you will have complete control over your own code, where you should be able to register, enqueue, and localize, without ever having the need to use inline JavaScript. But as the web becomes increasingly dependent on JavaScript, inline scripts are becoming increasingly popular.

Here's a quick console.log() to show you how to do it:

/**
 * Inline right after your other script has been output to the page
 */
function pdev_inline_scripts() {
       wp_add_inline_script (
             'pdev-your-script-id',  // Script handle from previous
             'console.log("hello")'  // Your raw JavaScript
       );
}
add_action( 'wp_enqueue_scripts', 'pdev_inline_scripts' );

OVERVIEW OF BUNDLED SCRIPTS

WordPress comes bundled with many extremely useful JavaScript libraries and tools. These tools are there to be used, and you should at all costs avoid inventing your own versions of these technologies (unless you have a specific reason to do so).

The reason so much JavaScript is bundled with WordPress is because WordPress itself uses a lot of JavaScript for many everyday functions that you may not have ultimately needed to consider. Admin area pages like Menus, the Customizer, the Media Library, and even the Dashboard all rely on JavaScript libraries to make them work.

As time goes on, many pieces of functionality are being rewritten using React, but it will be many years before jQuery is completely unplugged from WordPress Admin, likely requiring a complete ground‐up rewrite of the entire Dashboard.

jQuery UI and Other Scripts

The bulk of the bundled scripts belongs to a library called jQuery and its partner project jQuery UI. Together, these scripts account for nearly 50 different unique JavaScript files that all exist to help make many complex tasks a breeze.

The list of bundled JavaScript changes rarely, but it does regularly enough that including a comprehensive list of them here would likely be out‐of‐date relatively quickly, so rather than list them all, we'll show you how to enqueue them quickly.

Let's say you want to include the jQuery UI library Sortable, because you have a need to make certain aspects of your plugin UI be able to be rearranged by the user. Thanks to the fact that all of these bundled libraries are already registered inside WordPress, you would simply need to enqueue it like so:

/**
 * Enqueue only on single pages using Gallery shortcodes
 */
function pdev_enqueue_sortable_scripts() {
       wp_enqueue_script( 'jquery-ui-sortable' );
}
add_action( 'wp_enqueue_scripts', 'pdev_enqueue_sortable_scripts' );

You may have noticed that we never enqueued jQuery itself. That's because WordPress already registered it as a dependency and knows that if you want jQuery UI Sortable, it needs to include jQuery ahead of it in the first place or your Sortables will not work.

In addition to jQuery, there are multiple color pickers, image croppers, Backbone, Underscore, zxcvbn, Masonry, CodeMirror, Twemoji, and many other useful tools to help you get a jump‐start on your plugin development.

The WP Global

The wp JavaScript global is a monolithic object that is used to encapsulate a ton of extremely useful utilities. Behind the scenes, WordPress has been using this global for years now as the place where it attaches most of its JavaScript‐related needs.

In recent years, this global has become the home to emoji parsing, the Heartbeat API, JavaScript Hooks, svgPainter, a11y Speak, Ajax, and many more (especially when viewing a page that uses the block‐based editor!).

There are so many utilities in there, it is impossible to document them all, so we are going to pick out a few of the more important and useful ones. At the time of this writing, there is no comprehensive documentation on most of these helpers. Your best bet to learn more today is to open your browser console in Inspector, type console.log( wp ), and start poking around to see what is available.

a11y Speak

Accessibility and JavaScript sometimes do not play nicely together. As the web becomes more interactive—more like an application than a page—the need to announce changes in page content has arisen.

wp.a11y.speak() exists as the de facto way in WordPress to tell the user, using JavaScript, that the web page content has changed. Information is available at make.wordpress.org/accessibility/handbook/markup/wp-a11y-speak.

Escaping

wp.escapeHtml is a polyfill that provides helper functions for escaping quotation marks, ampersands, less‐than symbols, HTML, and entire attribute values. As you start to write more React‐based JavaScript later, the need to control how your code is escaped will become an important security measure.

i18n

wp.i18n is the utility you will use to localize the strings that are embedded inside your React‐based JavaScript files. You can now use many of the GetText‐style API function calls inside your JavaScript. We will be covering the better known PHP equivalents in Chapter 11.

This is the future of how you will be able to make your JavaScript code ready to be translated into every other language other than English. If you are going to include raw text strings in your JavaScript, we strongly encourage you to use these functions going forward to ensure that it can be localized.

Heartbeat

wp.heartbeat is a series of function calls used to manage how routine listeners are enqueued on the current page. As the needs of your application become increasingly complex, you may have things that need to be processed in the background, or you may have application states that need to be checked every few seconds. You would use the Heartbeat API to register how often you need to check for changes and listen to it for a response.

POLYFILLS

Since WordPress 5.0, polyfills exist as a way for WordPress to come bundled with fallback support for many of the JavaScript libraries that are considered to be required going forward for modern web development, in the event that something is missing or a browser does not meet certain requirements.

One example of a polyfill is React, which is a JavaScript library developed by Facebook to assist with rapidly developing reusable and interactive user interfaces. React is used extensively inside Gutenberg, as are a few dozen other of its dependencies.

You may never need to interact with these scripts directly, but it's important to understand what they are and why they exist so that when you start developing your own React components later, you know that React already exists for you here. We will be teaching you all about React in Chapter 7, which covers Gutenberg!

YOUR CUSTOM SCRIPTS

When you are writing advanced WordPress plugins, much of your time will be spent architecting, planning, and researching whether anyone has already solved the same problem that you are going to try to solve yourself. If you're lucky, something already exists, and you will be able to save some time by including their work in with yours. Otherwise, you may be on your own.

The custom JavaScript you write should be broken up into pieces much the same way that PHP files are separated out logically. This is your plugin, and you should keep your code organized and clean so that it is easy to pick up and work on later, maybe after you've forgotten a lot of what exactly is inside it today. There are dozens of open source tools available for compiling and transpiling your JavaScript, and you should feel comfortable using whichever ones meet your needs.

We recommend plugins have an /assets directory, with a /js subdirectory where all of the plugins JavaScript can live, all broken out and down into separate files as needed to maintain order within your plugin. You can always minify and compile them together later, but you can't always break everything all apart into smaller more easily managed pieces.

If you are bundling third‐party libraries, create another subdirectory for them named /vendor underneath your /js directory. It is commonly understood that vendor code is code you've incorporated into your project that is outside your direct control but that your own code relies on to get the job done.

  • /your‐plugin/assets/
  • /your‐plugin/assets/js/
  • /your‐plugin/assets/js/vendor/

jQuery

jQuery is the world's most popular JavaScript framework. It is used by more than 80 percent of the top million sites followed by Quantcast (source: trends.builtwith.com/javascript) and is used by many different WordPress admin area pages.

There are many books on jQuery available, and since this is a WordPress book, we aren't going to go into too much detail here.

Benefits of Using jQuery

What makes jQuery such a great library and the reasons why it comes with WordPress are among the following:

  • The minified and gzipped library is only 24KB.
  • It uses a quick and terse syntax for faster developing.
  • It is completely cross‐browser compatible.
  • It supports all CSS selectors.
  • It makes events, DOM manipulation and traversing, and animations and effects all super easy.
  • It makes Ajax simpler, easily reading JSON and XML.
  • It has great documentation at docs.jquery.com.

It is possible to use any other library you'd like, but because WordPress uses jQuery for its own internal purposes, it's smart for beginners because there are many different examples already in the code base to use for your own starting‐off points.

jQuery Crash Course

The scope of this section is not to teach you how to master this powerful JavaScript library in a few minutes but to give you some basis to read on without being completely lost, as well as WordPress‐specific information.

The jQuery Object

In vanilla JavaScript, you may have written code like this:

document.getElementById('container').getElementsByTagName('a')

to select elements that your CSS would call #container a. With jQuery, you can now simply write the following:

jQuery('#container a')

Syntax and Chaining

jQuery methods can be chained together, which will return the jQuery object, as you will see in the following short practical example.

Create a minimalist HTML content that includes the latest jQuery script from the official website.

<html>
<head>
<script src='http://code.jquery.com/jquery.js'></script>
<title>Quick jQuery example</title>
</head>
<body>
<p class="target">click on me!</p>
<p class="target">click on me!</p>
<p class="target">click on me!</p>
</body>
</html>

Now, right before the closing </body> tag, insert a jQuery snippet to add a background and a border to each paragraph, and that, when clicked, changes the background color while shrinking it for two seconds before making it disappear.

<script>
jQuery('p.target')
    .css( { background:'#eef', border: '1px solid red' } )
    .click(function(){
    jQuery (this)
        .css('background','#aaf')
        .animate(
            { width:'300px', borderWidth:'30px', marginLeft:'100px'},
            2000,
            function(){
                jQuery (this).fadeOut();
            }
        );
    });
</script>

If you dissect this compact snippet, you can see the main structure.

jQuery ('p.target').css( ).click( function(){ } );

This applies some styling to the selected paragraph and then defines the behavior when the event click occurs on this element. Chaining enables a method to return an object itself as a result, reducing usage of temporary variables and enabling a compact syntax.

Similarly, within the function defining the click behavior, you can see several methods applied to the jQuery(this) object, referencing the current jQuery object instantiated by the initial jQuery(‘p.target’).

What you have now is three independently animated paragraph blocks!

No‐Conflict Mode in WordPress

To enable coexistence with other libraries, jQuery has a no‐conflict mode, activated by default within WordPress, which prevents using the dollar sign ( $) directly to call on jQuery itself. The result of this is that if you port existing jQuery code to a WordPress environment, you need to use one of these solutions:

  • Write jQuery() instead of each $().
  • Use a jQuery wrapper.

To illustrate this, consider the following initial jQuery code you would need to port into a WordPress no‐conflict environment:

$('.something').each( function(){
    $(this).addClass( 'stuff' );
});
$.data( document.body, 'foo', 1337 );

The first option would give the following result:

jQuery('.something').each( function(){
    jQuery(this).addClass( 'stuff' );
});
jQuery.data( document.body, 'foo', 1337 );

The second option would give the following result:

// jQuery noConflict wrapper:
(function($) {
    // $() will work here
    $('.something').each( function(){
        $(this).addClass( 'stuff' );
    });
    $.data( document.body, 'foo', 1337 );
})(jQuery);

Both solutions are programmatically equal, but using a no‐conflict wrapper will enable you to more conveniently and easily use existing code without having to replace each $ with a longer jQuery.

Launching Code on Document Ready

A frequent requirement in JavaScript is to make sure that elements in a page load before you can do something with them. Here is a snippet you may have used before:

window.onload = function(){
    /* do something */
}

This ancient technique has two weaknesses:

  • Another script can easily overwrite the window.onload definition with its own function.
  • The onload event in JavaScript waits for everything to be fully loaded before executing, including images, banner ads, external widgets, and so on.

With jQuery, you get a much better solution:

jQuery(document).ready( function(){
    /* do something */
});

Now, as soon as the DOM hierarchy has been fully constructed, the document “ready” event triggers. This happens before images load, before ads are shown, so the user experience is much smoother and faster.

You can combine the document‐ready function with a jQuery noConflict() wrapper, like the following:

jQuery(document).ready(function($) {
        
    // $() will work as an alias for jQuery() inside of this function
        
});

Using this technique, you can use the $() syntax and be sure that you do not reference a DOM element that has not been rendered by the browser yet.

Ajax

Ajax is a web development technique that enables a page to retrieve data asynchronously and to update parts of the page without the need to reload the entire thing all at once. The word originally was an acronym for Asynchronous JavaScript And XML, but the use of XML is not actually mandatory.

Ajax is not a technology or a programming language but rather a group of technologies that make up a methodology. It involves client‐side scripts such as JavaScript and server‐side scripts such as PHP that output content in HTML, CSS, XML, and JSON—or pretty much anything else!

Here is an extremely primitive Ajax example:

<!DOCTYPE html>
<html>
<body>
<script>
function loadExample() {
  var xhttp = new XMLHttpRequest();
  xhttp.onreadystatechange = function() {
    if (this.readyState == 4 && this.status == 200) {
     document.getElementById("demo").innerHTML = this.responseText;
    }
  };
  xhttp.open("GET", "example.com", true);
  xhttp.send();
}
</script>
 
<div id="demo">
  <h2> AJAX Will remove this </h2>
  <button type="button" onclick="loadExample()">Click to Change</button>
</div>
 
</body>
</html>

You can learn more about Ajax in WordPress by reading the developer documentation at developer.wordpress.org/plugins/javascript/ajax.

BACKBONE/UNDERSCORE

Backbone and Underscore were brought into WordPress when the Media Library was redesigned in 2011. They are largely intended to complement jQuery, and therefore we do not recommend investing too much time into learning these technologies, as React is generally considered the modern approach for the foreseeable future. They are worth mentioning here because nearly everything in the Media Library uses them, which is cleanly coded and fully documented. If you are curious to learn more about them, please refer to the Media Library code itself.

Lodash is also included in WordPress and in many ways is the successor to Underscore, much in the same way that using React will mean you will not really need to use Backbone.

Please visit backbonejs.org and underscorejs.org for more information.

REACT

React was invented by engineers at Facebook and is the new star of the JavaScript show. Not only is it bundled with WordPress, but its popularity has eclipsed that of other modern competitors like Angular and Vue. Its licensing was originally incompatible with the GPL license that WordPress uses, making it a complete nonoption at its inception. The web development community rallied to get Facebook to reconsider its licensing and it did, so here we are!

React by itself is a lovely and simple piece of software. Using it in WordPress today, though, does require a little bit of rule bending and head scratching. This is because React is new and designed to be used alongside a bevy of new JavaScript libraries and tools, but WordPress is a legacy piece of software with many years' worth of compromises that have been made over time.

How to best use React in WordPress has been iterated on and reinvented and changed many times since WordPress 5.0 was released. The dust is starting to settle, so we are going to teach you what is currently considered to be the best way to blend them both together in your own plugins.

Much like how jQuery UI complemented jQuery, libraries such as Babel, Redux, Moment, webpack, React DOM, and others exist in WordPress to complement React and to help make things like the block‐based editor—Gutenberg—possible.

Rather than try to deliver a complete crash course in React here, we are going to jump straight into applying everything we've learned so far in the next chapter. React requires a totally different (and very deep) dive into JavaScript concepts that are not really used anywhere else in WordPress. Get ready, because the next chapter is going to be intense!

SUMMARY

JavaScript now makes up around 30 percent of the WordPress code base, and there are no signs of that number getting smaller anytime soon. Just like with PHP, there is now an endless amount of material available that will take you on super‐deep dives into just about every different aspect of it.

This chapter has focused solely on the WordPress‐specific things that most other JavaScript texts would not think to include. You will be writing more and more JavaScript in your professional WordPress plugins, and there is no avoiding it anymore. Chapter 7 will continue your JavaScript education by fully immersing you in the wonderful world of Gutenberg blocks!

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.129.13.201