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. 🙇