Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
f8a7238
Remove the need to clone the Gutenberg repository.
desrosj Feb 23, 2026
29a617f
Rename `checkout` related scripts to `download`.
desrosj Feb 23, 2026
cd08d60
Rename `ref` to `sha`.
desrosj Feb 23, 2026
8729f37
Move the container registry reference out of code.
desrosj Feb 23, 2026
800fb06
Don't redownload without `--force`
desrosj Feb 23, 2026
7dfec4f
Switch to using the GHCR package from `gutenberg`.
desrosj Feb 23, 2026
c7563fa
Apply suggestions from code review.
desrosj Feb 24, 2026
9cfff8e
Several bug fixes and reverting a few changes.
desrosj Feb 24, 2026
732a54b
Correct a few paths and destinations.
desrosj Feb 27, 2026
7f932ec
A few bug fixes.
desrosj Feb 28, 2026
4faa486
Update Gutenberg hash.
desrosj Feb 28, 2026
82ae215
Address some review feedback.
desrosj Feb 28, 2026
d06292c
Extract the verification logic out of download.
desrosj Mar 2, 2026
83e549a
Change hyphenated grunt tasks to use colons.
desrosj Mar 2, 2026
16722a4
Remove `gutenberg` from `tools/gutenberg` names.
desrosj Mar 2, 2026
07f2e5c
Fix some JShint warnings.
desrosj Mar 2, 2026
6ec39d8
Convert to using a `.tar.gz` file.
desrosj Mar 3, 2026
a2c1856
Use correct multi-line inline comment format.
desrosj Mar 3, 2026
50c6285
Some code cleanup.
desrosj Mar 6, 2026
b1c3842
Utilize pre-existing Grunt tasks.
desrosj Mar 6, 2026
25c90b9
Try to fix timeout issues during `postinstall`.
desrosj Mar 6, 2026
330a83e
`postinstall build:gutenberg` shouldn't be needed.
desrosj Mar 6, 2026
fbb1c58
Fix coding standards issue.
desrosj Mar 6, 2026
3050cd1
Try using PHP to parse PHP instead of strings and RegExp
dmsnell Mar 7, 2026
f588cf5
Move function to top so it shows more clearly in the diff.
dmsnell Mar 7, 2026
e822046
Bump commit hash.
desrosj Mar 7, 2026
7d0ca6c
Update the pinned `gutenberg` hash.
desrosj Mar 9, 2026
5dffecc
Merge remote-tracking branch 'upstream/trunk' into try/remove-gutenbe…
desrosj Mar 9, 2026
29baaf4
Merge branch 'update/gutenberg-hash' into try/remove-gutenberg-git-ch…
desrosj Mar 9, 2026
fdda592
One more bump with additional upstream fixes.
desrosj Mar 10, 2026
5669f70
Merge remote-tracking branch 'upstream/trunk' into try/remove-gutenbe…
desrosj Mar 10, 2026
7ce0157
Sync hashes.
desrosj Mar 10, 2026
aad2939
Improvements to RegEx for modifying boot module asset.
desrosj Mar 10, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
160 changes: 126 additions & 34 deletions Gruntfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@ module.exports = function(grunt) {
webpackFiles = [
'wp-includes/assets/*',
'wp-includes/css/dist',
'wp-includes/blocks/**/*.css',
'!wp-includes/assets/script-loader-packages.min.php',
'!wp-includes/assets/script-modules-packages.min.php',
],
Expand Down Expand Up @@ -588,7 +587,97 @@ module.exports = function(grunt) {
certificates: {
src: 'vendor/composer/ca-bundle/res/cacert.pem',
dest: SOURCE_DIR + 'wp-includes/certificates/ca-bundle.crt'
}
},
// Gutenberg PHP infrastructure files (routes.php, pages.php, constants.php, pages/, routes/).
'gutenberg-php': {
options: {
process: function( content ) {
// Fix boot module asset file path for Core's different directory structure.
return content.replace(
/__DIR__\s*\.\s*(['"])\/..\/\..\/modules\/boot\/index\.min\.asset\.php\1/g,
'ABSPATH . WPINC . \'/js/dist/script-modules/boot/index.min.asset.php\''
);
}
},
files: [ {
expand: true,
cwd: 'gutenberg/build',
src: [
'routes.php',
'pages.php',
'constants.php',
'pages/**/*.php',
'routes/**/*.php',
],
dest: WORKING_DIR + 'wp-includes/build/',
} ],
},
'gutenberg-modules': {
files: [ {
expand: true,
cwd: 'gutenberg/build/modules',
src: [ '**/*', '!**/*.map' ],
dest: WORKING_DIR + 'wp-includes/js/dist/script-modules/',
} ],
},
'gutenberg-styles': {
files: [ {
expand: true,
cwd: 'gutenberg/build/styles',
src: [ '**/*', '!**/*.map' ],
dest: WORKING_DIR + 'wp-includes/css/dist/',
} ],
},
'gutenberg-theme-json': {
options: {
process: function( content, srcpath ) {
// Replace the local schema URL with the canonical public URL for Core.
if ( path.basename( srcpath ) === 'theme.json' ) {
return content.replace(
'"$schema": "../schemas/json/theme.json"',
'"$schema": "https://schemas.wp.org/trunk/theme.json"'
);
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this does in a string things that are likely to mis-parse or be mislead. again, there should be extra layers of protection here, however, it is not likely that much more difficult to do this in a more robust way.

process: function( content, srcpath ) {
	if ( path.basename( srcpath ) !== 'theme.json' ) {
		return content;
	}

	return JSON.stringify(
		JSON.parse( content ),
		( key, value ) =>
			( '$schema' === key && '../schemas/json/theme.json' === value )
				? 'https://schemas.wp.org/trunk/theme.json'
				: value,
		2
	);
}

this is marginally larger but contains none of the issues with treating JSON as a string. it’s not a big deal here, so not a blocker in any way, but it would be nice if we could at least follow-up after fixing things to return to these low-level build functions and make sure they don’t contain foot-guns for handling well-specified data.

return content;
}
},
files: [
{
src: 'gutenberg/lib/theme.json',
dest: WORKING_DIR + 'wp-includes/theme.json',
},
{
src: 'gutenberg/lib/theme-i18n.json',
dest: WORKING_DIR + 'wp-includes/theme-i18n.json',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

while it looks like theme-i18n.json contains no $schema property, is there a reason to explicitly avoid changing the relative path to an absolute one? it seems somewhat odd given that this list of files includes two files and the process function only operates on one of them.

not really a block, but something perhaps to earmark.

},
],
},
'gutenberg-icons': {
options: {
process: function( content, srcpath ) {
// Remove the 'gutenberg' text domain from _x() calls in manifest.php.
if ( path.basename( srcpath ) === 'manifest.php' ) {
return content.replace(
/_x\(\s*([^,]+),\s*([^,]+),\s*['"]gutenberg['"]\s*\)/g,
'_x( $1, $2 )'
);
}
return content;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

here again we’re apparently adding automation which nobody is likely to be maintaining familiarity with, doing something that looks sound today when all of the files are the way we expect them, and then one day it will all break and nobody will know what the goal here is. we’re also doing naive string parsing of JSON files again.

it seems like Gutenberg’s packages/icons/lib/generate-manifest-php.cjs is building the manifest.php from the JSON source anyway, so I wonder if we could parameterize that method with the intended text domain and simply regenerate this file.

should the shape of the manifest change, I have no idea how to expect someone to know what the original goal of this RegExp was supposed to be or do.

this is definitely a nice-to-have, particularly since the generator file should be available whenever we have the manifest.php file, but also potentially something to address in a follow-up.

I would think we could directly call the generator, like return iconPhpManifestGenerator.generateManifestPHP( null ) as long as we add the text domain parameters where appropriate

}
},
files: [
{
src: 'gutenberg/packages/icons/src/manifest.php',
dest: WORKING_DIR + 'wp-includes/icons/manifest.php',
},
{
expand: true,
cwd: 'gutenberg/packages/icons/src/library',
src: '*.svg',
dest: WORKING_DIR + 'wp-includes/icons/library/',
},
],
},
},
sass: {
colors: {
Expand Down Expand Up @@ -1323,20 +1412,21 @@ module.exports = function(grunt) {
},
{
expand: true,
flatten: true,
src: [
BUILD_DIR + 'wp-includes/js/dist/block-editor.js',
BUILD_DIR + 'wp-includes/js/dist/commands.js',
],
dest: BUILD_DIR + 'wp-includes/js/dist/'
cwd: BUILD_DIR + 'wp-includes/js/dist/',
src: [ '*.js' ],
dest: BUILD_DIR + 'wp-includes/js/dist/',
},
{
expand: true,
flatten: true,
src: [
BUILD_DIR + 'wp-includes/js/dist/vendor/**/*.js'
],
dest: BUILD_DIR + 'wp-includes/js/dist/vendor/'
cwd: BUILD_DIR + 'wp-includes/js/dist/vendor/',
src: [ '**/*.js' ],
dest: BUILD_DIR + 'wp-includes/js/dist/vendor/',
},
{
expand: true,
cwd: BUILD_DIR + 'wp-includes/js/dist/script-modules/',
src: [ '**/*.js' ],
dest: BUILD_DIR + 'wp-includes/js/dist/script-modules/',
}
]
}
Expand Down Expand Up @@ -1475,45 +1565,38 @@ module.exports = function(grunt) {
} );

// Gutenberg integration tasks.
grunt.registerTask( 'gutenberg-checkout', 'Checks out the Gutenberg repository.', function() {
grunt.registerTask( 'gutenberg:verify', 'Verifies the installed Gutenberg version matches the expected SHA.', function() {
const done = this.async();
grunt.util.spawn( {
cmd: 'node',
args: [ 'tools/gutenberg/checkout-gutenberg.js' ],
args: [ 'tools/gutenberg/utils.js' ],
opts: { stdio: 'inherit' }
}, function( error ) {
done( ! error );
} );
} );

grunt.registerTask( 'gutenberg-build', 'Builds the Gutenberg repository.', function() {
grunt.registerTask( 'gutenberg:download', 'Downloads the built Gutenberg artifact.', function() {
const done = this.async();
const args = [ 'tools/gutenberg/download.js' ];
if ( grunt.option( 'force' ) ) {
args.push( '--force' );
}
grunt.util.spawn( {
cmd: 'node',
args: [ 'tools/gutenberg/build-gutenberg.js' ],
args,
opts: { stdio: 'inherit' }
}, function( error ) {
done( ! error );
} );
} );

grunt.registerTask( 'gutenberg-copy', 'Copies Gutenberg build output to WordPress Core.', function() {
grunt.registerTask( 'gutenberg:copy', 'Copies Gutenberg JS packages and block assets to WordPress Core.', function() {
const done = this.async();
const buildDir = grunt.option( 'dev' ) ? 'src' : 'build';
grunt.util.spawn( {
cmd: 'node',
args: [ 'tools/gutenberg/copy-gutenberg-build.js', `--build-dir=${ buildDir }` ],
opts: { stdio: 'inherit' }
}, function( error ) {
done( ! error );
} );
} );

grunt.registerTask( 'gutenberg-sync', 'Syncs Gutenberg checkout and build if ref has changed.', function() {
const done = this.async();
grunt.util.spawn( {
cmd: 'node',
args: [ 'tools/gutenberg/sync-gutenberg.js' ],
args: [ 'tools/gutenberg/copy.js', `--build-dir=${ buildDir }` ],
opts: { stdio: 'inherit' }
}, function( error ) {
done( ! error );
Expand Down Expand Up @@ -1956,26 +2039,35 @@ module.exports = function(grunt) {
} );
} );

grunt.registerTask( 'build:gutenberg', [
'copy:gutenberg-php',
'gutenberg:copy',
'copy:gutenberg-modules',
'copy:gutenberg-styles',
'copy:gutenberg-theme-json',
'copy:gutenberg-icons',
] );

grunt.registerTask( 'build', function() {
if ( grunt.option( 'dev' ) ) {
grunt.task.run( [
'gutenberg:verify',
'build:js',
'build:css',
'build:codemirror',
'gutenberg-sync',
'gutenberg-copy',
'build:gutenberg',
'copy-vendor-scripts',
'build:certificates'
] );
} else {
grunt.task.run( [
'gutenberg:verify',
'build:certificates',
'build:files',
'build:js',
'build:css',
'build:codemirror',
'gutenberg-sync',
'gutenberg-copy',
'build:gutenberg',
'copy-vendor-scripts',
'replace:source-maps',
'verify:build'
Expand Down
12 changes: 6 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
"url": "https://develop.svn.wordpress.org/trunk"
},
"gutenberg": {
"ref": "7b7fa2bc97a8029a302bd6511cf0d206b5953172"
"sha": "9b8144036fa5faf75de43d4502ff9809fcf689ad",
"ghcrRepo": "WordPress/gutenberg/gutenberg-wp-develop-build"
},
"engines": {
"node": ">=20.10.0",
Expand Down Expand Up @@ -111,9 +112,10 @@
"wicg-inert": "3.1.3"
},
"scripts": {
"postinstall": "npm run gutenberg:sync && npm run gutenberg:copy -- --dev",
"postinstall": "npm run gutenberg:download",
"build": "grunt build",
"build:dev": "grunt build --dev",
"build:gutenberg": "grunt build:gutenberg",
"dev": "grunt watch --dev",
"test": "grunt test",
"watch": "grunt watch",
Expand All @@ -137,10 +139,8 @@
"test:e2e": "wp-scripts test-playwright --config tests/e2e/playwright.config.js",
"test:visual": "wp-scripts test-playwright --config tests/visual-regression/playwright.config.js",
"typecheck:php": "node ./tools/local-env/scripts/docker.js run --rm php composer phpstan",
"gutenberg:checkout": "node tools/gutenberg/checkout-gutenberg.js",
"gutenberg:build": "node tools/gutenberg/build-gutenberg.js",
"gutenberg:copy": "node tools/gutenberg/copy-gutenberg-build.js",
"gutenberg:sync": "node tools/gutenberg/sync-gutenberg.js",
"gutenberg:copy": "node tools/gutenberg/copy.js",
"gutenberg:download": "node tools/gutenberg/download.js",
"vendor:copy": "node tools/vendors/copy-vendors.js",
"sync-gutenberg-packages": "grunt sync-gutenberg-packages",
"postsync-gutenberg-packages": "grunt wp-packages:sync-stable-blocks && grunt build --dev && grunt build"
Expand Down
2 changes: 1 addition & 1 deletion tests/phpstan/base.neon
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ parameters:
- ../../src/wp-includes/deprecated.php
- ../../src/wp-includes/ms-deprecated.php
- ../../src/wp-includes/pluggable-deprecated.php
# These files are sourced by wordpress/gutenberg in `tools/release/sync-stable-blocks.js`.
# These files are autogenerated by tools/gutenberg/copy.js.
- ../../src/wp-includes/blocks
# Third-party libraries.
- ../../src/wp-admin/includes/class-ftp-pure.php
Expand Down
Loading