diff --git a/.eslintrc.js b/.eslintrc.js index fd7e9183781eaf..8a44b5ef74a1e6 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -51,6 +51,11 @@ const restrictedImports = [ message: 'Please use Reakit API through `@wordpress/components` instead.', }, + { + name: '@ariakit/react', + message: + 'Please use Ariakit API through `@wordpress/components` instead.', + }, { name: 'redux', importNames: [ 'combineReducers' ], diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs index 6e5072a91b0018..f6a641a5af9bbe 100644 --- a/.git-blame-ignore-revs +++ b/.git-blame-ignore-revs @@ -6,3 +6,9 @@ f63053cace3c02e284f00918e1854284c85b9132 # Prettier upgrade to 2.6.2. 33d84b036592a5bf31af05b7710f3b2b14163dc4 + +# Prettier upgrade to 2.8.5. +c56e8a1910ed74f405b74bbb12fe81dea974e5c3 + +# Prettier upgrade to 3.0.3. +0bee15148fe4330c20cf372cb46a33693e45cb5f diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 22404fc7c96ebe..1f944fa38b4840 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -22,6 +22,7 @@ /packages/block-library/src/comment-template @michalczaplinski /packages/block-library/src/comments @michalczaplinski /packages/block-library/src/table-of-contents @ZebulanStanphill +/packages/block-library/src/image @artemiomorales @michalczaplinski # Duotone /lib/block-supports/duotone.php @ajlende @@ -135,6 +136,7 @@ # PHP /lib @spacedmonkey +/lib/compat/*/html-api @dmsnell /lib/experimental/rest-api.php @timothybjacobs /lib/experimental/class-wp-rest-* @timothybjacobs /lib/experimental/class-wp-rest-block-editor-settings-controller.php @timothybjacobs @spacedmonkey @geriux diff --git a/.github/workflows/php-changes-detection.yml b/.github/workflows/php-changes-detection.yml index 189639c3f47648..b78a787f3a4b8d 100644 --- a/.github/workflows/php-changes-detection.yml +++ b/.github/workflows/php-changes-detection.yml @@ -17,7 +17,7 @@ jobs: - name: Get changed PHP files id: changed-files-php - uses: tj-actions/changed-files@48566bbcc22ceb7c5809ebdd27377309f2c3de8c # v39 + uses: tj-actions/changed-files@41960309398d165631f08c5df47a11147e14712b # v39.1.2 with: files: | *.{php} diff --git a/.github/workflows/pull-request-automation.yml b/.github/workflows/pull-request-automation.yml index 6691fec3341c9d..a34df5282d6d8c 100644 --- a/.github/workflows/pull-request-automation.yml +++ b/.github/workflows/pull-request-automation.yml @@ -26,7 +26,7 @@ jobs: node-version: ${{ matrix.node }} - name: Cache NPM packages - uses: actions/cache@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8 # v3.3.1 + uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3.3.2 with: # npm cache files are stored in `~/.npm` on Linux/macOS path: ~/.npm diff --git a/.github/workflows/rnmobile-android-runner.yml b/.github/workflows/rnmobile-android-runner.yml index 4b5a4393b70c5b..375e7e22fe7609 100644 --- a/.github/workflows/rnmobile-android-runner.yml +++ b/.github/workflows/rnmobile-android-runner.yml @@ -28,7 +28,7 @@ jobs: show-progress: ${{ runner.debug == '1' && 'true' || 'false' }} - name: Use desired version of Java - uses: actions/setup-java@cd89f46ac9d01407894225f350157564c9c7cee2 # v3.12.0 + uses: actions/setup-java@0ab4596768b603586c0de567f2430c30f5b0d2b0 # v3.13.0 with: distribution: 'corretto' java-version: '17' @@ -40,7 +40,7 @@ jobs: uses: gradle/gradle-build-action@ef76a971e2fa3f867b617efd72f2fbd72cf6f8bc # v2.8.0 - name: AVD cache - uses: actions/cache@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8 # v3.3.1 + uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3.3.2 id: avd-cache with: path: | diff --git a/.github/workflows/rnmobile-ios-runner.yml b/.github/workflows/rnmobile-ios-runner.yml index 3b82180be5567b..6a03547966fe10 100644 --- a/.github/workflows/rnmobile-ios-runner.yml +++ b/.github/workflows/rnmobile-ios-runner.yml @@ -34,7 +34,7 @@ jobs: run: find package-lock.json packages/react-native-editor/ios packages/react-native-aztec/ios packages/react-native-bridge/ios -type f -print0 | sort -z | xargs -0 shasum | tee ios-checksums.txt - name: Restore build cache - uses: actions/cache@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8 # v3.3.1 + uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3.3.2 with: path: | packages/react-native-editor/ios/build/GutenbergDemo/Build/Products/Release-iphonesimulator/GutenbergDemo.app @@ -42,7 +42,7 @@ jobs: key: ${{ runner.os }}-ios-build-${{ matrix.xcode }}-${{ matrix.device }}-${{ hashFiles('ios-checksums.txt') }} - name: Restore pods cache - uses: actions/cache@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8 # v3.3.1 + uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3.3.2 with: path: | packages/react-native-editor/ios/Pods diff --git a/.github/workflows/unit-test.yml b/.github/workflows/unit-test.yml index f48386cde43729..31d24974172726 100644 --- a/.github/workflows/unit-test.yml +++ b/.github/workflows/unit-test.yml @@ -126,7 +126,7 @@ jobs: # dependency versions are installed and cached. ## - name: Set up PHP - uses: shivammathur/setup-php@72ae4ccbe57f82bbe08411e84e2130bd4ba1c10f # v2.25.5 + uses: shivammathur/setup-php@7fdd3ece872ec7ec4c098ae5ab7637d5e0a96067 # v2.26.0 with: php-version: '${{ matrix.php }}' ini-file: development @@ -226,7 +226,7 @@ jobs: show-progress: ${{ runner.debug == '1' && 'true' || 'false' }} - name: Set up PHP - uses: shivammathur/setup-php@72ae4ccbe57f82bbe08411e84e2130bd4ba1c10f # v2.25.5 + uses: shivammathur/setup-php@7fdd3ece872ec7ec4c098ae5ab7637d5e0a96067 # v2.26.0 with: php-version: '7.4' coverage: none @@ -239,7 +239,7 @@ jobs: run: echo "date=$(/bin/date -u --date='last Mon' "+%F")" >> $GITHUB_OUTPUT - name: Cache PHPCS scan cache - uses: actions/cache@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8 # v3.3.1 + uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3.3.2 with: path: .cache/phpcs.json key: ${{ runner.os }}-date-${{ steps.get-date.outputs.date }}-phpcs-cache-${{ hashFiles('**/composer.json', 'phpcs.xml.dist') }} diff --git a/.npmpackagejsonlintrc.json b/.npmpackagejsonlintrc.json index 5c240bf5c3bf40..43c2e4552edbc8 100644 --- a/.npmpackagejsonlintrc.json +++ b/.npmpackagejsonlintrc.json @@ -29,6 +29,14 @@ "require-repository-directory": "off", "prefer-no-devDependencies": "off" } + }, + { + "patterns": [ "./platform-docs/package.json" ], + "rules": { + "require-publishConfig": "off", + "require-repository-directory": "off", + "prefer-no-devDependencies": "off" + } } ] } diff --git a/bin/cherry-pick.mjs b/bin/cherry-pick.mjs index 91ded84489e68e..0c6a6c613638ba 100644 --- a/bin/cherry-pick.mjs +++ b/bin/cherry-pick.mjs @@ -9,7 +9,7 @@ import { spawnSync } from 'node:child_process'; const LABEL = process.argv[ 2 ] || 'Backport to WP Beta/RC'; const BRANCH = getCurrentBranch(); const GITHUB_CLI_AVAILABLE = spawnSync( 'gh', [ 'auth', 'status' ] ) - ?.stderr?.toString() + ?.stdout?.toString() .includes( 'โœ“ Logged in to github.com as' ); const AUTO_PROPAGATE_RESULTS_TO_GITHUB = GITHUB_CLI_AVAILABLE; diff --git a/bin/packages/check-build-type-declaration-files.js b/bin/packages/check-build-type-declaration-files.js index cd8bad2a70b530..fff0b51e32fc24 100644 --- a/bin/packages/check-build-type-declaration-files.js +++ b/bin/packages/check-build-type-declaration-files.js @@ -83,7 +83,7 @@ async function checkUnverifiedDeclarationFiles() { const packageDir = path.resolve( 'packages' ); const packageDirs = ( await fs.readdir( packageDir, { withFileTypes: true } ) - ) + ) .filter( ( dirent ) => dirent.isDirectory() ) .map( ( dirent ) => path.join( packageDir, dirent.name ) ); @@ -97,7 +97,7 @@ async function checkUnverifiedDeclarationFiles() { : null ) ) - ).filter( Boolean ); + ).filter( Boolean ); const tscResults = await Promise.allSettled( declarations.map( typecheckDeclarations ) diff --git a/bin/plugin/commands/packages.js b/bin/plugin/commands/packages.js index 4cf509764436c6..fb83060b6e9240 100644 --- a/bin/plugin/commands/packages.js +++ b/bin/plugin/commands/packages.js @@ -198,10 +198,9 @@ async function updatePackages( config ) { ); const changelogFilesPublicPackages = changelogFiles.filter( ( changelogPath ) => { - const pkg = require( path.join( - path.dirname( changelogPath ), - 'package.json' - ) ); + const pkg = require( + path.join( path.dirname( changelogPath ), 'package.json' ) + ); return pkg.private !== true; } ); diff --git a/bin/plugin/commands/performance.js b/bin/plugin/commands/performance.js index e153f482137e57..4be675a0a5d40d 100644 --- a/bin/plugin/commands/performance.js +++ b/bin/plugin/commands/performance.js @@ -1,6 +1,7 @@ /** * External dependencies */ +const os = require( 'os' ); const fs = require( 'fs' ); const path = require( 'path' ); const SimpleGit = require( 'simple-git' ); @@ -13,7 +14,6 @@ const { runShellScript, readJSONFile, askForConfirmation, - getRandomTemporaryPath, getFilesFromDir, } = require( '../lib/utils' ); const config = require( '../config' ); @@ -31,6 +31,19 @@ const RESULTS_FILE_SUFFIX = '.performance-results.json'; * @property {string=} wpVersion The WordPress version to be used as the base install for testing. */ +/** + * A logging helper for printing steps and their substeps. + * + * @param {number} indent Value to indent the log. + * @param {any} msg Message to log. + * @param {...any} args Rest of the arguments to pass to console.log. + */ +function logAtIndent( indent, msg, ...args ) { + const prefix = indent === 0 ? 'โ–ถ ' : '> '; + const newline = indent === 0 ? '\n' : ''; + return log( newline + ' '.repeat( indent ) + prefix + msg, ...args ); +} + /** * Sanitizes branch name to be used in a path or a filename. * @@ -64,14 +77,14 @@ function median( array ) { /** * Runs the performance tests on the current branch. * - * @param {string} testSuite Name of the tests set. - * @param {string} performanceTestDirectory Path to the performance tests' clone. - * @param {string} runKey Unique identifier for the test run. + * @param {string} testSuite Name of the tests set. + * @param {string} testRunnerDir Path to the performance tests' clone. + * @param {string} runKey Unique identifier for the test run. */ -async function runTestSuite( testSuite, performanceTestDirectory, runKey ) { +async function runTestSuite( testSuite, testRunnerDir, runKey ) { await runShellScript( `npm run test:performance -- ${ testSuite }`, - performanceTestDirectory, + testRunnerDir, { ...process.env, WP_ARTIFACTS_PATH: ARTIFACTS_PATH, @@ -95,23 +108,23 @@ async function runPerformanceTests( branches, options ) { branches = [ 'trunk' ]; } + log( formats.title( '\n๐Ÿ’ƒ Performance Tests ๐Ÿ•บ' ) ); log( - formats.title( '\n๐Ÿ’ƒ Performance Tests ๐Ÿ•บ\n' ), - '\nWelcome! This tool runs the performance tests on multiple branches and displays a comparison table.\n' + - 'In order to run the tests, the tool is going to load a WordPress environment on ports 8888 and 8889.\n' + - 'Make sure these ports are not used before continuing.\n' + '\nWelcome! This tool runs the performance tests on multiple branches and displays a comparison table.' ); if ( ! runningInCI ) { + log( + formats.warning( + '\nIn order to run the tests, the tool is going to load a WordPress environment on ports 8888 and 8889.' + + '\nMake sure these ports are not used before continuing.\n' + ) + ); + await askForConfirmation( 'Ready to go? ' ); } - /* - * 1- Preparing the tests directory. - */ - - log( '\n>> Preparing the tests directories' ); - log( ' >> Cloning the repository' ); + logAtIndent( 0, 'Setting up' ); /** * @type {string[]} git refs against which to run tests; @@ -121,121 +134,162 @@ async function runPerformanceTests( branches, options ) { throw new Error( `Need at least two git refs to run` ); } - const baseDirectory = getRandomTemporaryPath(); - fs.mkdirSync( baseDirectory, { recursive: true } ); + const baseDir = path.join( os.tmpdir(), 'wp-performance-tests' ); + + if ( fs.existsSync( baseDir ) ) { + logAtIndent( 1, 'Removing existing files' ); + fs.rmSync( baseDir, { recursive: true } ); + } + + logAtIndent( 1, 'Creating base directory:', formats.success( baseDir ) ); + fs.mkdirSync( baseDir ); + + logAtIndent( 1, 'Setting up repository' ); + const sourceDir = path.join( baseDir, 'source' ); + + logAtIndent( 2, 'Creating directory:', formats.success( sourceDir ) ); + fs.mkdirSync( sourceDir ); // @ts-ignore - const git = SimpleGit( baseDirectory ); - await git + const sourceGit = SimpleGit( sourceDir ); + logAtIndent( + 2, + 'Initializing:', + formats.success( config.gitRepositoryURL ) + ); + await sourceGit .raw( 'init' ) .raw( 'remote', 'add', 'origin', config.gitRepositoryURL ); - for ( const branch of branches ) { - await git.raw( 'fetch', '--depth=1', 'origin', branch ); + for ( const [ i, branch ] of branches.entries() ) { + logAtIndent( + 2, + `Fetching environment branch (${ i + 1 } of ${ branches.length }):`, + formats.success( branch ) + ); + await sourceGit.raw( 'fetch', '--depth=1', 'origin', branch ); } - await git.raw( 'checkout', branches[ 0 ] ); + const testRunnerBranch = options.testsBranch || branches[ 0 ]; + if ( options.testsBranch && ! branches.includes( options.testsBranch ) ) { + logAtIndent( + 2, + 'Fetching test runner branch:', + formats.success( options.testsBranch ) + ); + // @ts-ignore + await sourceGit.raw( + 'fetch', + '--depth=1', + 'origin', + options.testsBranch + ); + } else { + logAtIndent( + 2, + 'Using test runner branch:', + formats.success( testRunnerBranch ) + ); + } - const rootDirectory = getRandomTemporaryPath(); - const performanceTestDirectory = rootDirectory + '/tests'; - await runShellScript( 'mkdir -p ' + rootDirectory ); - await runShellScript( - 'cp -R ' + baseDirectory + ' ' + performanceTestDirectory - ); + logAtIndent( 1, 'Setting up test runner' ); - if ( !! options.testsBranch ) { - const branchName = formats.success( options.testsBranch ); - log( ` >> Fetching the test-runner branch: ${ branchName }` ); + const testRunnerDir = path.join( baseDir + '/tests' ); - // @ts-ignore - await SimpleGit( performanceTestDirectory ) - .raw( 'fetch', '--depth=1', 'origin', options.testsBranch ) - .raw( 'checkout', options.testsBranch ); - } + logAtIndent( 2, 'Copying source to:', formats.success( testRunnerDir ) ); + await runShellScript( `cp -R ${ sourceDir } ${ testRunnerDir }` ); - log( ' >> Installing dependencies and building packages' ); + logAtIndent( + 2, + 'Checking out branch:', + formats.success( testRunnerBranch ) + ); + // @ts-ignore + await SimpleGit( testRunnerDir ).raw( 'checkout', testRunnerBranch ); + + logAtIndent( 2, 'Installing dependencies and building' ); await runShellScript( - `bash -c "${ [ - 'source $HOME/.nvm/nvm.sh', - 'nvm install', - 'npm ci', - 'npx playwright install chromium --with-deps', - 'npm run build:packages', - ].join( ' && ' ) }"`, - performanceTestDirectory + `bash -c "source $HOME/.nvm/nvm.sh && nvm install && npm ci && npx playwright install chromium --with-deps && npm run build:packages"`, + testRunnerDir ); - log( ' >> Creating the environment folders' ); - await runShellScript( 'mkdir -p ' + rootDirectory + '/envs' ); - /* - * 2- Preparing the environment directories per branch. - */ + logAtIndent( 1, 'Setting up test environments' ); + + const envsDir = path.join( baseDir, 'environments' ); + logAtIndent( 2, 'Creating parent directory:', formats.success( envsDir ) ); + fs.mkdirSync( envsDir ); + + let wpZipUrl = null; + if ( options.wpVersion ) { + // In order to match the topology of ZIP files at wp.org, remap .0 + // patch versions to major versions: + // + // 5.7 -> 5.7 (unchanged) + // 5.7.0 -> 5.7 (changed) + // 5.7.2 -> 5.7.2 (unchanged) + const zipVersion = options.wpVersion.replace( /^(\d+\.\d+).0/, '$1' ); + wpZipUrl = `https://wordpress.org/wordpress-${ zipVersion }.zip`; + } - log( '\n>> Preparing an environment directory per branch' ); - const branchDirectories = {}; + const branchDirs = {}; for ( const branch of branches ) { - log( ` >> Branch: ${ branch }` ); - const sanitizedBranch = sanitizeBranchName( branch ); - const environmentDirectory = rootDirectory + '/envs/' + sanitizedBranch; + logAtIndent( 2, 'Branch:', formats.success( branch ) ); + const sanitizedBranchName = sanitizeBranchName( branch ); + const envDir = path.join( envsDir, sanitizedBranchName ); + + logAtIndent( 3, 'Creating directory:', formats.success( envDir ) ); + fs.mkdirSync( envDir ); // @ts-ignore - branchDirectories[ branch ] = environmentDirectory; - const buildPath = `${ environmentDirectory }/plugin`; - await runShellScript( 'mkdir ' + environmentDirectory ); - await runShellScript( `cp -R ${ baseDirectory } ${ buildPath }` ); + branchDirs[ branch ] = envDir; + const buildDir = path.join( envDir, 'plugin' ); - const fancyBranch = formats.success( branch ); + logAtIndent( 3, 'Copying source to:', formats.success( buildDir ) ); + await runShellScript( `cp -R ${ sourceDir } ${ buildDir }` ); - if ( branch === options.testsBranch ) { - log( - ` >> Re-using the testing branch for ${ fancyBranch }` - ); - await runShellScript( - `cp -R ${ performanceTestDirectory } ${ buildPath }` - ); - } else { - log( ` >> Fetching the ${ fancyBranch } branch` ); - // @ts-ignore - await SimpleGit( buildPath ).reset( 'hard' ).checkout( branch ); - } + logAtIndent( 3, 'Checking out:', formats.success( branch ) ); + // @ts-ignore + await SimpleGit( buildDir ).raw( 'checkout', branch ); - log( ` >> Building the ${ fancyBranch } branch` ); + logAtIndent( 3, 'Installing dependencies and building' ); await runShellScript( - 'bash -c "source $HOME/.nvm/nvm.sh && nvm install && npm ci && npm run prebuild:packages && node ./bin/packages/build.js && npx wp-scripts build"', - buildPath + `bash -c "source $HOME/.nvm/nvm.sh && nvm install && npm ci && npm run build"`, + buildDir + ); + + const wpEnvConfigPath = path.join( envDir, '.wp-env.json' ); + + logAtIndent( + 3, + 'Saving wp-env config to:', + formats.success( wpEnvConfigPath ) ); - // Create the config file for the current env. fs.writeFileSync( - path.join( environmentDirectory, '.wp-env.json' ), + wpEnvConfigPath, JSON.stringify( { config: { WP_DEBUG: false, SCRIPT_DEBUG: false, }, - core: 'WordPress/WordPress', - plugins: [ path.join( environmentDirectory, 'plugin' ) ], - themes: [ - path.join( - performanceTestDirectory, - 'test/emptytheme' - ), - ], + core: wpZipUrl || 'WordPress/WordPress', + plugins: [ buildDir ], + themes: [ path.join( testRunnerDir, 'test/emptytheme' ) ], env: { tests: { mappings: { 'wp-content/mu-plugins': path.join( - performanceTestDirectory, + testRunnerDir, 'packages/e2e-tests/mu-plugins' ), 'wp-content/plugins/gutenberg-test-plugins': path.join( - performanceTestDirectory, + testRunnerDir, 'packages/e2e-tests/plugins' ), 'wp-content/themes/gutenberg-test-themes': path.join( - performanceTestDirectory, + testRunnerDir, 'test/gutenberg-test-themes' ), 'wp-content/themes/gutenberg-test-themes/twentytwentyone': @@ -251,99 +305,61 @@ async function runPerformanceTests( branches, options ) { ), 'utf8' ); - - if ( options.wpVersion ) { - // In order to match the topology of ZIP files at wp.org, remap .0 - // patch versions to major versions: - // - // 5.7 -> 5.7 (unchanged) - // 5.7.0 -> 5.7 (changed) - // 5.7.2 -> 5.7.2 (unchanged) - const zipVersion = options.wpVersion.replace( - /^(\d+\.\d+).0/, - '$1' - ); - const zipUrl = `https://wordpress.org/wordpress-${ zipVersion }.zip`; - log( ` Using WordPress version ${ zipVersion }` ); - - // Patch the environment's .wp-env.json config to use the specified WP - // version: - // - // { - // "core": "https://wordpress.org/wordpress-$VERSION.zip", - // ... - // } - const confPath = `${ environmentDirectory }/.wp-env.json`; - const conf = { ...readJSONFile( confPath ), core: zipUrl }; - await fs.writeFileSync( - confPath, - JSON.stringify( conf, null, 2 ), - 'utf8' - ); - } } - // Printing the used folders. - log( - '\n>> Perf Tests Directory : ' + - formats.success( performanceTestDirectory ) - ); - for ( const branch of branches ) { - // @ts-ignore - const envPath = formats.success( branchDirectories[ branch ] ); - log( `>> Environment Directory (${ branch }) : ${ envPath }` ); - } - - /* - * 3- Running the tests. - */ - - log( '\n>> Running the tests' ); + logAtIndent( 0, 'Looking for test files' ); const testSuites = getFilesFromDir( - path.join( performanceTestDirectory, 'test/performance/specs' ) - ).map( ( file ) => path.basename( file, '.spec.js' ) ); + path.join( testRunnerDir, 'test/performance/specs' ) + ).map( ( file ) => { + logAtIndent( 1, 'Found:', formats.success( file ) ); + return path.basename( file, '.spec.js' ); + } ); + + logAtIndent( 0, 'Running tests' ); + + if ( wpZipUrl ) { + logAtIndent( + 1, + 'Using:', + formats.success( `WordPress v${ options.wpVersion }` ) + ); + } else { + logAtIndent( 1, 'Using:', formats.success( 'WordPress trunk' ) ); + } - const wpEnvPath = path.join( - performanceTestDirectory, - 'node_modules/.bin/wp-env' - ); + const wpEnvPath = path.join( testRunnerDir, 'node_modules/.bin/wp-env' ); for ( const testSuite of testSuites ) { for ( let i = 1; i <= TEST_ROUNDS; i++ ) { - const roundInfo = `round ${ i } of ${ TEST_ROUNDS }`; - log( ` >> Suite: ${ testSuite } (${ roundInfo })` ); + logAtIndent( + 1, + // prettier-ignore + `Suite: ${ formats.success( testSuite ) } (round ${ i } of ${ TEST_ROUNDS })` + ); + for ( const branch of branches ) { - const sanitizedBranch = sanitizeBranchName( branch ); - const runKey = `${ testSuite }_${ sanitizedBranch }_round-${ i }`; + logAtIndent( 2, 'Branch:', formats.success( branch ) ); + + const sanitizedBranchName = sanitizeBranchName( branch ); + const runKey = `${ testSuite }_${ sanitizedBranchName }_round-${ i }`; // @ts-ignore - const environmentDirectory = branchDirectories[ branch ]; - log( ` >> Branch: ${ branch }` ); - log( ' >> Starting the environment.' ); - await runShellScript( - `${ wpEnvPath } start`, - environmentDirectory - ); - log( ' >> Running the test.' ); - await runTestSuite( - testSuite, - performanceTestDirectory, - runKey - ); - log( ' >> Stopping the environment' ); - await runShellScript( - `${ wpEnvPath } stop`, - environmentDirectory - ); + const envDir = branchDirs[ branch ]; + + logAtIndent( 3, 'Starting environment' ); + await runShellScript( `${ wpEnvPath } start`, envDir ); + + logAtIndent( 3, 'Running tests' ); + await runTestSuite( testSuite, testRunnerDir, runKey ); + + logAtIndent( 3, 'Stopping environment' ); + await runShellScript( `${ wpEnvPath } stop`, envDir ); } } } - /* - * 4- Formatting and saving the results. - */ + logAtIndent( 0, 'Calculating results' ); - // Load curated results from each round. const resultFiles = getFilesFromDir( ARTIFACTS_PATH ).filter( ( file ) => file.endsWith( RESULTS_FILE_SUFFIX ) ); @@ -352,17 +368,21 @@ async function runPerformanceTests( branches, options ) { // Calculate medians from all rounds. for ( const testSuite of testSuites ) { - results[ testSuite ] = {}; + logAtIndent( 1, 'Test suite:', formats.success( testSuite ) ); + results[ testSuite ] = {}; for ( const branch of branches ) { - const sanitizedBranch = sanitizeBranchName( branch ); + const sanitizedBranchName = sanitizeBranchName( branch ); const resultsRounds = resultFiles .filter( ( file ) => file.includes( - `${ testSuite }_${ sanitizedBranch }_round-` + `${ testSuite }_${ sanitizedBranchName }_round-` ) ) - .map( ( file ) => readJSONFile( file ) ); + .map( ( file ) => { + logAtIndent( 2, 'Reading from:', formats.success( file ) ); + return readJSONFile( file ); + } ); const metrics = Object.keys( resultsRounds[ 0 ] ); results[ testSuite ][ branch ] = {}; @@ -378,25 +398,31 @@ async function runPerformanceTests( branches, options ) { } } } + const calculatedResultsPath = path.join( + ARTIFACTS_PATH, + testSuite + RESULTS_FILE_SUFFIX + ); - // Save calculated results to file. + logAtIndent( + 2, + 'Saving curated results to:', + formats.success( calculatedResultsPath ) + ); fs.writeFileSync( - path.join( ARTIFACTS_PATH, testSuite + RESULTS_FILE_SUFFIX ), + calculatedResultsPath, JSON.stringify( results[ testSuite ], null, 2 ) ); } - /* - * 5- Displaying the results. - */ - - log( '\n>> ๐ŸŽ‰ Results.\n' ); + logAtIndent( 0, 'Printing results' ); log( - '\nPlease note that client side metrics EXCLUDE the server response time.\n' + formats.warning( + '\nPlease note that client side metrics EXCLUDE the server response time.' + ) ); for ( const testSuite of testSuites ) { - log( `\n>> ${ testSuite }\n` ); + logAtIndent( 0, formats.success( testSuite ) ); // Invert the results so we can display them in a table. /** @type {Record>} */ diff --git a/changelog.txt b/changelog.txt index 6d47c988544586..447476fea96de4 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,598 @@ == Changelog == += 16.7.0-rc.2 = + +## Changelog + +### Features + +#### Typography +- Font Library: Font Collections frontend. ([54566](https://github.com/WordPress/gutenberg/pull/54566)) + + +### Enhancements + +#### Interactivity API +- Query block: Start prefetching on first click to next/previous. ([54781](https://github.com/WordPress/gutenberg/pull/54781)) + +#### Collaborative Editing +- Try bundling sync package. ([54738](https://github.com/WordPress/gutenberg/pull/54738)) + +#### Patterns +- Memoize `useSelect` for `usePatterns`. ([54588](https://github.com/WordPress/gutenberg/pull/54588)) + +#### Design Tools +- Improve background image control. ([54439](https://github.com/WordPress/gutenberg/pull/54439)) + +#### List View +- Try directing focus to the list view toggle button when closing the list view. ([54175](https://github.com/WordPress/gutenberg/pull/54175)) + +#### Typography +- Font Library: Load collection JSON data from a URL in the collection configuration. ([54067](https://github.com/WordPress/gutenberg/pull/54067)) + + +### Bug Fixes + +- Block Editor: Fix 'isBlockSubtreeDisabled' private selector. ([54618](https://github.com/WordPress/gutenberg/pull/54618)) +- Make sure sync code only runs when experiment is enabled. ([54710](https://github.com/WordPress/gutenberg/pull/54710)) + +#### Patterns +- Add My patterns back to post editor inserter categories. ([54767](https://github.com/WordPress/gutenberg/pull/54767)) +- De-emphasise pattern filters in inserter. ([54681](https://github.com/WordPress/gutenberg/pull/54681)) +- Fix All Patterns category default display. ([54721](https://github.com/WordPress/gutenberg/pull/54721)) +- Fix bug with new categories not showing. ([54768](https://github.com/WordPress/gutenberg/pull/54768)) +- Fix bug with pattern categories not saving sometimes. ([54676](https://github.com/WordPress/gutenberg/pull/54676)) +- Fix category type for back link. ([54753](https://github.com/WordPress/gutenberg/pull/54753)) +- Fix duplication of uncategorized patterns. ([54755](https://github.com/WordPress/gutenberg/pull/54755)) +- Inject the theme name into the block attributes. ([54595](https://github.com/WordPress/gutenberg/pull/54595)) +- Reinstate my patterns category in site editor. ([54726](https://github.com/WordPress/gutenberg/pull/54726)) +- Require a title in the creation modal. ([54717](https://github.com/WordPress/gutenberg/pull/54717)) +- Use slug as fallback for empty title. ([54731](https://github.com/WordPress/gutenberg/pull/54731)) + +#### Typography +- Font Face: Get name from "fontFamily" setting, not "name". ([54615](https://github.com/WordPress/gutenberg/pull/54615)) +- Font Library: Fix modal width on mobile viewport. ([54518](https://github.com/WordPress/gutenberg/pull/54518)) + +#### Block Editor +- Reset page after changing pattern filters or search value. ([54774](https://github.com/WordPress/gutenberg/pull/54774)) + +#### Interactivity API +- Query Loop: Select first anchor inside Post Template with "enhanced pagination" enabled. ([54730](https://github.com/WordPress/gutenberg/pull/54730)) + +#### Plugin +- Update cherry-pick script to correctly verify GitHub CLI setup. ([54720](https://github.com/WordPress/gutenberg/pull/54720)) + +#### Block API +- Block Hooks: Avoid processing empty content for loaded templates. ([54719](https://github.com/WordPress/gutenberg/pull/54719)) + +#### Site Editor +- CreateTemplatePartModal: Disable the 'Create' button while saving. ([54716](https://github.com/WordPress/gutenberg/pull/54716)) + +#### Design Tools +- Background Image control: Use consistent button, ensure descriptive text accounts for no image selected. ([54711](https://github.com/WordPress/gutenberg/pull/54711)) + +#### Block Library +- Replace the `gutenberg_` prefix with `wp_` in image block. ([54678](https://github.com/WordPress/gutenberg/pull/54678)) + +#### Components +- DateTimePicker: Fix onChange callback check so that it also works inside iframes. ([54669](https://github.com/WordPress/gutenberg/pull/54669)) + +#### Fonts API +- Font Library: Fix space above theme fonts in font library modal. ([54598](https://github.com/WordPress/gutenberg/pull/54598)) + + +### Accessibility + +#### Components +- Allow Modal to place focus on first element within contents via new API. ([54590](https://github.com/WordPress/gutenberg/pull/54590)) +- Improve the placeholder instructions accessibility. ([45801](https://github.com/WordPress/gutenberg/pull/45801)) + + +### Documentation + +- Add missing global declaration in DocBlock of interactivity files. ([54683](https://github.com/WordPress/gutenberg/pull/54683)) + + +### Code Quality + +#### Site Editor +- Prune store constants. ([54585](https://github.com/WordPress/gutenberg/pull/54585)) +- Use constants rather than hard coded template strings. ([54586](https://github.com/WordPress/gutenberg/pull/54586)) + +#### Patterns +- Fix sidebar nav screen fallback category. ([54754](https://github.com/WordPress/gutenberg/pull/54754)) + +#### Typography +- Font Library: Refactor logic to disable font library in the frontend. ([54748](https://github.com/WordPress/gutenberg/pull/54748)) + +#### Plugin +- Ensure that Block Hooks work correctly after landing in WP core. ([54651](https://github.com/WordPress/gutenberg/pull/54651)) +- Update uuid package to 9.0.1. ([54725](https://github.com/WordPress/gutenberg/pull/54725)) + +### Tools + +#### Testing +- Font Library: Use resolvable domain in test. ([54763](https://github.com/WordPress/gutenberg/pull/54763)) + + +## Contributors + +The following contributors merged PRs in this release: + +@aaronrobertshaw @afercia @andrewserong @ciampo @DAreRodz @getdave @glendaviesnz @gziolo @hellofromtonya @kevin940726 @luisherranz @madhusudhand @Mamaduka @matiasbenedetto @mikachan @ramonjd @richtabor @SaxonF @scruffian @t-hamano @tellthemachines + + += 16.7.0-rc.1 = + +## Changelog + +### Features + +#### Typography +- Font Library: Add mime type validation for font uploads. ([53986](https://github.com/WordPress/gutenberg/pull/53986)) +- Font Library: Font Collection backend. ([54098](https://github.com/WordPress/gutenberg/pull/54098)) +- Font Library: Frontend [Stage 1]. ([53884](https://github.com/WordPress/gutenberg/pull/53884)) + +#### Patterns +- Allow import/export patterns as JSON files. ([54337](https://github.com/WordPress/gutenberg/pull/54337)) + +#### Block Editor +- Adds 'nofollow' setting to inline links (rich text only). ([53945](https://github.com/WordPress/gutenberg/pull/53945)) +- Rename Group blocks in the Editor via Modal. ([53735](https://github.com/WordPress/gutenberg/pull/53735)) + + +### Enhancements + +#### Core Data +- Add edits data to the useEntityRecord. ([54167](https://github.com/WordPress/gutenberg/pull/54167)) + +#### Components +- Add non-listbox functionality back to `CircularOptionPicker`. ([54290](https://github.com/WordPress/gutenberg/pull/54290)) +- Added missing "middle" allowed tooltip position. ([52147](https://github.com/WordPress/gutenberg/pull/52147)) +- BlockSettingsMenu: Ensure only one block settings menu is open at a time. ([54083](https://github.com/WordPress/gutenberg/pull/54083)) +- Bundle the block copy handler within the BlockCanvas component. ([54207](https://github.com/WordPress/gutenberg/pull/54207)) +- Bundle the block selection clearer hook into the BlockCanvas component. ([54209](https://github.com/WordPress/gutenberg/pull/54209)) +- Ensure that 'Duotone Filter' color pickers have relevant labels. ([54468](https://github.com/WordPress/gutenberg/pull/54468)) +- Export ProgressBar to allow it to be used. ([54404](https://github.com/WordPress/gutenberg/pull/54404)) +- FormTokenField - add prop to allow saving of tokens onBlur. ([53976](https://github.com/WordPress/gutenberg/pull/53976)) +- Refactoring `BorderControl`'s unit tests. ([54155](https://github.com/WordPress/gutenberg/pull/54155)) +- Remove unnecessary padding-right on the dismissible notice. ([52240](https://github.com/WordPress/gutenberg/pull/52240)) +- Support controlling open/closed state for Dropdown and DropdownMenu. ([54257](https://github.com/WordPress/gutenberg/pull/54257)) +- ToggleGroupControl: Rewrite backdrop animation with framer motion shared layout animations. ([50278](https://github.com/WordPress/gutenberg/pull/50278)) +- ToolTip: Refactor using ariakit. ([48440](https://github.com/WordPress/gutenberg/pull/48440)) +- Tooltip: Add `placement` prop to replace deprecated `position`. ([54264](https://github.com/WordPress/gutenberg/pull/54264)) +- Tooltip: Add new `hideOnClick` prop. ([54406](https://github.com/WordPress/gutenberg/pull/54406)) +- Tweak border control button to proper metrics and simpler action. ([53998](https://github.com/WordPress/gutenberg/pull/53998)) +- Update FormTokenField styling for consistency and visibility. ([54402](https://github.com/WordPress/gutenberg/pull/54402)) +- Update spacing sizes control metrics and icons. ([54470](https://github.com/WordPress/gutenberg/pull/54470)) +- Update/form token field onblur. ([54445](https://github.com/WordPress/gutenberg/pull/54445)) +- `Popover`: Update `positionToPlacement` types. ([54101](https://github.com/WordPress/gutenberg/pull/54101)) +- `SearchControl`: Allow for 32px compact size, introduce option to change default size to 40px. ([54548](https://github.com/WordPress/gutenberg/pull/54548)) + +#### Block Library +- #39457: Image block keep image size on replacing image. ([49982](https://github.com/WordPress/gutenberg/pull/49982)) +- Add __next40pxDefaultSize to featured image opacity control. ([54389](https://github.com/WordPress/gutenberg/pull/54389)) +- Add aspect ratio to image placeholder. ([54216](https://github.com/WordPress/gutenberg/pull/54216)) +- Allow using a button element for button blocks. ([54206](https://github.com/WordPress/gutenberg/pull/54206)) +- Buttons Block: Show inserter if button have variations (#53498). ([53783](https://github.com/WordPress/gutenberg/pull/53783)) +- Change dialogdescription for renaming group block. ([54358](https://github.com/WordPress/gutenberg/pull/54358)) +- Footnotes: Add missing placeholder instructions text. ([54056](https://github.com/WordPress/gutenberg/pull/54056)) +- Heading block: Add support for writingMode. ([54351](https://github.com/WordPress/gutenberg/pull/54351)) +- Improved description for the post-terms core block. ([47715](https://github.com/WordPress/gutenberg/pull/47715)) +- Make matrix position behave like valign. ([54050](https://github.com/WordPress/gutenberg/pull/54050)) +- Navigation block: Add `core/buttons` to the allowed blocks. ([53966](https://github.com/WordPress/gutenberg/pull/53966)) +- Remove unused prop from GroupPlaceHolder component. ([51493](https://github.com/WordPress/gutenberg/pull/51493)) +- Template parts: Use the template actions component for template parts patterns. ([54173](https://github.com/WordPress/gutenberg/pull/54173)) +- Text orientation: Rotate vertical text when the text is aligned (Upside down text). ([53175](https://github.com/WordPress/gutenberg/pull/53175)) +- Update parent labels in page attributes panel and page list block. ([54403](https://github.com/WordPress/gutenberg/pull/54403)) +- Use __next40pxDefaultSize on more UI. ([54400](https://github.com/WordPress/gutenberg/pull/54400)) + +#### Interactivity API +- Add `timeout` option to `navigate()`. ([54474](https://github.com/WordPress/gutenberg/pull/54474)) +- Add manual Server Side Rendering (SSR) to the Interactivity API blocks. ([54343](https://github.com/WordPress/gutenberg/pull/54343)) +- Ensure that the view scripts of core blocks have the `wp-interactivity` dependency. ([54594](https://github.com/WordPress/gutenberg/pull/54594)) +- Image block: Revise lightbox UI to remove 'behaviors'. ([53851](https://github.com/WordPress/gutenberg/pull/53851)) +- Image block: UI updates for the image lightbox (redo). ([54509](https://github.com/WordPress/gutenberg/pull/54509)) +- Override unfinished `navigate` calls. ([54201](https://github.com/WordPress/gutenberg/pull/54201)) +- Query Loop: Add design enhancements for the "enhanced pagination" setting. ([54455](https://github.com/WordPress/gutenberg/pull/54455)) +- Query Loop: Allow "enhanced pagination" only with core blocks. ([54347](https://github.com/WordPress/gutenberg/pull/54347)) + +#### Patterns +- Add categories to user patterns, and allow filtering by these in site and post editor. ([53835](https://github.com/WordPress/gutenberg/pull/53835)) +- Add editing of pattern categories to site editor. ([54640](https://github.com/WordPress/gutenberg/pull/54640)) +- Add user categories to site editor sidebar navigation screen. ([53837](https://github.com/WordPress/gutenberg/pull/53837)) +- Add user pattern categories to post editor inserter patterns tab. ([53933](https://github.com/WordPress/gutenberg/pull/53933)) +- Apply white background to the preview as a fallback. ([54534](https://github.com/WordPress/gutenberg/pull/54534)) +- Merge unsynced into inserter patterns tab and add paging and filtering. ([54007](https://github.com/WordPress/gutenberg/pull/54007)) +- Update empty template part label. ([53842](https://github.com/WordPress/gutenberg/pull/53842)) + +#### Design Tools +- Add back tooltip to styles UI. ([54574](https://github.com/WordPress/gutenberg/pull/54574)) +- Add block gap to Post Content block. ([54282](https://github.com/WordPress/gutenberg/pull/54282)) +- Add block instance elements support for buttons and headings. ([53667](https://github.com/WordPress/gutenberg/pull/53667)) +- Background Image block support: Add reset menu item. ([54341](https://github.com/WordPress/gutenberg/pull/54341)) +- Block Supports: Add background image support to Group block. ([53934](https://github.com/WordPress/gutenberg/pull/53934)) +- Columns: Adopt button and heading element colors. ([54104](https://github.com/WordPress/gutenberg/pull/54104)) +- Update block styles UI. ([54446](https://github.com/WordPress/gutenberg/pull/54446)) + +#### Site Editor +- Copy: End the Templates page description in the Site Editor with a period. ([54221](https://github.com/WordPress/gutenberg/pull/54221)) +- Edit Site: Update progress bar to determinate. ([53399](https://github.com/WordPress/gutenberg/pull/53399)) +- Follow up visual tweaks to block-specific commands. ([54427](https://github.com/WordPress/gutenberg/pull/54427)) +- Site editor sidebar: Abstracting footer so it can be used across details screens. ([54082](https://github.com/WordPress/gutenberg/pull/54082)) +- [Page Inspector]: Add ability to switch templates. ([51477](https://github.com/WordPress/gutenberg/pull/51477)) + +#### Global Styles +- Rename `settings` & `userSettings` props to `value` & `inheritedValue` respectively in ImageSettingsPanel. ([54593](https://github.com/WordPress/gutenberg/pull/54593)) +- Update Block specific CSS label to include additional instructions. ([49626](https://github.com/WordPress/gutenberg/pull/49626)) + +#### Block Editor +- Use gray color on link control advanced toggle. ([54545](https://github.com/WordPress/gutenberg/pull/54545)) +- Verse: Exit on triple Enter. ([53332](https://github.com/WordPress/gutenberg/pull/53332)) +- Block editor: hooks: Fix rules of hooks violations (2). ([48943](https://github.com/WordPress/gutenberg/pull/48943)) + +#### Typography +- Font Face: Backport from Core changeset 56500. ([54218](https://github.com/WordPress/gutenberg/pull/54218)) +- Font Library: Changing the upload directory to wp-content/fonts. ([54122](https://github.com/WordPress/gutenberg/pull/54122)) + +#### Themes +- Theme Previews: Make the back button customizable. ([54242](https://github.com/WordPress/gutenberg/pull/54242)) + +#### Plugin +- Remove 'Footnotes' and 'Comments' from the non-dynamic block registration list. ([54154](https://github.com/WordPress/gutenberg/pull/54154)) + +#### Media +- Correct function name handleFileChange is replaced by wrong function name. ([52250](https://github.com/WordPress/gutenberg/pull/52250)) + +#### List View +- Allow Escape key to deselect blocks if blocks are selected. ([48708](https://github.com/WordPress/gutenberg/pull/48708)) + +#### Block API +- Deprecated `get_file_path_from_theme` method. ([45831](https://github.com/WordPress/gutenberg/pull/45831)) + +#### Keyboard Shortcuts +- Make the shortcuts provider optional. ([54080](https://github.com/WordPress/gutenberg/pull/54080)) + +#### Blob +- refactor(blob): Type URL parameter as optional. ([49201](https://github.com/WordPress/gutenberg/pull/49201)) + + +### New APIs + +#### Components +- Revert "Export ProgressBar to allow it to be used". ([54428](https://github.com/WordPress/gutenberg/pull/54428)) + +#### Block API +- Stabilize Block Hooks feature. ([54293](https://github.com/WordPress/gutenberg/pull/54293)) + +#### Data Layer +- Data: Introduce `countSelectorsByStatus` redux metadata selector. ([53767](https://github.com/WordPress/gutenberg/pull/53767)) + +#### Framework +- Add useStateWithHistory hook and use to show a block editor with undo/redo. ([54377](https://github.com/WordPress/gutenberg/pull/54377)) +- BlockEditor: Add BlockCanvas component = Iframe + BlockList + WritingFlow. ([54149](https://github.com/WordPress/gutenberg/pull/54149)) +- Extract undo/redo as a separate package. ([54292](https://github.com/WordPress/gutenberg/pull/54292)) + +### Bug Fixes + +#### Components +- Add children back to toolbar item render for rendered components. ([53314](https://github.com/WordPress/gutenberg/pull/53314)) +- Add missing useState import in Border Control documentation. ([49476](https://github.com/WordPress/gutenberg/pull/49476)) +- Adjust input-style__focus mixin to proper focus size. ([54398](https://github.com/WordPress/gutenberg/pull/54398)) +- DropdownMenu v2: Fix submenu chevron direction in RTL languages. ([54036](https://github.com/WordPress/gutenberg/pull/54036)) +- Fix incorrect focus style size on InputControl. ([54394](https://github.com/WordPress/gutenberg/pull/54394)) +- Make `CircularOptionPicker` focus styles resilient to button size changes. ([54196](https://github.com/WordPress/gutenberg/pull/54196)) +- PaletteEdit: Fix padding in RTL mode. ([54034](https://github.com/WordPress/gutenberg/pull/54034)) +- Popover: Set is-positioned class only after animation has finished. ([54178](https://github.com/WordPress/gutenberg/pull/54178)) +- Storybook: Restore previous URL for the introduction documentation page. ([54247](https://github.com/WordPress/gutenberg/pull/54247)) +- Storybook: Update doc param values for ConfirmDialog. ([54130](https://github.com/WordPress/gutenberg/pull/54130)) +- Update borderFocus to ADMIN.theme. ([54425](https://github.com/WordPress/gutenberg/pull/54425)) +- Use standard focus style on BorderControl. ([54429](https://github.com/WordPress/gutenberg/pull/54429)) + +#### Post Editor +- Adds animation state for DFM off to post editor header. ([54244](https://github.com/WordPress/gutenberg/pull/54244)) +- Block Editor: Memoize the createPageEntity callback. ([54580](https://github.com/WordPress/gutenberg/pull/54580)) +- Edit Post: Avoid fetching the edited template for non-viewable posts. ([54158](https://github.com/WordPress/gutenberg/pull/54158)) +- Editor: Catch errors when creating terms. ([53369](https://github.com/WordPress/gutenberg/pull/53369)) +- Fix layout when post content is root block. ([54485](https://github.com/WordPress/gutenberg/pull/54485)) +- Make order of pinned items consistent. ([53908](https://github.com/WordPress/gutenberg/pull/53908)) +- Prevent the list view shortcut from typing unexpected characters. ([54078](https://github.com/WordPress/gutenberg/pull/54078)) +- Top Toolbar: Prevent the focus outline of the button from being cut off. ([54172](https://github.com/WordPress/gutenberg/pull/54172)) +- Try using fallback layout instead of default in post editor. ([54371](https://github.com/WordPress/gutenberg/pull/54371)) +- [Edit Post]: Toggle Distraction free mode mode based on compatibility. ([54073](https://github.com/WordPress/gutenberg/pull/54073)) + +#### Block Library +- Block Moving Mode: Prevent the block from being moved into itself. ([54137](https://github.com/WordPress/gutenberg/pull/54137)) +- Fix navigation block submenu focus when closing menu with the ESC key. ([54299](https://github.com/WordPress/gutenberg/pull/54299)) +- List Block: Fix numbering style to be applied correctly. ([53301](https://github.com/WordPress/gutenberg/pull/53301)) +- Navigation Link: Restore tooltip. ([54263](https://github.com/WordPress/gutenberg/pull/54263)) +- Post navigation link: Fix the writing mode setting on the front. ([54053](https://github.com/WordPress/gutenberg/pull/54053)) +- PreviewOptions: Fix critical error when children not passed. ([54284](https://github.com/WordPress/gutenberg/pull/54284)) +- Remove `role` attribute when set to `null` in `data-wp-bind`. ([54608](https://github.com/WordPress/gutenberg/pull/54608)) +- [Commands]: Add group/ungroup commands only when eligible. ([53988](https://github.com/WordPress/gutenberg/pull/53988)) + +#### Patterns +- Command Palette: Fix duplicate Patterns command. ([54133](https://github.com/WordPress/gutenberg/pull/54133)) +- Don't output root padding when editing patterns. ([54373](https://github.com/WordPress/gutenberg/pull/54373)) +- Fix user pattern categories in site editor inserter. ([54641](https://github.com/WordPress/gutenberg/pull/54641)) +- Remove pattern category as a variation for post terms block. ([54532](https://github.com/WordPress/gutenberg/pull/54532)) +- StartPageOptions: Improve conditions to show modal only on a brand new page. ([54245](https://github.com/WordPress/gutenberg/pull/54245)) + +#### Block Editor +- Add keyboardReturn submit button back to LinkControl. ([52620](https://github.com/WordPress/gutenberg/pull/52620)) +- Formats: Memoize link value passed to the LinkControl. ([54603](https://github.com/WordPress/gutenberg/pull/54603)) +- List: Merge consecutive lists. ([52995](https://github.com/WordPress/gutenberg/pull/52995)) +- Rich text: Fix useAnchor (remove nextElementSibling). ([54013](https://github.com/WordPress/gutenberg/pull/54013)) +- Iframe: Adjust keydown event bubbling. ([54565](https://github.com/WordPress/gutenberg/pull/54565)) + +#### Site Editor +- Bump the z-index of the rename modal. ([54277](https://github.com/WordPress/gutenberg/pull/54277)) +- Default template lookup should use slug, not the full permalink, in the site editor. ([54599](https://github.com/WordPress/gutenberg/pull/54599)) +- Fix "Blog title" input border radius in Index / Home details panel. ([54192](https://github.com/WordPress/gutenberg/pull/54192)) +- Hide ghost top toolbar. ([54555](https://github.com/WordPress/gutenberg/pull/54555)) + +#### Plugin +- Ensure font-face styles are printed in iframe editors. ([54313](https://github.com/WordPress/gutenberg/pull/54313)) +- Font Face & Font Library: Load PHP files only if the main class does not exist. ([54103](https://github.com/WordPress/gutenberg/pull/54103)) +- Gutenberg Plugin: Add hook to allow `writing-mode` as a safe CSS property. ([54581](https://github.com/WordPress/gutenberg/pull/54581)) +- Update readme.txt "tested up to 6.3". ([54072](https://github.com/WordPress/gutenberg/pull/54072)) + +#### Typography +- Font Library: Ensure merged fontFace data is enconded as an array instead of an object. ([54435](https://github.com/WordPress/gutenberg/pull/54435)) +- Font Library: Fix duplicate variants with different file types. ([54490](https://github.com/WordPress/gutenberg/pull/54490)) +- Font Library: Setting wp_font_family custom post type as _builtin and not plublic. ([54559](https://github.com/WordPress/gutenberg/pull/54559)) + +#### Widgets Editor +- Edit Widgets: Fix broken layout. ([54372](https://github.com/WordPress/gutenberg/pull/54372)) +- Edit Widgets: Fix invisible action area when the top toolbar is enabled. ([54329](https://github.com/WordPress/gutenberg/pull/54329)) +- Fix top toolbar for the customizer widgets sidebar control. ([54255](https://github.com/WordPress/gutenberg/pull/54255)) + +#### Global Styles +- Font Library: Fix notification error for actions related to custom fonts. ([54535](https://github.com/WordPress/gutenberg/pull/54535)) +- Prevent layout changes from saving the whole inherited settings object. ([54500](https://github.com/WordPress/gutenberg/pull/54500)) + +#### Block API +- Blocks: Fix incorrect placement for hooked blocks in the parent container. ([54349](https://github.com/WordPress/gutenberg/pull/54349)) +- Pass correct content argument to enter transforms. ([54108](https://github.com/WordPress/gutenberg/pull/54108)) + +#### Rich Text +- Revert: Rich text: Copy tag name on internal paste. ([54301](https://github.com/WordPress/gutenberg/pull/54301)) + +#### Interactivity API +- Image: Fix block serialization test case to cover deprecation of `behaviors`. ([54570](https://github.com/WordPress/gutenberg/pull/54570)) + +#### Icons +- Fix React forwardRef warnings for `TooltipAnchor`s. ([54492](https://github.com/WordPress/gutenberg/pull/54492)) + +#### History +- Fix extra undo/redo step when removing or replacing all blocks. ([54457](https://github.com/WordPress/gutenberg/pull/54457)) + +#### Synced Patterns +- Patterns: Apply layout and alignment to synced patterns in the editor. ([54416](https://github.com/WordPress/gutenberg/pull/54416)) + +#### npm Packages +- Workflow: Fix the issue with npm publishing for WP major version. ([54088](https://github.com/WordPress/gutenberg/pull/54088)) + +#### Media +- useMediaQuery: Avoid crashing on Safari < 14. ([54023](https://github.com/WordPress/gutenberg/pull/54023)) + +#### Nested / Inner Blocks +- Fix: InnerBlocks allowed blocks change with different sizes. ([53943](https://github.com/WordPress/gutenberg/pull/53943)) + +#### Layout +- Post Content: Ensure layout classnames are applied in readonly preview. ([53864](https://github.com/WordPress/gutenberg/pull/53864)) + +#### Document Settings +- Set the timezone correctly. ([48083](https://github.com/WordPress/gutenberg/pull/48083)) + +#### React i18n +- Fix: Invalid import in react-i18n documentation. ([54308](https://github.com/WordPress/gutenberg/pull/54308)) + + +### Accessibility + +#### Block Library +- Comments form: Accessibility fixes for back-end. ([54393](https://github.com/WordPress/gutenberg/pull/54393)) +- Navigation: Add ariaLabel block support. ([54418](https://github.com/WordPress/gutenberg/pull/54418)) +- Table block: Fix semantic structure for screen readers on back-end. ([54324](https://github.com/WordPress/gutenberg/pull/54324)) + +#### Components +- Improve Notice component accessibility. ([54498](https://github.com/WordPress/gutenberg/pull/54498)) +- Making Circular Option Picker a `listbox`. ([52255](https://github.com/WordPress/gutenberg/pull/52255)) + +#### Site Editor +- Clarify the "Entity" message of the snackbar. ([54333](https://github.com/WordPress/gutenberg/pull/54333)) +- Use solid accent color selection in command palette. ([54318](https://github.com/WordPress/gutenberg/pull/54318)) + +#### Block Editor +- Update nofollow control label. ([54184](https://github.com/WordPress/gutenberg/pull/54184)) + + +### Performance + +- Use median instead of average to stabilize First Block metric. ([54157](https://github.com/WordPress/gutenberg/pull/54157)) +- improvement: Reduce the use of the `_wp_array_get` function. ([51116](https://github.com/WordPress/gutenberg/pull/51116)) + +#### Block Library +- Footnotes: Add block-level caching when parsing content for footnotes. ([52577](https://github.com/WordPress/gutenberg/pull/52577)) +- Table of Contents: Use a custom store subscription for observing headings. ([54094](https://github.com/WordPress/gutenberg/pull/54094)) +- getClientIdsOfDescendants: Support single 'clientId' as a argument. ([54421](https://github.com/WordPress/gutenberg/pull/54421)) + +#### Site Editor +- Edit site: Prevent enqueuing entire stylesheet in iframe. ([54254](https://github.com/WordPress/gutenberg/pull/54254)) +- Fix first block locator's page reference. ([54188](https://github.com/WordPress/gutenberg/pull/54188)) + +#### Patterns +- Move mapping of values from core-data selector into consumers. ([54576](https://github.com/WordPress/gutenberg/pull/54576)) + +#### Block API +- Unnecessary JSON decoding in block parser. ([54424](https://github.com/WordPress/gutenberg/pull/54424)) + +#### Components +- Tooltip: Render tooltip markup in the DOM only when open. ([54312](https://github.com/WordPress/gutenberg/pull/54312)) + +#### Post Editor +- Editor: Memoize 'getNestedEditedPostProperty' selector helper. ([54160](https://github.com/WordPress/gutenberg/pull/54160)) + +#### Developer Experience +- Tests: Improve the environment setup. ([54309](https://github.com/WordPress/gutenberg/pull/54309)) + +### Experiments + +#### Interactivity API +- Remove `wp_store` from query block. ([54359](https://github.com/WordPress/gutenberg/pull/54359)) + + +### Documentation + +- Add a documentation page to explain how to implement undo/redo in a third-party editor. ([54546](https://github.com/WordPress/gutenberg/pull/54546)) +- Add the Commands Data page to Handbook. ([53634](https://github.com/WordPress/gutenberg/pull/53634)) +- Bootstrap a documentation website tailored towards the usage of Gutenberg outside WordPress. ([54375](https://github.com/WordPress/gutenberg/pull/54375)) +- Button: Undocument the `focus` prop. ([54397](https://github.com/WordPress/gutenberg/pull/54397)) +- Docs: Add missing callout class. ([54558](https://github.com/WordPress/gutenberg/pull/54558)) +- Docs: Add note about enqueueing assets in the iframe and trim whitespace. ([54125](https://github.com/WordPress/gutenberg/pull/54125)) +- Docs: Consolidated design Reference with the main Design Contributions doc. ([51065](https://github.com/WordPress/gutenberg/pull/51065)) +- Docs: Move Glossary page to Getting Started. ([54120](https://github.com/WordPress/gutenberg/pull/54120)) +- Docs: Move the FAQ page to Getting Started. ([54117](https://github.com/WordPress/gutenberg/pull/54117)) +- Docs: Overhaul the Development Environment section of the Block Editor Handbook. ([54395](https://github.com/WordPress/gutenberg/pull/54395)) +- Docs: Remove Outreach doc from Getting Started section. ([54314](https://github.com/WordPress/gutenberg/pull/54314)) +- Docs: Remove unneeded block theme docs. ([51071](https://github.com/WordPress/gutenberg/pull/51071)) +- Fix bullet hierarchy. ([47178](https://github.com/WordPress/gutenberg/pull/47178)) +- Fix createI18n package import location. ([51328](https://github.com/WordPress/gutenberg/pull/51328)) +- Fix incorrect image src in Design Contributions doc. ([54302](https://github.com/WordPress/gutenberg/pull/54302)) +- Fix: Broken links on ToolbarGroup documentation. ([54229](https://github.com/WordPress/gutenberg/pull/54229)) +- Fix: Remove unrequired code from BorderControl documentation. ([54348](https://github.com/WordPress/gutenberg/pull/54348)) +- Fix: Wrapped `ref` in quotes in theme.json documentation. ([54591](https://github.com/WordPress/gutenberg/pull/54591)) +- Incorrect file extension?. ([54134](https://github.com/WordPress/gutenberg/pull/54134)) +- Theme JSON schema: Fix "not allowed error" in settings property. ([54521](https://github.com/WordPress/gutenberg/pull/54521)) +- Try: Allow `multiple` attribute to be a string in upload components. ([53350](https://github.com/WordPress/gutenberg/pull/53350)) +- Update Commands documentation with examples and more context. ([54441](https://github.com/WordPress/gutenberg/pull/54441)) +- Update the components changelog to mark the popover slot removal as a breaking change. ([54022](https://github.com/WordPress/gutenberg/pull/54022)) +- Update versions in WP for 6.3.1. ([54069](https://github.com/WordPress/gutenberg/pull/54069)) +- Updated Related Components Links. ([49176](https://github.com/WordPress/gutenberg/pull/49176)) +- Updates Edit and Save code examples to have matching open/closing tags. ([53915](https://github.com/WordPress/gutenberg/pull/53915)) +- [Docs: Getting Started / Block Development Environment] Updates on the text to improve clarity and preciseness. ([54563](https://github.com/WordPress/gutenberg/pull/54563)) +- documentation - Contribution Triage: Formatted text and changed some titles and structure. ([54258](https://github.com/WordPress/gutenberg/pull/54258)) +- documentation [Block Editor Handbook / Getting Started / Block Development Environment]: Fix links. ([54571](https://github.com/WordPress/gutenberg/pull/54571)) + + +### Code Quality + +- Adds removal notice to view.js.mustache. ([54105](https://github.com/WordPress/gutenberg/pull/54105)) +- Block editor: Remove `__unstableElementContext` and filter `EditorStyles` instead. ([52888](https://github.com/WordPress/gutenberg/pull/52888)) +- Improving error messages and codes in jest-console, matcher.js. ([53743](https://github.com/WordPress/gutenberg/pull/53743)) +- Indicate nested paths on __experimentalSaveSpecifiedEntityEdits. ([54161](https://github.com/WordPress/gutenberg/pull/54161)) +- JS unit tests: Update popover matcher. ([54168](https://github.com/WordPress/gutenberg/pull/54168)) +- Style engine: Sync doc changes from core. ([54650](https://github.com/WordPress/gutenberg/pull/54650)) + +#### Components +- Composite: Refactor to TypeScript. ([54028](https://github.com/WordPress/gutenberg/pull/54028)) +- FocusableIframe: Refactor to TypeScript. ([53979](https://github.com/WordPress/gutenberg/pull/53979)) +- IsolatedEventContainer to Typescript (just test file). ([54316](https://github.com/WordPress/gutenberg/pull/54316)) +- Popover: Remove custom frame scroll/resize listeners. ([54286](https://github.com/WordPress/gutenberg/pull/54286)) +- Revert FormTokenField - add prop to allow saving of tokens onBlur. ([54444](https://github.com/WordPress/gutenberg/pull/54444)) +- Toolbar/ToolbarDropdownMenu Typescript Conversion. ([54321](https://github.com/WordPress/gutenberg/pull/54321)) +- ToolbarGroup - Typescript. ([54317](https://github.com/WordPress/gutenberg/pull/54317)) +- with-focus-outside: Convert to TypeScript. ([53980](https://github.com/WordPress/gutenberg/pull/53980)) + +#### Patterns +- Revert usePatternsState to return an array instead of object. ([54582](https://github.com/WordPress/gutenberg/pull/54582)) +- Add missing dependency of `@wordpress/patterns` on `@babel/runtime`. ([54118](https://github.com/WordPress/gutenberg/pull/54118)) +- Move category map creation out of useSelect. ([54584](https://github.com/WordPress/gutenberg/pull/54584)) +- Remove experimental prefixes from patterns package. ([54338](https://github.com/WordPress/gutenberg/pull/54338)) +- Site editor: Consolidate constants. ([54484](https://github.com/WordPress/gutenberg/pull/54484)) + +#### Post Editor +- Annotations: Run end-to-end tests with iframe. ([54191](https://github.com/WordPress/gutenberg/pull/54191)) +- EditPostPreferencesModal: Refactor to remove snapshots for index.js. ([54141](https://github.com/WordPress/gutenberg/pull/54141)) +- Extract WordPress specific styles from the BlockTools component. ([54356](https://github.com/WordPress/gutenberg/pull/54356)) +- PageAttributesParent: A minor fixes for useSelect and useMemo hook usages. ([54433](https://github.com/WordPress/gutenberg/pull/54433)) +- PostSyncStatus: Derive sync status inside the selector. ([54159](https://github.com/WordPress/gutenberg/pull/54159)) + +#### Block Library +- Heading: Remove unused 'aria-label'. ([54223](https://github.com/WordPress/gutenberg/pull/54223)) +- Image Editor: Fix ESLint warnings and remove unnecessary dependencies. ([53506](https://github.com/WordPress/gutenberg/pull/53506)) +- Pattern Category: Set 'publicly_queryable' to false. ([54567](https://github.com/WordPress/gutenberg/pull/54567)) +- Post Terms: Fix a 'useSelect' warning in the 'usePostTerms' hook. ([54068](https://github.com/WordPress/gutenberg/pull/54068)) + +#### Interactivity API +- Prepare image lightbox for private version of the Interactivity API in 6 4. ([54547](https://github.com/WordPress/gutenberg/pull/54547)) +- Remove `gutenberg_should_block_use_interactivity_api ` and the old implementation of interactive blocks. ([54297](https://github.com/WordPress/gutenberg/pull/54297)) +- Search block: Switch interactivity to the Interactivity API. ([53343](https://github.com/WordPress/gutenberg/pull/53343)) + +#### Site Editor +- Remove Tooltip workarounds added in the site and block editor. ([54450](https://github.com/WordPress/gutenberg/pull/54450)) +- Revisions: Remove 'gutenberg' query param from revisions.php. ([54166](https://github.com/WordPress/gutenberg/pull/54166)) + +#### Rich Text +- RichText: Remove __unstableOnSplitMiddle. ([54183](https://github.com/WordPress/gutenberg/pull/54183)) + +#### Typography +- Fluid typography: Backporting Core @since annotations. ([54204](https://github.com/WordPress/gutenberg/pull/54204)) +- Font Face: Remove static instance in wp_print_font_faces(). ([54228](https://github.com/WordPress/gutenberg/pull/54228)) + +#### Block Editor +- Improve code commenting around focus mount behaviour of rich text Link UI. ([54085](https://github.com/WordPress/gutenberg/pull/54085)) +- List e2e: Run all tests with iframe. ([54181](https://github.com/WordPress/gutenberg/pull/54181)) + +#### Layout +- Use override editor style API. ([54466](https://github.com/WordPress/gutenberg/pull/54466)) + +#### Plugin +- Require minimum WordPress 6.2. ([53451](https://github.com/WordPress/gutenberg/pull/53451)) + +#### Themes +- Iframe: Skip scoping styles. ([46752](https://github.com/WordPress/gutenberg/pull/46752)) + + +### Tools + +#### Testing +- Button: Update test assertion to match test name. ([54260](https://github.com/WordPress/gutenberg/pull/54260)) +- E2E: Do not run page actions in beforeEach hook when using fixme. ([54065](https://github.com/WordPress/gutenberg/pull/54065)) +- Fix Font library unit tests. ([54645](https://github.com/WordPress/gutenberg/pull/54645)) +- Font Library: Remove upload_mimes filter after uploading fonts. ([54647](https://github.com/WordPress/gutenberg/pull/54647)) +- Migrate RichText end-to-end tests to Playwright. ([53493](https://github.com/WordPress/gutenberg/pull/53493)) +- Perf Tests: Update base point to compare. ([54111](https://github.com/WordPress/gutenberg/pull/54111)) +- Puppeteer tests: Try to fix failing tests related to notices in core. ([54452](https://github.com/WordPress/gutenberg/pull/54452)) +- Remove accidental addition of perf test results (2). ([54363](https://github.com/WordPress/gutenberg/pull/54363)) +- Remove accidental addition of perf test results. ([54355](https://github.com/WordPress/gutenberg/pull/54355)) +- Update WPCS to v3.0, and fix all reported Coding Standards issues. ([53866](https://github.com/WordPress/gutenberg/pull/53866)) +- `Modal`: Add more unit tests. ([54569](https://github.com/WordPress/gutenberg/pull/54569)) +- end-to-end Test Utils: Add new fixtures for performance metrics. ([52993](https://github.com/WordPress/gutenberg/pull/52993)) +- end-to-end Tests: Fix 'no-useless-not' ESLint warnings. ([54652](https://github.com/WordPress/gutenberg/pull/54652)) +- package(e2e-test-utils): Update fixtures. ([54128](https://github.com/WordPress/gutenberg/pull/54128)) +- wp-scripts: Add support for Playwright. ([53108](https://github.com/WordPress/gutenberg/pull/53108)) + +#### Build Tooling +- Backport tools: Filter PRs to be cherry picked by merged date. ([54171](https://github.com/WordPress/gutenberg/pull/54171)) +- Changelog tool: Update Automated Testing label. ([54070](https://github.com/WordPress/gutenberg/pull/54070)) +- Running npm run format:Php may result in an error. ([54162](https://github.com/WordPress/gutenberg/pull/54162)) +- Scripts: Correctly resolve entry points when the directory is symlinked. ([54212](https://github.com/WordPress/gutenberg/pull/54212)) +- Upgrade wp-prettier to v3.0.3. ([54539](https://github.com/WordPress/gutenberg/pull/54539)) +- Update typescript-eslint to v6. ([53975](https://github.com/WordPress/gutenberg/pull/53975)) + + +## First time contributors + +The following PRs were merged by first time contributors: + +- @andrewhayward: Making Circular Option Picker a `listbox`. ([52255](https://github.com/WordPress/gutenberg/pull/52255)) +- @jamiemchale: Fix createI18n package import location. ([51328](https://github.com/WordPress/gutenberg/pull/51328)) +- @johnhooks: refactor(blob): Type URL parameter as optional. ([49201](https://github.com/WordPress/gutenberg/pull/49201)) +- @MericKarabulut: Improving error messages and codes in jest-console, matcher.js. ([53743](https://github.com/WordPress/gutenberg/pull/53743)) +- @Piyush-Deshmukh: Fix: Wrapped `ref` in quotes in theme.json documentation. ([54591](https://github.com/WordPress/gutenberg/pull/54591)) +- @Rajinsharwar: Editor: Catch errors when creating terms. ([53369](https://github.com/WordPress/gutenberg/pull/53369)) +- @toolstack: Set the timezone correctly. ([48083](https://github.com/WordPress/gutenberg/pull/48083)) + + +## Contributors + +The following contributors merged PRs in this release: + +@aaronrobertshaw @afercia @alexstine @andrewhayward @andrewserong @annezazu @anomiex @anton-vlasenko @aristath @artemiomorales @atachibana @bangank36 @bfintal @bph @brookewp @c4rl0sbr4v0 @carolinan @chad1008 @chintu51 @ciampo @DAreRodz @dcalhoun @derekblank @draganescu @ediamin @ellatrix @fluiddot @gaambo @geriux @getdave @glendaviesnz @gvgvgvijayan @gziolo @hellofromtonya @jameskoster @jamiemchale @jffng @johnhooks @jordesign @jorgefilipecosta @joshuatf @jrtashjian @jsnajdr @juanmaguitar @kevin940726 @kkoppenhaver @kmanijak @leewillis77 @luisherranz @madhusudhand @Mamaduka @margolisj @masteradhoc @matiasbenedetto @mburridge @mcsf @MericKarabulut @mhimon @michalczaplinski @mikachan @mikejolley @mokagio @ndiego @ntsekouras @Olein-jp @petitphp @Piyush-Deshmukh @Rajinsharwar @ramonjd @richtabor @SantosGuillamot @scruffian @spacedmonkey @stokesman @swissspidy @t-hamano @tellthemachines @thelovekesh @toolstack @torounit @tyxla @vcanales @walbo @WunderBart @youknowriad + + = 16.6.0 = ## Changelog diff --git a/composer.json b/composer.json index 134e366befdb94..3571377bd58bd7 100644 --- a/composer.json +++ b/composer.json @@ -26,10 +26,8 @@ } }, "require-dev": { - "dealerdirect/phpcodesniffer-composer-installer": "^0.7", - "squizlabs/php_codesniffer": "^3.5", "phpcompatibility/phpcompatibility-wp": "^2.1.3", - "wp-coding-standards/wpcs": "^2.2", + "wp-coding-standards/wpcs": "^3.0", "sirbrillig/phpcs-variable-analysis": "^2.8", "spatie/phpunit-watcher": "^1.23", "yoast/phpunit-polyfills": "^1.0", diff --git a/docs/contributors/code/coding-guidelines.md b/docs/contributors/code/coding-guidelines.md index e7ff0a40843060..12c3ad96cb85f3 100644 --- a/docs/contributors/code/coding-guidelines.md +++ b/docs/contributors/code/coding-guidelines.md @@ -207,24 +207,25 @@ You can attach private selectors and actions to a public store: ```js // In packages/package1/store.js: -import { privateHasContentRoleAttribute, ...selectors } from './selectors'; -import { privateToggleFeature, ...actions } from './selectors'; +import { privateHasContentRoleAttribute } from './private-selectors'; +import { privateToggleFeature } from './private-actions'; // The `lock` function is exported from the internal private-apis.js file where // the opt-in function was called. import { lock, unlock } from './lock-unlock'; -export const store = registerStore(/* ... */); +export const store = registerStore( /* ... */ ); // Attach a private action to the exported store: -unlock( store ).registerPrivateActions({ - privateToggleFeature +unlock( store ).registerPrivateActions( { + privateToggleFeature, } ); // Attach a private action to the exported store: -unlock( store ).registerPrivateSelectors({ - privateHasContentRoleAttribute +unlock( store ).registerPrivateSelectors( { + privateHasContentRoleAttribute, } ); +``` - +```js // In packages/package2/MyComponent.js: import { store } from '@wordpress/package1'; import { useSelect } from '@wordpress/data'; @@ -233,17 +234,18 @@ import { useSelect } from '@wordpress/data'; import { unlock } from './lock-unlock'; function MyComponent() { - const hasRole = useSelect( ( select ) => ( - // Use the private selector: - unlock( select( store ) ).privateHasContentRoleAttribute() + const hasRole = useSelect( + ( select ) => + // Use the private selector: + unlock( select( store ) ).privateHasContentRoleAttribute() // Note the unlock() is required. This line wouldn't work: - // select( store ).privateHasContentRoleAttribute() - ) ); + // select( store ).privateHasContentRoleAttribute() + ); // Use the private action: unlock( useDispatch( store ) ).privateToggleFeature(); - // ... + // ... } ``` @@ -263,7 +265,9 @@ lock( privateApis, { privateClass: class PrivateClass {}, privateVariable: 5, } ); +``` +```js // In packages/package2/index.js: import { privateApis } from '@wordpress/package1'; import { unlock } from './lock-unlock'; @@ -336,7 +340,9 @@ export function validateBlocks( blocks ) { export const privateApis = {}; lock( privateApis, { privateValidateBlocks } ); +``` +```js // In @wordpress/package2/index.js: import { privateApis as package1PrivateApis } from '@wordpress/package1'; import { unlock } from './lock-unlock'; @@ -363,30 +369,30 @@ const PrivateMyButton = ( { title, privateShowIcon = true } ) => { return ( ); -} +}; // The stable public component is a thin wrapper that calls the // private component with the private features disabled -export const MyButton = ( { title } ) => - +export const MyButton = ( { title } ) => ( + +); export const privateApis = {}; lock( privateApis, { PrivateMyButton } ); +``` - +```js // In @wordpress/package2/index.js: import { privateApis } from '@wordpress/package1'; import { unlock } from './lock-unlock'; // The private component may be "unlocked" given the stable component: -const { PrivateMyButton } = unlock(privateApis); +const { PrivateMyButton } = unlock( privateApis ); export function MyComponent() { - return ( - - ) + return ; } ``` @@ -438,13 +444,14 @@ function privateInCorePublicInPlugin() {} // Gutenberg treats both functions as private APIs internally: const privateApis = {}; -lock(privateApis, { privateEverywhere, privateInCorePublicInPlugin }); +lock( privateApis, { privateEverywhere, privateInCorePublicInPlugin } ); // The privateInCorePublicInPlugin function is explicitly exported, // but this export will not be merged into WordPress core thanks to // the process.env.IS_GUTENBERG_PLUGIN check. if ( process.env.IS_GUTENBERG_PLUGIN ) { - export const privateInCorePublicInPlugin = unlock( privateApis ).privateInCorePublicInPlugin; + export const privateInCorePublicInPlugin = + unlock( privateApis ).privateInCorePublicInPlugin; } ``` @@ -459,7 +466,7 @@ const a = 10; // Bad: const object = { a: a, - performAction: function() { + performAction: function () { // ... }, }; @@ -771,7 +778,7 @@ Documenting a function component should be treated the same as any other functio * * @return {?string} Block title. */ -``` +```` For class components, there is no recommendation for documenting the props of the component. Gutenberg does not use or endorse the [`propTypes` static class member](https://react.dev/reference/react/Component#static-proptypes). diff --git a/docs/explanations/history.md b/docs/explanations/history.md index db2b7518bd8969..c5d8cbf8554f5a 100644 --- a/docs/explanations/history.md +++ b/docs/explanations/history.md @@ -2,22 +2,35 @@ A set of links and resources covering the history of the Gutenberg project, how it got started, sources of inspiration, and initial thinking. -## Survey - -There was a survey done: [https://make.wordpress.org/core/2017/04/07/editor-experience-survey-results/](https://make.wordpress.org/core/2017/04/07/editor-experience-survey-results/) - ## Inspiration -This includes a list of historical articles and influences on the Gutenberg project. +A community [Editor Experience Survey](https://make.wordpress.org/core/2017/04/07/editor-experience-survey-results/) was conducted in early 2017, which reinforced the need for a new editing experience in WordPress. -- LivingDocs: [https://beta.livingdocs.io/articles](https://beta.livingdocs.io/articles) -- Parrot: [https://intenseminimalism.com/2017/parrot-an-integrated-site-builder-and-editor-concept-for-wordpress/](https://intenseminimalism.com/2017/parrot-an-integrated-site-builder-and-editor-concept-for-wordpress/) +This is a list of historical articles and products that influenced the Gutenberg project and the creation of the Block Editor. + +- [Parrot: an integrated site builder and editor concept for WordPress](https://intenseminimalism.com/2017/parrot-an-integrated-site-builder-and-editor-concept-for-wordpress/) +- LivingDocs - Apple Keynote - Slack - Google Sites v2 -## Blog posts by the team - -- Gutenberg tag on make/core: updates and much more: [https://make.wordpress.org/core/tag/gutenberg/](https://make.wordpress.org/core/tag/gutenberg/) -- Suggested revised timeline: [https://make.wordpress.org/core/2017/08/11/revised-suggested-roadmap-for-gutenberg-and-customization/](https://make.wordpress.org/core/2017/08/11/revised-suggested-roadmap-for-gutenberg-and-customization/) -- Discovering Gutenberg: [https://make.wordpress.org/core/2017/08/08/discovering-gutenberg-and-next-steps/](https://make.wordpress.org/core/2017/08/08/discovering-gutenberg-and-next-steps/) +### Gutenberg updates and feature overviews + +- [Themes of the Future](https://wordpress.tv/2021/01/21/eileen-violini-themes-of-the-future-the-new-frontier-of-gutenberg-block-based-themes-and-theme-development/), Eileen Violini (January 2021) +- [Status Check: Site Editing & Customization](https://make.wordpress.org/core/2020/12/10/status-check-site-editing-and-customization/), Matรญas Ventura Bausero (December 2020) +- [State of the Word 2020 FSE Demo](https://youtu.be/QI3qCoiuG3w?t=1279), Matt Mullenweg (December 2020) +- [Embrace the Modularity](https://riad.blog/2020/01/28/embrace-the-modularity/), Riad Benguella (January 2020) +- [State of the Word 2019 Gutenberg Demo](https://www.youtube.com/watch?v=LezbkeV059Q), Matt Mullenweg (December 2019) +- [Growing JavaScript Skills with WordPress](https://gziolo.pl/2019/07/15/growing-javascript-skills-with-wordpress/) at JavaScript for WordPress conference (July 2019) +- [Beyond Gutenberg](https://wordpress.tv/2018/07/09/matias-ventura-beyond-gutenberg/), Matรญas Ventura Bausero (July 2018) +- [Anatomy of a block: Gutenberg design patterns](https://wordpress.tv/2018/07/08/tammie-lister-anatomy-of-a-block-gutenberg-design-patterns/), Tammie Lister (July 2018) +- [The Language of Gutenberg](https://lamda.blog/2018/04/22/the-language-of-gutenberg/), Miguel Fonseca (April 2018) +- [State of the Word 2017 Gutenberg Demo](https://youtu.be/XOY3ZUO6P0k?t=2100), Matt Mullenweg with demo by Matรญas Ventura Bausero (December 2017) +- [Gutenberg, or the Ship of Theseus](https://matiasventura.com/post/gutenberg-or-the-ship-of-theseus/), Matรญas Ventura Bausero (October 2017) +- [We Called It Gutenberg for a Reason](https://ma.tt/2017/08/we-called-it-gutenberg-for-a-reason/), Matt Mullenweg (August 2017) +- [How Gutenberg is Changing WordPress Development](https://riad.blog/2017/10/06/how-gutenberg-is-changing-wordpress-development/), Riad Benguella (October 2017) +- [Revised suggested roadmap for Gutenberg and Customization](https://make.wordpress.org/core/2017/08/11/revised-suggested-roadmap-for-gutenberg-and-customization/), Tammie Lister (August 2017) +- [Discovering Gutenberg and next steps](https://make.wordpress.org/core/2017/08/08/discovering-gutenberg-and-next-steps/), Tammie Lister (August 2017) +- [How Gutenberg Will Shape the Future of WordPress](https://www.linkedin.com/pulse/gutenberg-morten-rand-hendriksen/), Morten Rand-Henrikson (August 2017) + +You can also view this [Index of Gutenberg related posts](https://make.wordpress.org/core/handbook/references/keeping-up-with-gutenberg-index/) for more resources. \ No newline at end of file diff --git a/docs/getting-started/README.md b/docs/getting-started/README.md index 0c3cd4b9c4e4fd..136caa5607e487 100644 --- a/docs/getting-started/README.md +++ b/docs/getting-started/README.md @@ -15,6 +15,17 @@ Welcome! Let's get started building with blocks. Blocks are at the core of exten [Create a Block Tutorial](/docs/getting-started/create-block/README.md) - Learn how to create your first block for the WordPress block editor. +## Learn WordPress Courses + +At [Learn WordPress](https://learn.wordpress.org/), you can find [tutorials](https://learn.wordpress.org/tutorials/), [courses](https://learn.wordpress.org/courses/), and [online workshops](https://learn.wordpress.org/online-workshops/) to learn more about developing for the Block Editor. Here is a selection of current offerings. + +- [Intro to Block Development: Build Your First Custom Block](https://learn.wordpress.org/course/introduction-to-block-development-build-your-first-custom-block/) +- [Converting a Shortcode to a Block](https://learn.wordpress.org/course/converting-a-shortcode-to-a-block/) +- [Using the WordPress Data Layer](https://learn.wordpress.org/course/using-the-wordpress-data-layer/) +- [Registering Block Patterns](https://learn.wordpress.org/workshop/registering-block-patterns/) +- [Intro to Gutenberg Block Development](https://learn.wordpress.org/workshop/intro-to-gutenberg-block-development/) +- [Intro to Publishing with the Block Editor](https://learn.wordpress.org/workshop/intro-to-publishing-with-the-block-editor/) + ## Ways to Stay Informed New features and changes are important to keep up to date on as the Gutenberg project continues. Each person will have their own unique needs in keeping up with a project of this scale. What follows is more of a catalogue of ways to keep up rather than a recommendation for how to do so. @@ -50,4 +61,4 @@ Checking in on [issues](https://github.com/WordPress/gutenberg/issues) and [PRs] - [Glossary](/docs/getting-started/glossary.md) - [Frequently Asked Questions](/docs/getting-started/faq.md) - [Project History](/docs/explanations/history.md) -- [Outreach](/docs/getting-started/outreach.md) +- [Gutenberg related Make posts](https://make.wordpress.org/core/handbook/references/keeping-up-with-gutenberg-index/) \ No newline at end of file diff --git a/docs/getting-started/devenv/README.md b/docs/getting-started/devenv/README.md index 7c55bcb6393f1b..d6e8d9e1ae24b2 100644 --- a/docs/getting-started/devenv/README.md +++ b/docs/getting-started/devenv/README.md @@ -1,228 +1,51 @@ -# Development Environment +# Block Development Environment -This guide is for setting up your local environment for JavaScript development for creating plugins and tools to extend WordPress and the block editor. If you are looking to contribute to Gutenberg project itself, see additional documentation in the [Getting Started guide](/docs/contributors/code/getting-started-with-code-contribution.md). +This guide will help you set up the right development environment to create blocks and other plugins that extend and modify the Block Editor in WordPress. -A development environment is a catch-all term for what you need setup on your computer to work. The three main pieces needed for our development environment are: +To contribute to the Gutenberg project itself, refer to the additional documentation in the [code contribution guide](/docs/contributors/code/getting-started-with-code-contribution.md).` -1. Node/NPM Development Tools -2. WordPress Development Site -3. Code Editor +A block development environment includes the tools you need on your computer to successfully develop for the Block Editor. The three essential requirements are: -## Quick Start +1. [Code editor](#code-editor) +2. [Node.js development tools](#node-js-development-tools) +3. [Local WordPress environment (site)](#local-wordpress-environment) -Here is a summary of the guide. See each section for additional details and explanations. +## Code editor -**1. Install Node development tools** +A code editor is used to write code, and you can use whichever editor you're most comfortable with. The key is having a way to open, edit, and save text files. -Download and install [Node Version Manager](https://github.com/nvm-sh/nvm) (nvm) +If you do not already have a preferred code editor, [Visual Studio Code](https://code.visualstudio.com/) (VS Code) is a popular choice for JavaScript development among Core contributors. It works well across the three major platforms (Windows, Linux, and Mac) and is open-source and actively maintained by Microsoft. VS Code also has a vibrant community providing plugins and extensions, including many for WordPress development. -``` -curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh | bash -``` +## Node.js development tools -Quit and restart terminal -Install Node.js v16. +Node.js (`node`) is an open-source runtime environment that allows you to execute JavaScript outside of the web browser. While Node.js is not required for all WordPress JavaScript development, it's essential when working with modern JavaScript tools and developing for the Block Editor. -``` -nvm install 16 -``` +Node.js and its accompanying development tools allow you to: -**2. WordPress Development Site** +- Install and run WordPress packages needed for Block Editor development, such as `wp-scripts` +- Setup local WordPress environments with `wp-env` and `wp-now` +- Use the latest ECMAScript features and write code in ESNext +- Lint, format, and test JavaScript code +- Scaffold custom blocks with the `create-block` package -First download, install, and start [Docker Desktop](https://www.docker.com/products/docker-desktop) following the instructions for your OS. +The list goes on. While modern JavaScript development can be challenging, WordPress provides several tools, like [`wp-scripts`](https://developer.wordpress.org/block-editor/reference-guides/packages/packages-scripts/) and [`create-block`](https://developer.wordpress.org/block-editor/reference-guides/packages/packages-create-block/), that streamline the process and are made possible by Node.js development tools. -- Install WordPress environment tool +**The recommended Node.js version for block development is [Active LTS](https://nodejs.dev/en/about/releases/) (Long Term Support)**. However, there are times when you need to to use different versions. A Node.js version manager tool like `nvm` is strongly recommended and allows you to easily change your `node` version when required. You will also need Node Package Manager (`npm`) and the Node Package eXecute (`npx`) to work with some WordPress packages. Both are installed automatically with Node.js. -``` -npm -g install @wordpress/env -``` +To be able to use the Node.js tools and [packages provided by WordPress](https://github.com/WordPress/gutenberg/tree/trunk/packages) for block development, you'll need to set a proper Node.js runtime environment on your machine.. To learn more about how to do this, refer to the links below. -Start the environment from an existing plugin or theme directory, or a new working directory: +- [Install Node.js for Mac and Linux](/docs/getting-started/devenv/nodejs-development-environment.md#node-js-installation-on-mac-and-linux-with-nvm) +- [Install Node.js for Windows](/docs/getting-started/devenv/nodejs-development-environment.md#node-js-installation-on-windows-and-others) -``` -wp-env start -``` +## Local WordPress environment -You will have a full WordPress site installed, navigate to: http://localhost:8888/ using your browser, log in to the WordPress dashboard at http://localhost:8888/wp-admin/ using Username "admin" and Password "password", without the quotes. +A local WordPress environment (site) provides a controlled, efficient, and secure space for development, allowing you to build and test your code before deploying it to a production site. The [same requirements](https://en-gb.wordpress.org/about/requirements/) for WordPress apply to local sites. -**3. Code Editor** +Many tools are available for setting up a local WordPress environment on your computer. The Block Editor Handbook covers `wp-env` and `wp-now`, both of which are open-source and maintained by the WordPress project itself. -You can use any text editor to write code. For example, [Visual Studio Code](https://code.visualstudio.com/) is a popular open-source editor. You can follow instructions on their site to install it for your OS. +Refer to the individual guides below for setup instructions. -## Node Development Tools +- [Get started with `wp-env`](/docs/getting-started/devenv/get-started-with-wp-env.md) +- [Get started with `wp-now`](/docs/getting-started/devenv/get-started-with-wp-now.md) -The tools needed for development are **Node** and **NPM**. **Nodejs** is a runtime environment that allows running JavaScript outside of the browser. NPM is the Node Package Manager, it is used for installing dependencies and running scripts. The script `npx` is also installed with Nodejsโ€”this script is used to run packages not yet installedโ€”we will use `npx` to bootstrap a block. - -The tools are used to convert the JavaScript we are going to write into a format that browsers can run. This is called transpiling or the build step. - -For Mac and Linux, it is recommended to use the [Node Version Manager](https://github.com/nvm-sh/nvm) (nvm). Using `nvm` to install node allows installing specific versions, plus installs locally in your home directory and avoids any global permission issues. - -For Windows, or alternative installs, you can [download a Nodejs installer](https://nodejs.org/en/download/) directly from the main Node.js website, v14 is recommended. Installers are available for Windows and Mac, and binaries available for Linux. See Node.js site for additional installation methods. - -Here are the quick instructions to install using nvm, see the [full installation instructions](https://github.com/nvm-sh/nvm#installing-and-updating) for additional details. - -Run the following on the command-line to install nvm: - -```sh -curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh | bash -``` - -Note: On macOS, the required developer tools are not installed by default, if not already installed you may be prompted to download the install. - -Mac git command requires command line developer tools - -After installing nvm, you need to use it to install Node.js, to install v16, run: - -```sh -nvm install 16 -``` - -If there is an error running the above command, for example a common error that occurs is: - -```sh -$ nvm install 16 -zsh: command not found: nvm -``` - -First, try quitting and restarting your terminal to pick up the installed config. - -If restarting did not resolve the problem, you might need to create the default profile file. - -On macOS Catalina, the default shell is zsh, to create the profile file type `touch ~/.zshrc` on the command-line. It is fine to run if the file already exists. Note, `~/` is a shortcut to your home directory. For Ubuntu, including WSL, the default profile is bash, use `touch ~/.bashrc` to create. - -After creating the profile file, re-run the install command: - -```sh -nvm install 16 -``` - -The important part after installing is being able to use them in your terminal. Open a terminal command-line and type `node -v` and `npm -v` to confirm they are installed. - -```sh -> node -v -v16.20.1 - -> npm -v -8.19.4 -``` - -Your versions may not match exactly, that is fine. The minimum version for Node.js is >= 12 and for npm >= 6.9, using v14 will be supported until upgrade is required. - -## WordPress Development Site - -There are several ways to run WordPress locally on your own computer, or you could even develop on a cloud hosted computer, though this may be slower. - -The WordPress [wp-env package](https://www.npmjs.com/package/@wordpress/env) lets you set up a local WordPress environment for building and testing plugins and themes, without any additional configuration. - -The `wp-env` tool uses Docker to create a virtual machine that runs the WordPress site. There are instructions available for installing Docker on [Windows 10 Pro](https://docs.docker.com/docker-for-windows/install/), [other versions of Windows 10](https://docs.docker.com/docker-for-windows/wsl/), [macOS](https://docs.docker.com/docker-for-mac/install/), and [Linux](https://docs.docker.com/v17.12/install/linux/docker-ce/ubuntu/#install-using-the-convenience-script). If using Ubuntu, see our additional notes for [help installing Docker on Ubuntu](/docs/getting-started/devenv/docker-ubuntu.md). - -After you have installed Docker, go ahead and install the `wp-env` tool. This command will install the tool globally, which means you can run it from any directory: - -```sh -npm -g install @wordpress/env -``` - -To confirm it is installed and available, run: - -```sh -wp-env --version -> 1.6.0 -``` - -The `wp-env` script is used to create a Docker WordPress environment. You can use this script to start an environment with your plugin activated by running it from the directory containing your plugin. For example if you are following the create block tutorial, this would be in the generated directory like so: - -```sh -npx @wordpress/create-block starter-block -cd starter-block -wp-env start -``` - -You can access your environment in your browser at: [http://localhost:8888/](http://localhost:8888/), the default username is `admin` and default password is `password`. For more information controlling the Docker environment see the [@wordpress/env package readme](/packages/env/README.md). - -When using the script while developing a single plugin, `wp-env start` can mount and activate the plugin automatically when run from the directory containing the plugin. Note: This also works for themes when run from the directory in which you are developing the theme. - -If you run `wp-env start` from a directory that is not a plugin or theme, a generic WordPress environment will be created. The script will display the following warning, it is fine if this is your intention. - -``` -!! Warning: could not find a .wp-env.json configuration file and could not determine if 'DIR' is a WordPress installation, a plugin, or a theme. -``` - -You can use the `.wp-env.json` configuration file to create an environment that works with multiple plugins and/or themes. See the [@wordpress/env package for additional details](/packages/env/README.md#wp-envjson). - -#### Troubleshooting - -A common issue when running `wp-env` is `Error while running docker-compose command.` - -- Check that Docker Desktop is started and running. -- Check Docker Desktop dashboard for logs, restart, or remove existing VMs. - -If you see the error: `Host is already in use by another container` - -- The container is already running, or another one is. You can stop an existing container running use `wp-env stop` from the directory you started it. -- If you do not remember the directory you started wp-env in, you can stop all containers with `docker stop $(docker ps -q)`. Please note, this will stop all containers, use caution with this command. - -### Alternative to Docker - -Docker is just one method to run a local WordPress environment. Block development and extending WordPress is done using normal plugins, so any WordPress environment can be used. Here are some alternatives that you can consider which do not require installing Docker. - -- [Local](https://localwp.com/) - Local is a single application you download and install. You will need to know where the plugin directory is located after install. If you create a site called `mywp` typically the plugin directory is installed at `~\Local Sites\mywp\app\public\wp-content\plugins`. When working with gutenberg it is recommended to place your install in your own gutenberg folder. This avoids potential issue with the build processes. - -- [WampServer](http://www.wampserver.com/en/) or [MAMP](https://www.mamp.info/) environments, both are quite similar to Local, combining a web server, PHP, and database. However these tools are not WordPress specific, so if you are not already using them, Local might be an easier option. - -- Remote server - you can work on a remote server, most hosts provide a quick WordPress setup. However, this will require additional time thorughout development syncing to the server, or working directly on the remote server. - -The important part is having a WordPress site installed, and know where and how to update files in the plugins directory. - -## Code Editor - -[Visual Studio Code](https://code.visualstudio.com/) is a popular code editor for JavaScript development. It works quite well across the three major platforms (Windows, Linux, and Mac), it is open-source and actively maintained by Microsoft. Plus Visual Studio Code has a vibrant community providing plugins and extensions; it is becoming the defacto standard for web development. - -Alternative editors include [Sublime Text](https://www.sublimetext.com/) that is also available across platforms, though is a commercial product; or other free alternatives include [Vim](https://www.vim.org/), [Atom](https://atom.io/), and [Notepad++](https://notepad-plus-plus.org/) all support standard JavaScript style development. - -You can use any editor you're comfortable with, it is more a personal preference. The development setup for WordPress block editor is a common JavaScript environment and most editors have plugins and support. The key is having a way to open, edit, and save text files. - -## Uninstall - Start Over - -Here are a few instructions if you need to start over, or want to remove what was installed. - -### Local Environment - -- If you just want to reset and clean the WordPress database: - -``` -wp-env clean all -``` - -- To remove the local environment completely for a specific project: - -``` -wp-env destroy -``` - -- To completely uninstall wp-env tool: - -``` -npm -g uninstall @wordpress/env -``` - -- To uninstall Docker, or Visual Studio Code use your OS method to remove packages. For example, on Windows run "Add or remove programs". You can additionally uninstall from the Docker Desktop app, click the bug icon at the top to switch to this Troubleshoot screen. Click Uninstall or remove. - -![Docker Troubleshoot Screenshot](https://developer.wordpress.org/files/2020/08/docker-uninstall-screen.png) - -### Uninstall Node/NVM - -To uninstall Node/NVM, delete the NVM directory, this is typically installed at `$HOME/.nvm`, delete using - -``` -rm -rf "$HOME/.nvm" -``` - -If this does not work and the `$NVM_DIR` environment variable is set you can remove using `rm -rf "$NVM_DIR"` - -To clean up any installed JavaScript packages remove the global `.npm` directory at `$HOME/.npm`, - -``` -rm -rf "$HOME/.npm" -``` - -Just as you confirmed the installation worked, you can confirm the uninstall worked. First quit and restart terminal and then try to run `npm -v`, `node -v`, and `nvm -v` you should then see a "command not found" error in the terminal. +Of the two, `wp-env` is the more solid and complete solution. It's also the recommended tool for Gutenberg development. On the other hand, `wp-now` offers a simplified setup but is more limited than `wp-env`. Both are valid options, so the choice is yours. diff --git a/docs/getting-started/devenv/docker-ubuntu.md b/docs/getting-started/devenv/docker-ubuntu.md deleted file mode 100644 index 680798d74f4e8c..00000000000000 --- a/docs/getting-started/devenv/docker-ubuntu.md +++ /dev/null @@ -1,60 +0,0 @@ -# How to setup local WordPress environment on Ubuntu - -This article covers setting up the local WordPress development environment using Docker on Ubuntu. - -For Ubuntu 20.04.1, the standard docker binaries in the repository work as needed: - -``` -sudo apt install docker.io docker-compose -``` - -For earlier versions of Ubuntu, the docker binaries included in repositories did not support the features needed for the WordPress environment. - -- For Ubuntu prior to 20.04.1, follow these [directions from Docker to install](https://docs.docker.com/install/linux/docker-ce/ubuntu/). Additionally `docker-compose` is required, you may need to install separately, see [ Docker compose documentation](https://docs.docker.com/compose/install/). - -## Troubleshooting - -If you run into this error, when running `npm run wp-env` from the Gutenberg directory: - -``` -ERROR: Couldn't connect to Docker daemon at http+docker://localhost - is it running? - -If it's at a non-standard location, specify the URL with the DOCKER_HOST environment variable. -``` - -First, make sure docker is running. You can check using `ps -ef | grep docker` which should show something like: - -``` -/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock -``` - -If docker is not running, try to start the service using: - -``` -sudo systemctl start docker.service -``` - -If docker is running, then it is not listening how the WordPress environment is trying to communicate. Try adding the following service override file to include listening on tcp. See [this Docker documentation](https://docs.docker.com/config/daemon/remote-access/) on how to configure remote access for Docker daemon. - -``` -# /etc/systemd/system/docker.service.d/override.conf -[Service] -ExecStart= -ExecStart=/usr/bin/dockerd -H fd:// -H tcp://0.0.0.0:2376 -``` - -Restart the service from the command-line - -``` -sudo systemctl daemon-reload -sudo systemctl restart docker.service -``` - -After restarting the services, set the environment variable DOCKER_HOST and try starting using: - -``` -export DOCKER_HOST=tcp://127.0.0.1:2376 -npm run wp-env start -``` - -Your environment should be setup at: http://localhost:8888/ diff --git a/docs/getting-started/devenv/get-started-with-wp-env.md b/docs/getting-started/devenv/get-started-with-wp-env.md new file mode 100644 index 00000000000000..f2c78c6fd236b2 --- /dev/null +++ b/docs/getting-started/devenv/get-started-with-wp-env.md @@ -0,0 +1,140 @@ +# Get started with wp-env + +The [@wordpress/env](https://www.npmjs.com/package/@wordpress/env) package (`wp-env`) lets you set up a local WordPress environment (site) for building and testing plugins and themes, without any additional configuration. + +Before following this guide, install [Node.js development tools](/docs/getting-started/devenv#node-js-development-tools) if you have not already done so. + +## Quick start + +1. Download, install, and start [Docker Desktop](https://www.docker.com/products/docker-desktop) following the instructions for your operating system. +2. Run `npm -g install @wordpress/env` in the terminal to install `wp-env` globally. +3. In the terminal, navigate to an existing plugin directory, theme directory, or a new working directory. +4. Run `wp-env start` in the terminal to start the local WordPress environment. +5. After the script runs, navigate to `http://localhost:8888/wp-admin/` and log into the WordPress dashboard using username `admin` and password `password`. + +## Set up Docker Desktop + +The `wp-env` tool uses [Docker](https://www.docker.com/) to create a virtual machine that runs the local WordPress site. The Docker Desktop application is free for small businesses, personal use, education, and non-commercial open-source projects. See their [FAQ](https://docs.docker.com/desktop/faqs/general/#do-i-need-to-pay-to-use-docker-desktop) for more information. + +Use the links below to download and install Docker Desktop for your operating system. + +- [Docker Desktop for Mac](https://docs.docker.com/desktop/install/mac-install/) +- [Docker Desktop for Windows](https://docs.docker.com/desktop/install/windows-install/) +- [Docker Desktop for Linux](https://docs.docker.com/desktop/install/linux-install/) + +If you are using a version of Ubuntu prior to 20.04.1, see the additional [troubleshooting notes](#ubuntu-docker-setup) below. + +After successful installation, start the Docker Desktop application and follow the prompts to get set up. You should generally use the recommended (default) settings, and creating a Docker account is optional. + +## Install and run `wp-env` + +The `wp-env` tool is used to create a local WordPress environment with Docker. So, after you have set up Docker Desktop, open the terminal and install the `wp-env` by running the command: + +```sh +npm -g install @wordpress/env +``` + +This will install the `wp-env` globally, allowing the tool to be run from any directory. To confirm it's installed and available, run `wp-env --version`, and the version number should appear. + +Next, navigate to an existing plugin directory, theme directory, or a new working directory in the terminal and run: + +```sh +wp-env start +``` + +Once the script completes, you can access the local environment at: `http://localhost:8888`. Log into the WordPress dashboard using username `admin` and password `password`. + +
+ Some projects, like Gutenberg, include their own specific wp-env configurations, and the documentation might prompt you to run npm run start wp-env instead. +
+ +For more information on controlling the Docker environment, see the [@wordpress/env package](/packages/env/README.md) readme. + +### Where to run `wp-env` + +The `wp-env` tool can run from practically anywhere. When using the script while developing a single plugin, `wp-env start` can mount and activate the plugin automatically when run from the directory containing the plugin. This also works for themes when run from the directory in which you are developing the theme. + +A generic WordPress environment will be created if you run `wp-env start` from a directory that is not a plugin or theme. The script will display the following warning, but ignore if this is your intention. + +``` +!! Warning: could not find a .wp-env.json configuration file and could not determine if 'DIR' is a WordPress installation, a plugin, or a theme. +``` + +You can also use the `.wp-env.json` configuration file to create an environment that works with multiple plugins and/or themes. See the [@wordpress/env package](/packages/env/README.md#wp-envjson) readme for more configuration details. + +### Uninstall or reset `wp-env` + +Here are a few instructions if you need to start over or want to remove what was installed. + +- If you just want to reset and clean the WordPress database, run `wp-env clean all` +- To remove the local environment completely for a specific project, run `wp-env destroy` +- To globally uninstall the `wp-env` tool, run `npm -g uninstall @wordpress/env` + +## Troubleshooting + +### Common errors + +When using `wp-env`, it's common to get the error: `Error while running docker-compose command` + +- Check that Docker Desktop is started and running. +- Check Docker Desktop dashboard for logs, restart, or remove existing virtual machines. +- Then try rerunning `wp-env start`. + +If you see the error: `Host is already in use by another container` + +- The container you are attempting to start is already running, or another container is. You can stop an existing container by running `wp-env stop` from the directory that you started it in. +- If you do not remember the directory where you started `wp-env`, you can stop all containers by running `docker stop $(docker ps -q)`. This will stop all Docker containers, so use with caution. +- Then try rerunning `wp-env start`. + +### Ubuntu Docker setup + +If you are using a version of Ubuntu prior to 20.04.1, you may encounter errors when setting up a local WordPress environment with `wp-env`. + +To resolve this, start by following the [installation guide](https://docs.docker.com/install/linux/docker-ce/ubuntu/) from Docker. `docker-compose` is also required, which you may need to install separately. Refer to the [Docker compose documentation](https://docs.docker.com/compose/install/). + +Once Docker and `wp-env` are installed, and assuming `wp-env` is configured globally, try running `wp-env start` in a directory. If you run into this error: + +``` +ERROR: Couldn't connect to Docker daemon at http+docker://localhost - is it running? + +If it's at a non-standard location, specify the URL with the DOCKER_HOST environment variable. +``` + +First, make sure Docker is running. You can check by running `ps -ef | grep docker`, which should return something like: + +``` +/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock +``` + +If Docker is not running, try starting the service by running `sudo systemctl start docker.service`. + +If Docker is running, then it is not listening to how the WordPress environment is trying to communicate. Try adding the following service override file to include listening on `tcp`. See [this Docker documentation](https://docs.docker.com/config/daemon/remote-access/) on how to configure remote access for Docker daemon. + +``` +# /etc/systemd/system/docker.service.d/override.conf +[Service] +ExecStart= +ExecStart=/usr/bin/dockerd -H fd:// -H tcp://0.0.0.0:2376 +``` + +Restart the service from the command-line: + +``` +sudo systemctl daemon-reload +sudo systemctl restart docker.service +``` + +After restarting the services, set the environment variable `DOCKER_HOST` and try starting `wp-env` with: + +``` +export DOCKER_HOST=tcp://127.0.0.1:2376 +wp-env start +``` + +Your environment should now be set up at `http://localhost:8888/`. + +## Additional resources + +- [@wordpress/env](https://www.npmjs.com/package/@wordpress/env) (Official documentation) +- [Docker Desktop](https://docs.docker.com/desktop) (Official documentation) +- [Quick and easy local WordPress development with wp-env](https://developer.wordpress.org/news/2023/03/quick-and-easy-local-wordpress-development-with-wp-env/) (WordPress Developer Blog) diff --git a/docs/getting-started/devenv/get-started-with-wp-now.md b/docs/getting-started/devenv/get-started-with-wp-now.md new file mode 100644 index 00000000000000..f4549735fcbdce --- /dev/null +++ b/docs/getting-started/devenv/get-started-with-wp-now.md @@ -0,0 +1,66 @@ +# Get started with wp-now + +The [@wp-now/wp-now](https://www.npmjs.com/package/@wordpress/env) package (`wp-now`) is a lightweight tool powered by [WordPress Playground](https://developer.wordpress.org/playground/) that streamlines setting up a local WordPress environment. + +Before following this guide, install [Node.js development tools](/docs/getting-started/devenv#node-js-development-tools) if you have not already done so. It's recommended that you use the latest version of `node`. `wp-now` requires at least `node` v18 and v20 if you intend to use its [Blueprints](https://github.com/WordPress/playground-tools/tree/trunk/packages/wp-now#using-blueprints) feature. + +## Quick start + +1. Run `npm -g install @wp-now/wp-now` in the terminal to install `wp-now` globally. +2. In the terminal, navigate to an existing plugin directory, theme directory, or a new working directory. +3. Run `wp-now start` in the terminal to start the local WordPress environment. +4. After the script runs, your default web browser will automatically open the new local site, and you'll be logged in with the username `admin` and the password `password`. + +## Install and run `wp-now` + +Under the hood, `wp-now` is powered by WordPress Playground and only requires Node.js, unlike `wp-env`, which also requires Docker. To install `wp-now`, open the terminal and run the command: + +```sh +npm -g install @wp-now/wp-now +``` + +This will install the `wp-now` globally, allowing the tool to be run from any directory. To confirm it's installed and available, run `wp-now --version`, and the version number should appear. + +Next, navigate to an existing plugin directory, theme directory, or a new working directory in the terminal and run: + +```sh +wp-now start +``` + +After the script runs, your default web browser will automatically open the new local site, and you'll be logged in with the username `admin` and the password `password`. + +
+ If you encounter any errors when running wp-now start, make sure that you are using at least node v18, or v20 if you are using the Blueprint feature. +
+ +When running `wp-now` you can also pass arguments that modify the behavior of the WordPress environment. For example, `wp-now start --wp=6.3 --php=8` will start a site running WordPress 6.3 and PHP 8, which can be useful for testing purposes. + +Refer to the [@wp-now/wp-now](https://github.com/WordPress/playground-tools/tree/trunk/packages/wp-now) documentation for all available arguments. + +### Where to run `wp-now` + +The `wp-now` tool can be used practically anywhere and has different modes depending on how the directory is set up when you run `wp-now start`. Despite the many options, when developing for the Block Editor, you will likely use: + +- `plugin`, `theme`, or `wp-content`: Loads the project files into a virtual filesystem with WordPress and a SQLite-based database. Everything (including WordPress core files, the database, wp-config.php, etc.) is stored in the user's home directory and loaded into the virtual filesystem. The mode will be determined by: + - `plugin`: Presence of a PHP file with 'Plugin Name:' in its contents. + - `theme`: Presence of a `style.css` file with 'Theme Name:' in its contents. + - `wp-content`: Presence of `/plugins` and `/themes` subdirectories. +- `playground`: If no other mode conditions are matched, `wp-now` launches a completely virtualized WordPress site. + +Refer to the [@wp-now/wp-now](https://github.com/WordPress/playground-tools/tree/trunk/packages/wp-now) documentation for a more detailed explanation of all modes. + +### Known issues + +Since `wp-now` is a relatively new tool, there are a few [known issues](https://github.com/WordPress/playground-tools/tree/trunk/packages/wp-now#known-issues) to be aware of. However, these issues are unlikely to impact most block, theme, or plugin development. + +### Uninstall or reset `wp-now` + +Here are a few instructions if you need to start over or want to remove what was installed. + +- If you just want to reset and clean the WordPress database, run `wp-now --reset` +- To globally uninstall the `wp-now` tool, run `npm -g uninstall @wp-now/wp-now` + +## Additional resources + +- [@wp-now/wp-now](https://github.com/WordPress/playground-tools/tree/trunk/packages/wp-now) (Official documentation) +- [WordPress Playground](https://developer.wordpress.org/playground/) (Developer overview) \ No newline at end of file diff --git a/docs/getting-started/devenv/nodejs-development-environment.md b/docs/getting-started/devenv/nodejs-development-environment.md new file mode 100644 index 00000000000000..6e1d3638f5f03c --- /dev/null +++ b/docs/getting-started/devenv/nodejs-development-environment.md @@ -0,0 +1,50 @@ +# Node.js development environment + +When developing for the Block Editor, you will need [Node.js](https://nodejs.org/en) development tools along with a code editor and a local WordPress environment (see [Block Development Environment](/docs/getting-started/devenv/README.md)). Node.js (`node`) is an open-source runtime environment that allows you to execute JavaScript code from the terminal (also known as a command-line interface, CLI, or shell) + +Installing `node` will automatically include the Node Package Manager (`npm`) and the Node Package eXecute (`npx`), two tools you will frequently use in block and plugin development. + +Node Package Manager ([`npm`](https://docs.npmjs.com/cli/v10/commands/npm)) serves multiple purposes, including dependency management and script execution. It's the recommended package manager and is extensively featured in all documentation. + +The Node Package eXecute ([`npx`](https://docs.npmjs.com/cli/v10/commands/npx)) tool is used to run commands from packages without installing them globally and is commonly used when scaffolding blocks with the [`create-block`](https://developer.wordpress.org/block-editor/reference-guides/packages/packages-create-block/) package. + + +## Node.js installation on Mac and Linux (with `nvm`) + +It's recommended that you use [Node Version Manager](https://github.com/nvm-sh/nvm) (`nvm`) to install Node.js. This allows you to install and manage specific versions of `node`, which are installed locally in your home directory, avoiding any global permission issues. + +Here are the quick instructions for installing `node` using `nvm` and setting the recommended Node.js version for block development. See the [complete installation guide](https://github.com/nvm-sh/nvm#installing-and-updating) for more details. + +1. Open the terminal and run the following to install `nvm`. On macOS, the required developer tools are not installed by default. Install them if prompted. + +```sh +curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.5/install.sh | bash +``` + +2. Quit and restart the terminal. +3. Run `nvm install --lts` in the terminal to install the latest [LTS](https://nodejs.dev/en/about/releases/) (Long Term Support) version of Node.js. +4. Run `node -v` and `npm -v` in the terminal to verify the installed `node` and `npm` versions. + +If needed, you can also install specific versions of `node`. For example, install version 18 by running `nvm install 18`, and switch between different versions by running `nvm use [version-number]`. See the `nvm` [usage guide](https://github.com/nvm-sh/nvm#usage) for more details. + +Some projects, like Gutenberg, include an [`.nvmrc`](https://github.com/WordPress/gutenberg/blob/trunk/.nvmrc) file which specifies the version of `node` that should be used. In this case, running `nvm use` will automatically select the correct version. If the version is not yet installed, you will get an error that tells you what version needs to be added. Run `nvm install [version-number]` followed by `nvm use`. + +## Node.js installation on Windows and others + +You can [download a Node.js installer](https://nodejs.org/en/download/) directly from the main Node.js website. The latest version is recommended. Installers are available for Windows and Mac, and binaries are available for Linux. + +Microsoft also provides a [detailed guide](https://learn.microsoft.com/en-us/windows/dev-environment/javascript/nodejs-on-windows#install-nvm-windows-nodejs-and-npm) on how to install `nvm` and Node.js on Windows and WSL. + +## Troubleshooting + +If you encounter the error `zsh: command not found: nvm` when attempting to install `node`, you might need to create the default profile file. + +The default shell is `zsh` on macOS, so create the profile file by running `touch ~/.zshrc` in the terminal. It's fine to run if the file already exists. The default profile is `bash` for Ubuntu, including WSL, so use `touch ~/.bashrc` instead. Then repeat steps 2-4. + +The latest `node` version should work for most development projects, but be aware that some packages and tools have specific requirements. If you encounter issues, you might need to install and use a previous `node` version. Also, make sure to check if the project has an `.nvmrc` and use the `node` version indicated. + +## Additional resources + +- [Node.js](https://nodejs.org/en) (Official documentation) +- [Node Version Manager](https://github.com/nvm-sh/nvm) (Official documentation) +- [Installing Node.js and npm for local WordPress development](https://learn.wordpress.org/tutorial/installing-node-js-and-npm-for-local-wordpress-development/) (Learn WordPress tutorial) \ No newline at end of file diff --git a/docs/getting-started/full-site-editing.md b/docs/getting-started/full-site-editing.md deleted file mode 100644 index ea24a659ab731c..00000000000000 --- a/docs/getting-started/full-site-editing.md +++ /dev/null @@ -1,58 +0,0 @@ -# Full Site Editing - -At the highest level, the vision of Full Site Editing is to provide a collection of features that bring the familiar experience and extendability of blocks to all parts of your site rather than just post and pages. You can think of Full Site Editing as the umbrella project name for various sub-projects within Gutenberg that make this vision possible. Projects under Full Site Editing (FSE) include everything from the Site Editor, Global Styles, numerous Site/Post/Page specific blocks, Query block, Navigation block, Templates, and block themes. What follows are brief descriptions of the major pieces with more details found [here](https://github.com/WordPress/gutenberg/issues/24551): - -- Site Editor: the cohesive experience that allows you to directly edit and navigate between various templates, template parts, styling options, and more. -- Template Editing: a scaled down direct editing experience allowing you to edit/change/create the template a post/page uses. -- Block Theme: work to allow for a theme that's built using templates composed using blocks that works with full site editing. More below. -- Styling: the feature that enables styling modifications across three levels (local blocks, theme defaults, and global modifications). -- Theme Blocks: new blocks that accomplish everything possible in traditional templates using template tags (ex: Post Author Block). -- Browsing: the feature that unlocks the ability to navigate between various entities in the site editing experience including templates, pages, etc. -- Navigation Block: a new block that allows you to edit a site's navigation menu, both in terms of structure and design. -- Query Block: a new block that replicates the classic WP_Query and allows for further customization with additional functionality. - -There are other projects, like the Navigation Editor and Widget Editor, that are meant to specifically help classic themes begin adapting more to the block framework and to act as a stepping stone of sorts to Full Site Editing. These are separate projects from Full Site Editing though but are worth being aware of as they ultimately help the cause of getting more people adjusted to using blocks in more places. - -**Jump in:** - -The best way to learn something is start playing with it. So jump in by installing the Gutenberg plugin from the plugins directory and activating a block theme on a test site. We recommend the [TT1 Blocks theme](https://wordpress.org/themes/tt1-blocks/), it is listed in the theme directory and our development reference theme. You can find other themes in the directory using the [full-site-editing feature tag](https://wordpress.org/themes/tags/full-site-editing/). - -## Get Involved - -An ongoing [FSE Outreach program](https://make.wordpress.org/test/handbook/full-site-editing-outreach-experiment/) is in place with calls for testing and is a great way to get involved and learn about the new features. - -- Join in on [WordPress Slack](https://make.wordpress.org/chat/) at [#fse-outreach-experiment](https://wordpress.slack.com/archives/C015GUFFC00) -- Participate in the [Calls for Testing](https://make.wordpress.org/test/tag/fse-testing-call/) by testing and giving feedback. -- See detailed [How to Test FSE instructions](https://make.wordpress.org/test/handbook/full-site-editing-outreach-experiment/how-to-test-fse/) to get setup to test FSE features. - -## Block Themes - -Block themes are themes built using templates composed using blocks. See the [block theme documentation](https://developer.wordpress.org/themes/block-themes/) for additional details. - -- For examples, see the [WordPress/theme-experiments](https://github.com/WordPress/theme-experiments/) repository with several block themes there including the source for the above mentioned TT1 Blocks. -- Use the `empty-theme.php` script from theme-experiments repo to generate a starter block theme, it will prompt you with a few questions and create a theme. - -``` -โฏ git clone https://github.com/WordPress/theme-experiments -โฏ cd theme-experiments -โฏ php new-empty-theme.php -Please provide the following information: -Theme name: TestTheme -Description: A theme to test -Author: Marcus Kazmierczak -Theme URI: https://github.com/mkaz - -Your new theme is ready! -``` - -You can then copy the generated directory to your `wp-content/themes` directory and start playing with the Site Editor to build and extend the theme. - -### Template and Template Parts - -See the [architecture document on templates](/docs/explanations/architecture/full-site-editing-templates.md) for an explanation on the internals of how templates and templates parts are rendered in the frontend and edited in the backend. - -### theme.json - -Instead of the proliferation of theme support flags or alternative methods, a new `theme.json` file is being used to define theme settings. - -See [documentation for theme.json](/docs/how-to-guides/themes/theme-json.md). diff --git a/docs/getting-started/outreach.md b/docs/getting-started/outreach.md deleted file mode 100644 index 9b51854f58926f..00000000000000 --- a/docs/getting-started/outreach.md +++ /dev/null @@ -1,87 +0,0 @@ -# Outreach - -This includes articles, talks, demos and anything the community is doing to discuss, learn about, and contribute to Gutenberg. This is not an exhaustive list; if we are missing your event or article, just let us know in the [#core-editor slack channel](https://make.wordpress.org/chat/). - -## Articles - -A short list of useful articles around defining, extending, and contributing to Gutenberg. - -### Overviews of Gutenberg - -- [Status Check: Site Editing & Customization](https://make.wordpress.org/core/2020/12/10/status-check-site-editing-and-customization/), Matรญas Ventura Bausero (December 2020) -- [Embrace the Modularity](https://riad.blog/2020/01/28/embrace-the-modularity/), Riad Benguella (January 2020) -- [The Language of Gutenberg](https://lamda.blog/2018/04/22/the-language-of-gutenberg/), Miguel Fonseca (April 2018) -- [Gutenberg, or the Ship of Theseus](https://matiasventura.com/post/gutenberg-or-the-ship-of-theseus/), Matรญas Ventura Bausero (October 2017) -- [We Called It Gutenberg for a Reason](https://ma.tt/2017/08/we-called-it-gutenberg-for-a-reason/), Matt Mullenweg (August 2017) -- [How Gutenberg is Changing WordPress Development](https://riad.blog/2017/10/06/how-gutenberg-is-changing-wordpress-development/), Riad Benguella (October 2017) -- [How Gutenberg Will Shape the Future of WordPress](https://www.linkedin.com/pulse/gutenberg-morten-rand-hendriksen/), Morten Rand-Henrikson (August 2017) - -You can view this [Index of Gutenberg related posts](https://make.wordpress.org/core/handbook/references/keeping-up-with-gutenberg-index/) for more information. - -### Extending Gutenberg - -- [How to Start Block Development with Scaffolding](https://gziolo.pl/2020/12/22/how-to-start-block-development-with-scaffolding/), Grzegorz Ziรณล‚kowski (December 2020) -- [Introducing BlockBook for WordPress](https://riad.blog/2020/07/22/introducing-blockbook-for-wordpress/), Riad Benguella (July 2020) -- [AsBlocks: an encrypted collaborative environment](https://riad.blog/2020/06/11/write-as-blocks-in-an-encrypted-collaborative-environment/), Riad Benguella (June 2020) -- [Thoughts on Themes](https://matiasventura.com/post/thoughts-on-themes/), Matรญas Ventura Bausero (April 2020) -- [Build a Block Series](https://mkaz.blog/code/build-a-block-series-1/), Marcus Kazmierczak (January 2020) -- [With Gutenberg, what happens to my Custom Fields?](https://riad.blog/2017/12/11/with-gutenberg-what-happens-to-my-custom-fields/), Riad Benguella (December 2017) -- [One thousand and one ways to extend Gutenberg today](https://riad.blog/2017/10/16/one-thousand-and-one-way-to-extend-gutenberg-today/), Riad Benguella (October 2017) -- [Gutenberg Plugin Boilerplate](https://github.com/ahmadawais/Gutenberg-Boilerplate/), Ahmad Awais (August 2017) - -### Community Contribution - -- [The WordPress block editor: a maintainerโ€™s story](https://riad.blog/2020/10/26/the-wordpress-block-editor-a-maintainers-story/), Riad Benguella (October 2020) -- [Good first issue on Gutenberg](https://mkaz.blog/code/good-first-issue-on-gutenberg/), Marcus Kazmierczak (August 2020) -- [How to Use the New WordPress Block Editor](https://www.codeinwp.com/blog/wordpress-gutenberg-guide/), Colin Newcomer (July 2020) -- [WordPress Gutenberg Developerโ€™s Guide](https://awhitepixel.com/guides/wordpress-gutenberg-developers-guide/), A White Pixel (2020) -- [Gutenberg Block Library](https://editorblockswp.com/library), Danny Cooper (August 2018) -- [A zero-configuration developer toolkit for building WordPress Gutenberg block plugins](https://ahmadawais.com/create-guten-block-toolkit/), Ahmad Awais (January 2018) -- [Contributing to Gutenberg Without Code](https://wordimpress.com/a-pot-stirrer-amongst-chefs-contributing-to-gutenberg-without-code/), Kevin Hoffman (August 2017) -- [Testing Flow in Gutenberg: Instructions for how to contribute to usability testing](https://make.wordpress.org/test/2017/11/22/testing-flow-in-gutenberg/), Anna Harrison (November 2017) - -### Article Compilations - -- [Full-Site-Editing: MVP and Ultimate Resource List](https://gutenbergtimes.com/full-site-editing/), Birgit Pauli-Haack (February 2021) -- [Theme Shaper posts about Block Themes](https://themeshaper.com/tag/block-based-themes/), various authors (2020-2021) -- [Gutenberg Times Updates](https://gutenbergtimes.com/category/updates/), Birgit Pauli-Haack -- [Curated Collection of Gutenberg Articles, Plugins, Blocks, Tutorials, etc](http://gutenberghub.com/), Munir Kamal -- [Gutenberg articles on ManageWP.org](https://managewp.org/search?q=gutenberg) - -## Talks - -Talks given about Gutenberg, including slides and videos as they are available. - -### Slides - -- [Growing JavaScript Skills with WordPress](https://gziolo.pl/2019/07/15/growing-javascript-skills-with-wordpress/) at JavaScript for WordPress conference (July 2019) -- [The new core WordPress editor](http://kimb.me/talk-bigwp-london-new-core-wordpress-editor/) at BigWP London (May 2017) -- [Gutenberg Notes](http://haiku2.com/2017/09/bend-wordpress-meetup-gutenberg-notes/) at Bend WordPress Meetup (September 2017) -- [Gutenberg and the Future of Content in WordPress](https://www.slideshare.net/andrewmduthie/gutenberg-and-the-future-of-content-in-wordpress) (September 2017) -- [Head first into Gutenberg](https://speakerdeck.com/prtksxna/head-first-into-gutenberg) at the [WordPress Goa Meet-up](https://www.meetup.com/WordPressGoa/events/245275573/) (December 2017) -- [Gutenberg : vers une approche plus fine du contenu](https://imathi.eu/2018/02/16/gutenberg-vers-une-approche-plus-fine-du-contenu/) at [WP Paris](https://wpparis.fr/) (February 2018) - -### Videos - -- [All `Gutenberg` tagged Talks at WordPress.tv](https://wordpress.tv/tag/gutenberg/) -- [Themes of the Future](https://wordpress.tv/2021/01/21/eileen-violini-themes-of-the-future-the-new-frontier-of-gutenberg-block-based-themes-and-theme-development/), Eileen Violini (January 2021) -- [Content Creation in WordPress using Gutenberg](https://wordpress.tv/2021/02/06/sayed-taqui-content-creation-in-wordpress-using-gutenberg/), - Sayed Taqui (January 2021) -- [Updates on WordPress Site-Editor (FSE) and Themes](https://www.youtube.com/watch?v=z-5OJq-OBjI&t), Gutenberg Times (January 2021) -- [State of the Word 2020 FSE Demo](https://youtu.be/QI3qCoiuG3w?t=1279), Matt Mullenweg (December 2020) -- [Full Site Editing! It's Coming, But Will Change How We Use WordPress?](https://www.youtube.com/watch?v=JHxsDSAImn0), WPCrafter.com (December 2020) -- [Advanced Layouts with the Block Editor](https://wordpress.tv/2020/12/06/advanced-layouts-with-the-block-editor/), Mel Choyce (December 2020) -- [State of the Word 2019 Gutenberg Demo](https://www.youtube.com/watch?v=LezbkeV059Q), Matt Mullenweg (December 2019) -- [Beyond Gutenberg](https://wordpress.tv/2018/07/09/matias-ventura-beyond-gutenberg/), Matรญas Ventura Bausero (July 2018) -- [Anatomy of a block: Gutenberg design patterns](https://wordpress.tv/2018/07/08/tammie-lister-anatomy-of-a-block-gutenberg-design-patterns/), Tammie Lister (July 2018) -- [State of the Word 2017 Gutenberg Demo](https://youtu.be/XOY3ZUO6P0k?t=2100), Matt Mullenweg with demo by Matรญas Ventura Bausero (December 2017) -- [Gutenberg is Coming (Donโ€™t Be Afraid)](https://training.ithemes.com/webinar/gutenberg-is-coming-dont-be-afraid/), iThemes Training (September 2017) - -## Learn WordPress Courses - -You can access all courses [here](https://learn.wordpress.org/). - -- [Intro to Block Development: Build Your First Custom Block](https://learn.wordpress.org/course/introduction-to-block-development-build-your-first-custom-block/), Jonathan Bossenger (2023) -- [Registering Block Patterns](https://learn.wordpress.org/workshop/registering-block-patterns/), Daisy Olsen (January 2021) -- [Intro to Gutenberg Block Development](https://learn.wordpress.org/workshop/intro-to-gutenberg-block-development/), Jonathan Bossenger (August 2020) -- [Intro to Publishing with the Block Editor](https://learn.wordpress.org/workshop/intro-to-publishing-with-the-block-editor/), Erica Varlese (August 2020) diff --git a/docs/how-to-guides/block-tutorial/writing-your-first-block-type.md b/docs/how-to-guides/block-tutorial/writing-your-first-block-type.md index 690a2f243f7050..b441a714a1c886 100644 --- a/docs/how-to-guides/block-tutorial/writing-your-first-block-type.md +++ b/docs/how-to-guides/block-tutorial/writing-your-first-block-type.md @@ -7,7 +7,7 @@ This guide takes you through creating a basic block to display a message in a po There are two main types of blocks: static and dynamic, this guide focuses on static blocks. A static block is used to insert HTML content into the post and save it with the post. A dynamic block builds the content on the fly when rendered on the front end, see the [dynamic blocks guide](/docs/how-to-guides/block-tutorial/creating-dynamic-blocks.md).
-This guide focuses on just the block, see the [Create a Block tutorial](/docs/getting-started/create-block/README.md) for a complete setup. +This guide focuses on just the block, see the Create a Block tutorial for a complete setup.
## Before you start diff --git a/docs/how-to-guides/themes/theme-json.md b/docs/how-to-guides/themes/theme-json.md index 418e076fa839a7..09264be194e894 100644 --- a/docs/how-to-guides/themes/theme-json.md +++ b/docs/how-to-guides/themes/theme-json.md @@ -968,7 +968,7 @@ You can use `ref: "styles.color.background"` to re-use the style for a block: ```JSON { "color": { - "text": { ref: "styles.color.background" } + "text": { "ref": "styles.color.background" } } } ``` diff --git a/docs/manifest.json b/docs/manifest.json index 75ae7d0b31f67d..338f2313e6ad18 100644 --- a/docs/manifest.json +++ b/docs/manifest.json @@ -12,15 +12,27 @@ "parent": null }, { - "title": "Development Environment", + "title": "Block Development Environment", "slug": "devenv", "markdown_source": "../docs/getting-started/devenv/README.md", "parent": "getting-started" }, { - "title": "How to setup local WordPress environment on Ubuntu", - "slug": "docker-ubuntu", - "markdown_source": "../docs/getting-started/devenv/docker-ubuntu.md", + "title": "Node.js development environment", + "slug": "nodejs-development-environment", + "markdown_source": "../docs/getting-started/devenv/nodejs-development-environment.md", + "parent": "devenv" + }, + { + "title": "Get started with wp-env", + "slug": "get-started-with-wp-env", + "markdown_source": "../docs/getting-started/devenv/get-started-with-wp-env.md", + "parent": "devenv" + }, + { + "title": "Get started with wp-now", + "slug": "get-started-with-wp-now", + "markdown_source": "../docs/getting-started/devenv/get-started-with-wp-now.md", "parent": "devenv" }, { @@ -71,18 +83,6 @@ "markdown_source": "../docs/getting-started/create-block/submitting-to-block-directory.md", "parent": "create-block" }, - { - "title": "Full Site Editing", - "slug": "full-site-editing", - "markdown_source": "../docs/getting-started/full-site-editing.md", - "parent": "getting-started" - }, - { - "title": "Outreach", - "slug": "outreach", - "markdown_source": "../docs/getting-started/outreach.md", - "parent": "getting-started" - }, { "title": "Glossary", "slug": "glossary", @@ -1919,6 +1919,12 @@ "markdown_source": "../packages/token-list/README.md", "parent": "packages" }, + { + "title": "@wordpress/undo-manager", + "slug": "packages-undo-manager", + "markdown_source": "../packages/undo-manager/README.md", + "parent": "packages" + }, { "title": "@wordpress/url", "slug": "packages-url", diff --git a/docs/reference-guides/block-api/block-attributes.md b/docs/reference-guides/block-api/block-attributes.md index eafc73c79938f3..0fbbeeb13680e6 100644 --- a/docs/reference-guides/block-api/block-attributes.md +++ b/docs/reference-guides/block-api/block-attributes.md @@ -305,39 +305,6 @@ Attribute available in the block: { "content": "The inner text of the figcaption element" } ``` -Use the `multiline` property to extract the inner HTML of matching tag names for the use in `RichText` with the `multiline` prop. - -_Example_: Extract the `content` attribute from a blockquote element found in the block's markup. - -Saved content: -```html -
- Block Content - -
-

First line

-

Second line

-
-
-``` - -Attribute definition: -```js -{ - content: { - type: 'string', - source: 'html', - multiline: 'p', - selector: 'blockquote', - } -} -``` - -Attribute available in the block: -```js -{ "content": "

First line

Second line

" } -``` - ### `query` source Use `query` to extract an array of values from markup. Entries of the array are determined by the `selector` argument, where each matched element within the block will have an entry structured corresponding to the second argument, an object of attribute sources. diff --git a/docs/reference-guides/block-api/block-metadata.md b/docs/reference-guides/block-api/block-metadata.md index ba24ff0f584011..22d9d66b4f4626 100644 --- a/docs/reference-guides/block-api/block-metadata.md +++ b/docs/reference-guides/block-api/block-metadata.md @@ -464,7 +464,7 @@ Plugins and Themes can also register [custom block style](/docs/reference-guides It provides structured example data for the block. This data is used to construct a preview for the block to be shown in the Inspector Help Panel when the user mouses over the block. -See the [the example documentation](/docs/reference-guides/block-api/block-registration.md#example-optional) for more details. +See the [Example documentation](/docs/reference-guides/block-api/block-registration.md#example-optional) for more details. ### Variations @@ -497,6 +497,25 @@ _Note: In JavaScript you can provide a function for the `isActive` property, and See the [the variations documentation](/docs/reference-guides/block-api/block-variations.md) for more details. +### Block Hooks + +- Type: `object` +- Optional +- Property: `blockHooks` +- Since: `WordPress 6.4.0` + +```json +{ + "blockHooks": { + "my-plugin/banner": "after" + } +} +``` + +Block Hooks is an API that allows a block to automatically insert itself next to all instances of a given block type, in a relative position also specified by the "hooked" block. That is, a block can opt to be inserted before or after a given block type, or as its first or last child (i.e. to be prepended or appended to the list of its child blocks, respectively). Hooked blocks will appear both on the frontend and in the editor (to allow for customization by the user). + +The key is the name of the block (`string`) to hook into, and the value is the position to hook into (`string`). Take a look at the [Block Hooks documentation](/docs/reference-guides/block-api/block-registration.md#block-hooks-optional) for more info about available configurations. + ### Editor Script - Type: `WPDefinedAsset`|`WPDefinedAsset[]` ([learn more](#wpdefinedasset)) diff --git a/docs/reference-guides/block-api/block-registration.md b/docs/reference-guides/block-api/block-registration.md index cecdb663e3d607..0fcaaa510b81a2 100644 --- a/docs/reference-guides/block-api/block-registration.md +++ b/docs/reference-guides/block-api/block-registration.md @@ -234,6 +234,7 @@ example: { #### variations (optional) - **Type:** `Object[]` +- **Since**: `WordPress 5.9.0` Similarly to how the block's styles can be declared, a block type can define block variations that the user can pick from. The difference is that, rather than changing only the visual appearance, this field provides a way to apply initial custom attributes and inner blocks at the time when a block is inserted. See the [Block Variations API](/docs/reference-guides/block-api/block-variations.md) for more details. @@ -265,6 +266,7 @@ parent: [ 'core/columns' ], #### ancestor (optional) - **Type:** `Array` +- **Since**: `WordPress 6.0.0` The `ancestor` property makes a block available inside the specified block types at any position of the ancestor block subtree. That allows, for example, to place a 'Comment Content' block inside a 'Column' block, as long as 'Column' is somewhere within a 'Comment Template' block. In comparison to the `parent` property blocks that specify their `ancestor` can be placed anywhere in the subtree whilst blocks with a specified `parent` need to be direct children. @@ -273,6 +275,35 @@ The `ancestor` property makes a block available inside the specified block types ancestor: [ 'core/columns' ], ``` +#### Block Hooks (optional) + +- **Type:** `Object` +- **Since**: `WordPress 6.4.0` + +Block Hooks is an API that allows a block to automatically insert itself next to all instances of a given block type, in a relative position also specified by the "hooked" block. That is, a block can opt to be inserted before or after a given block type, or as its first or last child (i.e. to be prepended or appended to the list of its child blocks, respectively). Hooked blocks will appear both on the frontend and in the editor (to allow for customization by the user). + +The key is the name of the block (`string`) to hook into, and the value is the position to hook into (`string`). Allowed target values are: + +- `before` โ€“ inject before the target block. +- `after` - inject after the target block. +- `firstChild` - inject before the first inner block of the target container block. +- `lastChild` - inject after the last inner block of the target container block. + +```js +{ + blockHooks: { + 'core/verse': 'before' + 'core/spacer': 'after', + 'core/column': 'firstChild', + 'core/group': 'lastChild', + } +} +``` + +Itโ€™s crucial to emphasize that the Block Hooks feature is only designed to work with _static_ block-based templates, template parts, and patterns. For patterns, this includes those provided by the theme, from [Block Pattern Directory](https://wordpress.org/patterns/), or from calls to [`register_block_pattern`](https://developer.wordpress.org/reference/functions/register_block_pattern/). + +Block Hooks will not work with post content or patterns crafted by the user, such as synced patterns, or theme templates and template parts that have been modified by the user. + ## Block Collections ## `registerBlockCollection` diff --git a/docs/reference-guides/core-blocks.md b/docs/reference-guides/core-blocks.md index e15f321b7b4204..f92e2d94751dc4 100644 --- a/docs/reference-guides/core-blocks.md +++ b/docs/reference-guides/core-blocks.md @@ -2,10 +2,9 @@ This page lists the blocks included in the block-library package. -- Items marked with a strikeout (~~strikeout~~) are explicitly disabled. -- Blocks marked with **Experimental:** true are only available when Gutenberg is active. -- Blocks marked with **Experimental:** fse are only available in the Site Editor. - +- Items marked with a strikeout (~~strikeout~~) are explicitly disabled. +- Blocks marked with **Experimental:** true are only available when Gutenberg is active. +- Blocks marked with **Experimental:** fse are only available in the Site Editor. @@ -240,7 +239,7 @@ Add an image or video with a text overlay. ([Source](https://github.com/WordPres - **Name:** core/cover - **Category:** media - **Supports:** align, anchor, color (heading, text, ~~background~~, ~~enableContrastChecker~~), layout (~~allowJustification~~), spacing (blockGap, margin, padding), typography (fontSize, lineHeight), ~~html~~ -- **Attributes:** allowedBlocks, alt, backgroundType, contentPosition, customGradient, customOverlayColor, dimRatio, focalPoint, gradient, hasParallax, id, isDark, isRepeated, minHeight, minHeightUnit, overlayColor, tagName, templateLock, url, useFeaturedImage +- **Attributes:** allowedBlocks, alt, backgroundType, contentPosition, customGradient, customOverlayColor, dimRatio, focalPoint, gradient, hasParallax, id, isDark, isRepeated, isUserOverlayColor, minHeight, minHeightUnit, overlayColor, tagName, templateLock, url, useFeaturedImage ## Details @@ -311,7 +310,7 @@ Introduce new sections and organize content to help visitors (and search engines - **Name:** core/heading - **Category:** text -- **Supports:** align (full, wide), anchor, className, color (background, gradients, link, text), spacing (margin, padding), typography (fontSize, lineHeight) +- **Supports:** __unstablePasteTextInline, align (full, wide), anchor, className, color (background, gradients, link, text), spacing (margin, padding), typography (fontSize, lineHeight) - **Attributes:** content, level, placeholder, textAlign ## Home Link @@ -339,8 +338,8 @@ Insert an image to make a visual statement. ([Source](https://github.com/WordPre - **Name:** core/image - **Category:** media -- **Supports:** anchor, behaviors (lightbox), color (~~background~~, ~~text~~), filter (duotone) -- **Attributes:** align, alt, aspectRatio, caption, height, href, id, linkClass, linkDestination, linkTarget, rel, scale, sizeSlug, title, url, width +- **Supports:** anchor, color (~~background~~, ~~text~~), filter (duotone) +- **Attributes:** align, alt, aspectRatio, caption, height, href, id, lightbox, linkClass, linkDestination, linkTarget, rel, scale, sizeSlug, title, url, width ## Latest Comments @@ -421,7 +420,7 @@ A collection of blocks that allow visitors to get around your site. ([Source](ht - **Name:** core/navigation - **Category:** theme -- **Supports:** align (full, wide), inserter, interactivity, layout (allowSizingOnChildren, default, ~~allowInheriting~~, ~~allowSwitching~~, ~~allowVerticalAlignment~~), spacing (blockGap, units), typography (fontSize, lineHeight), ~~html~~ +- **Supports:** align (full, wide), ariaLabel, inserter, interactivity, layout (allowSizingOnChildren, default, ~~allowInheriting~~, ~~allowSwitching~~, ~~allowVerticalAlignment~~), spacing (blockGap, units), typography (fontSize, lineHeight), ~~html~~ - **Attributes:** __unstableLocation, backgroundColor, customBackgroundColor, customOverlayBackgroundColor, customOverlayTextColor, customTextColor, hasIcon, icon, maxNestingLevel, openSubmenusOnClick, overlayBackgroundColor, overlayMenu, overlayTextColor, ref, rgbBackgroundColor, rgbTextColor, showSubmenuIcon, templateLock, textColor ## Custom Link @@ -563,7 +562,7 @@ Displays the contents of a post or page. ([Source](https://github.com/WordPress/ - **Name:** core/post-content - **Category:** theme -- **Supports:** align (full, wide), color (background, gradients, link, text), dimensions (minHeight), layout, typography (fontSize, lineHeight), ~~html~~ +- **Supports:** align (full, wide), color (background, gradients, link, text), dimensions (minHeight), layout, spacing (blockGap), typography (fontSize, lineHeight), ~~html~~ - **Attributes:** ## Date @@ -759,7 +758,7 @@ Help visitors find your content. ([Source](https://github.com/WordPress/gutenber - **Name:** core/search - **Category:** widgets -- **Supports:** align (center, left, right), color (background, gradients, text), typography (fontSize, lineHeight), ~~html~~ +- **Supports:** align (center, left, right), color (background, gradients, text), interactivity, typography (fontSize, lineHeight), ~~html~~ - **Attributes:** buttonBehavior, buttonPosition, buttonText, buttonUseIcon, isSearchFieldHidden, label, placeholder, query, showLabel, width, widthUnit ## Separator diff --git a/docs/reference-guides/data/data-core-block-editor.md b/docs/reference-guides/data/data-core-block-editor.md index 025b4eaf15ab8f..7b0bd386daaf48 100644 --- a/docs/reference-guides/data/data-core-block-editor.md +++ b/docs/reference-guides/data/data-core-block-editor.md @@ -473,11 +473,11 @@ Returns an array containing the clientIds of all descendants of the blocks given _Parameters_ - _state_ `Object`: Global application state. -- _clientIds_ `Array`: Array of blocks to inspect. +- _clientIds_ `string|string[]`: Client ID(s) for which descendant blocks are to be returned. _Returns_ -- `Array`: ids of descendants. +- `Array`: Client IDs of descendants. ### getClientIdsWithDescendants diff --git a/docs/reference-guides/data/data-core-edit-site.md b/docs/reference-guides/data/data-core-edit-site.md index 0cac2268b2ab29..6dea8e9b77d1b2 100644 --- a/docs/reference-guides/data/data-core-edit-site.md +++ b/docs/reference-guides/data/data-core-edit-site.md @@ -291,7 +291,7 @@ _Parameters_ _Returns_ -- `number`: The resolved template ID for the page route. +- `Object`: Action object. ### setHasPageContentFocus diff --git a/docs/reference-guides/data/data-core.md b/docs/reference-guides/data/data-core.md index f2bc3374f9e721..acaaa5f23f1b98 100644 --- a/docs/reference-guides/data/data-core.md +++ b/docs/reference-guides/data/data-core.md @@ -371,7 +371,7 @@ _Usage_ _Parameters_ -- _state_ `State`: Editor state. +- _state_ Editor state. _Returns_ @@ -403,6 +403,18 @@ _Returns_ - `Optional< any >`: The edit. +### getUserPatternCategories + +Retrieve the registered user pattern categories. + +_Parameters_ + +- _state_ `State`: Data state. + +_Returns_ + +- `Array< UserPatternCategory >`: User patterns category array. + ### getUserQueryResults Returns all the users returned by a query ID. diff --git a/docs/reference-guides/theme-json-reference/theme-json-living.md b/docs/reference-guides/theme-json-reference/theme-json-living.md index ba80addbd1f65a..4890386ca8333e 100644 --- a/docs/reference-guides/theme-json-reference/theme-json-living.md +++ b/docs/reference-guides/theme-json-reference/theme-json-living.md @@ -130,6 +130,17 @@ Settings related to layout. --- +### lightbox + +Settings related to the lightbox. + +| Property | Type | Default | Props | +| --- | --- | --- |--- | +| enabled | boolean | | | +| allowEditing | boolean | | | + +--- + ### position Settings related to position. @@ -183,16 +194,6 @@ Settings related to typography. Generate custom CSS custom properties of the form `--wp--custom--{key}--{nested-key}: {value};`. `camelCased` keys are transformed to `kebab-case` as to follow the CSS property naming schema. Keys at different depth levels are separated by `--`, so keys should not include `--` in the name. ---- - -### behaviors - -Settings related to behaviors. - -| Property | Type | Default | Props | -| --- | --- | --- |--- | -| lightbox | boolean | false | | - --- ## Styles diff --git a/docs/toc.json b/docs/toc.json index 233967098f1656..621fd7c48c7c9f 100644 --- a/docs/toc.json +++ b/docs/toc.json @@ -7,7 +7,13 @@ { "docs/getting-started/devenv/README.md": [ { - "docs/getting-started/devenv/docker-ubuntu.md": [] + "docs/getting-started/devenv/nodejs-development-environment.md": [] + }, + { + "docs/getting-started/devenv/get-started-with-wp-env.md": [] + }, + { + "docs/getting-started/devenv/get-started-with-wp-now.md": [] } ] }, @@ -36,8 +42,6 @@ } ] }, - { "docs/getting-started/full-site-editing.md": [] }, - { "docs/getting-started/outreach.md": [] }, { "docs/getting-started/glossary.md": [] }, { "docs/getting-started/faq.md": [] } ] diff --git a/gutenberg.php b/gutenberg.php index e9624e481e60f2..632f52eb5aa754 100644 --- a/gutenberg.php +++ b/gutenberg.php @@ -5,7 +5,7 @@ * Description: Printing since 1440. This is the development plugin for the block editor, site editor, and other future WordPress core functionality. * Requires at least: 6.2 * Requires PHP: 7.0 - * Version: 16.6.0 + * Version: 16.7.0-rc.2 * Author: Gutenberg Team * Text Domain: gutenberg * diff --git a/lib/block-supports/background.php b/lib/block-supports/background.php index 08a9c012a31458..bf5945312348b9 100644 --- a/lib/block-supports/background.php +++ b/lib/block-supports/background.php @@ -51,9 +51,9 @@ function gutenberg_render_background_support( $block_content, $block ) { return $block_content; } - $background_image_source = _wp_array_get( $block_attributes, array( 'style', 'background', 'backgroundImage', 'source' ), null ); - $background_image_url = _wp_array_get( $block_attributes, array( 'style', 'background', 'backgroundImage', 'url' ), null ); - $background_size = _wp_array_get( $block_attributes, array( 'style', 'background', 'backgroundSize' ), 'cover' ); + $background_image_source = $block_attributes['style']['background']['backgroundImage']['source'] ?? null; + $background_image_url = $block_attributes['style']['background']['backgroundImage']['url'] ?? null; + $background_size = $block_attributes['style']['background']['backgroundSize'] ?? 'cover'; $background_block_styles = array(); @@ -78,8 +78,11 @@ function gutenberg_render_background_support( $block_content, $block ) { $existing_style = $tags->get_attribute( 'style' ); $updated_style = ''; - if ( ! empty( $existing_style ) && ! str_ends_with( $existing_style, ';' ) ) { - $updated_style = $existing_style . '; '; + if ( ! empty( $existing_style ) ) { + $updated_style = $existing_style; + if ( ! str_ends_with( $existing_style, ';' ) ) { + $updated_style .= ';'; + } } $updated_style .= $styles['css']; diff --git a/lib/block-supports/behaviors.php b/lib/block-supports/behaviors.php index b6692195eb5fb5..cf668ed22d8875 100644 --- a/lib/block-supports/behaviors.php +++ b/lib/block-supports/behaviors.php @@ -2,6 +2,10 @@ /** * Behaviors block support flag. * + * This file will NOT be backported to Core. It exists to provide a + * migration path for theme.json files that used the deprecated "behaviors". + * This file will be removed from Gutenberg in version 17.0.0. + * * @package gutenberg */ @@ -37,13 +41,23 @@ function gutenberg_register_behaviors_support( $block_type ) { /** * Add the directives and layout needed for the lightbox behavior. - * This functions shouldn't be in this file. It should be moved to a package (or somewhere else), where all the behaviors logic is defined. * * @param string $block_content Rendered block content. * @param array $block Block object. * @return string Filtered block content. */ function gutenberg_render_behaviors_support_lightbox( $block_content, $block ) { + + // We've deprecated the lightbox implementation via behaviors. + // While we may continue to explore behaviors in the future, the lightbox + // logic seems very specific to the image and will likely never be a part + // of behaviors, even in the future. With that in mind, we've rewritten the lightbox + // to be a feature of the image block and will also soon remove the block_supports. + // *Note: This logic for generating the lightbox markup has been duplicated and moved + // to the image block's index.php.* + // See https://github.com/WordPress/gutenberg/issues/53403. + _deprecated_function( 'gutenberg_render_behaviors_support_lightbox', 'Gutenberg 17.0.0', '' ); + $link_destination = isset( $block['attrs']['linkDestination'] ) ? $block['attrs']['linkDestination'] : 'none'; // Get the lightbox setting from the block attributes. if ( isset( $block['attrs']['behaviors']['lightbox'] ) ) { diff --git a/lib/block-supports/border.php b/lib/block-supports/border.php index 486f6d99b64890..1a54371d082e17 100644 --- a/lib/block-supports/border.php +++ b/lib/block-supports/border.php @@ -94,14 +94,14 @@ function gutenberg_apply_border_support( $block_type, $block_attributes ) { ! wp_should_skip_block_supports_serialization( $block_type, '__experimentalBorder', 'color' ) ) { $preset_border_color = array_key_exists( 'borderColor', $block_attributes ) ? "var:preset|color|{$block_attributes['borderColor']}" : null; - $custom_border_color = _wp_array_get( $block_attributes, array( 'style', 'border', 'color' ), null ); + $custom_border_color = $block_attributes['style']['border']['color'] ?? null; $border_block_styles['color'] = $preset_border_color ? $preset_border_color : $custom_border_color; } // Generate styles for individual border sides. if ( $has_border_color_support || $has_border_width_support ) { foreach ( array( 'top', 'right', 'bottom', 'left' ) as $side ) { - $border = _wp_array_get( $block_attributes, array( 'style', 'border', $side ), null ); + $border = $block_attributes['style']['border'][ $side ] ?? null; $border_side_values = array( 'width' => isset( $border['width'] ) && ! wp_should_skip_block_supports_serialization( $block_type, '__experimentalBorder', 'width' ) ? $border['width'] : null, 'color' => isset( $border['color'] ) && ! wp_should_skip_block_supports_serialization( $block_type, '__experimentalBorder', 'color' ) ? $border['color'] : null, @@ -134,24 +134,24 @@ function gutenberg_apply_border_support( $block_type, $block_attributes ) { * flag nested under `experimentalBorder` must be enabled for the feature * to be opted into. * - * @param WP_Block_Type $block_type Block type to check for support. - * @param string $feature Name of the feature to check support for. - * @param mixed $default Fallback value for feature support, defaults to false. + * @param WP_Block_Type $block_type Block type to check for support. + * @param string $feature Name of the feature to check support for. + * @param mixed $default_value Fallback value for feature support, defaults to false. * * @return boolean Whether or not the feature is supported. */ -function gutenberg_has_border_feature_support( $block_type, $feature, $default = false ) { +function gutenberg_has_border_feature_support( $block_type, $feature, $default_value = false ) { // Check if all border support features have been opted into via `"__experimentalBorder": true`. - if ( - property_exists( $block_type, 'supports' ) && - ( true === _wp_array_get( $block_type->supports, array( '__experimentalBorder' ), $default ) ) - ) { - return true; + if ( property_exists( $block_type, 'supports' ) ) { + $block_type_supports_border = $block_type->supports['__experimentalBorder'] ?? $default_value; + if ( true === $block_type_supports_border ) { + return true; + } } // Check if the specific feature has been opted into individually // via nested flag under `__experimentalBorder`. - return block_has_support( $block_type, array( '__experimentalBorder', $feature ), $default ); + return block_has_support( $block_type, array( '__experimentalBorder', $feature ), $default_value ); } // Register the block support. diff --git a/lib/block-supports/colors.php b/lib/block-supports/colors.php index 88e13abfc9cc9b..6919f58c067e4a 100644 --- a/lib/block-supports/colors.php +++ b/lib/block-supports/colors.php @@ -11,13 +11,20 @@ * @param WP_Block_Type $block_type Block Type. */ function gutenberg_register_colors_support( $block_type ) { - $color_support = property_exists( $block_type, 'supports' ) ? _wp_array_get( $block_type->supports, array( 'color' ), false ) : false; - $has_text_colors_support = true === $color_support || ( is_array( $color_support ) && _wp_array_get( $color_support, array( 'text' ), true ) ); - $has_background_colors_support = true === $color_support || ( is_array( $color_support ) && _wp_array_get( $color_support, array( 'background' ), true ) ); - $has_gradients_support = _wp_array_get( $color_support, array( 'gradients' ), false ); - $has_link_colors_support = _wp_array_get( $color_support, array( 'link' ), false ); - $has_button_colors_support = _wp_array_get( $color_support, array( 'button' ), false ); - $has_heading_colors_support = _wp_array_get( $color_support, array( 'heading' ), false ); + $color_support = false; + if ( property_exists( $block_type, 'supports' ) ) { + $color_support = $block_type->supports['color'] ?? false; + } + $has_text_colors_support = true === $color_support || + ( isset( $color_support['text'] ) && $color_support['text'] ) || + ( is_array( $color_support ) && ! isset( $color_support['text'] ) ); + $has_background_colors_support = true === $color_support || + ( isset( $color_support['background'] ) && $color_support['background'] ) || + ( is_array( $color_support ) && ! isset( $color_support['background'] ) ); + $has_gradients_support = $color_support['gradients'] ?? false; + $has_link_colors_support = $color_support['link'] ?? false; + $has_button_colors_support = $color_support['button'] ?? false; + $has_heading_colors_support = $color_support['heading'] ?? false; $has_color_support = $has_text_colors_support || $has_background_colors_support || $has_gradients_support || @@ -65,7 +72,7 @@ function gutenberg_register_colors_support( $block_type ) { * @return array Colors CSS classes and inline styles. */ function gutenberg_apply_colors_support( $block_type, $block_attributes ) { - $color_support = _wp_array_get( $block_type->supports, array( 'color' ), false ); + $color_support = $block_type->supports['color'] ?? false; if ( is_array( $color_support ) && @@ -74,23 +81,27 @@ function gutenberg_apply_colors_support( $block_type, $block_attributes ) { return array(); } - $has_text_colors_support = true === $color_support || ( is_array( $color_support ) && _wp_array_get( $color_support, array( 'text' ), true ) ); - $has_background_colors_support = true === $color_support || ( is_array( $color_support ) && _wp_array_get( $color_support, array( 'background' ), true ) ); - $has_gradients_support = _wp_array_get( $color_support, array( 'gradients' ), false ); + $has_text_colors_support = true === $color_support || + ( isset( $color_support['text'] ) && $color_support['text'] ) || + ( is_array( $color_support ) && ! isset( $color_support['text'] ) ); + $has_background_colors_support = true === $color_support || + ( isset( $color_support['background'] ) && $color_support['background'] ) || + ( is_array( $color_support ) && ! isset( $color_support['background'] ) ); + $has_gradients_support = $color_support['gradients'] ?? false; $color_block_styles = array(); // Text colors. // Check support for text colors. if ( $has_text_colors_support && ! wp_should_skip_block_supports_serialization( $block_type, 'color', 'text' ) ) { $preset_text_color = array_key_exists( 'textColor', $block_attributes ) ? "var:preset|color|{$block_attributes['textColor']}" : null; - $custom_text_color = _wp_array_get( $block_attributes, array( 'style', 'color', 'text' ), null ); + $custom_text_color = $block_attributes['style']['color']['text'] ?? null; $color_block_styles['text'] = $preset_text_color ? $preset_text_color : $custom_text_color; } // Background colors. if ( $has_background_colors_support && ! wp_should_skip_block_supports_serialization( $block_type, 'color', 'background' ) ) { $preset_background_color = array_key_exists( 'backgroundColor', $block_attributes ) ? "var:preset|color|{$block_attributes['backgroundColor']}" : null; - $custom_background_color = _wp_array_get( $block_attributes, array( 'style', 'color', 'background' ), null ); + $custom_background_color = $block_attributes['style']['color']['background'] ?? null; $color_block_styles['background'] = $preset_background_color ? $preset_background_color : $custom_background_color; } @@ -98,7 +109,7 @@ function gutenberg_apply_colors_support( $block_type, $block_attributes ) { if ( $has_gradients_support && ! wp_should_skip_block_supports_serialization( $block_type, 'color', 'gradients' ) ) { $preset_gradient_color = array_key_exists( 'gradient', $block_attributes ) ? "var:preset|gradient|{$block_attributes['gradient']}" : null; - $custom_gradient_color = _wp_array_get( $block_attributes, array( 'style', 'color', 'gradient' ), null ); + $custom_gradient_color = $block_attributes['style']['color']['gradient'] ?? null; $color_block_styles['gradient'] = $preset_gradient_color ? $preset_gradient_color : $custom_gradient_color; } diff --git a/lib/block-supports/dimensions.php b/lib/block-supports/dimensions.php index d4d15cd609e63e..1ef43133c2cdfb 100644 --- a/lib/block-supports/dimensions.php +++ b/lib/block-supports/dimensions.php @@ -61,8 +61,11 @@ function gutenberg_apply_dimensions_support( $block_type, $block_attributes ) { $skip_min_height = wp_should_skip_block_supports_serialization( $block_type, 'dimensions', 'minHeight' ); $dimensions_block_styles = array(); - $dimensions_block_styles['minHeight'] = $has_min_height_support && ! $skip_min_height ? _wp_array_get( $block_styles, array( 'dimensions', 'minHeight' ), null ) : null; - $styles = gutenberg_style_engine_get_styles( array( 'dimensions' => $dimensions_block_styles ) ); + $dimensions_block_styles['minHeight'] = null; + if ( $has_min_height_support && ! $skip_min_height ) { + $dimensions_block_styles['minHeight'] = $block_styles['dimensions']['minHeight'] ?? null; + } + $styles = gutenberg_style_engine_get_styles( array( 'dimensions' => $dimensions_block_styles ) ); if ( ! empty( $styles['css'] ) ) { $attributes['style'] = $styles['css']; diff --git a/lib/block-supports/elements.php b/lib/block-supports/elements.php index 328d371c3e4fd8..2106360c4bd047 100644 --- a/lib/block-supports/elements.php +++ b/lib/block-supports/elements.php @@ -80,7 +80,7 @@ function gutenberg_render_elements_support( $block_content, $block ) { foreach ( $element_config['paths'] as $path ) { if ( null !== _wp_array_get( $block['attrs'], explode( '.', $path ), null ) ) { - $element_colors_set++; + ++$element_colors_set; } } } diff --git a/lib/block-supports/layout.php b/lib/block-supports/layout.php index 0cf501028efd88..0fe217cf832702 100644 --- a/lib/block-supports/layout.php +++ b/lib/block-supports/layout.php @@ -222,7 +222,7 @@ function gutenberg_register_layout_support( $block_type ) { * @return string CSS styles on success. Else, empty string. */ function gutenberg_get_layout_style( $selector, $layout, $has_block_gap_support = false, $gap_value = null, $should_skip_gap_serialization = false, $fallback_gap_value = '0.5em', $block_spacing = null ) { - $layout_type = isset( $layout['type'] ) ? $layout['type'] : 'default'; + $layout_type = $layout['type'] ?? 'default'; $layout_styles = array(); if ( 'default' === $layout_type ) { @@ -401,7 +401,10 @@ function gutenberg_get_layout_style( $selector, $layout, $has_block_gap_support $gap_sides = is_array( $gap_value ) ? array( 'top', 'left' ) : array( 'top' ); foreach ( $gap_sides as $gap_side ) { - $process_value = is_string( $gap_value ) ? $gap_value : _wp_array_get( $gap_value, array( $gap_side ), $fallback_gap_value ); + $process_value = $gap_value; + if ( is_array( $gap_value ) ) { + $process_value = $gap_value[ $gap_side ] ?? $fallback_gap_value; + } // Get spacing CSS variable from preset value if provided. if ( is_string( $process_value ) && str_contains( $process_value, 'var:preset|spacing|' ) ) { $index_to_splice = strrpos( $process_value, '|' ) + 1; @@ -482,7 +485,10 @@ function gutenberg_get_layout_style( $selector, $layout, $has_block_gap_support $gap_sides = is_array( $gap_value ) ? array( 'top', 'left' ) : array( 'top' ); foreach ( $gap_sides as $gap_side ) { - $process_value = is_string( $gap_value ) ? $gap_value : _wp_array_get( $gap_value, array( $gap_side ), $fallback_gap_value ); + $process_value = $gap_value; + if ( is_array( $gap_value ) ) { + $process_value = $gap_value[ $gap_side ] ?? $fallback_gap_value; + } // Get spacing CSS variable from preset value if provided. if ( is_string( $process_value ) && str_contains( $process_value, 'var:preset|spacing|' ) ) { $index_to_splice = strrpos( $process_value, '|' ) + 1; @@ -594,8 +600,11 @@ function gutenberg_render_layout_support_flag( $block_content, $block ) { } $global_settings = gutenberg_get_global_settings(); - $fallback_layout = ! empty( _wp_array_get( $block_type->supports, array( 'layout', 'default' ), array() ) ) ? _wp_array_get( $block_type->supports, array( 'layout', 'default' ), array() ) : _wp_array_get( $block_type->supports, array( '__experimentalLayout', 'default' ), array() ); - $used_layout = isset( $block['attrs']['layout'] ) ? $block['attrs']['layout'] : $fallback_layout; + $fallback_layout = $block_type->supports['layout']['default'] ?? array(); + if ( empty( $fallback_layout ) ) { + $fallback_layout = $block_type->supports['__experimentalLayout']['default'] ?? array(); + } + $used_layout = $block['attrs']['layout'] ?? $fallback_layout; $class_names = array(); $layout_definitions = gutenberg_get_layout_definitions(); @@ -606,7 +615,7 @@ function gutenberg_render_layout_support_flag( $block_content, $block ) { $used_layout['type'] = 'constrained'; } - $root_padding_aware_alignments = _wp_array_get( $global_settings, array( 'useRootPaddingAwareAlignments' ), false ); + $root_padding_aware_alignments = $global_settings['useRootPaddingAwareAlignments'] ?? false; if ( $root_padding_aware_alignments && isset( $used_layout['type'] ) && 'constrained' === $used_layout['type'] ) { $class_names[] = 'has-global-padding'; @@ -632,9 +641,9 @@ function gutenberg_render_layout_support_flag( $block_content, $block ) { // Get classname for layout type. if ( isset( $used_layout['type'] ) ) { - $layout_classname = _wp_array_get( $layout_definitions, array( $used_layout['type'], 'className' ), '' ); + $layout_classname = $layout_definitions[ $used_layout['type'] ]['className'] ?? ''; } else { - $layout_classname = _wp_array_get( $layout_definitions, array( 'default', 'className' ), '' ); + $layout_classname = $layout_definitions['default']['className'] ?? ''; } if ( $layout_classname && is_string( $layout_classname ) ) { @@ -647,7 +656,7 @@ function gutenberg_render_layout_support_flag( $block_content, $block ) { */ if ( ! current_theme_supports( 'disable-layout-styles' ) ) { - $gap_value = _wp_array_get( $block, array( 'attrs', 'style', 'spacing', 'blockGap' ) ); + $gap_value = $block['attrs']['style']['spacing']['blockGap'] ?? null; /* * Skip if gap value contains unsupported characters. @@ -662,8 +671,8 @@ function gutenberg_render_layout_support_flag( $block_content, $block ) { $gap_value = $gap_value && preg_match( '%[\\\(&=}]|/\*%', $gap_value ) ? null : $gap_value; } - $fallback_gap_value = _wp_array_get( $block_type->supports, array( 'spacing', 'blockGap', '__experimentalDefault' ), '0.5em' ); - $block_spacing = _wp_array_get( $block, array( 'attrs', 'style', 'spacing' ), null ); + $fallback_gap_value = $block_type->supports['spacing']['blockGap']['__experimentalDefault'] ?? '0.5em'; + $block_spacing = $block['attrs']['style']['spacing'] ?? null; /* * If a block's block.json skips serialization for spacing or spacing.blockGap, @@ -671,7 +680,7 @@ function gutenberg_render_layout_support_flag( $block_content, $block ) { */ $should_skip_gap_serialization = wp_should_skip_block_supports_serialization( $block_type, 'spacing', 'blockGap' ); - $block_gap = _wp_array_get( $global_settings, array( 'spacing', 'blockGap' ), null ); + $block_gap = $global_settings['spacing']['blockGap'] ?? null; $has_block_gap_support = isset( $block_gap ); $style = gutenberg_get_layout_style( @@ -833,7 +842,7 @@ function gutenberg_restore_group_inner_container( $block_content, $block ) { ); $updated_content = preg_replace_callback( $replace_regex, - static function( $matches ) { + static function ( $matches ) { return $matches[1] . '
' . $matches[2] . '
' . $matches[3]; }, $block_content diff --git a/lib/block-supports/position.php b/lib/block-supports/position.php index 62a51c486362e7..930e726d123211 100644 --- a/lib/block-supports/position.php +++ b/lib/block-supports/position.php @@ -44,8 +44,8 @@ function gutenberg_render_position_support( $block_content, $block ) { } $global_settings = gutenberg_get_global_settings(); - $theme_has_sticky_support = _wp_array_get( $global_settings, array( 'position', 'sticky' ), false ); - $theme_has_fixed_support = _wp_array_get( $global_settings, array( 'position', 'fixed' ), false ); + $theme_has_sticky_support = $global_settings['position']['sticky'] ?? false; + $theme_has_fixed_support = $global_settings['position']['fixed'] ?? false; // Only allow output for position types that the theme supports. $allowed_position_types = array(); @@ -56,11 +56,11 @@ function gutenberg_render_position_support( $block_content, $block ) { $allowed_position_types[] = 'fixed'; } - $style_attribute = _wp_array_get( $block, array( 'attrs', 'style' ), null ); + $style_attribute = $block['attrs']['style'] ?? null; $class_name = wp_unique_id( 'wp-container-' ); $selector = ".$class_name"; $position_styles = array(); - $position_type = _wp_array_get( $style_attribute, array( 'position', 'type' ), '' ); + $position_type = $style_attribute['position']['type'] ?? ''; $wrapper_classes = array(); if ( @@ -71,7 +71,7 @@ function gutenberg_render_position_support( $block_content, $block ) { $sides = array( 'top', 'right', 'bottom', 'left' ); foreach ( $sides as $side ) { - $side_value = _wp_array_get( $style_attribute, array( 'position', $side ) ); + $side_value = $style_attribute['position'][ $side ] ?? null; if ( null !== $side_value ) { /* * For fixed or sticky top positions, diff --git a/lib/block-supports/settings.php b/lib/block-supports/settings.php index aac4774b62fe8e..b175fe778ce1b0 100644 --- a/lib/block-supports/settings.php +++ b/lib/block-supports/settings.php @@ -26,7 +26,7 @@ function _gutenberg_add_block_level_presets_class( $block_content, $block ) { } // return early if no settings are found on the block attributes. - $block_settings = _wp_array_get( $block, array( 'attrs', 'settings' ), null ); + $block_settings = $block['attrs']['settings'] ?? null; if ( empty( $block_settings ) ) { return $block_content; } @@ -59,7 +59,7 @@ function _gutenberg_add_block_level_preset_styles( $pre_render, $block ) { } // return early if no settings are found on the block attributes. - $block_settings = _wp_array_get( $block, array( 'attrs', 'settings' ), null ); + $block_settings = $block['attrs']['settings'] ?? null; if ( empty( $block_settings ) ) { return null; } diff --git a/lib/block-supports/spacing.php b/lib/block-supports/spacing.php index e78fac6d62419d..86e6c750185a56 100644 --- a/lib/block-supports/spacing.php +++ b/lib/block-supports/spacing.php @@ -52,12 +52,19 @@ function gutenberg_apply_spacing_support( $block_type, $block_attributes ) { return $attributes; } - $skip_padding = wp_should_skip_block_supports_serialization( $block_type, 'spacing', 'padding' ); - $skip_margin = wp_should_skip_block_supports_serialization( $block_type, 'spacing', 'margin' ); - $spacing_block_styles = array(); - $spacing_block_styles['padding'] = $has_padding_support && ! $skip_padding ? _wp_array_get( $block_styles, array( 'spacing', 'padding' ), null ) : null; - $spacing_block_styles['margin'] = $has_margin_support && ! $skip_margin ? _wp_array_get( $block_styles, array( 'spacing', 'margin' ), null ) : null; - $styles = gutenberg_style_engine_get_styles( array( 'spacing' => $spacing_block_styles ) ); + $skip_padding = wp_should_skip_block_supports_serialization( $block_type, 'spacing', 'padding' ); + $skip_margin = wp_should_skip_block_supports_serialization( $block_type, 'spacing', 'margin' ); + $spacing_block_styles = array( + 'padding' => null, + 'margin' => null, + ); + if ( $has_padding_support && ! $skip_padding ) { + $spacing_block_styles['padding'] = $block_styles['spacing']['padding'] ?? null; + } + if ( $has_margin_support && ! $skip_margin ) { + $spacing_block_styles['margin'] = $block_styles['spacing']['margin'] ?? null; + } + $styles = gutenberg_style_engine_get_styles( array( 'spacing' => $spacing_block_styles ) ); if ( ! empty( $styles['css'] ) ) { $attributes['style'] = $styles['css']; diff --git a/lib/block-supports/typography.php b/lib/block-supports/typography.php index d0721503fb101e..5c051ee05cc2c2 100644 --- a/lib/block-supports/typography.php +++ b/lib/block-supports/typography.php @@ -15,21 +15,21 @@ function gutenberg_register_typography_support( $block_type ) { return; } - $typography_supports = _wp_array_get( $block_type->supports, array( 'typography' ), false ); + $typography_supports = $block_type->supports['typography'] ?? false; if ( ! $typography_supports ) { return; } - $has_font_family_support = _wp_array_get( $typography_supports, array( '__experimentalFontFamily' ), false ); - $has_font_size_support = _wp_array_get( $typography_supports, array( 'fontSize' ), false ); - $has_font_style_support = _wp_array_get( $typography_supports, array( '__experimentalFontStyle' ), false ); - $has_font_weight_support = _wp_array_get( $typography_supports, array( '__experimentalFontWeight' ), false ); - $has_letter_spacing_support = _wp_array_get( $typography_supports, array( '__experimentalLetterSpacing' ), false ); - $has_line_height_support = _wp_array_get( $typography_supports, array( 'lineHeight' ), false ); - $has_text_columns_support = _wp_array_get( $typography_supports, array( 'textColumns' ), false ); - $has_text_decoration_support = _wp_array_get( $typography_supports, array( '__experimentalTextDecoration' ), false ); - $has_text_transform_support = _wp_array_get( $typography_supports, array( '__experimentalTextTransform' ), false ); - $has_writing_mode_support = _wp_array_get( $typography_supports, array( '__experimentalWritingMode' ), false ); + $has_font_family_support = $typography_supports['__experimentalFontFamily'] ?? false; + $has_font_size_support = $typography_supports['fontSize'] ?? false; + $has_font_style_support = $typography_supports['__experimentalFontStyle'] ?? false; + $has_font_weight_support = $typography_supports['__experimentalFontWeight'] ?? false; + $has_letter_spacing_support = $typography_supports['__experimentalLetterSpacing'] ?? false; + $has_line_height_support = $typography_supports['lineHeight'] ?? false; + $has_text_columns_support = $typography_supports['textColumns'] ?? false; + $has_text_decoration_support = $typography_supports['__experimentalTextDecoration'] ?? false; + $has_text_transform_support = $typography_supports['__experimentalTextTransform'] ?? false; + $has_writing_mode_support = $typography_supports['__experimentalWritingMode'] ?? false; $has_typography_support = $has_font_family_support || $has_font_size_support @@ -80,7 +80,7 @@ function gutenberg_apply_typography_support( $block_type, $block_attributes ) { return array(); } - $typography_supports = _wp_array_get( $block_type->supports, array( 'typography' ), false ); + $typography_supports = $block_type->supports['typography'] ?? false; if ( ! $typography_supports ) { return array(); } @@ -89,16 +89,16 @@ function gutenberg_apply_typography_support( $block_type, $block_attributes ) { return array(); } - $has_font_family_support = _wp_array_get( $typography_supports, array( '__experimentalFontFamily' ), false ); - $has_font_size_support = _wp_array_get( $typography_supports, array( 'fontSize' ), false ); - $has_font_style_support = _wp_array_get( $typography_supports, array( '__experimentalFontStyle' ), false ); - $has_font_weight_support = _wp_array_get( $typography_supports, array( '__experimentalFontWeight' ), false ); - $has_letter_spacing_support = _wp_array_get( $typography_supports, array( '__experimentalLetterSpacing' ), false ); - $has_line_height_support = _wp_array_get( $typography_supports, array( 'lineHeight' ), false ); - $has_text_columns_support = _wp_array_get( $typography_supports, array( 'textColumns' ), false ); - $has_text_decoration_support = _wp_array_get( $typography_supports, array( '__experimentalTextDecoration' ), false ); - $has_text_transform_support = _wp_array_get( $typography_supports, array( '__experimentalTextTransform' ), false ); - $has_writing_mode_support = _wp_array_get( $typography_supports, array( '__experimentalWritingMode' ), false ); + $has_font_family_support = $typography_supports['__experimentalFontFamily'] ?? false; + $has_font_size_support = $typography_supports['fontSize'] ?? false; + $has_font_style_support = $typography_supports['__experimentalFontStyle'] ?? false; + $has_font_weight_support = $typography_supports['__experimentalFontWeight'] ?? false; + $has_letter_spacing_support = $typography_supports['__experimentalLetterSpacing'] ?? false; + $has_line_height_support = $typography_supports['lineHeight'] ?? false; + $has_text_columns_support = $typography_supports['textColumns'] ?? false; + $has_text_decoration_support = $typography_supports['__experimentalTextDecoration'] ?? false; + $has_text_transform_support = $typography_supports['__experimentalTextTransform'] ?? false; + $has_writing_mode_support = $typography_supports['__experimentalWritingMode'] ?? false; // Whether to skip individual block support features. $should_skip_font_size = wp_should_skip_block_supports_serialization( $block_type, 'typography', 'fontSize' ); @@ -140,11 +140,11 @@ function gutenberg_apply_typography_support( $block_type, $block_attributes ) { } if ( $has_line_height_support && ! $should_skip_line_height ) { - $typography_block_styles['lineHeight'] = _wp_array_get( $block_attributes, array( 'style', 'typography', 'lineHeight' ), null ); + $typography_block_styles['lineHeight'] = $block_attributes['style']['typography']['lineHeight'] ?? null; } if ( $has_text_columns_support && ! $should_skip_text_columns && isset( $block_attributes['style']['typography']['textColumns'] ) ) { - $typography_block_styles['textColumns'] = _wp_array_get( $block_attributes, array( 'style', 'typography', 'textColumns' ), null ); + $typography_block_styles['textColumns'] = $block_attributes['style']['typography']['textColumns'] ?? null; } if ( $has_text_decoration_support && ! $should_skip_text_decoration && isset( $block_attributes['style']['typography']['textDecoration'] ) ) { @@ -163,7 +163,7 @@ function gutenberg_apply_typography_support( $block_type, $block_attributes ) { } if ( $has_writing_mode_support && ! $should_skip_writing_mode && isset( $block_attributes['style']['typography']['writingMode'] ) ) { - $typography_block_styles['writingMode'] = _wp_array_get( $block_attributes, array( 'style', 'typography', 'writingMode' ), null ); + $typography_block_styles['writingMode'] = $block_attributes['style']['typography']['writingMode'] ?? null; } $attributes = array(); @@ -244,7 +244,6 @@ function gutenberg_render_typography_support( $block_content, $block ) { } return $block_content; - } /** diff --git a/lib/blocks.php b/lib/blocks.php index 34ef63f2e87ad9..537fa9ce4b45e1 100644 --- a/lib/blocks.php +++ b/lib/blocks.php @@ -274,7 +274,7 @@ function gutenberg_register_core_block_assets( $block_name ) { if ( ! $stylesheet_removed ) { add_action( 'wp_enqueue_scripts', - static function() { + static function () { wp_dequeue_style( 'wp-block-library-theme' ); } ); @@ -431,4 +431,33 @@ function gutenberg_legacy_wp_block_post_meta( $value, $object_id, $meta_key, $si return $value; } + add_filter( 'default_post_metadata', 'gutenberg_legacy_wp_block_post_meta', 10, 4 ); + +/** + * Complements the lightbox implementation for the 'core/image' block. + * + * This function is INTENTIONALLY left out of core as it only provides + * backwards compatibility for the legacy lightbox syntax that was only + * introduced in Gutenberg. The legacy syntax was using the `behaviors` key in + * the block attrbutes and the `theme.json` file. + * + * @since 16.7.0 + * + * @param array $block The block to check. + * @return array The block with the legacyLightboxSettings set if available. + */ +function gutenberg_should_render_lightbox( $block ) { + + if ( 'core/image' !== $block['blockName'] ) { + return $block; + } + + if ( isset( $block['attrs']['behaviors']['lightbox'] ) ) { + $block['legacyLightboxSettings'] = $block['attrs']['behaviors']['lightbox']; + } + + return $block; +} + +add_filter( 'render_block_data', 'gutenberg_should_render_lightbox', 15, 1 ); diff --git a/lib/class-wp-duotone-gutenberg.php b/lib/class-wp-duotone-gutenberg.php index 41120a882ed235..270c13875787f0 100644 --- a/lib/class-wp-duotone-gutenberg.php +++ b/lib/class-wp-duotone-gutenberg.php @@ -482,7 +482,7 @@ private static function is_preset( $duotone_attr ) { * @return string The CSS variable name. */ private static function get_css_custom_property_name( $slug ) { - return "--wp--preset--duotone--$slug"; + return "--wp--preset--duotone--$slug"; } /** @@ -492,7 +492,7 @@ private static function get_css_custom_property_name( $slug ) { * @return string The ID of the duotone filter. */ private static function get_filter_id( $slug ) { - return "wp-duotone-$slug"; + return "wp-duotone-$slug"; } /** @@ -655,14 +655,14 @@ private static function get_selector( $block_name ) { // `supports.filter.duotone` has not been set and the experimental // property has been, the experimental property value is copied into // `supports.filter.duotone`. - $duotone_support = _wp_array_get( $block_type->supports, array( 'filter', 'duotone' ), false ); + $duotone_support = $block_type->supports['filter']['duotone'] ?? false; if ( ! $duotone_support ) { return null; } // If the experimental duotone support was set, that value is to be // treated as a selector and requires scoping. - $experimental_duotone = _wp_array_get( $block_type->supports, array( 'color', '__experimentalDuotone' ), false ); + $experimental_duotone = $block_type->supports['color']['__experimentalDuotone'] ?? false; if ( $experimental_duotone ) { $root_selector = wp_get_block_css_selector( $block_type ); return is_string( $experimental_duotone ) @@ -750,7 +750,7 @@ public static function register_duotone_support( $block_type ) { if ( property_exists( $block_type, 'supports' ) ) { // Previous `color.__experimentalDuotone` support flag is migrated // to `filter.duotone` via `block_type_metadata_settings` filter. - $has_duotone_support = _wp_array_get( $block_type->supports, array( 'filter', 'duotone' ), null ); + $has_duotone_support = $block_type->supports['filter']['duotone'] ?? null; } if ( $has_duotone_support ) { @@ -775,7 +775,7 @@ public static function register_duotone_support( $block_type ) { public static function set_global_styles_presets() { // Get the per block settings from the theme.json. $tree = gutenberg_get_global_settings(); - $presets_by_origin = _wp_array_get( $tree, array( 'color', 'duotone' ), array() ); + $presets_by_origin = $tree['color']['duotone'] ?? array(); foreach ( $presets_by_origin as $presets ) { foreach ( $presets as $preset ) { @@ -995,7 +995,7 @@ public static function add_editor_settings( $settings ) { * @return array Filtered block type settings. */ public static function migrate_experimental_duotone_support_flag( $settings, $metadata ) { - $duotone_support = _wp_array_get( $metadata, array( 'supports', 'color', '__experimentalDuotone' ), null ); + $duotone_support = $metadata['supports']['color']['__experimentalDuotone'] ?? null; if ( ! isset( $settings['supports']['filter']['duotone'] ) && null !== $duotone_support ) { _wp_array_set( $settings, array( 'supports', 'filter', 'duotone' ), (bool) $duotone_support ); diff --git a/lib/class-wp-rest-global-styles-controller-gutenberg.php b/lib/class-wp-rest-global-styles-controller-gutenberg.php index 499a410b16f8ef..8125b2ebf1c288 100644 --- a/lib/class-wp-rest-global-styles-controller-gutenberg.php +++ b/lib/class-wp-rest-global-styles-controller-gutenberg.php @@ -302,7 +302,6 @@ public function update_item( $request ) { * * @since 5.9.0 * @since 6.2.0 Added validation of styles.css property. - * @since 6.4.0 Added validation of behaviors property. * * @param WP_REST_Request $request Request object. * @return stdClass|WP_Error Prepared item on success. WP_Error on when the custom CSS is not valid. @@ -322,7 +321,7 @@ protected function prepare_item_for_database( $request ) { } } - if ( isset( $request['styles'] ) || isset( $request['settings'] ) || isset( $request['behaviors'] ) ) { + if ( isset( $request['styles'] ) || isset( $request['settings'] ) ) { $config = array(); if ( isset( $request['styles'] ) ) { if ( isset( $request['styles']['css'] ) ) { @@ -340,11 +339,6 @@ protected function prepare_item_for_database( $request ) { } elseif ( isset( $existing_config['settings'] ) ) { $config['settings'] = $existing_config['settings']; } - if ( isset( $request['behaviors'] ) ) { - $config['behaviors'] = $request['behaviors']; - } elseif ( isset( $existing_config['behaviors'] ) ) { - $config['behaviors'] = $existing_config['behaviors']; - } $config['isGlobalStylesUserThemeJSON'] = true; $config['version'] = WP_Theme_JSON_Gutenberg::LATEST_SCHEMA; $changes->post_content = wp_json_encode( $config ); @@ -367,7 +361,6 @@ protected function prepare_item_for_database( $request ) { * * @since 5.9.0 * @since 6.2.0 Handling of style.css was added to WP_Theme_JSON. - * @since 6.4.0 Added `behavior` field. * * @param WP_Post $post Global Styles post object. * @param WP_REST_Request $request Request object. @@ -411,10 +404,6 @@ public function prepare_item_for_response( $post, $request ) { // phpcs:ignore V $data['styles'] = ! empty( $config['styles'] ) && $is_global_styles_user_theme_json ? $config['styles'] : new stdClass(); } - if ( rest_is_field_included( 'behaviors', $fields ) ) { - $data['behaviors'] = ! empty( $config['behaviors'] ) && $is_global_styles_user_theme_json ? $config['behaviors'] : new stdClass(); - } - $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; $data = $this->add_additional_fields_to_object( $data, $request ); $data = $this->filter_response_by_context( $data, $context ); @@ -521,7 +510,6 @@ public function get_collection_params() { * Retrieves the global styles type' schema, conforming to JSON Schema. * * @since 5.9.0 - * @since 6.4.0 Added `behaviors` property. * * @return array Item schema data. */ @@ -535,28 +523,23 @@ public function get_item_schema() { 'title' => $this->post_type, 'type' => 'object', 'properties' => array( - 'id' => array( + 'id' => array( 'description' => __( 'ID of global styles config.', 'gutenberg' ), 'type' => 'string', 'context' => array( 'embed', 'view', 'edit' ), 'readonly' => true, ), - 'styles' => array( + 'styles' => array( 'description' => __( 'Global styles.', 'gutenberg' ), 'type' => array( 'object' ), 'context' => array( 'view', 'edit' ), ), - 'settings' => array( + 'settings' => array( 'description' => __( 'Global settings.', 'gutenberg' ), 'type' => array( 'object' ), 'context' => array( 'view', 'edit' ), ), - 'behaviors' => array( - 'description' => __( 'Global behaviors.', 'default' ), - 'type' => array( 'object' ), - 'context' => array( 'view', 'edit' ), - ), - 'title' => array( + 'title' => array( 'description' => __( 'Title of the global styles variation.', 'gutenberg' ), 'type' => array( 'object', 'string' ), 'default' => '', @@ -614,7 +597,6 @@ public function get_theme_item_permissions_check( $request ) { // phpcs:ignore V * Returns the given theme global styles config. * * @since 5.9.0 - * @since 6.4.0 Added value for `behaviors` rest field. * * @param WP_REST_Request $request The request instance. * @return WP_REST_Response|WP_Error @@ -642,11 +624,6 @@ public function get_theme_item( $request ) { $data['styles'] = isset( $raw_data['styles'] ) ? $raw_data['styles'] : array(); } - if ( rest_is_field_included( 'behaviors', $fields ) ) { - $raw_data = $theme->get_raw_data(); - $data['behaviors'] = isset( $raw_data['behaviors'] ) ? $raw_data['behaviors'] : array(); - } - $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; $data = $this->add_additional_fields_to_object( $data, $request ); $data = $this->filter_response_by_context( $data, $context ); diff --git a/lib/class-wp-theme-json-data-gutenberg.php b/lib/class-wp-theme-json-data-gutenberg.php index db0737ebea08b6..f0d2025347493b 100644 --- a/lib/class-wp-theme-json-data-gutenberg.php +++ b/lib/class-wp-theme-json-data-gutenberg.php @@ -72,5 +72,4 @@ public function update_with( $new_data ) { public function get_data() { return $this->theme_json->get_raw_data(); } - } diff --git a/lib/class-wp-theme-json-gutenberg.php b/lib/class-wp-theme-json-gutenberg.php index 63de99624a0ac6..59a3bbc3eb2ef6 100644 --- a/lib/class-wp-theme-json-gutenberg.php +++ b/lib/class-wp-theme-json-gutenberg.php @@ -331,7 +331,6 @@ class WP_Theme_JSON_Gutenberg { 'templateParts', 'title', 'version', - 'behaviors', ); /** @@ -347,6 +346,7 @@ class WP_Theme_JSON_Gutenberg { * `position.fixed` and `position.sticky`. * @since 6.3.0 Removed `layout.definitions`. Added `typography.writingMode`. * @since 6.4.0 Added `layout.allowEditing`. + * @since 6.4.0 Added `lightbox`. * @var array */ const VALID_SETTINGS = array( @@ -387,6 +387,10 @@ class WP_Theme_JSON_Gutenberg { 'wideSize' => null, 'allowEditing' => null, ), + 'lightbox' => array( + 'enabled' => null, + 'allowEditing' => null, + ), 'position' => array( 'fixed' => null, 'sticky' => null, @@ -419,7 +423,6 @@ class WP_Theme_JSON_Gutenberg { 'textTransform' => null, 'writingMode' => null, ), - 'behaviors' => null, ); /** @@ -618,7 +621,7 @@ public function __construct( $theme_json = array(), $origin = 'theme' ) { $origin = 'theme'; } - $this->theme_json = WP_Theme_JSON_Schema::migrate( $theme_json ); + $this->theme_json = WP_Theme_JSON_Schema_Gutenberg::migrate( $theme_json ); $registry = WP_Block_Type_Registry::get_instance(); $valid_block_names = array_keys( $registry->get_all_registered() ); $valid_element_names = array_keys( static::ELEMENTS ); @@ -925,7 +928,7 @@ protected static function get_blocks_metadata() { // Keep backwards compatibility for support.color.__experimentalDuotone. if ( null === $duotone_selector ) { - $duotone_support = _wp_array_get( $block_type->supports, array( 'color', '__experimentalDuotone' ), null ); + $duotone_support = $block_type->supports['color']['__experimentalDuotone'] ?? null; if ( $duotone_support ) { $root_selector = wp_get_block_css_selector( $block_type ); @@ -1158,12 +1161,12 @@ protected function process_blocks_custom_css( $css, $selector ) { */ public function get_custom_css() { // Add the global styles root CSS. - $stylesheet = _wp_array_get( $this->theme_json, array( 'styles', 'css' ), '' ); + $stylesheet = $this->theme_json['styles']['css'] ?? ''; // Add the global styles block CSS. if ( isset( $this->theme_json['styles']['blocks'] ) ) { foreach ( $this->theme_json['styles']['blocks'] as $name => $node ) { - $custom_block_css = _wp_array_get( $this->theme_json, array( 'styles', 'blocks', $name, 'css' ) ); + $custom_block_css = $this->theme_json['styles']['blocks'][ $name ]['css'] ?? null; if ( $custom_block_css ) { $selector = static::$blocks_metadata[ $name ]['selector']; $stylesheet .= $this->process_blocks_custom_css( $custom_block_css, $selector ); @@ -1281,7 +1284,7 @@ protected function get_layout_styles( $block_metadata ) { } $selector = isset( $block_metadata['selector'] ) ? $block_metadata['selector'] : ''; - $has_block_gap_support = _wp_array_get( $this->theme_json, array( 'settings', 'spacing', 'blockGap' ) ) !== null; + $has_block_gap_support = isset( $this->theme_json['settings']['spacing']['blockGap'] ); $has_fallback_gap_support = ! $has_block_gap_support; // This setting isn't useful yet: it exists as a placeholder for a future explicit fallback gap styles support. $node = _wp_array_get( $this->theme_json, $block_metadata['path'], array() ); $layout_definitions = gutenberg_get_layout_definitions(); @@ -1295,7 +1298,7 @@ protected function get_layout_styles( $block_metadata ) { if ( ! $has_block_gap_support ) { $block_gap_value = static::ROOT_BLOCK_SELECTOR === $selector ? '0.5em' : null; if ( ! empty( $block_type ) ) { - $block_gap_value = _wp_array_get( $block_type->supports, array( 'spacing', 'blockGap', '__experimentalDefault' ), null ); + $block_gap_value = $block_type->supports['spacing']['blockGap']['__experimentalDefault'] ?? null; } } else { $block_gap_value = static::get_property_value( $node, array( 'spacing', 'blockGap' ) ); @@ -1321,8 +1324,8 @@ protected function get_layout_styles( $block_metadata ) { continue; } - $class_name = _wp_array_get( $layout_definition, array( 'className' ), false ); - $spacing_rules = _wp_array_get( $layout_definition, array( 'spacingStyles' ), array() ); + $class_name = $layout_definition['className'] ?? false; + $spacing_rules = $layout_definition['spacingStyles'] ?? array(); if ( ! empty( $class_name ) && @@ -1378,8 +1381,8 @@ protected function get_layout_styles( $block_metadata ) { ) { $valid_display_modes = array( 'block', 'flex', 'grid' ); foreach ( $layout_definitions as $layout_definition ) { - $class_name = _wp_array_get( $layout_definition, array( 'className' ), false ); - $base_style_rules = _wp_array_get( $layout_definition, array( 'baseStyles' ), array() ); + $class_name = $layout_definition['className'] ?? false; + $base_style_rules = $layout_definition['baseStyles'] ?? array(); if ( ! empty( $class_name ) && @@ -1811,7 +1814,7 @@ protected static function compute_preset_vars( $settings, $origins ) { */ protected static function compute_theme_vars( $settings ) { $declarations = array(); - $custom_values = _wp_array_get( $settings, array( 'custom' ), array() ); + $custom_values = $settings['custom'] ?? array(); $css_vars = static::flatten_tree( $custom_values ); foreach ( $css_vars as $key => $value ) { $declarations[] = array( @@ -2323,7 +2326,7 @@ public function get_styles_for_block( $block_metadata ) { $node = _wp_array_get( $this->theme_json, $block_metadata['path'], array() ); $use_root_padding = isset( $this->theme_json['settings']['useRootPaddingAwareAlignments'] ) && true === $this->theme_json['settings']['useRootPaddingAwareAlignments']; $selector = $block_metadata['selector']; - $settings = _wp_array_get( $this->theme_json, array( 'settings' ) ); + $settings = $this->theme_json['settings'] ?? null; $feature_declarations = static::get_feature_declarations_for_node( $block_metadata, $node ); @@ -2345,7 +2348,7 @@ public function get_styles_for_block( $block_metadata ) { // Prepend the variation selector to the current selector. $split_selectors = explode( ',', $shortened_selector ); $updated_selectors = array_map( - static function( $split_selector ) use ( $clean_style_variation_selector ) { + static function ( $split_selector ) use ( $clean_style_variation_selector ) { return $clean_style_variation_selector . $split_selector; }, $split_selectors @@ -2384,7 +2387,7 @@ static function( $split_selector ) use ( $clean_style_variation_selector ) { $pseudo_matches = array_values( array_filter( $element_pseudo_allowed, - static function( $pseudo_selector ) use ( $selector ) { + static function ( $pseudo_selector ) use ( $selector ) { return str_contains( $selector, $pseudo_selector ); } ) @@ -2476,7 +2479,7 @@ static function( $pseudo_selector ) use ( $selector ) { */ public function get_root_layout_rules( $selector, $block_metadata ) { $css = ''; - $settings = _wp_array_get( $this->theme_json, array( 'settings' ) ); + $settings = $this->theme_json['settings'] ?? array(); $use_root_padding = isset( $this->theme_json['settings']['useRootPaddingAwareAlignments'] ) && true === $this->theme_json['settings']['useRootPaddingAwareAlignments']; /* @@ -2510,11 +2513,11 @@ public function get_root_layout_rules( $selector, $block_metadata ) { // Right and left padding are applied to the first container with `.has-global-padding` class. $css .= '.has-global-padding { padding-right: var(--wp--style--root--padding-right); padding-left: var(--wp--style--root--padding-left); }'; // Nested containers with `.has-global-padding` class do not get padding. - $css .= '.has-global-padding :where(.has-global-padding) { padding-right: 0; padding-left: 0; }'; + $css .= '.has-global-padding :where(.has-global-padding:not(.wp-block-block)) { padding-right: 0; padding-left: 0; }'; // Alignfull children of the container with left and right padding have negative margins so they can still be full width. $css .= '.has-global-padding > .alignfull { margin-right: calc(var(--wp--style--root--padding-right) * -1); margin-left: calc(var(--wp--style--root--padding-left) * -1); }'; // The above rule is negated for alignfull children of nested containers. - $css .= '.has-global-padding :where(.has-global-padding) > .alignfull { margin-right: 0; margin-left: 0; }'; + $css .= '.has-global-padding :where(.has-global-padding:not(.wp-block-block)) > .alignfull { margin-right: 0; margin-left: 0; }'; // Some of the children of alignfull blocks without content width should also get padding: text blocks and non-alignfull container blocks. $css .= '.has-global-padding > .alignfull:where(:not(.has-global-padding):not(.is-layout-flex):not(.is-layout-grid)) > :where([class*="wp-block-"]:not(.alignfull):not([class*="__"]),.wp-block:not(.alignfull),p,h1,h2,h3,h4,h5,h6,ul,ol) { padding-right: var(--wp--style--root--padding-right); padding-left: var(--wp--style--root--padding-left); }'; // The above rule also has to be negated for blocks inside nested `.has-global-padding` blocks. @@ -2525,8 +2528,8 @@ public function get_root_layout_rules( $selector, $block_metadata ) { $css .= '.wp-site-blocks > .alignright { float: right; margin-left: 2em; }'; $css .= '.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }'; - $block_gap_value = _wp_array_get( $this->theme_json, array( 'styles', 'spacing', 'blockGap' ), '0.5em' ); - $has_block_gap_support = _wp_array_get( $this->theme_json, array( 'settings', 'spacing', 'blockGap' ) ) !== null; + $block_gap_value = $this->theme_json['styles']['spacing']['blockGap'] ?? '0.5em'; + $has_block_gap_support = isset( $this->theme_json['settings']['spacing']['blockGap'] ); if ( $has_block_gap_support ) { $block_gap_value = static::get_property_value( $this->theme_json, array( 'styles', 'spacing', 'blockGap' ) ); $css .= ":where(.wp-site-blocks) > * { margin-block-start: $block_gap_value; margin-block-end: 0; }"; @@ -2861,7 +2864,7 @@ protected static function filter_slugs( $node, $slugs ) { public static function remove_insecure_properties( $theme_json ) { $sanitized = array(); - $theme_json = WP_Theme_JSON_Schema::migrate( $theme_json ); + $theme_json = WP_Theme_JSON_Schema_Gutenberg::migrate( $theme_json ); $valid_block_names = array_keys( static::get_blocks_metadata() ); $valid_element_names = array_keys( static::ELEMENTS ); @@ -3357,7 +3360,7 @@ public function get_data() { * @return null|void */ public function set_spacing_sizes() { - $spacing_scale = _wp_array_get( $this->theme_json, array( 'settings', 'spacing', 'spacingScale' ), array() ); + $spacing_scale = $this->theme_json['settings']['spacing']['spacingScale'] ?? array(); // Gutenberg didn't have the 1st isset check. if ( ! isset( $spacing_scale['steps'] ) @@ -3415,7 +3418,7 @@ public function set_spacing_sizes() { } if ( $below_midpoint_count < $steps_mid_point - 2 ) { - $x_small_count++; + ++$x_small_count; } $slug -= 10; @@ -3452,7 +3455,7 @@ public function set_spacing_sizes() { } if ( $above_midpoint_count > 1 ) { - $x_large_count++; + ++$x_large_count; } $slug += 10; @@ -3543,7 +3546,7 @@ protected function get_feature_declarations_for_node( $metadata, &$node ) { return $declarations; } - $settings = _wp_array_get( $this->theme_json, array( 'settings' ) ); + $settings = $this->theme_json['settings'] ?? null; foreach ( $metadata['selectors'] as $feature => $feature_selectors ) { // Skip if this is the block's root selector or the block doesn't @@ -3728,10 +3731,10 @@ public static function resolve_variables( $theme_json ) { $theme_vars = static::compute_theme_vars( $settings ); $vars = array_reduce( array_merge( $preset_vars, $theme_vars ), - function( $carry, $item ) { + function ( $carry, $item ) { $name = $item['name']; $carry[ "var({$name})" ] = $item['value']; - return $carry; + return $carry; }, array() ); @@ -3739,5 +3742,4 @@ function( $carry, $item ) { $theme_json->theme_json['styles'] = self::convert_variables_to_value( $styles, $vars ); return $theme_json; } - } diff --git a/lib/class-wp-theme-json-resolver-gutenberg.php b/lib/class-wp-theme-json-resolver-gutenberg.php index 39721742946cd1..950d9e00e6243f 100644 --- a/lib/class-wp-theme-json-resolver-gutenberg.php +++ b/lib/class-wp-theme-json-resolver-gutenberg.php @@ -241,9 +241,9 @@ public static function get_theme_data( $deprecated = array(), $options = array() $options = wp_parse_args( $options, array( 'with_supports' => true ) ); if ( null === static::$theme || ! static::has_same_registered_blocks( 'theme' ) ) { - $theme_json_file = static::get_file_path_from_theme( 'theme.json' ); $wp_theme = wp_get_theme(); - if ( '' !== $theme_json_file ) { + $theme_json_file = $wp_theme->get_file_path( 'theme.json' ); + if ( is_readable( $theme_json_file ) ) { $theme_json_data = static::read_json_file( $theme_json_file ); $theme_json_data = static::translate( $theme_json_data, $wp_theme->get( 'TextDomain' ) ); } else { @@ -263,8 +263,8 @@ public static function get_theme_data( $deprecated = array(), $options = array() if ( $wp_theme->parent() ) { // Get parent theme.json. - $parent_theme_json_file = static::get_file_path_from_theme( 'theme.json', true ); - if ( '' !== $parent_theme_json_file ) { + $parent_theme_json_file = $wp_theme->parent()->get_file_path( 'theme.json' ); + if ( $theme_json_file !== $parent_theme_json_file && is_readable( $parent_theme_json_file ) ) { $parent_theme_json_data = static::read_json_file( $parent_theme_json_file ); $parent_theme_json_data = static::translate( $parent_theme_json_data, $wp_theme->parent()->get( 'TextDomain' ) ); $parent_theme = new WP_Theme_JSON_Gutenberg( $parent_theme_json_data ); @@ -383,7 +383,7 @@ public static function get_block_data() { if ( isset( $block_type->supports['spacing']['blockGap']['__experimentalDefault'] ) && - null === _wp_array_get( $config, array( 'styles', 'blocks', $block_name, 'spacing', 'blockGap' ), null ) + ! isset( $config['styles']['blocks'][ $block_name ]['spacing']['blockGap'] ) ) { // Ensure an empty placeholder value exists for the block, if it provides a default blockGap value. // The real blockGap value to be used will be determined when the styles are rendered for output. @@ -408,18 +408,18 @@ public static function get_block_data() { /** * When given an array, this will remove any keys with the name `//`. * - * @param array $array The array to filter. + * @param array $json_array The array to filter. * @return array The filtered array. */ - private static function remove_json_comments( $array ) { - unset( $array['//'] ); - foreach ( $array as $k => $v ) { + private static function remove_json_comments( $json_array ) { + unset( $json_array['//'] ); + foreach ( $json_array as $k => $v ) { if ( is_array( $v ) ) { - $array[ $k ] = static::remove_json_comments( $v ); + $json_array[ $k ] = static::remove_json_comments( $v ); } } - return $array; + return $json_array; } /** @@ -670,6 +670,8 @@ public static function theme_has_support() { * @return string The whole file path or empty if the file doesn't exist. */ protected static function get_file_path_from_theme( $file_name, $template = false ) { + // TODO: Remove this method from core on 6.3 release. + _deprecated_function( __METHOD__, '6.3.0' ); $path = $template ? get_template_directory() : get_stylesheet_directory(); $candidate = $path . '/' . $file_name; diff --git a/lib/class-wp-theme-json-schema-gutenberg.php b/lib/class-wp-theme-json-schema-gutenberg.php new file mode 100644 index 00000000000000..d11545751af362 --- /dev/null +++ b/lib/class-wp-theme-json-schema-gutenberg.php @@ -0,0 +1,202 @@ + 'border.radius', + 'spacing.customMargin' => 'spacing.margin', + 'spacing.customPadding' => 'spacing.padding', + 'typography.customLineHeight' => 'typography.lineHeight', + ); + + /** + * Function that migrates a given theme.json structure to the last version. + * + * @since 5.9.0 + * + * @param array $theme_json The structure to migrate. + * + * @return array The structure in the last version. + */ + public static function migrate( $theme_json ) { + if ( ! isset( $theme_json['version'] ) ) { + $theme_json = array( + 'version' => WP_Theme_JSON::LATEST_SCHEMA, + ); + } + + if ( 1 === $theme_json['version'] ) { + $theme_json = self::migrate_v1_to_v2( $theme_json ); + } + + if ( 2 === $theme_json['version'] ) { + $theme_json = self::migrate_deprecated_lightbox_behaviors( $theme_json ); + } + + return $theme_json; + } + + /** + * Removes the custom prefixes for a few properties + * that were part of v1: + * + * 'border.customRadius' => 'border.radius', + * 'spacing.customMargin' => 'spacing.margin', + * 'spacing.customPadding' => 'spacing.padding', + * 'typography.customLineHeight' => 'typography.lineHeight', + * + * @since 5.9.0 + * + * @param array $old Data to migrate. + * + * @return array Data without the custom prefixes. + */ + private static function migrate_v1_to_v2( $old ) { + // Copy everything. + $new = $old; + + // Overwrite the things that changed. + if ( isset( $old['settings'] ) ) { + $new['settings'] = self::rename_paths( $old['settings'], self::V1_TO_V2_RENAMED_PATHS ); + } + + // Set the new version. + $new['version'] = 2; + + return $new; + } + + + /** + * Migrate away from the previous syntax that used a top-level "behaviors" key + * in the `theme.json` to a new "lightbox" setting. + * + * This function SHOULD NOT be ported to Core!!! + * + * It is a temporary migration that will be removed in Gutenberg 17.0.0 + * + * @since 16.7.0 + * + * @param array $old Data with (potentially) behaviors. + * @return array Data with behaviors removed. + */ + private static function migrate_deprecated_lightbox_behaviors( $old ) { + // Copy everything. + $new = $old; + + // Migrate the old behaviors syntax to the new "lightbox" syntax. + if ( isset( $old['behaviors']['blocks']['core/image']['lightbox']['enabled'] ) ) { + _wp_array_set( + $new, + array( 'settings', 'blocks', 'core/image', 'lightbox', 'enabled' ), + $old['behaviors']['blocks']['core/image']['lightbox']['enabled'] + ); + } + + // Migrate the behaviors setting to the new syntax. This setting controls + // whether the Lightbox UI shows up in the block editor. + if ( isset( $old['settings']['blocks']['core/image']['behaviors']['lightbox'] ) ) { + _wp_array_set( + $new, + array( 'settings', 'blocks', 'core/image', 'lightbox', 'allowEditing' ), + $old['settings']['blocks']['core/image']['behaviors']['lightbox'] + ); + } + + return $new; + } + + /** + * Processes the settings subtree. + * + * @since 5.9.0 + * + * @param array $settings Array to process. + * @param array $paths_to_rename Paths to rename. + * + * @return array The settings in the new format. + */ + private static function rename_paths( $settings, $paths_to_rename ) { + $new_settings = $settings; + + // Process any renamed/moved paths within default settings. + self::rename_settings( $new_settings, $paths_to_rename ); + + // Process individual block settings. + if ( isset( $new_settings['blocks'] ) && is_array( $new_settings['blocks'] ) ) { + foreach ( $new_settings['blocks'] as &$block_settings ) { + self::rename_settings( $block_settings, $paths_to_rename ); + } + } + + return $new_settings; + } + + /** + * Processes a settings array, renaming or moving properties. + * + * @since 5.9.0 + * + * @param array $settings Reference to settings either defaults or an individual block's. + * @param array $paths_to_rename Paths to rename. + */ + private static function rename_settings( &$settings, $paths_to_rename ) { + foreach ( $paths_to_rename as $original => $renamed ) { + $original_path = explode( '.', $original ); + $renamed_path = explode( '.', $renamed ); + $current_value = _wp_array_get( $settings, $original_path, null ); + + if ( null !== $current_value ) { + _wp_array_set( $settings, $renamed_path, $current_value ); + self::unset_setting_by_path( $settings, $original_path ); + } + } + } + + /** + * Removes a property from within the provided settings by its path. + * + * @since 5.9.0 + * + * @param array $settings Reference to the current settings array. + * @param array $path Path to the property to be removed. + */ + private static function unset_setting_by_path( &$settings, $path ) { + $tmp_settings = &$settings; // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable + $last_key = array_pop( $path ); + foreach ( $path as $key ) { + $tmp_settings = &$tmp_settings[ $key ]; + } + + unset( $tmp_settings[ $last_key ] ); + } +} diff --git a/lib/compat/wordpress-6.3/block-editor-settings.php b/lib/compat/wordpress-6.3/block-editor-settings.php index 59f46d7edb9890..b478d022c16dd9 100644 --- a/lib/compat/wordpress-6.3/block-editor-settings.php +++ b/lib/compat/wordpress-6.3/block-editor-settings.php @@ -78,7 +78,7 @@ function gutenberg_get_block_editor_settings_experimental( $settings ) { $template_blocks = parse_blocks( $current_template[0]->content ); $post_content_block = gutenberg_find_first_block( 'core/post-content', $template_blocks ); - if ( ! empty( $post_content_block['attrs'] ) ) { + if ( isset( $post_content_block['attrs'] ) ) { $settings['postContentAttributes'] = $post_content_block['attrs']; } } diff --git a/lib/compat/wordpress-6.3/blocks.php b/lib/compat/wordpress-6.3/blocks.php index 962c9ee3e07ef3..001416b42566f7 100644 --- a/lib/compat/wordpress-6.3/blocks.php +++ b/lib/compat/wordpress-6.3/blocks.php @@ -104,7 +104,7 @@ function gutenberg_wp_block_register_post_meta() { $post_type, 'wp_pattern_sync_status', array( - 'auth_callback' => function() { + 'auth_callback' => function () { return current_user_can( 'edit_posts' ); }, 'sanitize_callback' => 'sanitize_text_field', diff --git a/lib/compat/wordpress-6.3/class-gutenberg-navigation-fallback.php b/lib/compat/wordpress-6.3/class-gutenberg-navigation-fallback.php index fcf6e13b0954d7..fcd70da61f57ed 100644 --- a/lib/compat/wordpress-6.3/class-gutenberg-navigation-fallback.php +++ b/lib/compat/wordpress-6.3/class-gutenberg-navigation-fallback.php @@ -154,7 +154,7 @@ private static function get_fallback_classic_menu() { private static function get_most_recently_created_nav_menu( $classic_nav_menus ) { usort( $classic_nav_menus, - static function( $a, $b ) { + static function ( $a, $b ) { return $b->term_id - $a->term_id; } ); diff --git a/lib/compat/wordpress-6.3/html-api/class-gutenberg-html-tag-processor-6-3.php b/lib/compat/wordpress-6.3/html-api/class-gutenberg-html-tag-processor-6-3.php index b869e2ef1e1c16..73cdb9342490c1 100644 --- a/lib/compat/wordpress-6.3/html-api/class-gutenberg-html-tag-processor-6-3.php +++ b/lib/compat/wordpress-6.3/html-api/class-gutenberg-html-tag-processor-6-3.php @@ -947,7 +947,7 @@ private function parse_next_tag() { if ( '/' === $this->html[ $at + 1 ] ) { $this->is_closing_tag = true; - $at++; + ++$at; } else { $this->is_closing_tag = false; } @@ -1016,7 +1016,7 @@ private function parse_next_tag() { * * See https://html.spec.whatwg.org/#parse-error-incorrectly-closed-comment */ - $closer_at--; // Pre-increment inside condition below reduces risk of accidental infinite looping. + --$closer_at; // Pre-increment inside condition below reduces risk of accidental infinite looping. while ( ++$closer_at < strlen( $html ) ) { $closer_at = strpos( $html, '--', $closer_at ); if ( false === $closer_at ) { @@ -1097,7 +1097,7 @@ private function parse_next_tag() { * See https://html.spec.whatwg.org/#parse-error-missing-end-tag-name */ if ( '>' === $html[ $at + 1 ] ) { - $at++; + ++$at; continue; } @@ -1739,7 +1739,7 @@ public function get_attribute( $name ) { * @param string $prefix Prefix of requested attribute names. * @return array|null List of attribute names, or `null` when no tag opener is matched. */ - function get_attribute_names_with_prefix( $prefix ) { + public function get_attribute_names_with_prefix( $prefix ) { if ( $this->is_closing_tag || null === $this->tag_name_starts_at ) { return null; } @@ -2282,11 +2282,9 @@ private function matches() { * See https://html.spec.whatwg.org/#attributes-3 * See https://html.spec.whatwg.org/#space-separated-tokens */ - while ( - // phpcs:ignore WordPress.CodeAnalysis.AssignmentInCondition.FoundInWhileCondition - false !== ( $class_at = strpos( $this->html, $this->sought_class_name, $class_at ) ) && - $class_at < $class_end - ) { + do { + $class_at = strpos( $this->html, $this->sought_class_name, $class_at ); + /* * Verify this class starts at a boundary. */ @@ -2312,7 +2310,7 @@ private function matches() { } return true; - } + } while ( false !== $class_at && $class_at < $class_end ); return false; } diff --git a/lib/compat/wordpress-6.3/rest-api.php b/lib/compat/wordpress-6.3/rest-api.php index 041398eda24b4f..fc0c295bdaaf83 100644 --- a/lib/compat/wordpress-6.3/rest-api.php +++ b/lib/compat/wordpress-6.3/rest-api.php @@ -70,9 +70,9 @@ function add_modified_wp_template_schema() { 'context' => array( 'view', 'edit' ), 'readonly' => true, ), - 'get_callback' => function( $object ) { - if ( ! empty( $object['wp_id'] ) ) { - $post = get_post( $object['wp_id'] ); + 'get_callback' => function ( $template_object ) { + if ( ! empty( $template_object['wp_id'] ) ) { + $post = get_post( $template_object['wp_id'] ); if ( $post && isset( $post->post_modified ) ) { return mysql_to_rfc3339( $post->post_modified ); } @@ -85,19 +85,6 @@ function add_modified_wp_template_schema() { } add_filter( 'rest_api_init', 'add_modified_wp_template_schema' ); -// If the Block Hooks experiment is enabled, we load the block patterns -// controller in lib/experimental/rest-api.php instead. -if ( ! gutenberg_is_experiment_enabled( 'gutenberg-block-hooks' ) ) { - /** - * Registers the block patterns REST API routes. - */ - function gutenberg_register_rest_block_patterns() { - $block_patterns = new Gutenberg_REST_Block_Patterns_Controller_6_3(); - $block_patterns->register_routes(); - } - add_action( 'rest_api_init', 'gutenberg_register_rest_block_patterns' ); -} - /** * Registers the Navigation Fallbacks REST API routes. */ diff --git a/lib/compat/wordpress-6.3/script-loader.php b/lib/compat/wordpress-6.3/script-loader.php index 8f7bda2a648114..9cbd3771ee328b 100644 --- a/lib/compat/wordpress-6.3/script-loader.php +++ b/lib/compat/wordpress-6.3/script-loader.php @@ -79,9 +79,13 @@ function _gutenberg_get_iframed_editor_assets() { } } + // Remove the deprecated `print_emoji_styles` handler. + // It avoids breaking style generation with a deprecation message. + remove_action( 'wp_print_styles', 'print_emoji_styles' ); ob_start(); wp_print_styles(); $styles = ob_get_clean(); + add_action( 'wp_print_styles', 'print_emoji_styles' ); ob_start(); wp_print_head_scripts(); @@ -100,7 +104,7 @@ function _gutenberg_get_iframed_editor_assets() { add_filter( 'block_editor_settings_all', - static function( $settings ) { + static function ( $settings ) { // We must override what core is passing now. $settings['__unstableResolvedAssets'] = _gutenberg_get_iframed_editor_assets(); return $settings; diff --git a/lib/experimental/block-hooks.php b/lib/compat/wordpress-6.4/block-hooks.php similarity index 86% rename from lib/experimental/block-hooks.php rename to lib/compat/wordpress-6.4/block-hooks.php index abe85ee3b9ace8..07f5aaf218d67a 100644 --- a/lib/experimental/block-hooks.php +++ b/lib/compat/wordpress-6.4/block-hooks.php @@ -13,10 +13,10 @@ * @return array Updated settings array. */ function gutenberg_add_hooked_blocks( $settings, $metadata ) { - if ( ! isset( $metadata['__experimentalBlockHooks'] ) ) { + if ( ! isset( $metadata['blockHooks'] ) ) { return $settings; } - $block_hooks = $metadata['__experimentalBlockHooks']; + $block_hooks = $metadata['blockHooks']; /** * Map the camelCased position string from block.json to the snake_cased block type position @@ -87,7 +87,6 @@ function gutenberg_add_hooked_blocks( $settings, $metadata ) { return $settings; } -add_filter( 'block_type_metadata_settings', 'gutenberg_add_hooked_blocks', 10, 2 ); /** * Register a hooked block for automatic insertion into a given block hook. @@ -152,20 +151,34 @@ function gutenberg_add_hooked_block( $hooked_block, $position, $anchor_block ) { * @return callable A function that accepts a block's content and returns the content with the inserted block. */ function gutenberg_insert_hooked_block( $inserted_block, $relative_position, $anchor_block_type ) { - return function( $block ) use ( $inserted_block, $relative_position, $anchor_block_type ) { + return function ( $block ) use ( $inserted_block, $relative_position, $anchor_block_type ) { if ( $anchor_block_type === $block['blockName'] ) { if ( 'first_child' === $relative_position ) { array_unshift( $block['innerBlocks'], $inserted_block ); // Since WP_Block::render() iterates over `inner_content` (rather than `inner_blocks`) // when rendering blocks, we also need to prepend a value (`null`, to mark a block - // location) to that array. - array_unshift( $block['innerContent'], null ); + // location) to that array after HTML content for the inner blocks wrapper. + $chunk_index = 0; + for ( $index = $chunk_index; $index < count( $block['innerContent'] ); $index++ ) { + if ( is_null( $block['innerContent'][ $index ] ) ) { + $chunk_index = $index; + break; + } + } + array_splice( $block['innerContent'], $chunk_index, 0, array( null ) ); } elseif ( 'last_child' === $relative_position ) { array_push( $block['innerBlocks'], $inserted_block ); // Since WP_Block::render() iterates over `inner_content` (rather than `inner_blocks`) - // when rendering blocks, we also need to prepend a value (`null`, to mark a block - // location) to that array. - array_push( $block['innerContent'], null ); + // when rendering blocks, we also need to correctly append a value (`null`, to mark a block + // location) to that array before the remaining HTML content for the inner blocks wrapper. + $chunk_index = count( $block['innerContent'] ); + for ( $index = count( $block['innerContent'] ); $index > 0; $index-- ) { + if ( is_null( $block['innerContent'][ $index - 1 ] ) ) { + $chunk_index = $index; + break; + } + } + array_splice( $block['innerContent'], $chunk_index, 0, array( null ) ); } return $block; } @@ -173,7 +186,7 @@ function gutenberg_insert_hooked_block( $inserted_block, $relative_position, $an $anchor_block_index = array_search( $anchor_block_type, array_column( $block['innerBlocks'], 'blockName' ), true ); if ( false !== $anchor_block_index && ( 'after' === $relative_position || 'before' === $relative_position ) ) { if ( 'after' === $relative_position ) { - $anchor_block_index++; + ++$anchor_block_index; } array_splice( $block['innerBlocks'], $anchor_block_index, 0, array( $inserted_block ) ); @@ -181,9 +194,9 @@ function gutenberg_insert_hooked_block( $inserted_block, $relative_position, $an $chunk_index = 0; while ( $anchor_block_index > 0 ) { if ( ! is_string( $block['innerContent'][ $chunk_index ] ) ) { - $anchor_block_index--; + --$anchor_block_index; } - $chunk_index++; + ++$chunk_index; } // Since WP_Block::render() iterates over `inner_content` (rather than `inner_blocks`) // when rendering blocks, we also need to insert a value (`null`, to mark a block @@ -204,7 +217,7 @@ function gutenberg_insert_hooked_block( $inserted_block, $relative_position, $an * @return callable A filter for the `rest_prepare_block_type` hook that adds a `block_hooks` field to the network response. */ function gutenberg_add_block_hooks_field_to_block_type_controller( $inserted_block_type, $position, $anchor_block_type ) { - return function( $response, $block_type ) use ( $inserted_block_type, $position, $anchor_block_type ) { + return function ( $response, $block_type ) use ( $inserted_block_type, $position, $anchor_block_type ) { if ( $block_type->name !== $inserted_block_type ) { return $response; } @@ -233,7 +246,7 @@ function gutenberg_add_block_hooks_field_to_block_type_controller( $inserted_blo */ function gutenberg_parse_and_serialize_block_templates( $query_result ) { foreach ( $query_result as $block_template ) { - if ( 'custom' === $block_template->source ) { + if ( empty( $block_template->content ) || 'custom' === $block_template->source ) { continue; } $blocks = parse_blocks( $block_template->content ); @@ -242,7 +255,6 @@ function gutenberg_parse_and_serialize_block_templates( $query_result ) { return $query_result; } -add_filter( 'get_block_templates', 'gutenberg_parse_and_serialize_block_templates', 10, 1 ); /** * Filters the block template object after it has been (potentially) fetched from the theme file. @@ -256,13 +268,46 @@ function gutenberg_parse_and_serialize_block_templates( $query_result ) { * @param WP_Block_Template|null $block_template The found block template, or null if there is none. */ function gutenberg_parse_and_serialize_blocks( $block_template ) { + if ( empty( $block_template->content ) ) { + return $block_template; + } $blocks = parse_blocks( $block_template->content ); $block_template->content = gutenberg_serialize_blocks( $blocks ); return $block_template; } -add_filter( 'get_block_file_template', 'gutenberg_parse_and_serialize_blocks', 10, 1 ); + +/** + * Register the `block_hooks` field for the block-types REST API controller. + * + * @return void + */ +function gutenberg_register_block_hooks_rest_field() { + register_rest_field( + 'block-type', + 'block_hooks', + array( + 'schema' => array( + 'description' => __( 'This block is automatically inserted near any occurence of the block types used as keys of this map, into a relative position given by the corresponding value.', 'gutenberg' ), + 'patternProperties' => array( + '^[a-zA-Z0-9-]+/[a-zA-Z0-9-]+$' => array( + 'type' => 'string', + 'enum' => array( 'before', 'after', 'first_child', 'last_child' ), + ), + ), + ), + ) + ); +} + +// Install the polyfill for Block Hooks only if it isn't already handled in WordPress core. +if ( ! function_exists( 'traverse_and_serialize_blocks' ) ) { + add_filter( 'block_type_metadata_settings', 'gutenberg_add_hooked_blocks', 10, 2 ); + add_filter( 'get_block_templates', 'gutenberg_parse_and_serialize_block_templates', 10, 1 ); + add_filter( 'get_block_file_template', 'gutenberg_parse_and_serialize_blocks', 10, 1 ); + add_action( 'rest_api_init', 'gutenberg_register_block_hooks_rest_field' ); +} // Helper functions. // ----------------- @@ -328,27 +373,3 @@ function gutenberg_serialize_block( $block ) { function gutenberg_serialize_blocks( $blocks ) { return implode( '', array_map( 'gutenberg_serialize_block', $blocks ) ); } - -/** - * Register the `block_hooks` field for the block-types REST API controller. - * - * @return void - */ -function gutenberg_register_block_hooks_rest_field() { - register_rest_field( - 'block-type', - 'block_hooks', - array( - 'schema' => array( - 'description' => __( 'This block is automatically inserted near any occurence of the block types used as keys of this map, into a relative position given by the corresponding value.', 'gutenberg' ), - 'patternProperties' => array( - '^[a-zA-Z0-9-]+/[a-zA-Z0-9-]+$' => array( - 'type' => 'string', - 'enum' => array( 'before', 'after', 'first_child', 'last_child' ), - ), - ), - ), - ) - ); -} -add_action( 'rest_api_init', 'gutenberg_register_block_hooks_rest_field' ); diff --git a/lib/compat/wordpress-6.4/block-patterns.php b/lib/compat/wordpress-6.4/block-patterns.php index aa4c5ef378bc7a..922dea910b47a0 100644 --- a/lib/compat/wordpress-6.4/block-patterns.php +++ b/lib/compat/wordpress-6.4/block-patterns.php @@ -16,20 +16,20 @@ */ function gutenberg_register_taxonomy_patterns() { $args = array( - array( - 'public' => false, - 'hierarchical' => false, - 'labels' => array( - 'name' => _x( 'Pattern Categories', 'taxonomy general name' ), - 'singular_name' => _x( 'Pattern Category', 'taxonomy singular name' ), - ), - 'query_var' => false, - 'rewrite' => false, - 'show_ui' => false, - '_builtin' => true, - 'show_in_nav_menus' => false, - 'show_in_rest' => true, + 'public' => true, + 'publicly_queryable' => false, + 'hierarchical' => false, + 'labels' => array( + 'name' => _x( 'Pattern Categories', 'taxonomy general name' ), + 'singular_name' => _x( 'Pattern Category', 'taxonomy singular name' ), ), + 'query_var' => false, + 'rewrite' => false, + 'show_ui' => true, + '_builtin' => true, + 'show_in_nav_menus' => false, + 'show_in_rest' => true, + 'show_admin_column' => true, ); register_taxonomy( 'wp_pattern_category', array( 'wp_block' ), $args ); } diff --git a/lib/experimental/class-gutenberg-rest-block-patterns-controller.php b/lib/compat/wordpress-6.4/class-gutenberg-rest-block-patterns-controller.php similarity index 84% rename from lib/experimental/class-gutenberg-rest-block-patterns-controller.php rename to lib/compat/wordpress-6.4/class-gutenberg-rest-block-patterns-controller.php index e4ac5581910e00..3fb7eef547e469 100644 --- a/lib/experimental/class-gutenberg-rest-block-patterns-controller.php +++ b/lib/compat/wordpress-6.4/class-gutenberg-rest-block-patterns-controller.php @@ -26,12 +26,18 @@ class Gutenberg_REST_Block_Patterns_Controller extends Gutenberg_REST_Block_Patt */ public function prepare_item_for_response( $item, $request ) { $response = parent::prepare_item_for_response( $item, $request ); - if ( ! gutenberg_is_experiment_enabled( 'gutenberg-block-hooks' ) ) { + + // Run the polyfill for Block Hooks only if it isn't already handled in WordPress core. + if ( function_exists( 'traverse_and_serialize_blocks' ) ) { return $response; } $data = $response->get_data(); + if ( empty( $data['content'] ) ) { + return $response; + } + $blocks = parse_blocks( $data['content'] ); $data['content'] = gutenberg_serialize_blocks( $blocks ); // Serialize or render? diff --git a/lib/compat/wordpress-6.4/class-gutenberg-rest-global-styles-revisions-controller-6-4.php b/lib/compat/wordpress-6.4/class-gutenberg-rest-global-styles-revisions-controller-6-4.php index 75b3916a1697df..910f6973e53f8f 100644 --- a/lib/compat/wordpress-6.4/class-gutenberg-rest-global-styles-revisions-controller-6-4.php +++ b/lib/compat/wordpress-6.4/class-gutenberg-rest-global-styles-revisions-controller-6-4.php @@ -19,7 +19,6 @@ class Gutenberg_REST_Global_Styles_Revisions_Controller_6_4 extends Gutenberg_RE * Prepares the revision for the REST response. * * @since 6.3.0 - * @since 6.4.0 Added `behaviors` field to the response. * * @param WP_Post $post Post revision object. * @param WP_REST_Request $request Request object. @@ -36,7 +35,7 @@ public function prepare_item_for_response( $post, $request ) { $fields = $this->get_fields_for_response( $request ); $data = array(); - if ( ! empty( $global_styles_config['styles'] ) || ! empty( $global_styles_config['settings'] ) || ! empty( $global_styles_config['behaviors'] ) ) { + if ( ! empty( $global_styles_config['styles'] ) || ! empty( $global_styles_config['settings'] ) ) { $global_styles_config = ( new WP_Theme_JSON_Gutenberg( $global_styles_config, 'custom' ) )->get_raw_data(); if ( rest_is_field_included( 'settings', $fields ) ) { $data['settings'] = ! empty( $global_styles_config['settings'] ) ? $global_styles_config['settings'] : new stdClass(); @@ -44,9 +43,6 @@ public function prepare_item_for_response( $post, $request ) { if ( rest_is_field_included( 'styles', $fields ) ) { $data['styles'] = ! empty( $global_styles_config['styles'] ) ? $global_styles_config['styles'] : new stdClass(); } - if ( rest_is_field_included( 'behaviors', $fields ) ) { - $data['behaviors'] = ! empty( $global_styles_config['behaviors'] ) ? $global_styles_config['behaviors'] : new stdClass(); - } } if ( rest_is_field_included( 'author', $fields ) ) { @@ -88,7 +84,6 @@ public function prepare_item_for_response( $post, $request ) { * Retrieves the revision's schema, conforming to JSON Schema. * * @since 6.3.0 - * @since 6.4.0 Added `behaviors` field to the schema properties. * * @return array Item schema data. */ @@ -159,11 +154,6 @@ public function get_item_schema() { 'type' => array( 'object' ), 'context' => array( 'view', 'edit' ), ), - 'behaviors' => array( - 'description' => __( 'Global behaviors.', 'gutenberg' ), - 'type' => array( 'object' ), - 'context' => array( 'view', 'edit' ), - ), ), ); diff --git a/lib/compat/wordpress-6.4/fonts/font-face/class-wp-font-face-resolver.php b/lib/compat/wordpress-6.4/fonts/font-face/class-wp-font-face-resolver.php index 84375b6c52f5d4..01b9d4566aa670 100644 --- a/lib/compat/wordpress-6.4/fonts/font-face/class-wp-font-face-resolver.php +++ b/lib/compat/wordpress-6.4/fonts/font-face/class-wp-font-face-resolver.php @@ -5,6 +5,8 @@ * @package WordPress * @subpackage Fonts * @since 6.4.0 + * + * @core-merge: this file is located in `wp-includes/fonts/`. */ if ( class_exists( 'WP_Font_Face_Resolver' ) ) { @@ -33,7 +35,7 @@ public static function get_fonts_from_theme_json() { $settings = gutenberg_get_global_settings(); // Bail out early if there are no font settings. - if ( empty( $settings['typography'] ) || empty( $settings['typography']['fontFamilies'] ) ) { + if ( empty( $settings['typography']['fontFamilies'] ) ) { return array(); } @@ -54,30 +56,54 @@ private static function parse_settings( array $settings ) { foreach ( $settings['typography']['fontFamilies'] as $font_families ) { foreach ( $font_families as $definition ) { - // Skip if font-family "name" is not defined. - if ( empty( $definition['name'] ) ) { + // Skip if "fontFace" is not defined, meaning there are no variations. + if ( empty( $definition['fontFace'] ) ) { continue; } - // Skip if "fontFace" is not defined, meaning there are no variations. - if ( empty( $definition['fontFace'] ) ) { + // Skip if "fontFamily" is not defined. + if ( empty( $definition['fontFamily'] ) ) { continue; } - $font_family = $definition['name']; + $font_family_name = static::maybe_parse_name_from_comma_separated_list( $definition['fontFamily'] ); + + // Skip if no font family is defined. + if ( empty( $font_family_name ) ) { + continue; + } // Prepare the fonts array structure for this font-family. - if ( ! array_key_exists( $font_family, $fonts ) ) { - $fonts[ $font_family ] = array(); + if ( ! array_key_exists( $font_family_name, $fonts ) ) { + $fonts[ $font_family_name ] = array(); } - $fonts[ $font_family ] = static::convert_font_face_properties( $definition['fontFace'], $font_family ); + $fonts[ $font_family_name ] = static::convert_font_face_properties( $definition['fontFace'], $font_family_name ); } } return $fonts; } + /** + * Parse font-family name from comma-separated lists. + * + * If the given `fontFamily` is a comma-separated lists (example: "Inter, sans-serif" ), + * parse and return the fist font from the list. + * + * @since 6.4.0 + * + * @param string $font_family Font family `fontFamily' to parse. + * @return string Font-family name. + */ + private static function maybe_parse_name_from_comma_separated_list( $font_family ) { + if ( str_contains( $font_family, ',' ) ) { + $font_family = explode( ',', $font_family )[0]; + } + + return trim( $font_family, "\"'" ); + } + /** * Converts font-face properties from theme.json format. * diff --git a/lib/compat/wordpress-6.4/fonts/font-face/class-wp-font-face.php b/lib/compat/wordpress-6.4/fonts/font-face/class-wp-font-face.php index 0489fe4f4fbd52..8bb1d55414854f 100644 --- a/lib/compat/wordpress-6.4/fonts/font-face/class-wp-font-face.php +++ b/lib/compat/wordpress-6.4/fonts/font-face/class-wp-font-face.php @@ -5,6 +5,8 @@ * @package WordPress * @subpackage Fonts * @since 6.4.0 + * + * @core-merge: this file is located in `wp-includes/fonts/`. */ if ( class_exists( 'WP_Font_Face' ) ) { @@ -82,23 +84,6 @@ class WP_Font_Face { * @since 6.4.0 */ public function __construct() { - /** - * Filters the font-face property defaults. - * - * @since 6.4.0 - * - * @param array $defaults { - * An array of required font-face properties and defaults. - * - * @type string $provider The provider ID. Default 'local'. - * @type string $font-family The font-family property. Default empty string. - * @type string $font-style The font-style property. Default 'normal'. - * @type string $font-weight The font-weight property. Default '400'. - * @type string $font-display The font-display property. Default 'fallback'. - * } - */ - $this->font_face_property_defaults = apply_filters( 'wp_font_face_property_defaults', $this->font_face_property_defaults ); - if ( function_exists( 'is_admin' ) && ! is_admin() && @@ -113,7 +98,9 @@ function_exists( 'current_theme_supports' ) && ! current_theme_supports( 'html5' * * @since 6.4.0 * - * @param array $fonts The fonts to generate and print @font-face styles. + * @param array[][] $fonts Optional. The font-families and their font variations. + * See {@see wp_print_font_faces()} for the supported fields. + * Default empty array. */ public function generate_and_print( array $fonts ) { $fonts = $this->validate_fonts( $fonts ); @@ -123,10 +110,21 @@ public function generate_and_print( array $fonts ) { return; } - printf( - $this->get_style_element(), - $this->get_css( $fonts ) - ); + $css = $this->get_css( $fonts ); + + /* + * The font-face CSS is contained within and open a ', '' ), '', ob_get_clean() ) ); } /** diff --git a/packages/block-library/src/code/block.json b/packages/block-library/src/code/block.json index 4d19423f1b6291..80df74b5062b56 100644 --- a/packages/block-library/src/code/block.json +++ b/packages/block-library/src/code/block.json @@ -10,7 +10,8 @@ "content": { "type": "string", "source": "html", - "selector": "code" + "selector": "code", + "__unstablePreserveWhiteSpace": true } }, "supports": { diff --git a/packages/block-library/src/code/edit.js b/packages/block-library/src/code/edit.js index 4153b14d753cdc..a3dbedeaf23352 100644 --- a/packages/block-library/src/code/edit.js +++ b/packages/block-library/src/code/edit.js @@ -3,20 +3,32 @@ */ import { __ } from '@wordpress/i18n'; import { RichText, useBlockProps } from '@wordpress/block-editor'; +import { createBlock, getDefaultBlockName } from '@wordpress/blocks'; -export default function CodeEdit( { attributes, setAttributes, onRemove } ) { +export default function CodeEdit( { + attributes, + setAttributes, + onRemove, + insertBlocksAfter, + mergeBlocks, +} ) { const blockProps = useBlockProps(); return (
 			 setAttributes( { content } ) }
 				onRemove={ onRemove }
+				onMerge={ mergeBlocks }
 				placeholder={ __( 'Write codeโ€ฆ' ) }
 				aria-label={ __( 'Code' ) }
 				preserveWhiteSpace
 				__unstablePastePlainText
+				__unstableOnSplitAtDoubleLineEnd={ () =>
+					insertBlocksAfter( createBlock( getDefaultBlockName() ) )
+				}
 			/>
 		
); diff --git a/packages/block-library/src/code/index.js b/packages/block-library/src/code/index.js index 091c59ffbfca47..c602045256d6e9 100644 --- a/packages/block-library/src/code/index.js +++ b/packages/block-library/src/code/index.js @@ -29,6 +29,11 @@ export const settings = { /* eslint-enable @wordpress/i18n-no-collapsible-whitespace */ }, }, + merge( attributes, attributesToMerge ) { + return { + content: attributes.content + '\n\n' + attributesToMerge.content, + }; + }, transforms, edit, save, diff --git a/packages/block-library/src/comment-template/index.php b/packages/block-library/src/comment-template/index.php index 5a0eef5685cf1c..915c5880a8f962 100644 --- a/packages/block-library/src/comment-template/index.php +++ b/packages/block-library/src/comment-template/index.php @@ -28,7 +28,7 @@ function block_core_comment_template_render_comments( $comments, $block ) { $content = ''; foreach ( $comments as $comment ) { $comment_id = $comment->comment_ID; - $filter_block_context = static function( $context ) use ( $comment_id ) { + $filter_block_context = static function ( $context ) use ( $comment_id ) { $context['commentId'] = $comment_id; return $context; }; diff --git a/packages/block-library/src/comments-pagination-next/index.php b/packages/block-library/src/comments-pagination-next/index.php index 5a8df691ff0924..51d1f75c58d477 100644 --- a/packages/block-library/src/comments-pagination-next/index.php +++ b/packages/block-library/src/comments-pagination-next/index.php @@ -26,7 +26,7 @@ function render_block_core_comments_pagination_next( $attributes, $content, $blo $label = isset( $attributes['label'] ) && ! empty( $attributes['label'] ) ? $attributes['label'] : $default_label; $pagination_arrow = get_comments_pagination_arrow( $block, 'next' ); - $filter_link_attributes = static function() { + $filter_link_attributes = static function () { return get_block_wrapper_attributes(); }; add_filter( 'next_comments_link_attributes', $filter_link_attributes ); diff --git a/packages/block-library/src/comments-pagination-previous/index.php b/packages/block-library/src/comments-pagination-previous/index.php index ed3fa653abda9e..f194e8ab517f57 100644 --- a/packages/block-library/src/comments-pagination-previous/index.php +++ b/packages/block-library/src/comments-pagination-previous/index.php @@ -22,7 +22,7 @@ function render_block_core_comments_pagination_previous( $attributes, $content, $label = $pagination_arrow . $label; } - $filter_link_attributes = static function() { + $filter_link_attributes = static function () { return get_block_wrapper_attributes(); }; add_filter( 'previous_comments_link_attributes', $filter_link_attributes ); diff --git a/packages/block-library/src/cover/block.json b/packages/block-library/src/cover/block.json index e88dd2d65a3722..c186a2416f5c9e 100644 --- a/packages/block-library/src/cover/block.json +++ b/packages/block-library/src/cover/block.json @@ -42,6 +42,9 @@ "customOverlayColor": { "type": "string" }, + "isUserOverlayColor": { + "type": "boolean" + }, "backgroundType": { "type": "string", "default": "image" diff --git a/packages/block-library/src/cover/deprecated.js b/packages/block-library/src/cover/deprecated.js index d1801a11ade9de..fc15cb4ac46d49 100644 --- a/packages/block-library/src/cover/deprecated.js +++ b/packages/block-library/src/cover/deprecated.js @@ -97,7 +97,7 @@ const blockAttributes = { }, }; -const v8ToV10BlockAttributes = { +const v8ToV11BlockAttributes = { url: { type: 'string', }, @@ -164,7 +164,19 @@ const v8ToV10BlockAttributes = { }, }; -const v7toV10BlockSupports = { +const v12BlockAttributes = { + ...v8ToV11BlockAttributes, + useFeaturedImage: { + type: 'boolean', + default: false, + }, + tagName: { + type: 'string', + default: 'div', + }, +}; + +const v7toV11BlockSupports = { anchor: true, align: true, html: false, @@ -182,10 +194,222 @@ const v7toV10BlockSupports = { }, }; +const v12BlockSupports = { + ...v7toV11BlockSupports, + spacing: { + padding: true, + margin: [ 'top', 'bottom' ], + blockGap: true, + __experimentalDefaultControls: { + padding: true, + blockGap: true, + }, + }, + __experimentalBorder: { + color: true, + radius: true, + style: true, + width: true, + __experimentalDefaultControls: { + color: true, + radius: true, + style: true, + width: true, + }, + }, + color: { + __experimentalDuotone: + '> .wp-block-cover__image-background, > .wp-block-cover__video-background', + heading: true, + text: true, + background: false, + __experimentalSkipSerialization: [ 'gradients' ], + enableContrastChecker: false, + }, + typography: { + fontSize: true, + lineHeight: true, + __experimentalFontFamily: true, + __experimentalFontWeight: true, + __experimentalFontStyle: true, + __experimentalTextTransform: true, + __experimentalTextDecoration: true, + __experimentalLetterSpacing: true, + __experimentalDefaultControls: { + fontSize: true, + }, + }, + layout: { + allowJustification: false, + }, +}; + +// Deprecation for blocks to prevent auto overlay color from overriding previously set values. +const v12 = { + attributes: v12BlockAttributes, + supports: v12BlockSupports, + isEligible( attributes ) { + return ( + attributes.customOverlayColor !== undefined || + attributes.overlayColor !== undefined + ); + }, + migrate( attributes ) { + return { + ...attributes, + isUserOverlayColor: true, + }; + }, + save( { attributes } ) { + const { + backgroundType, + gradient, + contentPosition, + customGradient, + customOverlayColor, + dimRatio, + focalPoint, + useFeaturedImage, + hasParallax, + isDark, + isRepeated, + overlayColor, + url, + alt, + id, + minHeight: minHeightProp, + minHeightUnit, + tagName: Tag, + } = attributes; + const overlayColorClass = getColorClassName( + 'background-color', + overlayColor + ); + const gradientClass = __experimentalGetGradientClass( gradient ); + const minHeight = + minHeightProp && minHeightUnit + ? `${ minHeightProp }${ minHeightUnit }` + : minHeightProp; + + const isImageBackground = IMAGE_BACKGROUND_TYPE === backgroundType; + const isVideoBackground = VIDEO_BACKGROUND_TYPE === backgroundType; + + const isImgElement = ! ( hasParallax || isRepeated ); + + const style = { + minHeight: minHeight || undefined, + }; + + const bgStyle = { + backgroundColor: ! overlayColorClass + ? customOverlayColor + : undefined, + background: customGradient ? customGradient : undefined, + }; + + const objectPosition = + // prettier-ignore + focalPoint && isImgElement + ? mediaPosition(focalPoint) + : undefined; + + const backgroundImage = url ? `url(${ url })` : undefined; + + const backgroundPosition = mediaPosition( focalPoint ); + + const classes = classnames( + { + 'is-light': ! isDark, + 'has-parallax': hasParallax, + 'is-repeated': isRepeated, + 'has-custom-content-position': + ! isContentPositionCenter( contentPosition ), + }, + getPositionClassName( contentPosition ) + ); + + const imgClasses = classnames( + 'wp-block-cover__image-background', + id ? `wp-image-${ id }` : null, + { + 'has-parallax': hasParallax, + 'is-repeated': isRepeated, + } + ); + + const gradientValue = gradient || customGradient; + + return ( + +