In this series of posts, I’m going to share my experience building JavaScript-driven UIs for AutomateWoo using components from WooCommerce Admin and Gutenberg. The aim for these posts is to be of practical use for other WooCommerce extension developers, and they will include step by step instructions based on what we’ve done for AutomateWoo.
To provide a little background, AutomateWoo is a five-year-old WooCommerce extension with a UI built primarily with PHP. I think it’s also worth mentioning that I come from a primarily WordPress/PHP background and have had a fairly small amount of past JavaScript experience.
I have to admit that a couple of years ago when I first heard that the WooCommerce admin interface was going to become JavaScript-based, I was a bit worried. Rebuilding a large extension like AutomateWoo seemed like a huge task and that’s still true. However, I now see the benefits are completely worth it and the paradigm shift is vital for the future of WooCommerce!
So let’s get started! In this post I’ll cover:
- Setting up
@wordpress/scripts
- Customizing the default webpack config
- Bundling SASS and CSS
- Linting JavaScript files
- Loading the new JavaScript and CSS files
Setting up @wordpress/scripts
With AutomateWoo we have been using Gulp to minify JS files and perform various tasks like generating translation files and building plugin ZIP files. We still use Gulp for several things but have chosen to use the @wordpress/scripts package to handle our newer JS files. @wordpress/scripts
comes with a collection of useful tools for JavaScript WordPress development. For example, I wanted to use the cool new ES6 and JSX syntaxes which @wordpress/scripts
compiles automatically to browser-compatible JavaScript.
- Install npm
- In your plugin directory run
npm init
to create apackage.json
file - Run
npm install @wordpress/scripts --save-dev
- Open
package.json
and update thescripts
property to:
{
"scripts": {
"build": "wp-scripts build",
"start": "wp-scripts start",
}
}
- Create
src/index.js
- Run
npm run build
Now you should have a build/
directory containing a compiled index.js
file and an index.asset.php
file. You can also run npm run start
which will build, and then watch, the files in src/
for changes.
Customizing the default webpack config
The build and start scripts use webpack behind the scenes and @wordpress/scripts
has a useful default webpack config that can be customized.
For AutomateWoo, I didn’t want the src/
and build/
directories in the plugin’s root directory. To change them create a webpack.config.js
file in your plugin directory with the following:
// Load the default @wordpress/scripts config object
const defaultConfig = require( '@wordpress/scripts/config/webpack.config' );
// Use the defaultConfig but replace the entry and output properties
module.exports = {
...defaultConfig,
entry: {
index: './assets/src/index.js',
},
output: {
filename: '[name].js',
path: __dirname + '/assets/build',
},
};
Now move src/index.js
to assets/src/index.js
and after running npm run build
the built files will be added to the assets/build/
directory.
Bundling SASS and CSS with webpack
@wordpress/scripts
can bundle .scss
and .css
files out of the box making it possible to import styles from JavaScript files. This makes it easy to keep a component’s JavaScript and CSS files in the same directory which I’ve found to be a nice pattern. For example:
./assets/src/components/
|โโ button/
โโโ index.js
|โโ style.scss
// assets/src/components/button/index.js
import './style.scss'
const button = ( props ) => {
// ...
};
export default button;
Linting JavaScript files
Linting is another great feature of @wordpress/scripts
and helps enforce code style guidelines for your plugin’s JavaScript files. @wordpress/scripts
uses ESLint under the hood and comes with a preconfigured set of recommended rules for WordPress development. For WooCommerce development I’d recommend using the @woocommerce/eslint-plugin
package which extends the WordPress defaults and adds some helpful additional rules.
- Open
package.json
and add a new entry to thescripts
property:
{
"scripts": {
"lint:js": "wp-scripts lint-js assets/src",
}
}
2. Run npm install @woocommerce/eslint-plugin --save-dev
3. Create a .eslintrc.js
file in your plugin directory with the following:
module.exports = {
extends: [ 'plugin:@woocommerce/eslint-plugin/recommended' ],
};
4. Now running npm run lint:js
will check the files in assets/src/
for code style issues.
If an ESLint integration is available with your IDE, I’d recommend enabling it as I found the warnings generated when running npm run lint:js
could often be hard to understand.
Loading the new JavaScript and CSS files
Now it’s time to load the new JavaScript and CSS files from the build/
directory in the WordPress admin area. We can use the familiar wp_enqueue_script()
and wp_enqueue_style()
functions for this. However, there is one special thing about @wordpress/scripts
that’s worth noting. Remember the index.asset.php
file from earlier? This file is generated each time your JavaScript is built and returns an array containing:
dependencies
: an array of all JavaScript dependencies e.g.[ wp-components ]
version
: a generated string that changes for each build
This makes our loader slightly more complex but means we will never need to manually add dependencies. Here’s an example loader for our new JavaScript-driven WooCommerce plugin:
<?php
namespace DanBitzer/MyPlugin/Admin;
use DanBitzer/MyPlugin/PluginInfo;
/**
* Class AssetLoader.
*
* Loads JavaScript and CSS files.
*/
class AssetLoader {
/**
* @var PluginInfo
*/
protected $plugin_info;
/**
* AssetLoader constructor.
*
* @param PluginInfo $plugin_info
*/
public function __construct( PluginInfo $plugin_info ) {
$this->plugin_info = $plugin_info;
add_action( 'admin_enqueue_scripts', [ $this, 'handle_admin_enqueue_scripts_action' ] );
}
/**
* Register asset loader hooks.
*/
public function handle_admin_enqueue_scripts_action() {
// Load assets if on an WooCommerce Admin page
if ( function_exists( 'wc_admin_is_registered_page' ) && wc_admin_is_registered_page() ) {
$this->load_js_and_css();
}
}
/**
* Load JS and CSS assets.
*/
protected function load_js_and_css() {
$handle = 'dan-bitzer-my-plugin';
$build_path = '/assets/build';
$script_asset_path = $this->plugin_info->get_path() . $build_path . '/index.asset.php';
$script_info = file_exists( $script_asset_path )
? include $script_asset_path
: [ 'dependencies' => [], 'version' => $this->plugin_info::VERSION ];
wp_register_script(
$handle,
$this->plugin_info->get_url() . $build_path . '/index.js',
$script_info['dependencies'],
$script_info['version'],
true
);
wp_register_style(
$handle,
$this->plugin_info->get_url() . $build_path . '/index.css',
// Add the WooCommerce Admin styles as a dependency
[ 'wc-admin-app' ],
$this->plugin_info::VERSION
);
wp_enqueue_script( $handle );
wp_enqueue_style( $handle );
}
}
Check out the full example plugin in part one to see how it all fits together.
That’s all, Thanks for reading!
Leave a Reply