From d7bdf169d54a468166b56faad415a595917fe964 Mon Sep 17 00:00:00 2001 From: Jonathan Desrosiers <359867+desrosj@users.noreply.github.com> Date: Fri, 5 Jun 2026 09:57:20 +0200 Subject: [PATCH 01/12] Include icon library-related files in clean. --- Gruntfile.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Gruntfile.js b/Gruntfile.js index 815ccce3af535..128300261120b 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -51,6 +51,8 @@ module.exports = function(grunt) { gutenbergFiles = [ 'wp-includes/js/dist', 'wp-includes/css/dist', + 'wp-includes/images/icon-library', + 'wp-includes/assets/icon-library-manifest.php', // Old location kept temporarily to ensure they are cleaned up. 'wp-includes/icons', ], From 59b88f3b9fa1d069464f8a6eb8065ac9b93fd04f Mon Sep 17 00:00:00 2001 From: Jonathan Desrosiers <359867+desrosj@users.noreply.github.com> Date: Fri, 5 Jun 2026 09:57:32 +0200 Subject: [PATCH 02/12] Ensure `clean:gutenberg` runs prior to building. --- Gruntfile.js | 1 + 1 file changed, 1 insertion(+) diff --git a/Gruntfile.js b/Gruntfile.js index 128300261120b..3601dc13143ab 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -2159,6 +2159,7 @@ module.exports = function(grunt) { } ); grunt.registerTask( 'build:gutenberg', [ + 'clean:gutenberg', 'copy:gutenberg-php', 'routes:setup', 'copy:routes', From 25b9b9ebada2ebbe952123e6ecdab06ed79c9dc5 Mon Sep 17 00:00:00 2001 From: Jonathan Desrosiers <359867+desrosj@users.noreply.github.com> Date: Fri, 5 Jun 2026 10:28:44 +0200 Subject: [PATCH 03/12] Exclude manifest file. This is meant to include directories. --- Gruntfile.js | 1 - 1 file changed, 1 deletion(-) diff --git a/Gruntfile.js b/Gruntfile.js index 3601dc13143ab..7023edb0f177d 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -52,7 +52,6 @@ module.exports = function(grunt) { 'wp-includes/js/dist', 'wp-includes/css/dist', 'wp-includes/images/icon-library', - 'wp-includes/assets/icon-library-manifest.php', // Old location kept temporarily to ensure they are cleaned up. 'wp-includes/icons', ], From b3341ca6839a8433a72cdfc04cb31baedd1896fd Mon Sep 17 00:00:00 2001 From: Jonathan Desrosiers <359867+desrosj@users.noreply.github.com> Date: Fri, 5 Jun 2026 10:45:43 +0200 Subject: [PATCH 04/12] Reorganize tasks to avoid repetition. --- Gruntfile.js | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/Gruntfile.js b/Gruntfile.js index 7023edb0f177d..aa7bb553a1c10 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -2158,6 +2158,7 @@ module.exports = function(grunt) { } ); grunt.registerTask( 'build:gutenberg', [ + 'gutenberg:verify', 'clean:gutenberg', 'copy:gutenberg-php', 'routes:setup', @@ -2174,24 +2175,22 @@ module.exports = function(grunt) { grunt.registerTask( 'build', function() { if ( grunt.option( 'dev' ) ) { grunt.task.run( [ - 'gutenberg:verify', + 'build:gutenberg', 'build:js', 'build:css', 'build:codemirror', - 'build:gutenberg', - 'build:certificates' + 'build:certificates', ] ); } else { grunt.task.run( [ - 'gutenberg:verify', - 'build:certificates', + 'build:gutenberg', 'build:files', 'build:js', 'build:css', 'build:codemirror', - 'build:gutenberg', + 'build:certificates', 'replace:source-maps', - 'verify:build' + 'verify:build', ] ); } } ); From 640397bef081aa3d2fdaabc377d25aa9e39b78ab Mon Sep 17 00:00:00 2001 From: Jonathan Desrosiers <359867+desrosj@users.noreply.github.com> Date: Fri, 5 Jun 2026 16:21:18 +0200 Subject: [PATCH 05/12] Ensure files deleted in `gutenberg` are removed. --- Gruntfile.js | 52 ++++++++++++++++++++++++++++++----------- tools/gutenberg/copy.js | 19 ++++----------- 2 files changed, 43 insertions(+), 28 deletions(-) diff --git a/Gruntfile.js b/Gruntfile.js index aa7bb553a1c10..9034055de5f06 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -47,15 +47,22 @@ module.exports = function(grunt) { 'wp-includes/js/', ], - // All files copied from the Gutenberg repository excluded from version control. + // Unversioned files copied from the Gutenberg repository. gutenbergFiles = [ 'wp-includes/js/dist', 'wp-includes/css/dist', - 'wp-includes/images/icon-library', // Old location kept temporarily to ensure they are cleaned up. 'wp-includes/icons', ], + // Files copied from Gutenberg subject to version control. + gutenbergVersionedFiles = [ + 'wp-includes/images/icon-library', + 'wp-includes/build', + 'wp-includes/blocks/*', + '!wp-includes/blocks/index.php', + ], + // All files built by Webpack, in /src or /build. // Webpack only builds Core-specific media files and development scripts. // Blocks, packages, script modules, and vendors come from the Gutenberg build. @@ -246,6 +253,25 @@ module.exports = function(grunt) { gutenberg: gutenbergFiles.map( function( file ) { return setFilePath( WORKING_DIR, file ); }), + + /* + * Delete directories and files subjet to version control where the contents come from Gutenberg. + * + * This handles instances where a file remains present even after being deleted upstream. + * + * This task is intentionally skipped unless the current task will re-copy the corresponding files. + */ + 'gutenberg-versioned': { + filter: function() { + var allowedTasks = [ 'build', 'build:dev', 'build:gutenberg', 'clean:gutenberg-versioned' ]; + return allowedTasks.some( function( task ) { + return grunt.cli.tasks.indexOf( task ) !== -1; + } ); + }, + src: gutenbergVersionedFiles.map( function( file ) { + return setFilePath( SOURCE_DIR, file ); + } ), + }, dynamic: { dot: true, expand: true, @@ -667,7 +693,7 @@ module.exports = function(grunt) { 'constants.php', 'pages/**/*.php', ], - dest: WORKING_DIR + 'wp-includes/build/', + dest: SOURCE_DIR + 'wp-includes/build/', } ], }, /* @@ -684,7 +710,7 @@ module.exports = function(grunt) { expand: true, cwd: 'gutenberg/build', src: [], - dest: WORKING_DIR + 'wp-includes/build/', + dest: SOURCE_DIR + 'wp-includes/build/', }, 'gutenberg-js': { files: [ { @@ -693,7 +719,7 @@ module.exports = function(grunt) { src: [ 'pages/**/*.js', ], - dest: WORKING_DIR + 'wp-includes/build/', + dest: SOURCE_DIR + 'wp-includes/build/', } ], }, 'gutenberg-modules': { @@ -707,7 +733,7 @@ module.exports = function(grunt) { // with no debugging value over the minified versions. '!vips/!(*.min).js', ], - dest: WORKING_DIR + 'wp-includes/js/dist/script-modules/', + dest: SOURCE_DIR + 'wp-includes/js/dist/script-modules/', } ], }, 'gutenberg-styles': { @@ -720,7 +746,7 @@ module.exports = function(grunt) { // Per-block CSS is copied to wp-includes/blocks/ by tools/gutenberg/copy.js. '!block-library/*/**', ], - dest: WORKING_DIR + 'wp-includes/css/dist/', + dest: SOURCE_DIR + 'wp-includes/css/dist/', } ], }, 'gutenberg-theme-json': { @@ -739,11 +765,11 @@ module.exports = function(grunt) { files: [ { src: 'gutenberg/lib/theme.json', - dest: WORKING_DIR + 'wp-includes/theme.json', + dest: SOURCE_DIR + 'wp-includes/theme.json', }, { src: 'gutenberg/lib/theme-i18n.json', - dest: WORKING_DIR + 'wp-includes/theme-i18n.json', + dest: SOURCE_DIR + 'wp-includes/theme-i18n.json', }, ], }, @@ -752,7 +778,7 @@ module.exports = function(grunt) { expand: true, cwd: 'gutenberg/packages/icons/src/library', src: '*.svg', - dest: WORKING_DIR + 'wp-includes/images/icon-library', + dest: SOURCE_DIR + 'wp-includes/images/icon-library', } ], }, 'icon-library-manifest': { @@ -774,7 +800,7 @@ module.exports = function(grunt) { }, files: [ { src: 'gutenberg/packages/icons/src/manifest.php', - dest: WORKING_DIR + 'wp-includes/assets/icon-library-manifest.php', + dest: SOURCE_DIR + 'wp-includes/assets/icon-library-manifest.php', } ], }, }, @@ -1678,10 +1704,9 @@ module.exports = function(grunt) { 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.js', `--build-dir=${ buildDir }` ], + args: [ 'tools/gutenberg/copy.js' ], opts: { stdio: 'inherit' } }, function( error ) { done( ! error ); @@ -2159,6 +2184,7 @@ module.exports = function(grunt) { grunt.registerTask( 'build:gutenberg', [ 'gutenberg:verify', + 'clean:gutenberg-versioned', 'clean:gutenberg', 'copy:gutenberg-php', 'routes:setup', diff --git a/tools/gutenberg/copy.js b/tools/gutenberg/copy.js index 8589c9581bed1..f6a24d2306db3 100644 --- a/tools/gutenberg/copy.js +++ b/tools/gutenberg/copy.js @@ -19,21 +19,10 @@ const rootDir = path.resolve( __dirname, '../..' ); const gutenbergDir = path.join( rootDir, 'gutenberg' ); const gutenbergBuildDir = path.join( gutenbergDir, 'build' ); -/* - * Determine build target from command line argument (--dev or --build-dir). - * Default to 'src' for development. - */ -const args = process.argv.slice( 2 ); -const buildDirArg = args.find( ( arg ) => arg.startsWith( '--build-dir=' ) ); -const buildTarget = buildDirArg - ? buildDirArg.split( '=' )[ 1 ] - : args.includes( '--dev' ) - ? 'src' - : 'build'; - -const wpIncludesDir = path.join( rootDir, buildTarget, 'wp-includes' ); +// All files handled in this script are subject to version control, so they should always be placed into src/. +const wpIncludesDir = path.join( rootDir, 'src', 'wp-includes' ); -/** +/* * Copy configuration. * Defines what to copy from Gutenberg build and where it goes in Core. */ @@ -508,7 +497,7 @@ function generateBlocksJson() { * Main execution function. */ async function main() { - console.log( `š¦ Copying Gutenberg build to ${ buildTarget }/...` ); + console.log( 'š¦ Copying versioned Gutenberg files to src/...' ); if ( ! fs.existsSync( gutenbergBuildDir ) ) { console.error( 'ā Gutenberg build directory not found' ); From 89173c9fff507769173fff92cb0eba6c6d83748b Mon Sep 17 00:00:00 2001 From: Jonathan Desrosiers <359867+desrosj@users.noreply.github.com> Date: Fri, 5 Jun 2026 16:44:16 +0200 Subject: [PATCH 06/12] Run for expanded tasks calling `build`. --- Gruntfile.js | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/Gruntfile.js b/Gruntfile.js index 9034055de5f06..f6e8d1a4d4c6d 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -263,7 +263,19 @@ module.exports = function(grunt) { */ 'gutenberg-versioned': { filter: function() { - var allowedTasks = [ 'build', 'build:dev', 'build:gutenberg', 'clean:gutenberg-versioned' ]; + var allowedTasks = [ + 'build', + 'build:dev', + 'build:gutenberg', + 'clean:gutenberg-versioned', + /* + * These tasks chain `build` internally, but grunt.cli.tasks only reflects the current task, + * which does not include expanded tasks. + */ + 'default', + 'qunit:compiled', + 'test', + ]; return allowedTasks.some( function( task ) { return grunt.cli.tasks.indexOf( task ) !== -1; } ); From 7e7c8cc788f8e0a67c7c406f8abee80fcc13097f Mon Sep 17 00:00:00 2001 From: Jonathan Desrosiers <359867+desrosj@users.noreply.github.com> Date: Fri, 5 Jun 2026 18:23:31 +0200 Subject: [PATCH 07/12] Fix some inconsistencies. --- Gruntfile.js | 59 +++++++++++++++++++++++++++++++------- tools/gutenberg/copy.js | 63 ++++++++++++++++++++++++++++------------- 2 files changed, 93 insertions(+), 29 deletions(-) diff --git a/Gruntfile.js b/Gruntfile.js index f6e8d1a4d4c6d..caa72b936ac1d 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -265,8 +265,8 @@ module.exports = function(grunt) { filter: function() { var allowedTasks = [ 'build', - 'build:dev', 'build:gutenberg', + 'build:gutenberg:versioned', 'clean:gutenberg-versioned', /* * These tasks chain `build` internally, but grunt.cli.tasks only reflects the current task, @@ -329,6 +329,8 @@ module.exports = function(grunt) { cwd: SOURCE_DIR, src: buildFiles.concat( [ '!wp-includes/assets/**', // Assets is extracted into separate copy tasks. + // Gutenberg-sourced manifest lives in src/wp-includes/assets/ and needs to propagate. + 'wp-includes/assets/icon-library-manifest.php', '!js/**', // JavaScript is extracted into separate copy tasks. '!.{svn,git}', // Exclude version control folders. '!wp-includes/version.php', // Exclude version.php. @@ -745,7 +747,7 @@ module.exports = function(grunt) { // with no debugging value over the minified versions. '!vips/!(*.min).js', ], - dest: SOURCE_DIR + 'wp-includes/js/dist/script-modules/', + dest: WORKING_DIR + 'wp-includes/js/dist/script-modules/', } ], }, 'gutenberg-styles': { @@ -758,7 +760,7 @@ module.exports = function(grunt) { // Per-block CSS is copied to wp-includes/blocks/ by tools/gutenberg/copy.js. '!block-library/*/**', ], - dest: SOURCE_DIR + 'wp-includes/css/dist/', + dest: WORKING_DIR + 'wp-includes/css/dist/', } ], }, 'gutenberg-theme-json': { @@ -1714,11 +1716,20 @@ module.exports = function(grunt) { } ); } ); + // Underlying runner. Accepts colon-suffixed scope (`:versioned`, `:unversioned`) + // to drive the corresponding subset of tools/gutenberg/copy.js. With no scope + // (`gutenberg:copy`), the script runs in `all` mode. grunt.registerTask( 'gutenberg:copy', 'Copies Gutenberg JS packages and block assets to WordPress Core.', function() { const done = this.async(); + const scope = this.args[ 0 ] || 'all'; + const args = [ 'tools/gutenberg/copy.js', `--scope=${ scope }` ]; + // Unversioned JS packages need to know WORKING_DIR semantics; versioned files always land in src/. + if ( scope !== 'versioned' ) { + args.push( `--build-dir=${ grunt.option( 'dev' ) ? 'src' : 'build' }` ); + } grunt.util.spawn( { cmd: 'node', - args: [ 'tools/gutenberg/copy.js' ], + args: args, opts: { stdio: 'inherit' } }, function( error ) { done( ! error ); @@ -2194,20 +2205,43 @@ module.exports = function(grunt) { ) ); } ); - grunt.registerTask( 'build:gutenberg', [ + /* + * Versioned half: paths under version control. Always written to src/. + * + * Called early in prod builds so the fresh content propagates from src/ to + * build/ via the subsequent build:files ā copy:files step. + */ + grunt.registerTask( 'build:gutenberg:versioned', [ 'gutenberg:verify', 'clean:gutenberg-versioned', - 'clean:gutenberg', 'copy:gutenberg-php', 'routes:setup', 'copy:routes', 'copy:gutenberg-js', - 'gutenberg:copy', - 'copy:gutenberg-modules', - 'copy:gutenberg-styles', 'copy:gutenberg-theme-json', 'copy:icon-library-images', 'copy:icon-library-manifest', + 'gutenberg:copy:versioned', + ] ); + + /* + * Unversioned half: gitignored dist artifacts. Written to WORKING_DIR + * (src/ in dev, build/ in prod). + * + * Called late in prod builds so the freshly-built dist content is not wiped + * by clean:files / clean:js. + */ + grunt.registerTask( 'build:gutenberg:unversioned', [ + 'clean:gutenberg', + 'copy:gutenberg-modules', + 'copy:gutenberg-styles', + 'gutenberg:copy:unversioned', + ] ); + + // Combined target for callers that don't need to interleave with the rest of the build. + grunt.registerTask( 'build:gutenberg', [ + 'build:gutenberg:versioned', + 'build:gutenberg:unversioned', ] ); grunt.registerTask( 'build', function() { @@ -2221,11 +2255,16 @@ module.exports = function(grunt) { ] ); } else { grunt.task.run( [ - 'build:gutenberg', + // Refresh versioned src/ paths first so copy:files (inside build:files) + // propagates the new Gutenberg state into build/. + 'build:gutenberg:versioned', 'build:files', 'build:js', 'build:css', 'build:codemirror', + // Populate dist artifacts in build/ last so clean:files/clean:js + // can't wipe them. + 'build:gutenberg:unversioned', 'build:certificates', 'replace:source-maps', 'verify:build', diff --git a/tools/gutenberg/copy.js b/tools/gutenberg/copy.js index f6a24d2306db3..ce3df4602cb78 100644 --- a/tools/gutenberg/copy.js +++ b/tools/gutenberg/copy.js @@ -19,8 +19,29 @@ const rootDir = path.resolve( __dirname, '../..' ); const gutenbergDir = path.join( rootDir, 'gutenberg' ); const gutenbergBuildDir = path.join( gutenbergDir, 'build' ); -// All files handled in this script are subject to version control, so they should always be placed into src/. +/* + * Scope selects which subset of files to copy. + * - `versioned` : blocks/, generated PHP under assets/ (script-loader, script-modules), blocks-json, + * require-{dynamic,static}-blocks. Always written under src/. + * - `unversioned`: top-level @wordpress JS packages under wp-includes/js/dist/. Written to the + * directory chosen by --build-dir / --dev (src/ in dev builds, build/ in prod builds). + * - `all` (default): both, with the same target-dir rules as above. + */ +const args = process.argv.slice( 2 ); +const scopeArg = args.find( ( arg ) => arg.startsWith( '--scope=' ) ); +const scope = scopeArg ? scopeArg.split( '=' )[ 1 ] : 'all'; + +const buildDirArg = args.find( ( arg ) => arg.startsWith( '--build-dir=' ) ); +const buildDir = buildDirArg + ? buildDirArg.split( '=' )[ 1 ] + : args.includes( '--dev' ) + ? 'src' + : 'build'; + +// Versioned outputs always go to src/. const wpIncludesDir = path.join( rootDir, 'src', 'wp-includes' ); +// Unversioned JS packages follow WORKING_DIR (--build-dir / --dev). +const unversionedWpIncludesDir = path.join( rootDir, buildDir, 'wp-includes' ); /* * Copy configuration. @@ -497,7 +518,7 @@ function generateBlocksJson() { * Main execution function. */ async function main() { - console.log( 'š¦ Copying versioned Gutenberg files to src/...' ); + console.log( `š¦ Copying Gutenberg build (scope: ${ scope })...` ); if ( ! fs.existsSync( gutenbergBuildDir ) ) { console.error( 'ā Gutenberg build directory not found' ); @@ -505,11 +526,12 @@ async function main() { process.exit( 1 ); } - // 1. Copy JavaScript packages. + // 1. Copy JavaScript packages (unversioned ā WORKING_DIR). + if ( scope === 'unversioned' || scope === 'all' ) { console.log( '\nš¦ Copying JavaScript packages...' ); const scriptsConfig = COPY_CONFIG.scripts; const scriptsSrc = path.join( gutenbergBuildDir, scriptsConfig.source ); - const scriptsDest = path.join( wpIncludesDir, scriptsConfig.destination ); + const scriptsDest = path.join( unversionedWpIncludesDir, scriptsConfig.destination ); if ( fs.existsSync( scriptsSrc ) ) { const entries = fs.readdirSync( scriptsSrc, { withFileTypes: true } ); @@ -590,26 +612,29 @@ async function main() { console.log( ' ā JavaScript packages copied' ); } + } - // 2. Copy blocks (unified: scripts, styles, PHP, JSON). - console.log( '\nš¦ Copying blocks...' ); - copyBlockAssets( COPY_CONFIG.blocks ); + if ( scope === 'versioned' || scope === 'all' ) { + // 2. Copy blocks (unified: scripts, styles, PHP, JSON). + console.log( '\nš¦ Copying blocks...' ); + copyBlockAssets( COPY_CONFIG.blocks ); - // 3. Generate script-modules-packages.php from individual asset files. - console.log( '\nš¦ Generating script-modules-packages.php...' ); - generateScriptModulesPackages(); + // 3. Generate script-modules-packages.php from individual asset files. + console.log( '\nš¦ Generating script-modules-packages.php...' ); + generateScriptModulesPackages(); - // 4. Generate script-loader-packages.php. - console.log( '\nš¦ Generating script-loader-packages.php...' ); - generateScriptLoaderPackages(); + // 4. Generate script-loader-packages.php. + console.log( '\nš¦ Generating script-loader-packages.php...' ); + generateScriptLoaderPackages(); - // 5. Generate require-dynamic-blocks.php and require-static-blocks.php. - console.log( '\nš¦ Generating block registration files...' ); - generateBlockRegistrationFiles(); + // 5. Generate require-dynamic-blocks.php and require-static-blocks.php. + console.log( '\nš¦ Generating block registration files...' ); + generateBlockRegistrationFiles(); - // 6. Generate blocks-json.php from block.json files. - console.log( '\nš¦ Generating blocks-json.php...' ); - generateBlocksJson(); + // 6. Generate blocks-json.php from block.json files. + console.log( '\nš¦ Generating blocks-json.php...' ); + generateBlocksJson(); + } console.log( '\nā Copy complete!' ); } From 8936aa9e75b39eee0b827f36b6e71163752e9a76 Mon Sep 17 00:00:00 2001 From: Jonathan Desrosiers <359867+desrosj@users.noreply.github.com> Date: Sat, 6 Jun 2026 01:04:10 +0200 Subject: [PATCH 08/12] Fix sequence issues. --- Gruntfile.js | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/Gruntfile.js b/Gruntfile.js index caa72b936ac1d..82c346bec7443 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -329,8 +329,10 @@ module.exports = function(grunt) { cwd: SOURCE_DIR, src: buildFiles.concat( [ '!wp-includes/assets/**', // Assets is extracted into separate copy tasks. - // Gutenberg-sourced manifest lives in src/wp-includes/assets/ and needs to propagate. + // Gutenberg-sourced files in src/wp-includes/assets/ that must propagate to build/. 'wp-includes/assets/icon-library-manifest.php', + 'wp-includes/assets/script-loader-packages.php', + 'wp-includes/assets/script-modules-packages.php', '!js/**', // JavaScript is extracted into separate copy tasks. '!.{svn,git}', // Exclude version control folders. '!wp-includes/version.php', // Exclude version.php. @@ -2228,11 +2230,11 @@ module.exports = function(grunt) { * Unversioned half: gitignored dist artifacts. Written to WORKING_DIR * (src/ in dev, build/ in prod). * - * Called late in prod builds so the freshly-built dist content is not wiped - * by clean:files / clean:js. + * Called late in the build chain so the freshly-built dist content is not + * wiped by clean:files / clean:js. Intentionally does NOT call clean:gutenberg + * because that would wipe vendor files placed earlier by copy:vendor-js. */ grunt.registerTask( 'build:gutenberg:unversioned', [ - 'clean:gutenberg', 'copy:gutenberg-modules', 'copy:gutenberg-styles', 'gutenberg:copy:unversioned', @@ -2247,10 +2249,13 @@ module.exports = function(grunt) { grunt.registerTask( 'build', function() { if ( grunt.option( 'dev' ) ) { grunt.task.run( [ - 'build:gutenberg', + // Refresh versioned src/ paths first. + 'build:gutenberg:versioned', 'build:js', 'build:css', 'build:codemirror', + // Populate dist artifacts LAST so clean:js doesn't wipe them. + 'build:gutenberg:unversioned', 'build:certificates', ] ); } else { From 967998bceb654b037ba980601e3c122bf99bced6 Mon Sep 17 00:00:00 2001 From: Jonathan Desrosiers <359867+desrosj@users.noreply.github.com> Date: Sat, 6 Jun 2026 01:10:37 +0200 Subject: [PATCH 09/12] Bump hash in package file. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 430efdd2fba85..8cc9c16fcef07 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "url": "https://develop.svn.wordpress.org/trunk" }, "gutenberg": { - "sha": "a2a354cf35e5b69c3330d6c1cfd42d8dc2efb9fd", + "sha": "ac1566bd9ac5a8e4b26e4d2093bea4a5525ae001", "ghcrRepo": "WordPress/gutenberg/gutenberg-wp-develop-build" }, "engines": { From c7d1808c6c6312eddfdd2da4731fa2c2bec33672 Mon Sep 17 00:00:00 2001 From: "wordpress-develop-pr-bot[bot]" <1178653+wordpress-develop-pr-bot[bot]@users.noreply.github.com> Date: Fri, 5 Jun 2026 23:13:25 +0000 Subject: [PATCH 10/12] Automation: Updating built files with changes. --- .../assets/script-loader-packages.php | 126 +- .../assets/script-modules-packages.php | 61 +- src/wp-includes/blocks/accordion-item.php | 1 - .../blocks/accordion-item/block.json | 1 + src/wp-includes/blocks/blocks-json.php | 93 +- src/wp-includes/blocks/button.php | 68 + src/wp-includes/blocks/button/block.json | 14 +- src/wp-includes/blocks/cover.php | 8 +- src/wp-includes/blocks/group/block.json | 7 +- src/wp-includes/blocks/home-link.php | 57 +- src/wp-includes/blocks/home-link/block.json | 7 + src/wp-includes/blocks/icon.php | 4 +- src/wp-includes/blocks/image.php | 10 +- src/wp-includes/blocks/image/block.json | 4 + src/wp-includes/blocks/latest-posts.php | 2 +- src/wp-includes/blocks/list-item/block.json | 1 + src/wp-includes/blocks/loginout.php | 13 + src/wp-includes/blocks/navigation-link.php | 64 +- .../blocks/navigation-link/block.json | 5 + src/wp-includes/blocks/navigation-submenu.php | 87 +- src/wp-includes/blocks/navigation.php | 11 - src/wp-includes/blocks/page-list.php | 51 +- src/wp-includes/blocks/post-author-name.php | 2 +- src/wp-includes/blocks/post-date.php | 2 +- src/wp-includes/blocks/post-date/block.json | 4 +- .../blocks/post-excerpt/block.json | 4 +- .../blocks/post-featured-image.php | 8 +- .../blocks/post-navigation-link/block.json | 4 +- src/wp-includes/blocks/post-template.php | 3 + src/wp-includes/blocks/post-title/block.json | 7 +- src/wp-includes/blocks/pullquote/block.json | 5 +- src/wp-includes/blocks/query-title.php | 2 +- src/wp-includes/blocks/query-title/block.json | 4 +- src/wp-includes/blocks/read-more.php | 4 +- src/wp-includes/blocks/search.php | 28 +- src/wp-includes/blocks/search/block.json | 10 +- .../blocks/site-tagline/block.json | 10 +- src/wp-includes/blocks/site-title/block.json | 4 +- src/wp-includes/build/constants.php | 2 +- src/wp-includes/build/pages.php | 14 +- .../pages/font-library/page-wp-admin.php | 23 +- .../build/pages/font-library/page.php | 45 +- .../options-connectors/page-wp-admin.php | 23 +- .../build/pages/options-connectors/page.php | 45 +- .../build/routes/connectors-home/content.js | 10797 +++++++++++++++- .../connectors-home/content.min.asset.php | 2 +- .../routes/connectors-home/content.min.js | 26 +- .../build/routes/font-list/content.js | 10482 +++++++++++++-- .../routes/font-list/content.min.asset.php | 2 +- .../build/routes/font-list/content.min.js | 36 +- src/wp-includes/images/icon-library/tab.svg | 2 +- .../images/icon-library/tabs-menu-item.svg | 1 - .../images/icon-library/tabs-menu.svg | 1 - .../images/icon-library/time-to-read.svg | 3 - src/wp-includes/theme.json | 25 + 55 files changed, 20526 insertions(+), 1799 deletions(-) delete mode 100644 src/wp-includes/images/icon-library/tabs-menu-item.svg delete mode 100644 src/wp-includes/images/icon-library/tabs-menu.svg delete mode 100644 src/wp-includes/images/icon-library/time-to-read.svg diff --git a/src/wp-includes/assets/script-loader-packages.php b/src/wp-includes/assets/script-loader-packages.php index 5dccb121dbb83..930cb7a0136e9 100644 --- a/src/wp-includes/assets/script-loader-packages.php +++ b/src/wp-includes/assets/script-loader-packages.php @@ -4,7 +4,7 @@ 'wp-dom-ready', 'wp-i18n' ), - 'version' => 'af934e5259bc51b8718e' + 'version' => '483af07a6016f640f456' ), 'annotations.js' => array( 'dependencies' => array( @@ -13,14 +13,15 @@ 'wp-i18n', 'wp-rich-text' ), - 'version' => '4b07d06c67c3b5ea590c' + 'version' => 'd4fe1eeb787c2fd5ee89' ), 'api-fetch.js' => array( 'dependencies' => array( 'wp-i18n', + 'wp-private-apis', 'wp-url' ), - 'version' => 'd7efe4dc1468d36c39b8' + 'version' => 'b5b51750518787a93005' ), 'autop.js' => array( 'dependencies' => array( @@ -42,6 +43,8 @@ ), 'block-directory.js' => array( 'dependencies' => array( + 'react', + 'react-dom', 'react-jsx-runtime', 'wp-a11y', 'wp-api-fetch', @@ -59,9 +62,11 @@ 'wp-notices', 'wp-plugins', 'wp-primitives', + 'wp-private-apis', + 'wp-theme', 'wp-url' ), - 'version' => '23207f52d0d266f6e1c4' + 'version' => '9a05dcf7adb71a472989' ), 'block-editor.js' => array( 'dependencies' => array( @@ -69,7 +74,6 @@ 'react-dom', 'react-jsx-runtime', 'wp-a11y', - 'wp-api-fetch', 'wp-blob', 'wp-block-serialization-default-parser', 'wp-blocks', @@ -100,11 +104,12 @@ 'wp-url', 'wp-warning' ), - 'version' => '93c3566b7f24c15b7e17' + 'version' => '914422971dc7fd6a8ca7' ), 'block-library.js' => array( 'dependencies' => array( 'react', + 'react-dom', 'react-jsx-runtime', 'wp-a11y', 'wp-api-fetch', @@ -132,6 +137,8 @@ 'wp-private-apis', 'wp-rich-text', 'wp-server-side-render', + 'wp-shortcode', + 'wp-theme', 'wp-upload-media', 'wp-url', 'wp-wordcount' @@ -142,7 +149,7 @@ 'import' => 'dynamic' ) ), - 'version' => '2dffdfe77b9c5cba960e' + 'version' => 'b449c385f68d1a30885b' ), 'block-serialization-default-parser.js' => array( 'dependencies' => array( @@ -175,7 +182,7 @@ 'wp-shortcode', 'wp-warning' ), - 'version' => 'ef38e42500165bfda301' + 'version' => 'd0d5baf8255b4c1d0118' ), 'commands.js' => array( 'dependencies' => array( @@ -187,10 +194,11 @@ 'wp-element', 'wp-i18n', 'wp-keyboard-shortcuts', + 'wp-preferences', 'wp-primitives', 'wp-private-apis' ), - 'version' => 'e3d8bba53f4ffea4fcd2' + 'version' => '8b8663311faa33540c1b' ), 'components.js' => array( 'dependencies' => array( @@ -212,9 +220,10 @@ 'wp-primitives', 'wp-private-apis', 'wp-rich-text', + 'wp-theme', 'wp-warning' ), - 'version' => '5dedfe13f08880193a28' + 'version' => '086638a36f34ea68ff91' ), 'compose.js' => array( 'dependencies' => array( @@ -226,9 +235,10 @@ 'wp-is-shallow-equal', 'wp-keycodes', 'wp-priority-queue', + 'wp-private-apis', 'wp-undo-manager' ), - 'version' => 'edb5a8c0b5bf71686403' + 'version' => 'e234bbf2606001a9cdd3' ), 'core-commands.js' => array( 'dependencies' => array( @@ -245,7 +255,7 @@ 'wp-router', 'wp-url' ), - 'version' => 'b209152e7e51279d7c28' + 'version' => 'c387d70a2b85c37011a2' ), 'core-data.js' => array( 'dependencies' => array( @@ -257,20 +267,23 @@ 'wp-data', 'wp-deprecated', 'wp-element', - 'wp-hooks', 'wp-html-entities', 'wp-i18n', 'wp-private-apis', 'wp-rich-text', + 'wp-sync', 'wp-undo-manager', 'wp-url', 'wp-warning' ), - 'version' => '89931f90e4df5eb5f8a3' + 'version' => '853feaa4b95feec3595f' ), 'customize-widgets.js' => array( 'dependencies' => array( + 'react', + 'react-dom', 'react-jsx-runtime', + 'wp-a11y', 'wp-block-editor', 'wp-block-library', 'wp-blocks', @@ -289,9 +302,10 @@ 'wp-preferences', 'wp-primitives', 'wp-private-apis', + 'wp-theme', 'wp-widgets' ), - 'version' => '524dc7a4326b77064831' + 'version' => '4da0091c281df82bd222' ), 'data.js' => array( 'dependencies' => array( @@ -304,7 +318,7 @@ 'wp-private-apis', 'wp-redux-routine' ), - 'version' => '1756b6a2676c1b3369ab' + 'version' => '17619b19747bc3be28d6' ), 'data-controls.js' => array( 'dependencies' => array( @@ -319,7 +333,7 @@ 'moment', 'wp-deprecated' ), - 'version' => 'c9f8e7dd3232716f34e9' + 'version' => '2faaf49020b2074de156' ), 'deprecated.js' => array( 'dependencies' => array( @@ -331,7 +345,7 @@ 'dependencies' => array( 'wp-deprecated' ), - 'version' => '66a6cf58e0c4cd128af0' + 'version' => 'ea68e9ed0a44f0e21a67' ), 'dom-ready.js' => array( 'dependencies' => array( @@ -381,7 +395,7 @@ 'import' => 'static' ) ), - 'version' => '28ef50b859708963e197' + 'version' => 'f8be112640231f962022' ), 'edit-site.js' => array( 'dependencies' => array( @@ -409,6 +423,7 @@ 'wp-i18n', 'wp-keyboard-shortcuts', 'wp-keycodes', + 'wp-media-utils', 'wp-notices', 'wp-patterns', 'wp-plugins', @@ -420,7 +435,8 @@ 'wp-theme', 'wp-url', 'wp-warning', - 'wp-widgets' + 'wp-widgets', + 'wp-wordcount' ), 'module_dependencies' => array( array( @@ -428,7 +444,7 @@ 'import' => 'static' ) ), - 'version' => 'dfd078032a67983c4d32' + 'version' => '45fb7cc8e84472d82ad3' ), 'edit-widgets.js' => array( 'dependencies' => array( @@ -469,7 +485,7 @@ 'import' => 'static' ) ), - 'version' => '899c5ac5dcb94e19d378' + 'version' => '3382b8166d24bc8ebc42' ), 'editor.js' => array( 'dependencies' => array( @@ -519,7 +535,7 @@ 'import' => 'static' ) ), - 'version' => '37faadbdf6c40cb0c71c' + 'version' => '048000f0b955802a6c37' ), 'element.js' => array( 'dependencies' => array( @@ -527,7 +543,7 @@ 'react-dom', 'wp-escape-html' ), - 'version' => '15ba804677f72a8db97b' + 'version' => 'ce395381f7d64d2a6d71' ), 'escape-html.js' => array( 'dependencies' => array( @@ -537,6 +553,8 @@ ), 'format-library.js' => array( 'dependencies' => array( + 'react', + 'react-dom', 'react-jsx-runtime', 'wp-a11y', 'wp-block-editor', @@ -549,6 +567,7 @@ 'wp-primitives', 'wp-private-apis', 'wp-rich-text', + 'wp-theme', 'wp-url' ), 'module_dependencies' => array( @@ -557,7 +576,7 @@ 'import' => 'dynamic' ) ), - 'version' => 'f89be9586f2d9ce4545a' + 'version' => '8c583695084dbc2a18a8' ), 'hooks.js' => array( 'dependencies' => array( @@ -575,7 +594,7 @@ 'dependencies' => array( 'wp-hooks' ), - 'version' => '781d11515ad3d91786ec' + 'version' => '125448662852c5e18937' ), 'is-shallow-equal.js' => array( 'dependencies' => array( @@ -590,7 +609,7 @@ 'wp-element', 'wp-keycodes' ), - 'version' => '2ed78d3b4c23f38804e0' + 'version' => '0dd268b2132a3f82b1d4' ), 'keycodes.js' => array( 'dependencies' => array( @@ -608,7 +627,7 @@ 'wp-element', 'wp-i18n' ), - 'version' => '2e35ebd5dbaccb5a90c5' + 'version' => 'a44da9be02cdfef6e44d' ), 'media-utils.js' => array( 'dependencies' => array( @@ -628,13 +647,14 @@ 'wp-i18n', 'wp-keycodes', 'wp-notices', + 'wp-preferences', 'wp-primitives', 'wp-private-apis', 'wp-theme', 'wp-url', 'wp-warning' ), - 'version' => '85f1375ab5f23cd5d13c' + 'version' => '26ed91fd3dc2e7851d8d' ), 'notices.js' => array( 'dependencies' => array( @@ -642,20 +662,14 @@ 'wp-components', 'wp-data' ), - 'version' => '218d0173a31ae7269246' + 'version' => '505026883bbd05994872' ), 'nux.js' => array( 'dependencies' => array( - 'react-jsx-runtime', - 'wp-components', - 'wp-compose', 'wp-data', - 'wp-deprecated', - 'wp-element', - 'wp-i18n', - 'wp-primitives' + 'wp-deprecated' ), - 'version' => '14d2335a0007b36b9112' + 'version' => 'b0afe722eacfd6e9a364' ), 'patterns.js' => array( 'dependencies' => array( @@ -687,7 +701,7 @@ 'wp-is-shallow-equal', 'wp-primitives' ), - 'version' => '72e3cf01c2b3535a9432' + 'version' => 'fb81afeb7c472b9fb513' ), 'preferences.js' => array( 'dependencies' => array( @@ -703,7 +717,7 @@ 'wp-primitives', 'wp-private-apis' ), - 'version' => '035813168e404aa30193' + 'version' => '918930601e250eee727e' ), 'preferences-persistence.js' => array( 'dependencies' => array( @@ -728,7 +742,7 @@ 'dependencies' => array( ), - 'version' => '835912f0086b9e59aed4' + 'version' => '66edb99c6699f7777c4f' ), 'react-i18n.js' => array( 'dependencies' => array( @@ -758,7 +772,7 @@ 'wp-primitives', 'wp-url' ), - 'version' => '21d86e46535b79d9afda' + 'version' => '372c845659b9a298e4fb' ), 'rich-text.js' => array( 'dependencies' => array( @@ -773,7 +787,7 @@ 'wp-keycodes', 'wp-private-apis' ), - 'version' => '16449e6108f48327f368' + 'version' => 'da75f56985c87415ce86' ), 'router.js' => array( 'dependencies' => array( @@ -797,7 +811,7 @@ 'wp-i18n', 'wp-url' ), - 'version' => '10a51bf05ced35b78092' + 'version' => '48cee6850e8be3502509' ), 'shortcode.js' => array( 'dependencies' => array( @@ -809,7 +823,15 @@ 'dependencies' => array( ), - 'version' => 'faa37ce61b7ec8394b2a' + 'version' => '10a88969c2fbccc89f91' + ), + 'sync.js' => array( + 'dependencies' => array( + 'wp-api-fetch', + 'wp-hooks', + 'wp-private-apis' + ), + 'version' => 'a35c75f515f3913a8186' ), 'theme.js' => array( 'dependencies' => array( @@ -817,7 +839,7 @@ 'wp-element', 'wp-private-apis' ), - 'version' => 'e22ce547a4420507b323' + 'version' => 'be051486f7cd1f4e4c56' ), 'token-list.js' => array( 'dependencies' => array( @@ -848,21 +870,21 @@ 'import' => 'dynamic' ) ), - 'version' => 'd359c2cccf866d7082d2' + 'version' => '6fa03c5e3b6ceff0c630' ), 'url.js' => array( 'dependencies' => array( ), - 'version' => 'bb0f766c3d2efe497871' + 'version' => '9dd5f16a5ce37bf4ba2c' ), 'viewport.js' => array( 'dependencies' => array( - 'react-jsx-runtime', 'wp-compose', - 'wp-data' + 'wp-data', + 'wp-element' ), - 'version' => '8614025b8075d220d78f' + 'version' => '83b39beb77dcc56c4d26' ), 'warning.js' => array( 'dependencies' => array( @@ -885,7 +907,7 @@ 'wp-notices', 'wp-primitives' ), - 'version' => '02b8dd683bc610f979fa' + 'version' => '3ab93e442c755a6b2b4e' ), 'wordcount.js' => array( 'dependencies' => array( diff --git a/src/wp-includes/assets/script-modules-packages.php b/src/wp-includes/assets/script-modules-packages.php index 30b248da04fc1..e8ac04b8f8ee8 100644 --- a/src/wp-includes/assets/script-modules-packages.php +++ b/src/wp-includes/assets/script-modules-packages.php @@ -34,7 +34,7 @@ 'import' => 'static' ) ), - 'version' => '2af01b43d30739c3fb8d' + 'version' => 'f77b871ece5a791f449e' ), 'block-library/file/view.js' => array( 'dependencies' => array( @@ -46,7 +46,7 @@ 'import' => 'static' ) ), - 'version' => '7d4d261d10dca47ebecb' + 'version' => 'a9114a756e418400594c' ), 'block-library/form/view.js' => array( 'dependencies' => array( @@ -88,7 +88,7 @@ 'import' => 'static' ) ), - 'version' => '99f747d731f80246db11' + 'version' => '3440d5367efaa2741a5b' ), 'block-library/query/view.js' => array( 'dependencies' => array( @@ -166,7 +166,7 @@ 'import' => 'static' ) ), - 'version' => '54bb5a420026a61c7e4f' + 'version' => 'eec7937231238adf50e3' ), 'connectors/index.js' => array( 'dependencies' => array( @@ -177,7 +177,42 @@ 'wp-i18n', 'wp-private-apis' ), - 'version' => '274797868955a828dfdc' + 'version' => '753a649aa400199df0fd' + ), + 'content-types/index.js' => array( + 'dependencies' => array( + 'react', + 'react-dom', + 'react-jsx-runtime', + 'wp-components', + 'wp-compose', + 'wp-core-data', + 'wp-data', + 'wp-date', + 'wp-deprecated', + 'wp-element', + 'wp-i18n', + 'wp-is-shallow-equal', + 'wp-keycodes', + 'wp-notices', + 'wp-preferences', + 'wp-primitives', + 'wp-private-apis', + 'wp-theme', + 'wp-url', + 'wp-warning' + ), + 'module_dependencies' => array( + array( + 'id' => '@wordpress/a11y', + 'import' => 'static' + ), + array( + 'id' => '@wordpress/route', + 'import' => 'static' + ) + ), + 'version' => '6f3ac3460f86fd737f84' ), 'core-abilities/index.js' => array( 'dependencies' => array( @@ -190,7 +225,7 @@ 'import' => 'static' ) ), - 'version' => '012760fd849397dd0031' + 'version' => 'ed8d088084da397754c1' ), 'edit-site-init/index.js' => array( 'dependencies' => array( @@ -205,7 +240,7 @@ 'import' => 'static' ) ), - 'version' => 'e57f44d1a9f69e75d2d9' + 'version' => '03b5e26742d2806990c6' ), 'interactivity/index.js' => array( 'dependencies' => array( @@ -273,7 +308,7 @@ 'wp-private-apis', 'wp-style-engine' ), - 'version' => '30ab62f45bfe9f971ea0' + 'version' => 'e9a1d3da960d762c5954' ), 'route/index.js' => array( 'dependencies' => array( @@ -282,7 +317,7 @@ 'react-jsx-runtime', 'wp-private-apis' ), - 'version' => 'c5843b6c5e84b352f43b' + 'version' => '48a77bfa70722b4254e4' ), 'vips/loader.js' => array( 'dependencies' => array( @@ -300,7 +335,7 @@ 'dependencies' => array( ), - 'version' => 'aff5e5c5b28ae6b73aaa' + 'version' => '7ba90481a9cc1776ce7a' ), 'workflow/index.js' => array( 'dependencies' => array( @@ -319,8 +354,12 @@ array( 'id' => '@wordpress/abilities', 'import' => 'static' + ), + array( + 'id' => '@wordpress/core-abilities', + 'import' => 'static' ) ), - 'version' => '13556bc597bbf2a8d620' + 'version' => 'c5983b82ce036952b349' ) ); \ No newline at end of file diff --git a/src/wp-includes/blocks/accordion-item.php b/src/wp-includes/blocks/accordion-item.php index a16a1426e346d..8530b34de12d8 100644 --- a/src/wp-includes/blocks/accordion-item.php +++ b/src/wp-includes/blocks/accordion-item.php @@ -39,7 +39,6 @@ function block_core_accordion_item_render( array $attributes, string $content ): if ( $p->next_tag( array( 'class_name' => 'wp-block-accordion-heading__toggle' ) ) ) { $p->set_attribute( 'data-wp-on--click', 'actions.toggle' ); - $p->set_attribute( 'data-wp-on--keydown', 'actions.handleKeyDown' ); $p->set_attribute( 'id', $unique_id ); $p->set_attribute( 'aria-controls', $unique_id . '-panel' ); $p->set_attribute( 'data-wp-bind--aria-expanded', 'state.isOpen' ); diff --git a/src/wp-includes/blocks/accordion-item/block.json b/src/wp-includes/blocks/accordion-item/block.json index 74bfddde0e68b..22987b9558a5f 100644 --- a/src/wp-includes/blocks/accordion-item/block.json +++ b/src/wp-includes/blocks/accordion-item/block.json @@ -16,6 +16,7 @@ "interactivity": true, "spacing": { "margin": [ "top", "bottom" ], + "padding": true, "blockGap": true }, "__experimentalBorder": { diff --git a/src/wp-includes/blocks/blocks-json.php b/src/wp-includes/blocks/blocks-json.php index e905b113502ac..1f61f615b6dfa 100644 --- a/src/wp-includes/blocks/blocks-json.php +++ b/src/wp-includes/blocks/blocks-json.php @@ -224,6 +224,7 @@ 'top', 'bottom' ), + 'padding' => true, 'blockGap' => true ), '__experimentalBorder' => array( @@ -759,9 +760,6 @@ ), 'gradient' => array( 'type' => 'string' - ), - 'width' => array( - 'type' => 'number' ) ), 'supports' => array( @@ -777,6 +775,15 @@ 'text' => true ) ), + 'dimensions' => array( + 'width' => true, + '__experimentalSkipSerialization' => array( + 'width' + ), + '__experimentalDefaultControls' => array( + 'width' => true + ) + ), 'typography' => array( '__experimentalSkipSerialization' => array( 'fontSize', @@ -851,6 +858,10 @@ 'root' => '.wp-block-button .wp-block-button__link', 'typography' => array( 'writingMode' => '.wp-block-button' + ), + 'dimensions' => array( + 'root' => '.wp-block-button', + 'width' => '.wp-block-button' ) ) ), @@ -2865,8 +2876,10 @@ 'background' => array( 'backgroundImage' => true, 'backgroundSize' => true, + 'gradient' => true, '__experimentalDefaultControls' => array( - 'backgroundImage' => true + 'backgroundImage' => true, + 'gradient' => true ) ), 'color' => array( @@ -2893,7 +2906,8 @@ ) ), 'dimensions' => array( - 'minHeight' => true + 'minHeight' => true, + 'minWidth' => true ), '__experimentalBorder' => array( 'color' => true, @@ -3034,6 +3048,13 @@ 'label' => array( 'type' => 'string', 'role' => 'content' + ), + 'opensInNewTab' => array( + 'type' => 'boolean', + 'default' => false + ), + 'description' => array( + 'type' => 'string' ) ), 'usesContext' => array( @@ -3291,6 +3312,10 @@ 'source' => 'attribute', 'selector' => 'figure > a', 'attribute' => 'target' + ), + 'isDecorative' => array( + 'type' => 'boolean', + 'default' => false ) ), 'supports' => array( @@ -3711,6 +3736,7 @@ ), 'supports' => array( 'anchor' => true, + 'html' => false, 'className' => false, 'splitting' => true, '__experimentalBorder' => array( @@ -4378,6 +4404,11 @@ 'clientNavigation' => true ) ), + 'selectors' => array( + 'states' => array( + '@current' => '.wp-block-navigation .current-menu-item' + ) + ), 'editorStyle' => 'wp-block-navigation-link-editor', 'style' => 'wp-block-navigation-link' ), @@ -5348,9 +5379,6 @@ 'type' => 'string', 'role' => 'content' ), - 'textAlign' => array( - 'type' => 'string' - ), 'format' => array( 'type' => 'string' ), @@ -5387,6 +5415,7 @@ 'typography' => array( 'fontSize' => true, 'lineHeight' => true, + 'textAlign' => true, '__experimentalFontFamily' => true, '__experimentalFontWeight' => true, '__experimentalFontStyle' => true, @@ -5423,9 +5452,6 @@ 'description' => 'Display the excerpt.', 'textdomain' => 'default', 'attributes' => array( - 'textAlign' => array( - 'type' => 'string' - ), 'moreText' => array( 'type' => 'string', 'role' => 'content' @@ -5466,6 +5492,7 @@ 'typography' => array( 'fontSize' => true, 'lineHeight' => true, + 'textAlign' => true, 'textColumns' => true, '__experimentalFontFamily' => true, '__experimentalFontWeight' => true, @@ -5624,9 +5651,6 @@ 'description' => 'Displays the next or previous post link that is adjacent to the current post.', 'textdomain' => 'default', 'attributes' => array( - 'textAlign' => array( - 'type' => 'string' - ), 'type' => array( 'type' => 'string', 'default' => 'next' @@ -5665,6 +5689,7 @@ 'typography' => array( 'fontSize' => true, 'lineHeight' => true, + 'textAlign' => true, '__experimentalFontFamily' => true, '__experimentalFontWeight' => true, '__experimentalFontStyle' => true, @@ -5922,9 +5947,6 @@ 'queryId' ), 'attributes' => array( - 'textAlign' => array( - 'type' => 'string' - ), 'level' => array( 'type' => 'number', 'default' => 2 @@ -5947,6 +5969,9 @@ 'type' => 'string', 'default' => '_self', 'role' => 'content' + ), + 'placeholder' => array( + 'type' => 'string' ) ), 'example' => array( @@ -5975,6 +6000,7 @@ 'typography' => array( 'fontSize' => true, 'lineHeight' => true, + 'textAlign' => true, '__experimentalFontFamily' => true, '__experimentalFontWeight' => true, '__experimentalFontStyle' => true, @@ -6114,10 +6140,7 @@ ) ), 'dimensions' => array( - 'minHeight' => true, - '__experimentalDefaultControls' => array( - 'minHeight' => false - ) + 'minHeight' => true ), 'spacing' => array( 'margin' => true, @@ -6523,9 +6546,6 @@ 'type' => array( 'type' => 'string' ), - 'textAlign' => array( - 'type' => 'string' - ), 'level' => array( 'type' => 'number', 'default' => 1 @@ -6571,6 +6591,7 @@ 'typography' => array( 'fontSize' => true, 'lineHeight' => true, + 'textAlign' => true, '__experimentalFontFamily' => true, '__experimentalFontStyle' => true, '__experimentalFontWeight' => true, @@ -6984,10 +7005,6 @@ 'default' => array( ) - ), - 'isSearchFieldHidden' => array( - 'type' => 'boolean', - 'default' => false ) ), 'supports' => array( @@ -7038,7 +7055,11 @@ 'html' => false ), 'editorStyle' => 'wp-block-search-editor', - 'style' => 'wp-block-search' + 'style' => 'wp-block-search', + 'selectors' => array( + 'color' => '.wp-block-search .wp-block-search__button, .wp-block-search.wp-block-search__no-button .wp-block-search__input', + 'border' => '.wp-block-search.wp-block-search__button-outside .wp-block-search__input, .wp-block-search.wp-block-search__button-outside .wp-block-search__button, .wp-block-search.wp-block-search__no-button .wp-block-search__input, .wp-block-search.wp-block-search__button-only .wp-block-search__input, .wp-block-search.wp-block-search__button-only .wp-block-search__button, .wp-block-search.wp-block-search__button-inside .wp-block-search__inside-wrapper' + ) ), 'separator' => array( '$schema' => 'https://schemas.wp.org/trunk/block.json', @@ -7224,9 +7245,6 @@ ), 'textdomain' => 'default', 'attributes' => array( - 'textAlign' => array( - 'type' => 'string' - ), 'level' => array( 'type' => 'number', 'default' => 0 @@ -7247,7 +7265,11 @@ 'example' => array( 'viewportWidth' => 350, 'attributes' => array( - 'textAlign' => 'center' + 'style' => array( + 'typography' => array( + 'textAlign' => 'center' + ) + ) ) ), 'supports' => array( @@ -7276,6 +7298,7 @@ 'typography' => array( 'fontSize' => true, 'lineHeight' => true, + 'textAlign' => true, '__experimentalFontFamily' => true, '__experimentalTextTransform' => true, '__experimentalTextDecoration' => true, @@ -7325,9 +7348,6 @@ 6 ) ), - 'textAlign' => array( - 'type' => 'string' - ), 'isLink' => array( 'type' => 'boolean', 'default' => true, @@ -7369,6 +7389,7 @@ 'typography' => array( 'fontSize' => true, 'lineHeight' => true, + 'textAlign' => true, '__experimentalFontFamily' => true, '__experimentalTextTransform' => true, '__experimentalTextDecoration' => true, diff --git a/src/wp-includes/blocks/button.php b/src/wp-includes/blocks/button.php index 0d03440b1cb0f..8a7b43a2df315 100644 --- a/src/wp-includes/blocks/button.php +++ b/src/wp-includes/blocks/button.php @@ -60,6 +60,74 @@ function render_block_core_button( $attributes, $content ) { return ''; } + $width = $attributes['style']['dimensions']['width'] ?? null; + + if ( $width ) { + // Resolve preset references to their actual values. + $resolved_width = $width; + $is_preset = str_starts_with( $width, 'var:preset|dimension|' ); + + if ( $is_preset ) { + $slug = substr( $width, strlen( 'var:preset|dimension|' ) ); + $dimension_presets = wp_get_global_settings( + array( 'dimensions', 'dimensionSizes' ), + array( 'block_name' => 'core/button' ) + ); + + // Search origins in priority order: custom > theme > default. + if ( is_array( $dimension_presets ) ) { + foreach ( array( 'custom', 'theme', 'default' ) as $origin ) { + if ( empty( $dimension_presets[ $origin ] ) || ! is_array( $dimension_presets[ $origin ] ) ) { + continue; + } + foreach ( $dimension_presets[ $origin ] as $preset ) { + if ( isset( $preset['slug'] ) && $preset['slug'] === $slug ) { + $resolved_width = $preset['size'] ?? $width; + break 2; + } + } + } + } + } + + $is_percentage = str_ends_with( $resolved_width, '%' ); + + $processor = new WP_HTML_Tag_Processor( $content ); + // Target the outer wrapper div. + if ( $processor->next_tag( array( 'class_name' => 'wp-block-button' ) ) ) { + $processor->add_class( 'has-custom-width' ); + $existing_style = $processor->get_attribute( 'style' ); + $existing_style = is_string( $existing_style ) ? $existing_style : ''; + + if ( $is_percentage ) { + $numeric_width = (float) $resolved_width; + $processor->add_class( 'wp-block-button__width' ); + + // Maintain legacy class for the standard percentage widths. + $legacy_widths = array( + '25%' => 'wp-block-button__width-25', + '50%' => 'wp-block-button__width-50', + '75%' => 'wp-block-button__width-75', + '100%' => 'wp-block-button__width-100', + ); + if ( isset( $legacy_widths[ $resolved_width ] ) ) { + $processor->add_class( $legacy_widths[ $resolved_width ] ); + } + + $width_style = "--wp--block-button--width: $numeric_width;"; + $processor->set_attribute( 'style', $width_style . ( $existing_style ? ' ' . $existing_style : '' ) ); + } else { + $css_value = $is_preset + ? 'var(--wp--preset--dimension--' . _wp_to_kebab_case( $slug ) . ')' + : $width; + $width_style = "width: $css_value;"; + $processor->set_attribute( 'style', $width_style . ( $existing_style ? ' ' . $existing_style : '' ) ); + } + + $content = $processor->get_updated_html(); + } + } + return $content; } diff --git a/src/wp-includes/blocks/button/block.json b/src/wp-includes/blocks/button/block.json index 50ba4cda9c688..2e23a64c8f559 100644 --- a/src/wp-includes/blocks/button/block.json +++ b/src/wp-includes/blocks/button/block.json @@ -63,9 +63,6 @@ }, "gradient": { "type": "string" - }, - "width": { - "type": "number" } }, "supports": { @@ -81,6 +78,13 @@ "text": true } }, + "dimensions": { + "width": true, + "__experimentalSkipSerialization": [ "width" ], + "__experimentalDefaultControls": { + "width": true + } + }, "typography": { "__experimentalSkipSerialization": [ "fontSize", @@ -145,6 +149,10 @@ "root": ".wp-block-button .wp-block-button__link", "typography": { "writingMode": ".wp-block-button" + }, + "dimensions": { + "root": ".wp-block-button", + "width": ".wp-block-button" } } } diff --git a/src/wp-includes/blocks/cover.php b/src/wp-includes/blocks/cover.php index 8da5db23ddc3f..16533acacd764 100644 --- a/src/wp-includes/blocks/cover.php +++ b/src/wp-includes/blocks/cover.php @@ -39,13 +39,13 @@ function render_block_core_cover( $attributes, $content ) { $lower_src = strtolower( $iframe_src ); $provider = null; - if ( strpos( $lower_src, 'youtube.com' ) !== false || strpos( $lower_src, 'youtu.be' ) !== false ) { + if ( str_contains( $lower_src, 'youtube.com' ) || str_contains( $lower_src, 'youtu.be' ) ) { $provider = 'youtube'; - } elseif ( strpos( $lower_src, 'vimeo.com' ) !== false ) { + } elseif ( str_contains( $lower_src, 'vimeo.com' ) ) { $provider = 'vimeo'; - } elseif ( strpos( $lower_src, 'videopress.com' ) !== false ) { + } elseif ( str_contains( $lower_src, 'videopress.com' ) ) { $provider = 'videopress'; - } elseif ( strpos( $lower_src, 'wordpress.tv' ) !== false ) { + } elseif ( str_contains( $lower_src, 'wordpress.tv' ) ) { $provider = 'wordpress-tv'; } diff --git a/src/wp-includes/blocks/group/block.json b/src/wp-includes/blocks/group/block.json index e83fb60d31fc7..7fa2ad2ccf4c7 100644 --- a/src/wp-includes/blocks/group/block.json +++ b/src/wp-includes/blocks/group/block.json @@ -28,8 +28,10 @@ "background": { "backgroundImage": true, "backgroundSize": true, + "gradient": true, "__experimentalDefaultControls": { - "backgroundImage": true + "backgroundImage": true, + "gradient": true } }, "color": { @@ -53,7 +55,8 @@ } }, "dimensions": { - "minHeight": true + "minHeight": true, + "minWidth": true }, "__experimentalBorder": { "color": true, diff --git a/src/wp-includes/blocks/home-link.php b/src/wp-includes/blocks/home-link.php index d61aa0bc235e2..48c4b5b191807 100644 --- a/src/wp-includes/blocks/home-link.php +++ b/src/wp-includes/blocks/home-link.php @@ -59,36 +59,6 @@ function block_core_home_link_build_css_colors( $context ) { return $colors; } -/** - * Build an array with CSS classes and inline styles defining the font sizes - * which will be applied to the home link markup in the front-end. - * - * @since 6.0.0 - * - * @param array $context Home link block context. - * @return array Font size CSS classes and inline styles. - */ -function block_core_home_link_build_css_font_sizes( $context ) { - // CSS classes. - $font_sizes = array( - 'css_classes' => array(), - 'inline_styles' => '', - ); - - $has_named_font_size = array_key_exists( 'fontSize', $context ); - $has_custom_font_size = isset( $context['style']['typography']['fontSize'] ); - - if ( $has_named_font_size ) { - // Add the font size class. - $font_sizes['css_classes'][] = sprintf( 'has-%s-font-size', $context['fontSize'] ); - } elseif ( $has_custom_font_size ) { - // Add the custom font size inline style. - $font_sizes['inline_styles'] = sprintf( 'font-size: %s;', $context['style']['typography']['fontSize'] ); - } - - return $font_sizes; -} - /** * Builds an array with classes and style for the li wrapper * @@ -98,13 +68,12 @@ function block_core_home_link_build_css_font_sizes( $context ) { * @return string The li wrapper attributes. */ function block_core_home_link_build_li_wrapper_attributes( $context ) { - $colors = block_core_home_link_build_css_colors( $context ); - $font_sizes = block_core_home_link_build_css_font_sizes( $context ); - $classes = array_merge( - $colors['css_classes'], - $font_sizes['css_classes'] + $colors = block_core_home_link_build_css_colors( $context ); + $classes = array_merge( + $colors['css_classes'] ); - $style_attribute = ( $colors['inline_styles'] . $font_sizes['inline_styles'] ); + + $style_attribute = ( $colors['inline_styles'] ); $classes[] = 'wp-block-navigation-item'; if ( is_front_page() ) { @@ -148,12 +117,24 @@ function render_block_core_home_link( $attributes, $content, $block ) { $aria_current = ' aria-current="page"'; } + $target = ''; + if ( isset( $attributes['opensInNewTab'] ) && true === $attributes['opensInNewTab'] ) { + $target = ' target="_blank"'; + } + + $description = ''; + if ( ! empty( $attributes['description'] ) ) { + $description = ''; + } + return sprintf( - '