mkaz.blog

Gutenberg and WordPress Core

I recently had the need to update Gutenberg packages that are in WordPress core for a point release. This required setting up a development environment where I can test Gutenberg code in WordPress but without using the Gutenberg plugin.

This is not something most developers will need to do, it is my first time after working on Gutenberg for a couple years now. Even if you don't need to do this, you may find it useful to get a better understanding how Gutenberg packages relate to WordPress core.

TL;DR

Here's the TL;DR for the set of commands I used to setup my environment. In this case, I was modifying two packages (rich-text and editor) in Gutenberg that I wanted to use in core WordPress source.

The key is symlinking the packages in WP source to Gutenberg source.

git clone https://github.com/WordPress/wordpress-develop
cd wordpress-develop
git switch 5.8       # switch to branch
npm ci
 
cd ../
git clone https://github.com/WordPress/gutenberg
cd gutenberg
git switch wp/5.8    # switch to branch
npm ci
##-- do code things --#
npm run build
 
# back to wordpress-develop
# symlink node packages to gutenberg source
cd ../wordpress-develop/node_modules/@wordpress
rm -rf rich-text editor
ln -s ../../../gutenberg/packages/rich-text
ln -s ../../../gutenberg/packages/editor
 
# top of wordpress-develop
cd ../../
npm run build

My local WordPress environment points to wordpress-develop/build/ directory.

Gutenberg packages in WordPress core

When Gutenberg is "merged" in to core, it is not really a single piece of software copied into core but a set of JavaScript packages that core uses. The packages are published to NPM under @wordpress/ prefix, see all packages here.

Those packages are then listed as dependencies in WordPress, if you look at the package.json file in the source, you will see the list of packages as dependencies with their respective versions.

A WordPress release is based on this set of packages and versions. After a release the minor version is incremented for all the packages, so then if any updates are needed they can be made to a specific package as a point release.

For example, the rich-text package 4.1.5 is the version released in WordPress 5.8, after the release the version was incremented to 4.2.0 and trunk development can continue.

The update for WordPress 5.8 required changes to the rich-text package v4.1.5. These changes bumped the version to v4.1.6 and published to NPM. So then a point release for WordPress 5.8.1 can use the package as a dependency.

Note: Often people will ask which version of Gutenberg is in a WordPress release. This is hard to answer, as you see, there isn't a single version but a collection of packages each with their own version. Also, not every package in Gutenberg repository is used by core as there are experimental feature not quite ready.

Building with local NPM packages

Working with local NPM packages are always a bit tricky. Within the Gutenberg project it works fine using file references, but I was not able to get this to work from the WordPress source to the Gutenberg project.

A file reference for NPM packages is listing a file path instead of a version number. For example in package.json this would be the ideal solution:

"dependencies": {
        ...
        "@wordpress/rich-text": "file:../gutenberg/packages/rich-text",
        ...
}

For whatever reason that does not work, if you know why, or a work around, please leave a comment below.

So my solution was to use a symlink from inside the node_modules back out. This needs to be done after the initial npm install or in my example I use npm ci that does a fresh install using the package-lock.json.

Setting up a dev environment

Here's a more detailed walk through of the process I outlined at the top.

Setup WordPress source

My first step is to check out the WordPress source

git clone https://github.com/WordPress/wordpress-develop
 
# if you want to work in a specific branch
git switch 5.8

Note: The wordpress-develop source is not the official source repository for WordPress but an up-to-date mirror synced to official subversion repository. For me it is easier to work with the git repo—you can even use git diff to create a core patch, but that's for a different post.

If you are unfamiliar with the WordPress source code, the main source is in the src/ directory, this includes the PHP, JS, and CSS files. The project uses grunt to build the necessary CSS and JavaScript, you can see the dependencies and script specified in the package.json.

To build:

cd wordpress-develop/
npm ci
npm run build

After running, a build/ directory is created that is a full working WordPress—the same thing you would get by unzipping a download. If you point a web server at the build/ directory (and configure with a wp-config.php) it will be a working install.

Any subsequent npm run build will update the files for that environment.

This build will use the NPM packages specified in package.json. It downloads the package from the NPM registry and installs them to the node_modules directory. This is what we will replace with the Gutenberg source.

Note: For your WordPress development site, you can use wp-env to set it up. I personally do not use wp-env but many find it easier. See the env package readme for usage. To set the build directory use a .wp-env.json config like so:

{
    "core": "./build",
    "plugins": [],
    "themes": [],
    "config": {
        "WP_DEBUG": false,
        "SCRIPT_DEBUG": false
    }
}

Setup Gutenberg source

git clone https://github.com/WordPress/gutenberg
 
# if you want to work in a specific branch
git switch wp/5.8

The Gutenberg development process is the same, make any necessary code changes and do a build using:

npm ci
npm run build

Connect WordPress to Gutenberg

The key to connecting WordPress source to Gutenberg packages is using symlinks in the wordpress-develop/node_modules to point to the Gutenberg source.

cd wordpress-develop/node_modules/@wordpress

Remove existing package(s):

rm -rf rich-text

Add symlink to Gutenberg package(s):

ln -s ../../../gutenberg/rich-text

My example here is just changing the single rich-text package, if you want to change all your packages, you can run something like this:

for i in $(\ls -1); do rm -rf $i; ln -s ../../../gutenberg/packages/$i; done;

Note: If you mess up the node_modules, just run npm ci and it will reset.

Build process

Once everything is connected up, the on-going development process is to make the changes in Gutenberg. Run a build there npm run build and then switch to the WordPress source directory and run another build to use the newly built Gutenberg packages.

cd gutenberg/
# do code things
npm run build
 
cd ../wordpress-develop/
npm run build

Your WordPress test site pointing at the build/ directory will then be using the Gutenberg packages from the WordPress source, not using Gutenberg as a plugin. So be sure to disable Gutenberg plugin if activated.

Node Versions

When possible, we will back port necessary fixes to older versions of WordPress, typically security patches, this can go back several years. The example above uses 5.8 but the same process will work for all older versions of Gutenberg back to WP 5.0, the start of Gutenberg in Dec 2018.

If updating an older version of WordPress you will need to use the older version of node used at that time. Check the .nvmrc file in Gutenberg repository for that branch, it will specify the version.

If you use nvm you can switch to the proper version by running:

nvm use
nvm install

In my efforts to Rustify all my CLI tools, I use volta. So to switch to an older version I'd use the command volta install node@10 or whatever version specified.

Summary

So that's how I have my Gutenberg and WordPress core environment setup. I hope you found this helpful. It is probably not the optimal setup, so welcome any suggestions or comments if you have a better way.


Thanks to Adam Zielinski for proof reading, testing, and providing the bash script for linking all packages. 🙇