diff --git a/.eslintrc.js b/.eslintrc.js index 13c7e260e9bd9..4063bb42cf32a 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -105,6 +105,7 @@ const restrictedImports = [ 'lowerCase', 'map', 'mapKeys', + 'mapValues', 'maxBy', 'memoize', 'merge', diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index d3ba813d3cd8a..d578b20c6cb61 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,5 +1,5 @@ # Documentation -/docs @ajitbohra @ryanwelcher @juanmaguitar @fabiankaegy +/docs @ajitbohra @ryanwelcher @juanmaguitar @fabiankaegy @ndiego # Schemas /schemas/json @ajlende @@ -57,7 +57,7 @@ # Tooling /bin @ntwb @nerrad @ajitbohra /bin/api-docs @ntwb @nerrad @ajitbohra -/docs/tool @ajitbohra +/docs/tool @ajitbohra @ndiego /packages/babel-plugin-import-jsx-pragma @ntwb @nerrad @ajitbohra /packages/babel-plugin-makepot @ntwb @nerrad @ajitbohra /packages/babel-preset-default @gziolo @ntwb @nerrad @ajitbohra @@ -125,7 +125,7 @@ /packages/report-flaky-tests @kevin940726 # wp-env -/packages/env @noahtallen +/packages/env @noahtallen @ObliviousHarmony # PHP /lib @spacedmonkey diff --git a/.github/workflows/check-components-changelog.yml b/.github/workflows/check-components-changelog.yml index 23fbe9183ca8d..c0cb4894009a2 100644 --- a/.github/workflows/check-components-changelog.yml +++ b/.github/workflows/check-components-changelog.yml @@ -42,8 +42,8 @@ jobs: exit 1 fi - pr_link_pattern="\(\[#${PR_NUMBER}\]\(https://github\.com/WordPress/gutenberg/pull/${PR_NUMBER}\)\)" - pr_link_grep_pattern="(\[#${PR_NUMBER}\](https://github\.com/WordPress/gutenberg/pull/${PR_NUMBER}))" + pr_link_pattern="\[#${PR_NUMBER}\]\(https://github\.com/WordPress/gutenberg/pull/${PR_NUMBER}\)" + pr_link_grep_pattern="\[#${PR_NUMBER}\](https://github\.com/WordPress/gutenberg/pull/${PR_NUMBER})" unreleased_section=$(sed -n '/^## Unreleased$/,/^## /p' "${changelog_path}") diff --git a/.github/workflows/unit-test.yml b/.github/workflows/unit-test.yml index 230a971e8f39d..16a7eba93858c 100644 --- a/.github/workflows/unit-test.yml +++ b/.github/workflows/unit-test.yml @@ -180,11 +180,35 @@ jobs: - name: Running single site unit tests if: ${{ ! matrix.multisite }} - run: npm run test:unit:php + run: | + set -o pipefail + npm run test:unit:php | tee phpunit.log - name: Running multisite unit tests if: ${{ matrix.multisite }} - run: npm run test:unit:php:multisite + run: | + set -o pipefail + npm run test:unit:php:multisite | tee phpunit.log + + # Verifies that PHPUnit actually runs in the first place. We want visibility + # into issues which can cause it to fail silently, so we check the output + # to verify that at least 500 tests have passed. This is an arbitrary + # number, but makes sure a drastic change doesn't happen without us noticing. + - name: Check number of passed tests + run: | + # Note: relies on PHPUnit execution to fail on test failure. + # Extract the number of executed tests from the log file. + if ! num_tests=$(grep -Eo 'OK \([0-9]+ tests' phpunit.log) ; then + if ! num_tests=$(grep -Eo 'Tests: [0-9]+, Assertions:' phpunit.log) ; then + echo "PHPUnit failed or did not run. Check the PHPUnit output in the previous step to debug." && exit 1 + fi + fi + # Extract just the number of tests from the string. + num_tests=$(echo "$num_tests" | grep -Eo '[0-9]+') + if [ $num_tests -lt 500 ] ; then + echo "Only $num_tests tests passed, which is much fewer than expected." && exit 1 + fi + echo "$num_tests tests passed." phpcs: name: PHP coding standards diff --git a/bin/packages/build-worker.js b/bin/packages/build-worker.js index e82091ff84374..3f1512ef0feb7 100644 --- a/bin/packages/build-worker.js +++ b/bin/packages/build-worker.js @@ -103,9 +103,13 @@ async function buildCSS( file ) { 'animations', 'z-index', ] - // Editor styles should be excluded from the default CSS vars output. + // Editor and component styles should be excluded from the default CSS vars output. .concat( - file.includes( 'common.scss' ) || ! file.includes( 'block-library' ) + file.includes( 'common.scss' ) || + ! ( + file.includes( 'block-library' ) || + file.includes( 'components' ) + ) ? [ 'default-custom-properties' ] : [] ) diff --git a/bin/plugin/commands/changelog.js b/bin/plugin/commands/changelog.js index dfee1faa50065..69be77ac66991 100644 --- a/bin/plugin/commands/changelog.js +++ b/bin/plugin/commands/changelog.js @@ -919,6 +919,10 @@ function getContributorProps( pullRequests ) { getContributorPropsMarkdownList, ] )( pullRequests ); + if ( ! contributorsList ) { + return ''; + } + return ( '## First time contributors' + '\n\n' + diff --git a/bin/plugin/commands/performance.js b/bin/plugin/commands/performance.js index 0804c794e9d8e..57c6674500a22 100644 --- a/bin/plugin/commands/performance.js +++ b/bin/plugin/commands/performance.js @@ -3,7 +3,6 @@ */ const fs = require( 'fs' ); const path = require( 'path' ); -const { mapValues } = require( 'lodash' ); const SimpleGit = require( 'simple-git' ); /** @@ -475,10 +474,26 @@ async function runPerformanceTests( branches, options ) { ( r ) => r[ branch ][ dataPoint ] ); } ); - const medians = mapValues( resultsByDataPoint, median ); + // @ts-ignore + const medians = Object.fromEntries( + Object.entries( resultsByDataPoint ).map( + ( [ dataPoint, dataPointResults ] ) => [ + dataPoint, + median( dataPointResults ), + ] + ) + ); // Format results as times. - results[ testSuite ][ branch ] = mapValues( medians, formatTime ); + // @ts-ignore + results[ testSuite ][ branch ] = Object.fromEntries( + Object.entries( medians ).map( + ( [ dataPoint, dataPointMedian ] ) => [ + dataPoint, + formatTime( dataPointMedian ), + ] + ) + ); } } diff --git a/bin/plugin/commands/test/changelog.js b/bin/plugin/commands/test/changelog.js index 6d201fbc27c96..52a9391af11d1 100644 --- a/bin/plugin/commands/test/changelog.js +++ b/bin/plugin/commands/test/changelog.js @@ -485,6 +485,11 @@ describe( 'getContributorProps', () => { // npm run other:changelog -- --milestone="Gutenberg 11.3" expect( getContributorProps( pullRequests ) ).toMatchSnapshot(); } ); + test( 'do not include first time contributors section if there are not any', () => { + expect( + getContributorProps( pullRequests.slice( 0, 4 ) ) + ).toMatchInlineSnapshot( `""` ); + } ); } ); describe( 'getContributorList', () => { diff --git a/changelog.txt b/changelog.txt index 79f119e74f776..c0eb6f61a62ae 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,9 +1,329 @@ == Changelog == -= 15.7.0-rc.1 = += 15.8.0-rc.1 = + +## Changelog + +### Features + +- Add the command center to the post editor. ([50128](https://github.com/WordPress/gutenberg/pull/50128)) +- Add revisions UI. ([50089](https://github.com/WordPress/gutenberg/pull/50089)) +- Add Theme Previews for block themes. ([50030](https://github.com/WordPress/gutenberg/pull/50030)) + + +### Enhancements + +#### Global Styles +- Fluid typography: Use `layout.wideSize` as max viewport width. ([49815](https://github.com/WordPress/gutenberg/pull/49815)) +- Global styles revisions: Remove human time diff and custom author fields from the API response. ([50234](https://github.com/WordPress/gutenberg/pull/50234)) +- Unify the global block styles panel with the block inspector panels. ([49428](https://github.com/WordPress/gutenberg/pull/49428)) + +#### Post Editor +- Add `` component. ([50260](https://github.com/WordPress/gutenberg/pull/50260)) +- Update background color of post editor when viewing mobile or tablet viewports, or in template mode. ([50361](https://github.com/WordPress/gutenberg/pull/50361)) +- Display device icon on "preview" and "view" buttons. ([50218](https://github.com/WordPress/gutenberg/pull/50218)) +- Improve "switch to draft" placement. ([50217](https://github.com/WordPress/gutenberg/pull/50217)) +- Post Featured Image: New design for Replace and Remove buttons. ([50269](https://github.com/WordPress/gutenberg/pull/50269)) + +#### Block Library +- More intuitive Details block with summary and innerBlocks content. ([49808](https://github.com/WordPress/gutenberg/pull/49808)) +- Simplify cover block description. ([50355](https://github.com/WordPress/gutenberg/pull/50355)) +- Cover: Only show overlay controls when color support enabled. ([50115](https://github.com/WordPress/gutenberg/pull/50115)) +- Navigation: Hide color controls when color support is disabled. ([50368](https://github.com/WordPress/gutenberg/pull/50368)) +- Post Featured Image: Hide overlay controls when color support is disabled. ([50331](https://github.com/WordPress/gutenberg/pull/50331)) +- Social Icons: Hide color controls when color support is disabled. ([50275](https://github.com/WordPress/gutenberg/pull/50275)) + +#### Fonts API +- Separate BC Layer. ([50077](https://github.com/WordPress/gutenberg/pull/50077)) + +#### Site Editor +- Add the pages menu to the site editor. ([50463](https://github.com/WordPress/gutenberg/pull/50463)) +- Introduce new PluginTemplateSettingPanel slot. ([50257](https://github.com/WordPress/gutenberg/pull/50257)) +- Add chevrons to the templates and template parts in site editor. ([50076](https://github.com/WordPress/gutenberg/pull/50076)) + +#### Components +- Button: Add opt-in prop for next 40px default size. ([50254](https://github.com/WordPress/gutenberg/pull/50254)) +- Consolidate and add documentation to Storybook. ([50226](https://github.com/WordPress/gutenberg/pull/50226)) +- DimensionControl: Use WordPress package instead of react in code example. ([50435](https://github.com/WordPress/gutenberg/pull/50435)) +- FormTokenField, ComboboxControl: Add opt-in prop for next 40px default size. ([50261](https://github.com/WordPress/gutenberg/pull/50261)) +- Global Styles: Fix palette color popovers. ([49975](https://github.com/WordPress/gutenberg/pull/49975)) +- Relax link pattern matching in CHANGELOG CI check. ([50248](https://github.com/WordPress/gutenberg/pull/50248)) +- Remove custom padding for tertiary buttons. ([50276](https://github.com/WordPress/gutenberg/pull/50276)) +- Update `Autocomplete` usage example. ([49965](https://github.com/WordPress/gutenberg/pull/49965)) +- Update default accent color. ([50193](https://github.com/WordPress/gutenberg/pull/50193)) +- Update has-text has-icon button spacing. ([50277](https://github.com/WordPress/gutenberg/pull/50277)) + +#### CSS & Styling +- Polish confirm dialog padding. ([50283](https://github.com/WordPress/gutenberg/pull/50283)) + +#### Template Editor +- Remove `start blank` option in template pattern suggestions and add `skip` button. ([50099](https://github.com/WordPress/gutenberg/pull/50099)) +- Templates: Sort by the rendered title instead of the slug. ([50353](https://github.com/WordPress/gutenberg/pull/50353)) + + +#### Block Editor +- List View: Allow dragging to all levels of the block hierarchy. ([49742](https://github.com/WordPress/gutenberg/pull/49742)) +- Allow dragging-and-dropping images from the inserter to image blocks. ([49673](https://github.com/WordPress/gutenberg/pull/49673)) +- Try always showing the dimensions controls. ([50305](https://github.com/WordPress/gutenberg/pull/50305)) +- Adds a renderAdditionalBlockUI prop to ListView. ([50465](https://github.com/WordPress/gutenberg/pull/50465)) +- Update the expanded text color so that it works in both a dark and light context. ([50434](https://github.com/WordPress/gutenberg/pull/50434)) +- Enable Loginout block in Nav block. ([49160](https://github.com/WordPress/gutenberg/pull/49160)) +- Mark related selector as resolved when sideloading Navigation fallback. ([50324](https://github.com/WordPress/gutenberg/pull/50324)) +- Update Template Parts icon to use the symbol. ([50410](https://github.com/WordPress/gutenberg/pull/50410)) +- Use Core Data for Nav fallbacks and side load resulting entity into state. ([50032](https://github.com/WordPress/gutenberg/pull/50032)) +- Tweak copy for block settings menu "Insert..." to "Add...". ([50444](https://github.com/WordPress/gutenberg/pull/50444)) +- Block settings menu: Rearrange items. ([50453](https://github.com/WordPress/gutenberg/pull/50453)) + +#### Rest API +- Update image editor to use new REST API. ([28530](https://github.com/WordPress/gutenberg/pull/28530)) + + + +### Bug Fixes + +#### Block Library +- Center align button text in editor. ([50228](https://github.com/WordPress/gutenberg/pull/50228)) +- Comment Template Block: Set `commentId` context via filter. ([50279](https://github.com/WordPress/gutenberg/pull/50279)) +- Cover: Use overflow: clip, falling back to overflow: Hidden to allow sticky children (technically). ([50237](https://github.com/WordPress/gutenberg/pull/50237)) +- Ensure imported Classic Menu dirty state to include in Editor entity changes list. ([50318](https://github.com/WordPress/gutenberg/pull/50318)) +- File Block: Defer hiding PDF embeds for unsupported browsers until the page has loaded. ([50113](https://github.com/WordPress/gutenberg/pull/50113)) +- Fix template part area variation matching. ([49500](https://github.com/WordPress/gutenberg/pull/49500)) +- Fix the pocket casts embed variation. ([50132](https://github.com/WordPress/gutenberg/pull/50132)) +- Gallery: Fix inner block selection. ([50363](https://github.com/WordPress/gutenberg/pull/50363)) +- Post Terms: Use publicly_queryable to query taxonomies used to register variations. ([50244](https://github.com/WordPress/gutenberg/pull/50244)) +- Remove extraneous "Link" copy from PanelBody components. ([50186](https://github.com/WordPress/gutenberg/pull/50186)) +- Remove Quote transform from Group ([50424](https://github.com/WordPress/gutenberg/pull/50424)) +- [Post Featured Image]: Revert maxWidth addition. ([50427](https://github.com/WordPress/gutenberg/pull/50427)) +- [Post Title]: Insert default block on Enter at end. ([50312](https://github.com/WordPress/gutenberg/pull/50312)) +- Ensure that view scripts are correctly registered for core blocks. ([50364](https://github.com/WordPress/gutenberg/pull/50364)) + +#### Global Styles +- Close stylebook if the editor canvas container slot is not filled. ([50086](https://github.com/WordPress/gutenberg/pull/50086)) +- Fix positioning of gradient palette popovers on mobile. ([50233](https://github.com/WordPress/gutenberg/pull/50233)) +- Fix/wp get global styles for custom props returns internal variable. ([50366](https://github.com/WordPress/gutenberg/pull/50366)) +- Revisions controller: Fix author and date fields. ([50117](https://github.com/WordPress/gutenberg/pull/50117)) +- Fix hover/focus styles for `style variation` buttons. ([50056](https://github.com/WordPress/gutenberg/pull/50056)) + +#### Block Editor +- Fix issue with margin collapsing when selecting blocks. ([50215](https://github.com/WordPress/gutenberg/pull/50215)) +- List View / Block Draggable: Fix scroll to top issue when dragging the second last block in the list. ([50119](https://github.com/WordPress/gutenberg/pull/50119)) +- Multi-select: Capitalise B in blocks. ([50356](https://github.com/WordPress/gutenberg/pull/50356)) +- URLInput: Update the 'ENTER' key down event handler. ([50158](https://github.com/WordPress/gutenberg/pull/50158)) +- Update OffCanvas component's more menu to get clientId from block rather than passed in as prop. ([50473](https://github.com/WordPress/gutenberg/pull/50473)) +- Block Toolbar: Don't use effects for focus management. ([50497](https://github.com/WordPress/gutenberg/pull/50497)) +- Don't remount the block when the 'templateLock' is set to 'contentOnly'. ([50292](https://github.com/WordPress/gutenberg/pull/50292)) + +#### Themes +- Refactor theme previews. ([50338](https://github.com/WordPress/gutenberg/pull/50338)) +- Remove gutenberg plugin mention in schema. ([50207](https://github.com/WordPress/gutenberg/pull/50207)) +- Theme Preview: Restrict to admin users. ([50335](https://github.com/WordPress/gutenberg/pull/50335)) +- Theme Previews: Fix refactor. ([50354](https://github.com/WordPress/gutenberg/pull/50354)) + +#### Site Editor +- Display conditionally the `styles` in sidebar main navigation screen. ([50329](https://github.com/WordPress/gutenberg/pull/50329)) +- Remove canvas box shadow. ([50374](https://github.com/WordPress/gutenberg/pull/50374)) +- Save Button: Fix the label in the disabled state. ([50284](https://github.com/WordPress/gutenberg/pull/50284)) +- Remove white background on Site Editor 'Frame'. ([48970](https://github.com/WordPress/gutenberg/pull/48970)) +- Update some visual details in the add-template modal(s). ([50143](https://github.com/WordPress/gutenberg/pull/50143)) + +#### Components +- Spacing: Fix reset of spacing sizes control. ([50455](https://github.com/WordPress/gutenberg/pull/50455)) +- `NavigableContailer`: Do not trap focus in `TabbableContainer`. ([49846](https://github.com/WordPress/gutenberg/pull/49846)) +- Remove fill="none" from levelUp icon. ([50264](https://github.com/WordPress/gutenberg/pull/50264)) + + +#### Accessibility +- Add missing tooltip to Site Editor navigation Back icon button. ([50104](https://github.com/WordPress/gutenberg/pull/50104)) +- Fix Multiple Tooltips from Focus Toolbar Shortcut on Widget Editor. ([50344](https://github.com/WordPress/gutenberg/pull/50344)) +- Site Editor Keyboard Navigation Flow. ([50296](https://github.com/WordPress/gutenberg/pull/50296)) +- Small improvements for the sidebars and Close buttons labeling. ([49614](https://github.com/WordPress/gutenberg/pull/49614)) + +#### Design Tools +- Changed so that borders and radius are maintained when Duotone is changed. ([50088](https://github.com/WordPress/gutenberg/pull/50088)) +- LineHeightControl: Fix application of zero values in editor. ([48917](https://github.com/WordPress/gutenberg/pull/48917)) + +#### Fonts API +- [Font API] Do not print in admin using 'admin_print_styles' for themes with theme.json. ([50259](https://github.com/WordPress/gutenberg/pull/50259)) + +#### Widget Editor +- Fixes fixed block toolbar in widgets editor. ([50371](https://github.com/WordPress/gutenberg/pull/50371)) + + +### Performance +- Improve Site Editor loading experience([50222](https://github.com/WordPress/gutenberg/pull/50222)) + + +### Experiments + +#### Interactivity API +- Add Interactivity API runtime. ([49994](https://github.com/WordPress/gutenberg/pull/49994)) +- Navigation block with the Interactivity API. ([50041](https://github.com/WordPress/gutenberg/pull/50041)) + +#### Command Center +- Update the experiment label. ([50467](https://github.com/WordPress/gutenberg/pull/50467)) +- Add an API to open/close the command center. ([50423](https://github.com/WordPress/gutenberg/pull/50423)) +- Fix a style glitch on Safari. ([50138](https://github.com/WordPress/gutenberg/pull/50138)) +- Add a button to open it from the site editor view mode. ([50425](https://github.com/WordPress/gutenberg/pull/50425)) +- Do not show dynamic add new post, add new page commands. ([50221](https://github.com/WordPress/gutenberg/pull/50221)) +- Extract the WordPress reusable commands to a dedicated package. ([49956](https://github.com/WordPress/gutenberg/pull/49956)) +- Fix command menu not re-opening after closing it. ([50213](https://github.com/WordPress/gutenberg/pull/50213)) + + +### Documentation + +- Add changelog for eslint-plugin validating dependencies in `useSelect` and `useSuspenseSelect` hooks. ([50247](https://github.com/WordPress/gutenberg/pull/50247)) +- Add client-side filter reference to Curating the Editor doc and fix links. ([50203](https://github.com/WordPress/gutenberg/pull/50203)) +- Add missing closing parenthesis in code example. ([50253](https://github.com/WordPress/gutenberg/pull/50253)) +- Adds example to change the permalink structure. ([50251](https://github.com/WordPress/gutenberg/pull/50251)) +- Adds links to REST-API reference. ([50070](https://github.com/WordPress/gutenberg/pull/50070)) +- Create-block script includes link to documentation in render.php file. ([50206](https://github.com/WordPress/gutenberg/pull/50206)) +- Block API > Registration: Switch markdown to a-tags. ([50110](https://github.com/WordPress/gutenberg/pull/50110)) +- Don't use markdown in the callout section. ([50437](https://github.com/WordPress/gutenberg/pull/50437)) +- Remove mention of perf testing from release documentation. ([50345](https://github.com/WordPress/gutenberg/pull/50345)) +- Update Callout documentation on links. ([50131](https://github.com/WordPress/gutenberg/pull/50131)) +- Fix incorrect label in contributor docs. ([50201](https://github.com/WordPress/gutenberg/pull/50201)) +- Fix minor formatting issues in Performance doc. ([50202](https://github.com/WordPress/gutenberg/pull/50202)) +- Fixes incorrect URLs in doc blocks. ([50123](https://github.com/WordPress/gutenberg/pull/50123)) +- Use alert callout in the block deprecation documentation. ([50286](https://github.com/WordPress/gutenberg/pull/50286)) +- Improve CardMedia documentation. ([50074](https://github.com/WordPress/gutenberg/pull/50074)) +- Update README of TreeGrid with data-expanded attribute usage. ([50026](https://github.com/WordPress/gutenberg/pull/50026)) + + +### Code Quality + +- Block Editor: Directly import useShouldContextualToolbarShow hook. ([50506](https://github.com/WordPress/gutenberg/pull/50506)) +- BlockControls, InspectorControls: Remove useSlot, unify behavior on bad group. ([50198](https://github.com/WordPress/gutenberg/pull/50198)) +- Enqueue registered block assets and resolve iframe styles end-to-end failure. ([50185](https://github.com/WordPress/gutenberg/pull/50185)) +- Make eslint-plugin validate dependencies in `useSelect` and `useSuspenseSelect` hooks. ([49900](https://github.com/WordPress/gutenberg/pull/49900)) +- Save Hub: Reuse the save button component to save code. ([50145](https://github.com/WordPress/gutenberg/pull/50145)) +- Use apiFetch instead of window.fetch. ([50043](https://github.com/WordPress/gutenberg/pull/50043)) +- Add types to dispatch and select. ([49930](https://github.com/WordPress/gutenberg/pull/49930)) +- Remove duplicate comment. ([50304](https://github.com/WordPress/gutenberg/pull/50304)) + +#### Lodash removal +- Remove from blocks store reducer. ([50471](https://github.com/WordPress/gutenberg/pull/50471)) +- Remove `_.mapValues()` from `getBlockContentSchemaFromTransforms`. ([50096](https://github.com/WordPress/gutenberg/pull/50096)) +- Refactor away from `_.mapValues()`. ([50285](https://github.com/WordPress/gutenberg/pull/50285)) +- Remove `_.mapValues()` from blocks reducer. ([50097](https://github.com/WordPress/gutenberg/pull/50097)) + +#### Components +- Fix incorrect focus style widths. ([50127](https://github.com/WordPress/gutenberg/pull/50127)) +- Refactor/toolbar item component to typescript. ([49190](https://github.com/WordPress/gutenberg/pull/49190)) +- SlotFill: Several code cleanups. ([50098](https://github.com/WordPress/gutenberg/pull/50098)) +- SlotFill: Some code cleanups of the bubblesVirtually version. ([50133](https://github.com/WordPress/gutenberg/pull/50133)) +- Convert `NavigableContainer` to TypeScript. ([49377](https://github.com/WordPress/gutenberg/pull/49377)) + +#### Block Editor +- Block Editor: Add names for the 'editor.BlockListBlock' filter HoCs. ([50513](https://github.com/WordPress/gutenberg/pull/50513)) +- Refactor around missing dependency in Link Control internal value sync effect. ([49509](https://github.com/WordPress/gutenberg/pull/49509)) +- Don't export Slot/Fill constants separately. ([50274](https://github.com/WordPress/gutenberg/pull/50274)) + +#### Block Library +- Centralize constants for the navigation block. ([50191](https://github.com/WordPress/gutenberg/pull/50191)) +- Move deprecated Nav block functions to bottom of render file. ([50328](https://github.com/WordPress/gutenberg/pull/50328)) +- Refactor BlockList uses Hooks. ([50293](https://github.com/WordPress/gutenberg/pull/50293)) + +#### List View +- Replace OffCanvasEditor in browse mode with the List View component. ([50287](https://github.com/WordPress/gutenberg/pull/50287)) +- Use block select button class for retaining colors when expanded or hovered. ([50155](https://github.com/WordPress/gutenberg/pull/50155)) + +#### Global Styles +- Global styles revisions: Ensure the revisions endpoint permissions match the global styles controller. ([50270](https://github.com/WordPress/gutenberg/pull/50270)) +- Simplify CustomCSS UI. ([49721](https://github.com/WordPress/gutenberg/pull/49721)) + +#### Plugin +- Update REST API Controller PHPUnit tests. ([50120](https://github.com/WordPress/gutenberg/pull/50120)) +- Update the Gutenberg plugin to require at least the WP 6.1 version. ([50079](https://github.com/WordPress/gutenberg/pull/50079)) +- Update the tested up to version for the gutenberg plugin. ([50360](https://github.com/WordPress/gutenberg/pull/50360)) + +#### Native +- Add a few import required for the React Native wrapper distribution as iOS XCFramework. ([50009](https://github.com/WordPress/gutenberg/pull/50009)) + +#### Site Editor +- Extract the Router APIs and context into a dedicated package. ([50100](https://github.com/WordPress/gutenberg/pull/50100)) +- Move loading logic to a separate hook. ([50511](https://github.com/WordPress/gutenberg/pull/50511)) + + + +### Tools + +#### wp-env +- Add `wp-env` After Setup Command. ([50196](https://github.com/WordPress/gutenberg/pull/50196)) +- Fix wp-env destroy. ([50445](https://github.com/WordPress/gutenberg/pull/50445)) +- Refactored `wp-env` configuration Parsing. ([50071](https://github.com/WordPress/gutenberg/pull/50071)) +- Wp-env fix exec command in CI. ([50411](https://github.com/WordPress/gutenberg/pull/50411)) +- wp-env: Add better default PHPunit settings, fix Xdebug, and update documentation. ([50490](https://github.com/WordPress/gutenberg/pull/50490)) +- wp-env: Improve run command execution speed. ([50007](https://github.com/WordPress/gutenberg/pull/50007)) +- Cleaned up Port Validation and Removed Unnecessary Default Ports. ([50300](https://github.com/WordPress/gutenberg/pull/50300)) +- Match Container's User and Group to Host. ([49962](https://github.com/WordPress/gutenberg/pull/49962)) + +#### Testing +- Add end-to-end test for editing the title of a new custom template part. ([50195](https://github.com/WordPress/gutenberg/pull/50195)) +- Add test to verify image appears on frontend. ([50472](https://github.com/WordPress/gutenberg/pull/50472)) +- Add tests coverage for the navigation block frontend interactivity. ([50462](https://github.com/WordPress/gutenberg/pull/50462)) +- Migrate Adding Patterns Test to Playwright. ([50083](https://github.com/WordPress/gutenberg/pull/50083)) +- Migrate Keep Transform Block Test Case to Playwright. ([49719](https://github.com/WordPress/gutenberg/pull/49719)) +- Migrate PullQuote test case to playwright. ([50085](https://github.com/WordPress/gutenberg/pull/50085)) +- Migrate undo to Playwright. ([48701](https://github.com/WordPress/gutenberg/pull/48701)) +- Prerelease end-to-end Test Utils for Playwright. ([43998](https://github.com/WordPress/gutenberg/pull/43998)) +- Skip creating flaky issues on PRs. ([50146](https://github.com/WordPress/gutenberg/pull/50146)) +- end-to-end tests: Try to fix flaky global styles revisions tests. ([50454](https://github.com/WordPress/gutenberg/pull/50454)) +- Add BlockList text coverage. ([50252](https://github.com/WordPress/gutenberg/pull/50252)) + +#### Build Tooling +- Changelog automation: Apply proper top-level categorization precedence to meta PRs. ([50208](https://github.com/WordPress/gutenberg/pull/50208)) +- Do not include first time contributors section in changelog if there are not any. ([50291](https://github.com/WordPress/gutenberg/pull/50291)) +- Publish rich text build types. ([49651](https://github.com/WordPress/gutenberg/pull/49651)) +- Rich text: Rename index.js > index.ts for type-only exports. ([50212](https://github.com/WordPress/gutenberg/pull/50212)) +- Remove PHPUnit and Composer packages. ([50408](https://github.com/WordPress/gutenberg/pull/50408)) + +#### Repository Maintainance +- Add ndiego as codeowner for docs. ([50289](https://github.com/WordPress/gutenberg/pull/50289)) + + +## First time contributors + +The following PRs were merged by first time contributors: + +- @johnhooks: feature(data): Add types to dispatch and select. ([49930](https://github.com/WordPress/gutenberg/pull/49930)) +- @margolisj: Refactor/toolbar item component to typescript. ([49190](https://github.com/WordPress/gutenberg/pull/49190)) +- @n2erjo00: Create-block script includes link to documentation in render.php file. ([50206](https://github.com/WordPress/gutenberg/pull/50206)) +- @samnajian: Fix/wp get global styles for custom props returns internal variable. ([50366](https://github.com/WordPress/gutenberg/pull/50366)) + + +## Contributors + +The following contributors merged PRs in this release: + +@aaronrobertshaw @afercia @ajlende @alexstine @andrewserong @apeatling @artemiomorales @aurooba @bph @chad1008 @ciampo @DAreRodz @dcalhoun @draganescu @ecgan @fluiddot @fullofcaffeine @geriux @getdave @glendaviesnz @gziolo @hellofromtonya @ironprogrammer @jameskoster @jasmussen @jeryj @jhnstn @johnhooks @jsnajdr @juanfra @kevin940726 @kienstra @Mamaduka @margolisj @mburridge @mirka @mokagio @mtias @n2erjo00 @ndiego @noahtallen @noisysocks @ntsekouras @oandregal @ObliviousHarmony @ocean90 @ockham @pavanpatil1 @pooja-muchandikar @priethor @ramonjd @richtabor @samnajian @SantosGuillamot @scruffian @SiobhyB @t-hamano @talldan @tellthemachines @torounit @tyxla @westonruter @youknowriad + + += 15.7.1 = +## Changelog + +### Enhancements + +#### Fonts API +- Relocate which fonts to print into wp_print_fonts(). ([50151](https://github.com/WordPress/gutenberg/pull/50151)) + + +### Tools + +#### Testing +- Skip iframe-inline-styles end-to-end test. ([50320](https://github.com/WordPress/gutenberg/pull/50320)) + +## Contributors + +The following contributors merged PRs in this release: + +@hellofromtonya @scruffian + + += 15.7.0 = + ## Changelog ### Enhancements @@ -57,6 +377,8 @@ - Adjust copy of Site Logo Block. ([49540](https://github.com/WordPress/gutenberg/pull/49540)) - Adapt flex child controls for Spacer. ([49362](https://github.com/WordPress/gutenberg/pull/49362)) - Social Icon: Update the `link` and `mail` block variation's icons. ([49952](https://github.com/WordPress/gutenberg/pull/49952)) +- Cover: Re-instate overflow:Hidden rule to fix issue with border radius. ([50209](https://github.com/WordPress/gutenberg/pull/50209)) +- Fix site logo preview image size with long filenames. ([50242](https://github.com/WordPress/gutenberg/pull/50242)) #### Components - CheckboxControl: Add support custom IDs. ([49977](https://github.com/WordPress/gutenberg/pull/49977)) @@ -76,6 +398,7 @@ - Do not add unregistered style variations to the theme.json schema. ([49807](https://github.com/WordPress/gutenberg/pull/49807)) - Update preset styles to use Selectors API. ([49427](https://github.com/WordPress/gutenberg/pull/49427)) - Change the 'WP_Theme_JSON_Data_Gutenberg' class directory. ([50062](https://github.com/WordPress/gutenberg/pull/50062)) +- Layout: Fix issue where saving user global styles included layout definitions in layout settings. ([50268](https://github.com/WordPress/gutenberg/pull/50268)) #### Site Editor - Fix screen flash when deleting templates in templates list. ([48449](https://github.com/WordPress/gutenberg/pull/48449)) @@ -88,7 +411,7 @@ - Correctly return 'isResolving' from 'useAlternativeTemplateParts' hook. ([49921](https://github.com/WordPress/gutenberg/pull/49921)) #### Patterns -- Increase dimensions of the pattern modal that appears when creating a new page. ([49859](https://github.com/WordPress/gutenberg/pull/49859)) +- Increase the dimensions of the pattern modal that appears when creating a new page. ([49859](https://github.com/WordPress/gutenberg/pull/49859)) - Update full screen modal dimensions, and pattern grids. ([49894](https://github.com/WordPress/gutenberg/pull/49894)) - Increase pattern modal dimensions when creating a new template. ([49722](https://github.com/WordPress/gutenberg/pull/49722)) @@ -206,6 +529,8 @@ The following contributors merged PRs in this release: @aaronrobertshaw @adamziel @ajlende @alexstine @andrewserong @annziel @aurooba @bdurette @bph @carolinan @chad1008 @chintu51 @courtneyr-dev @dcalhoun @derekblank @draganescu @ellatrix @fluiddot @gaambo @geriux @getdave @gigitux @guarani @gvgvgvijayan @gziolo @hellofromtonya @jameskoster @jasmussen @jeryj @jhnstn @jsnajdr @juanmaguitar @kevin940726 @m0hanraj @MaggieCabrera @MahendraBishnoi29 @Mamaduka @masteradhoc @mburridge @mcsf @mikachan @mirka @mokagio @mtias @ndiego @noahtallen @ntsekouras @oandregal @ObliviousHarmony @priethor @ramonjd @scruffian @SiobhyB @Soean @sque89 @t-hamano @talldan @tellthemachines @tyrann0us @tyxla @Wtower @youknowriad @zzap + + = 15.6.2 = diff --git a/docs/contributors/code/release.md b/docs/contributors/code/release.md index 8d9f46120d2f5..3dd8863859e37 100644 --- a/docs/contributors/code/release.md +++ b/docs/contributors/code/release.md @@ -17,7 +17,7 @@ We release a new major version approximately every two weeks. The current and ne - **On the date of the current milestone**, we publish a release candidate and make it available for plugin authors and users to test. If any regressions are found with a release candidate, a new one can be published. On this date, all remaining PRs on the milestone are moved automatically to the next release. Release candidates should be versioned incrementally, starting with `-rc.1`, then `-rc.2`, and so on. [Preparation of the release post starts here](/docs/block-editor/contributors/code/release/#writing-the-release-notes-and-post) and spans until the final release. -- **One week after the first release candidate**, the stable version is created based on the last release candidate and any necessary regression fixes. Once the stable version is released, the release post is published, including a [performance audit](/docs/block-editor/contributors/testing-overview/#performance-testing). +- **One week after the first release candidate**, the stable version is created based on the last release candidate and any necessary regression fixes. Once the stable version is released and the release post is published. If critical bugs are discovered on stable versions of the plugin, patch versions can be released at any time. @@ -103,8 +103,7 @@ Documenting the release is a group effort between the release manager, Gutenberg 1. Curating the changelog - Wednesday after the RC release to Friday 2. Selecting the release highlights - Friday to Monday 3. Drafting the release post - Monday to Wednesday -4. Running the performance tests - Wednesday right after the stable release -5. Publishing the post - Wednesday after stable release +4. Publishing the post - Wednesday after stable release #### 1. Curating the changelog @@ -140,21 +139,6 @@ When possible, the highlighted changes in the release post should include an ani These visual assets should maintain consistency with previous release posts; using lean, white themes helps in this regard and visually integrate well with the [make.wordpress.org/core](https://make.wordpress.org/core/) blog aesthetics. Including copyrighted material should be avoided, and browser plugins that can be seen in the browser canvas (spell checkers, form fillers, etc.) disabled when capturing the assets. -#### 4. Running the performance tests - -The post should also include a performance audit at the end, comparing the current Gutenberg release with both the previous one and the latest WordPress major version. There are GitHub worfklows in place to do this comparison as part of the Continuous Integration setup, so the performance audit results can be found at the workflow run generated by the release commit in the [Performance Tests workflows](https://github.com/WordPress/gutenberg/actions/workflows/performance.yml) page, with the job name `Compare performance with current WordPress Core and previous Gutenberg versions`. - -If the GitHub workflow fails, the performance audit can be executed locally using `bin/plugin/cli.js perf` and passing the branches to run the performance suite against as parameters. In addition, the current major WP version can be passed to avoid running tests against the WP `trunk`. Example: - -``` -node ./bin/plugin/cli.js perf release/x.y release/x.z wp/a.b --wp-version wp.major -``` - -The performance values usually displayed in the release post are: - -- Time to the first block (test named `firstBlock`) -- KeyPress Event (typing) (test named `type`) - #### 5. Publishing the post Once the post content is ready, an author already having permissions to post in [make.wordpress.org/core](https://make.wordpress.org/core/) will create a new draft and import the content; this post should be published after the actual release, helping external media to echo and amplify the release news. Remember asking for peer review is encouraged by the [make/core posting guidelines](https://make.wordpress.org/core/handbook/best-practices/post-comment-guidelines/#peer-review)! @@ -165,7 +149,7 @@ Occasionally it's necessary to create a minor release (i.e. X.Y.**Z**) of the Pl As you proceed with the following process, it's worth bearing in mind that such minor releases are not created as branches in their own right (e.g. `release/12.5.0`) but are simply [tags](https://github.com/WordPress/gutenberg/releases/tag/v12.5.1). -The method for minor releases is nearly identical to the main Plugin release process (see above) but has some notable exceptions. Please make sure to read _the whole_ of this guide before proceeding. +The method for minor releases is nearly identical to the main Plugin release process (see above) but has some notable exceptions. Please make sure to read _the entire_ guide before proceeding. #### Updating the release branch @@ -217,7 +201,7 @@ This is expected. The draft release will contain only the plugin zip. Only once > Do I need to publish point releases to WordPress.org? -Yes. The method for this is identical to the main Plugin release process. You will need a Gutenberg Core team member to approve the release workflow. +Yes. The method for this is identical to the main Plugin release process. You will need a member of the Gutenberg Core team the Gutenberg Release team to approve the release workflow. > The release process failed to cherry-pick version bump commit to the trunk branch. diff --git a/docs/explanations/faq.md b/docs/explanations/faq.md index f9c6b059e133d..4a365ce5b41d1 100644 --- a/docs/explanations/faq.md +++ b/docs/explanations/faq.md @@ -151,7 +151,7 @@ This is the canonical list of keyboard shortcuts: Z - Show or hide the settings sidebar. + Show or hide the Settings sidebar. Ctrl+Shift+, , diff --git a/docs/how-to-guides/themes/theme-json.md b/docs/how-to-guides/themes/theme-json.md index 5956f36d52563..4a3dc8f70a85e 100644 --- a/docs/how-to-guides/themes/theme-json.md +++ b/docs/how-to-guides/themes/theme-json.md @@ -1174,7 +1174,7 @@ Currently block variations exist for "header" and "footer" values of the area te ### patterns -
Supported in WordPress from version 6.0 using [version 2](https://developer.wordpress.org/block-editor/reference-guides/theme-json-reference/theme-json-living/) of `theme.json`.
+
Supported in WordPress from version 6.0 using version 2 of theme.json.
Within this field themes can list patterns to register from [Pattern Directory](https://wordpress.org/patterns/). The `patterns` field is an array of pattern `slugs` from the Pattern Directory. Pattern slugs can be extracted by the `url` in single pattern view at the Pattern Directory. For example in this url `https://wordpress.org/patterns/pattern/partner-logos` the slug is `partner-logos`. diff --git a/docs/manifest.json b/docs/manifest.json index 304acd00a79ea..8b6677d39c559 100644 --- a/docs/manifest.json +++ b/docs/manifest.json @@ -1577,6 +1577,12 @@ "markdown_source": "../packages/dom/README.md", "parent": "packages" }, + { + "title": "@wordpress/e2e-test-utils-playwright", + "slug": "packages-e2e-test-utils-playwright", + "markdown_source": "../packages/e2e-test-utils-playwright/README.md", + "parent": "packages" + }, { "title": "@wordpress/e2e-test-utils", "slug": "packages-e2e-test-utils", diff --git a/docs/reference-guides/block-api/block-deprecation.md b/docs/reference-guides/block-api/block-deprecation.md index 7154f84072e61..d40c13c040612 100644 --- a/docs/reference-guides/block-api/block-deprecation.md +++ b/docs/reference-guides/block-api/block-deprecation.md @@ -55,7 +55,9 @@ Deprecations are defined on a block type as its `deprecated` property, an array - _Return_ - `boolean`: Whether or not this otherwise valid block is eligible to be migrated by this deprecation. -It's important to note that `attributes`, `supports`, and `save` are not automatically inherited from the current version, since they can impact parsing and serialization of a block, so they must be defined on the deprecated object in order to be processed during a migration. +
+It's important to note that attributes, supports, and save are not automatically inherited from the current version, since they can impact parsing and serialization of a block, so they must be defined on the deprecated object in order to be processed during a migration. +
### Example: diff --git a/docs/reference-guides/core-blocks.md b/docs/reference-guides/core-blocks.md index 751fe394962f6..25790ba3ab4e9 100644 --- a/docs/reference-guides/core-blocks.md +++ b/docs/reference-guides/core-blocks.md @@ -226,7 +226,7 @@ Displays a title with the number of comments ([Source](https://github.com/WordPr ## Cover -Add an image or video with a text overlay — great for headers. ([Source](https://github.com/WordPress/gutenberg/tree/trunk/packages/block-library/src/cover)) +Add an image or video with a text overlay. ([Source](https://github.com/WordPress/gutenberg/tree/trunk/packages/block-library/src/cover)) - **Name:** core/cover - **Category:** media @@ -235,30 +235,12 @@ Add an image or video with a text overlay — great for headers. ([Source](https ## Details -A block that displays a summary and shows or hides additional content. ([Source](https://github.com/WordPress/gutenberg/tree/trunk/packages/block-library/src/details)) +Hide and show additional content. ([Source](https://github.com/WordPress/gutenberg/tree/trunk/packages/block-library/src/details)) - **Name:** core/details - **Category:** text -- **Supports:** align, color (background, gradients, link, text), spacing (margin, padding), typography (fontSize, lineHeight), ~~html~~ -- **Attributes:** showContent - -## Details Content - -Add content that may be shown or hidden via a Details block. ([Source](https://github.com/WordPress/gutenberg/tree/trunk/packages/block-library/src/details-content)) - -- **Name:** core/details-content -- **Category:** text -- **Supports:** color (background, gradients, link, text), spacing (margin, padding), typography (fontSize, lineHeight), ~~align~~, ~~html~~, ~~lock~~, ~~multiple~~, ~~reusable~~ -- **Attributes:** - -## Details Summary - -Provide summary text used to toggle the display of content inside a Details block. ([Source](https://github.com/WordPress/gutenberg/tree/trunk/packages/block-library/src/details-summary)) - -- **Name:** core/details-summary -- **Category:** text -- **Supports:** color (background, gradients, text), spacing (margin, padding), typography (fontSize, lineHeight), ~~align~~, ~~html~~, ~~lock~~, ~~multiple~~, ~~reusable~~ -- **Attributes:** summary +- **Supports:** align (full, wide), color (background, gradients, link, text), spacing (margin, padding), typography (fontSize, lineHeight), ~~html~~ +- **Attributes:** showContent, summary ## Embed @@ -383,7 +365,7 @@ Show login & logout links. ([Source](https://github.com/WordPress/gutenberg/tree - **Name:** core/loginout - **Category:** theme -- **Supports:** anchor, className, typography (~~fontSize~~) +- **Supports:** anchor, className, typography (fontSize, lineHeight) - **Attributes:** displayLoginAsForm, redirectToCurrent ## Media & Text diff --git a/docs/reference-guides/data/data-core.md b/docs/reference-guides/data/data-core.md index ca925ef741e77..1ee04e09550e2 100644 --- a/docs/reference-guides/data/data-core.md +++ b/docs/reference-guides/data/data-core.md @@ -126,6 +126,18 @@ _Returns_ - `any`: The current theme. +### getCurrentThemeGlobalStylesRevisions + +Returns the revisions of the current global styles theme. + +_Parameters_ + +- _state_ `State`: Data state. + +_Returns_ + +- `Object | null`: The current global styles. + ### getCurrentUser Returns the current user. @@ -317,6 +329,18 @@ _Returns_ - `any`: The entity record's save error. +### getNavigationFallbackId + +Retrieve the fallback Navigation. + +_Parameters_ + +- _state_ `State`: Data state. + +_Returns_ + +- `EntityRecordKey | undefined`: The ID for the fallback Navigation post. + ### getRawEntityRecord Returns the entity's record object by key, with its attributes mapped to their raw values. @@ -607,6 +631,18 @@ _Returns_ - `Object`: Action object. +### receiveNavigationFallbackId + +Returns an action object signalling that the fallback Navigation Menu id has been received. + +_Parameters_ + +- _fallbackId_ `integer`: the id of the fallback Navigation Menu + +_Returns_ + +- `Object`: Action object. + ### receiveThemeSupports > **Deprecated** since WP 5.9, this is not useful anymore, use the selector direclty. diff --git a/gutenberg.php b/gutenberg.php index 6a5b12a03f26f..ce72c8eb81e4c 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.1 * Requires PHP: 5.6 - * Version: 15.7.0-rc.1 + * Version: 15.8.0-rc.1 * Author: Gutenberg Team * Text Domain: gutenberg * diff --git a/lib/block-editor-settings.php b/lib/block-editor-settings.php new file mode 100644 index 0000000000000..c0f514da8d85e --- /dev/null +++ b/lib/block-editor-settings.php @@ -0,0 +1,82 @@ + 'variables', + '__unstableType' => 'presets', + 'isGlobalStyles' => true, + ), + array( + 'css' => 'presets', + '__unstableType' => 'presets', + 'isGlobalStyles' => true, + ), + ); + foreach ( $presets as $preset_style ) { + $actual_css = gutenberg_get_global_stylesheet( array( $preset_style['css'] ) ); + if ( '' !== $actual_css ) { + $preset_style['css'] = $actual_css; + $global_styles[] = $preset_style; + } + } + + if ( wp_theme_has_theme_json() ) { + $block_classes = array( + 'css' => 'styles', + '__unstableType' => 'theme', + 'isGlobalStyles' => true, + ); + $actual_css = gutenberg_get_global_stylesheet( array( $block_classes['css'] ) ); + if ( '' !== $actual_css ) { + $block_classes['css'] = $actual_css; + $global_styles[] = $block_classes; + } + + /* + * Add the custom CSS as a separate stylesheet so any invalid CSS + * entered by users does not break other global styles. + */ + $global_styles[] = array( + 'css' => gutenberg_get_global_styles_custom_css(), + '__unstableType' => 'user', + 'isGlobalStyles' => true, + ); + } else { + // If there is no `theme.json` file, ensure base layout styles are still available. + $block_classes = array( + 'css' => 'base-layout-styles', + '__unstableType' => 'base-layout', + 'isGlobalStyles' => true, + ); + $actual_css = gutenberg_get_global_stylesheet( array( $block_classes['css'] ) ); + if ( '' !== $actual_css ) { + $block_classes['css'] = $actual_css; + $global_styles[] = $block_classes; + } + } + + $settings['styles'] = array_merge( $global_styles, get_block_editor_theme_styles() ); + + // Copied from get_block_editor_settings() at wordpress-develop/block-editor.php. + $settings['__experimentalFeatures'] = gutenberg_get_global_settings(); + + return $settings; +} +add_filter( 'block_editor_settings_all', 'gutenberg_get_block_editor_settings', PHP_INT_MAX ); diff --git a/lib/block-supports/typography.php b/lib/block-supports/typography.php index 8fc7a9bdcafb3..f1d29217e3883 100644 --- a/lib/block-supports/typography.php +++ b/lib/block-supports/typography.php @@ -265,12 +265,11 @@ function gutenberg_get_typography_value_and_unit( $raw_value, $options = array() return null; } - // Converts numeric values to pixel values by default. if ( empty( $raw_value ) ) { return null; } - // Converts numbers to pixel values by default. + // Converts numeric values to pixel values by default. if ( is_numeric( $raw_value ) ) { $raw_value = $raw_value . 'px'; } @@ -429,7 +428,10 @@ function gutenberg_get_typography_font_size_value( $preset, $should_use_fluid_ty } // Checks if fluid font sizes are activated. - $typography_settings = gutenberg_get_global_settings( array( 'typography' ) ); + $global_settings = gutenberg_get_global_settings(); + $typography_settings = isset( $global_settings['typography'] ) ? $global_settings['typography'] : array(); + $layout_settings = isset( $global_settings['layout'] ) ? $global_settings['layout'] : array(); + $should_use_fluid_typography = isset( $typography_settings['fluid'] ) && ( true === $typography_settings['fluid'] || is_array( $typography_settings['fluid'] ) ) ? @@ -443,7 +445,7 @@ function gutenberg_get_typography_font_size_value( $preset, $should_use_fluid_ty $fluid_settings = isset( $typography_settings['fluid'] ) && is_array( $typography_settings['fluid'] ) ? $typography_settings['fluid'] : array(); // Defaults. - $default_maximum_viewport_width = '1600px'; + $default_maximum_viewport_width = isset( $layout_settings['wideSize'] ) ? $layout_settings['wideSize'] : '1600px'; $default_minimum_viewport_width = '320px'; $default_minimum_font_size_factor_max = 0.75; $default_minimum_font_size_factor_min = 0.25; diff --git a/lib/blocks.php b/lib/blocks.php index 5fd004c007ad4..8ed03ee04de04 100644 --- a/lib/blocks.php +++ b/lib/blocks.php @@ -23,8 +23,6 @@ function gutenberg_reregister_core_block_types() { 'columns', 'comments', 'details', - 'details-content', - 'details-summary', 'group', 'html', 'list', @@ -139,8 +137,6 @@ function gutenberg_reregister_core_block_types() { $block_folders = $details['block_folders']; $block_names = $details['block_names']; - $registry = WP_Block_Type_Registry::get_instance(); - foreach ( $block_folders as $folder_name ) { $block_json_file = $blocks_dir . $folder_name . '/block.json'; @@ -152,10 +148,7 @@ function gutenberg_reregister_core_block_types() { continue; } - if ( $registry->is_registered( $metadata['name'] ) ) { - $registry->unregister( $metadata['name'] ); - } - + gutenberg_deregister_core_block_and_assets( $metadata['name'] ); gutenberg_register_core_block_assets( $folder_name ); register_block_type_from_metadata( $block_json_file ); } @@ -167,9 +160,7 @@ function gutenberg_reregister_core_block_types() { $sub_block_names_normalized = is_string( $sub_block_names ) ? array( $sub_block_names ) : $sub_block_names; foreach ( $sub_block_names_normalized as $block_name ) { - if ( $registry->is_registered( $block_name ) ) { - $registry->unregister( $block_name ); - } + gutenberg_deregister_core_block_and_assets( $block_name ); gutenberg_register_core_block_assets( $block_name ); } @@ -180,6 +171,28 @@ function gutenberg_reregister_core_block_types() { add_action( 'init', 'gutenberg_reregister_core_block_types' ); +/** + * Deregisters the existing core block type and its assets. + * + * @param string $block_name The name of the block. + * + * @return void + */ +function gutenberg_deregister_core_block_and_assets( $block_name ) { + $registry = WP_Block_Type_Registry::get_instance(); + if ( $registry->is_registered( $block_name ) ) { + $block_type = $registry->get_registered( $block_name ); + if ( ! empty( $block_type->view_script_handles ) ) { + foreach ( $block_type->view_script_handles as $view_script_handle ) { + if ( str_starts_with( $view_script_handle, 'wp-block-' ) ) { + wp_deregister_script( $view_script_handle ); + } + } + } + $registry->unregister( $block_name ); + } +} + /** * Registers block styles for a core block. * diff --git a/lib/class-wp-theme-json-gutenberg.php b/lib/class-wp-theme-json-gutenberg.php index fbbf9a05d1c81..dc9c25c8f90a5 100644 --- a/lib/class-wp-theme-json-gutenberg.php +++ b/lib/class-wp-theme-json-gutenberg.php @@ -795,7 +795,7 @@ protected static function sanitize( $input, $valid_block_names, $valid_element_n if ( empty( $result ) ) { unset( $output[ $subtree ] ); } else { - $output[ $subtree ] = $result; + $output[ $subtree ] = static::resolve_custom_css_format( $result ); } } @@ -1928,10 +1928,6 @@ protected static function compute_style_properties( $styles, $settings = array() /** * Returns the style property for the given path. * - * It also converts CSS Custom Property stored as - * "var:preset|color|secondary" to the form - * "--wp--preset--color--secondary". - * * It also converts references to a path to the value * stored at that location, e.g. * { "ref": "style.color.background" } => "#fff". @@ -1989,20 +1985,6 @@ protected static function get_property_value( $styles, $path, $theme_json = null return $value; } - // Convert custom CSS properties. - $prefix = 'var:'; - $prefix_len = strlen( $prefix ); - $token_in = '|'; - $token_out = '--'; - if ( 0 === strncmp( $value, $prefix, $prefix_len ) ) { - $unwrapped_name = str_replace( - $token_in, - $token_out, - substr( $value, $prefix_len ) - ); - $value = "var(--wp--$unwrapped_name)"; - } - return $value; } @@ -3578,4 +3560,51 @@ protected function get_feature_declarations_for_node( $metadata, &$node ) { return $declarations; } + + /** + * This is used to convert the internal representation of variables to the CSS representation. + * For example, `var:preset|color|vivid-green-cyan` becomes `var(--wp--preset--color--vivid-green-cyan)`. + * + * @since 6.3.0 + * @param string $value The variable such as var:preset|color|vivid-green-cyan to convert. + * @return string The converted variable. + */ + private static function convert_custom_properties( $value ) { + $prefix = 'var:'; + $prefix_len = strlen( $prefix ); + $token_in = '|'; + $token_out = '--'; + if ( 0 === strpos( $value, $prefix ) ) { + $unwrapped_name = str_replace( + $token_in, + $token_out, + substr( $value, $prefix_len ) + ); + $value = "var(--wp--$unwrapped_name)"; + } + + return $value; + } + + /** + * Given a tree, converts the internal representation of variables to the CSS representation. + * It is recursive and modifies the input in-place. + * + * @since 6.3.0 + * @param array $tree Input to process. + * @return array The modified $tree. + */ + private static function resolve_custom_css_format( $tree ) { + $prefix = 'var:'; + + foreach ( $tree as $key => $data ) { + if ( is_string( $data ) && 0 === strpos( $data, $prefix ) ) { + $tree[ $key ] = self::convert_custom_properties( $data ); + } elseif ( is_array( $data ) ) { + $tree[ $key ] = self::resolve_custom_css_format( $data ); + } + } + + return $tree; + } } diff --git a/lib/client-assets.php b/lib/client-assets.php index 9c0483ea539b9..9757e4b7ff24a 100644 --- a/lib/client-assets.php +++ b/lib/client-assets.php @@ -77,16 +77,8 @@ function gutenberg_override_script( $scripts, $handle, $src, $deps = array(), $v $scripts->add( $handle, $src, $deps, $ver, ( $in_footer ? 1 : null ) ); } - /* - * `WP_Dependencies::set_translations` will fall over on itself if setting - * translations on the `wp-i18n` handle, since it internally adds `wp-i18n` - * as a dependency of itself, exhausting memory. The same applies for the - * polyfill and hooks scripts, which are dependencies _of_ `wp-i18n`. - * - * See: https://core.trac.wordpress.org/ticket/46089 - */ - if ( ! in_array( $handle, array( 'wp-i18n', 'wp-polyfill', 'wp-hooks' ), true ) ) { - $scripts->set_translations( $handle, 'default' ); + if ( in_array( 'wp-i18n', $deps, true ) ) { + $scripts->set_translations( $handle ); } /* diff --git a/lib/compat/wordpress-6.2/block-editor-settings.php b/lib/compat/wordpress-6.2/block-editor-settings.php deleted file mode 100644 index 593a8b7e6b55f..0000000000000 --- a/lib/compat/wordpress-6.2/block-editor-settings.php +++ /dev/null @@ -1,31 +0,0 @@ - gutenberg_get_global_styles_custom_css(), - '__unstableType' => 'user', - 'isGlobalStyles' => true, - ); - } - - // Copied from get_block_editor_settings() at wordpress-develop/block-editor.php. - $settings['__experimentalFeatures'] = gutenberg_get_global_settings(); - - return $settings; -} - -add_filter( 'block_editor_settings_all', 'gutenberg_get_block_editor_settings_6_2', PHP_INT_MAX ); diff --git a/lib/compat/wordpress-6.2/default-filters.php b/lib/compat/wordpress-6.2/default-filters.php index 6a5bcb3b75b05..7e797af3e43b1 100644 --- a/lib/compat/wordpress-6.2/default-filters.php +++ b/lib/compat/wordpress-6.2/default-filters.php @@ -17,13 +17,6 @@ * @package gutenberg */ -/** - * When backporting to core, the existing filters hooked to WP_Theme_JSON_Resolver::clean_cached_data() - * need to be removed. - */ -add_action( 'start_previewing_theme', '_gutenberg_clean_theme_json_caches' ); -add_action( 'switch_theme', '_gutenberg_clean_theme_json_caches' ); - /** * This is a temporary fix to ensure that the block editor styles are enqueued * in the order the iframe expects. diff --git a/lib/compat/wordpress-6.2/get-global-styles-and-settings.php b/lib/compat/wordpress-6.2/get-global-styles-and-settings.php index e02a0466a0b98..eb1481a3808b6 100644 --- a/lib/compat/wordpress-6.2/get-global-styles-and-settings.php +++ b/lib/compat/wordpress-6.2/get-global-styles-and-settings.php @@ -59,176 +59,6 @@ function wp_theme_has_theme_json_clean_cache() { } } -/** - * Gets the global styles custom css from theme.json. - * - * @return string - */ -function gutenberg_get_global_styles_custom_css() { - // Ignore cache when `WP_DEBUG` is enabled, so it doesn't interfere with the theme developers workflow. - $can_use_cached = ! WP_DEBUG; - $cache_key = 'gutenberg_get_global_custom_css'; - $cache_group = 'theme_json'; - if ( $can_use_cached ) { - $cached = wp_cache_get( $cache_key, $cache_group ); - if ( $cached ) { - return $cached; - } - } - - if ( ! wp_theme_has_theme_json() ) { - return ''; - } - - $tree = WP_Theme_JSON_Resolver_Gutenberg::get_merged_data(); - $stylesheet = $tree->get_custom_css(); - - if ( $can_use_cached ) { - wp_cache_set( $cache_key, $stylesheet, $cache_group ); - } - - return $stylesheet; -} - -/** - * Returns the stylesheet resulting of merging core, theme, and user data. - * - * @param array $types Types of styles to load. Optional. - * It accepts as values: 'variables', 'presets', 'styles', 'base-layout-styles. - * If empty, it'll load the following: - * - for themes without theme.json: 'variables', 'presets', 'base-layout-styles'. - * - for themes with theme.json: 'variables', 'presets', 'styles'. - * - * @return string Stylesheet. - */ -function gutenberg_get_global_stylesheet( $types = array() ) { - // Ignore cache when `WP_DEBUG` is enabled, so it doesn't interfere with the theme developers workflow. - $can_use_cached = empty( $types ) && ! WP_DEBUG; - $cache_key = 'gutenberg_get_global_stylesheet'; - $cache_group = 'theme_json'; - if ( $can_use_cached ) { - $cached = wp_cache_get( $cache_key, $cache_group ); - if ( $cached ) { - return $cached; - } - } - $tree = WP_Theme_JSON_Resolver_Gutenberg::get_merged_data(); - $supports_theme_json = wp_theme_has_theme_json(); - if ( empty( $types ) && ! $supports_theme_json ) { - $types = array( 'variables', 'presets', 'base-layout-styles' ); - } elseif ( empty( $types ) ) { - $types = array( 'variables', 'presets', 'styles' ); - } - - /* - * If variables are part of the stylesheet, - * we add them. - * - * This is so themes without a theme.json still work as before 5.9: - * they can override the default presets. - * See https://core.trac.wordpress.org/ticket/54782 - */ - $styles_variables = ''; - if ( in_array( 'variables', $types, true ) ) { - /* - * We only use the default, theme, and custom origins. - * This is because styles for blocks origin are added - * at a later phase (render cycle) so we only render the ones in use. - * @see wp_add_global_styles_for_blocks - */ - $origins = array( 'default', 'theme', 'custom' ); - $styles_variables = $tree->get_stylesheet( array( 'variables' ), $origins ); - $types = array_diff( $types, array( 'variables' ) ); - } - - /* - * For the remaining types (presets, styles), we do consider origins: - * - * - themes without theme.json: only the classes for the presets defined by core - * - themes with theme.json: the presets and styles classes, both from core and the theme - */ - $styles_rest = ''; - if ( ! empty( $types ) ) { - /* - * We only use the default, theme, and custom origins. - * This is because styles for blocks origin are added - * at a later phase (render cycle) so we only render the ones in use. - * @see wp_add_global_styles_for_blocks - */ - $origins = array( 'default', 'theme', 'custom' ); - if ( ! $supports_theme_json ) { - $origins = array( 'default' ); - } - $styles_rest = $tree->get_stylesheet( $types, $origins ); - } - $stylesheet = $styles_variables . $styles_rest; - if ( $can_use_cached ) { - wp_cache_set( $cache_key, $stylesheet, $cache_group ); - } - return $stylesheet; -} - -/** - * Function to get the settings resulting of merging core, theme, and user data. - * - * @param array $path Path to the specific setting to retrieve. Optional. - * If empty, will return all settings. - * @param array $context { - * Metadata to know where to retrieve the $path from. Optional. - * - * @type string $block_name Which block to retrieve the settings from. - * If empty, it'll return the settings for the global context. - * @type string $origin Which origin to take data from. - * Valid values are 'all' (core, theme, and user) or 'base' (core and theme). - * If empty or unknown, 'all' is used. - * } - * - * @return array The settings to retrieve. - */ -function gutenberg_get_global_settings( $path = array(), $context = array() ) { - if ( ! empty( $context['block_name'] ) ) { - $new_path = array( 'blocks', $context['block_name'] ); - foreach ( $path as $subpath ) { - $new_path[] = $subpath; - } - $path = $new_path; - } - - // This is the default value when no origin is provided or when it is 'all'. - $origin = 'custom'; - if ( - ! wp_theme_has_theme_json() || - ( isset( $context['origin'] ) && 'base' === $context['origin'] ) - ) { - $origin = 'theme'; - } - - $cache_group = 'theme_json'; - $cache_key = 'gutenberg_get_global_settings_' . $origin; - $settings = wp_cache_get( $cache_key, $cache_group ); - - if ( false === $settings || WP_DEBUG ) { - $settings = WP_Theme_JSON_Resolver_Gutenberg::get_merged_data( $origin )->get_settings(); - wp_cache_set( $cache_key, $settings, $cache_group ); - } - - return _wp_array_get( $settings, $path, $settings ); -} - -/** - * Private function to clean the caches used by gutenberg_get_global_settings method. - * - * @access private - */ -function _gutenberg_clean_theme_json_caches() { - wp_cache_delete( 'wp_theme_has_theme_json', 'theme_json' ); - wp_cache_delete( 'gutenberg_get_global_stylesheet', 'theme_json' ); - wp_cache_delete( 'gutenberg_get_global_settings_custom', 'theme_json' ); - wp_cache_delete( 'gutenberg_get_global_settings_theme', 'theme_json' ); - wp_cache_delete( 'gutenberg_get_global_custom_css', 'theme_json' ); - WP_Theme_JSON_Resolver_Gutenberg::clean_cached_data(); -} - /** * Tell the cache mechanisms not to persist theme.json data across requests. * The data stored under this cache group: diff --git a/lib/compat/wordpress-6.2/html-api/class-wp-html-tag-processor.php b/lib/compat/wordpress-6.2/html-api/class-wp-html-tag-processor.php index 8c41e732154b4..f06302d4b742f 100644 --- a/lib/compat/wordpress-6.2/html-api/class-wp-html-tag-processor.php +++ b/lib/compat/wordpress-6.2/html-api/class-wp-html-tag-processor.php @@ -39,10 +39,10 @@ * * Example: * ```php - * $tags = new WP_HTML_Tag_Processor( $html ); - * if ( $tags->next_tag( 'option' ) ) { - * $tags->set_attribute( 'selected', true ); - * } + * $tags = new WP_HTML_Tag_Processor( $html ); + * if ( $tags->next_tag( 'option' ) ) { + * $tags->set_attribute( 'selected', true ); + * } * ``` * * ### Finding tags @@ -55,7 +55,7 @@ * * If you want to _find whatever the next tag is_: * ```php - * $tags->next_tag(); + * $tags->next_tag(); * ``` * * | Goal | Query | @@ -88,17 +88,17 @@ * * Example: * ```php - * // Paint up to the first five DIV or SPAN tags marked with the "jazzy" style. - * $remaining_count = 5; - * while ( $remaining_count > 0 && $tags->next_tag() ) { - * if ( - * ( 'DIV' === $tags->get_tag() || 'SPAN' === $tags->get_tag() ) && - * 'jazzy' === $tags->get_attribute( 'data-style' ) - * ) { - * $tags->add_class( 'theme-style-everest-jazz' ); - * $remaining_count--; - * } + * // Paint up to the first five DIV or SPAN tags marked with the "jazzy" style. + * $remaining_count = 5; + * while ( $remaining_count > 0 && $tags->next_tag() ) { + * if ( + * ( 'DIV' === $tags->get_tag() || 'SPAN' === $tags->get_tag() ) && + * 'jazzy' === $tags->get_attribute( 'data-style' ) + * ) { + * $tags->add_class( 'theme-style-everest-jazz' ); + * $remaining_count--; * } + * } * ``` * * `get_attribute()` will return `null` if the attribute wasn't present @@ -117,10 +117,10 @@ * * Example: * ```php - * if ( $tags->next_tag( array( 'class' => 'wp-group-block' ) ) ) { - * $tags->set_attribute( 'title', 'This groups the contained content.' ); - * $tags->remove_attribute( 'data-test-id' ); - * } + * if ( $tags->next_tag( array( 'class' => 'wp-group-block' ) ) ) { + * $tags->set_attribute( 'title', 'This groups the contained content.' ); + * $tags->remove_attribute( 'data-test-id' ); + * } * ``` * * If `set_attribute()` is called for an existing attribute it will @@ -142,29 +142,29 @@ * * Example: * ```php - * // from `Yippee!` - * // to `Yippee!` - * $tags->add_class( 'is-active' ); + * // from `Yippee!` + * // to `Yippee!` + * $tags->add_class( 'is-active' ); * - * // from `Yippee!` - * // to `Yippee!` - * $tags->add_class( 'is-active' ); + * // from `Yippee!` + * // to `Yippee!` + * $tags->add_class( 'is-active' ); * - * // from `Yippee!` - * // to `Yippee!` - * $tags->add_class( 'is-active' ); + * // from `Yippee!` + * // to `Yippee!` + * $tags->add_class( 'is-active' ); * - * // from `` - * // to ` - * $tags->remove_class( 'rugby' ); + * // from `` + * // to ` + * $tags->remove_class( 'rugby' ); * - * // from `` - * // to ` - * $tags->remove_class( 'rugby' ); + * // from `` + * // to ` + * $tags->remove_class( 'rugby' ); * - * // from `` - * // to ` - * $tags->remove_class( 'rugby' ); + * // from `` + * // to ` + * $tags->remove_class( 'rugby' ); * ``` * * When class changes are enqueued but a direct change to `class` is made via @@ -185,24 +185,24 @@ * bookmark and update it frequently, such as within a loop. * * ```php - * $total_todos = 0; - * while ( $p->next_tag( array( 'tag_name' => 'UL', 'class_name' => 'todo' ) ) ) { - * $p->set_bookmark( 'list-start' ); - * while ( $p->next_tag( array( 'tag_closers' => 'visit' ) ) ) { - * if ( 'UL' === $p->get_tag() && $p->is_tag_closer() ) { - * $p->set_bookmark( 'list-end' ); - * $p->seek( 'list-start' ); - * $p->set_attribute( 'data-contained-todos', (string) $total_todos ); - * $total_todos = 0; - * $p->seek( 'list-end' ); - * break; - * } + * $total_todos = 0; + * while ( $p->next_tag( array( 'tag_name' => 'UL', 'class_name' => 'todo' ) ) ) { + * $p->set_bookmark( 'list-start' ); + * while ( $p->next_tag( array( 'tag_closers' => 'visit' ) ) ) { + * if ( 'UL' === $p->get_tag() && $p->is_tag_closer() ) { + * $p->set_bookmark( 'list-end' ); + * $p->seek( 'list-start' ); + * $p->set_attribute( 'data-contained-todos', (string) $total_todos ); + * $total_todos = 0; + * $p->seek( 'list-end' ); + * break; + * } * - * if ( 'LI' === $p->get_tag() && ! $p->is_tag_closer() ) { - * $total_todos++; - * } + * if ( 'LI' === $p->get_tag() && ! $p->is_tag_closer() ) { + * $total_todos++; * } * } + * } * ``` * * ## Design and limitations @@ -229,11 +229,11 @@ * The Tag Processor's design incorporates a "garbage-in-garbage-out" philosophy. * HTML5 specifies that certain invalid content be transformed into different forms * for display, such as removing null bytes from an input document and replacing - * invalid characters with the Unicode replacement character U+FFFD �. Where errors - * or transformations exist within the HTML5 specification, the Tag Processor leaves - * those invalid inputs untouched, passing them through to the final browser to handle. - * While this implies that certain operations will be non-spec-compliant, such as - * reading the value of an attribute with invalid content, it also preserves a + * invalid characters with the Unicode replacement character `U+FFFD` (visually "�"). + * Where errors or transformations exist within the HTML5 specification, the Tag Processor + * leaves those invalid inputs untouched, passing them through to the final browser + * to handle. While this implies that certain operations will be non-spec-compliant, + * such as reading the value of an attribute with invalid content, it also preserves a * simplicity and efficiency for handling those error cases. * * Most operations within the Tag Processor are designed to minimize the difference @@ -253,9 +253,10 @@ class WP_HTML_Tag_Processor { * The maximum number of bookmarks allowed to exist at * any given time. * - * @see set_bookmark() * @since 6.2.0 * @var int + * + * @see WP_HTML_Tag_Processor::set_bookmark() */ const MAX_BOOKMARKS = 10; @@ -263,9 +264,10 @@ class WP_HTML_Tag_Processor { * Maximum number of times seek() can be called. * Prevents accidental infinite loops. * - * @see seek() * @since 6.2.0 * @var int + * + * @see WP_HTML_Tag_Processor::seek() */ const MAX_SEEK_OPS = 1000; @@ -317,23 +319,6 @@ class WP_HTML_Tag_Processor { */ private $stop_on_tag_closers; - /** - * Holds updated HTML as updates are applied. - * - * Updates and unmodified portions of the input document are - * appended to this value as they are applied. It will hold - * a copy of the updated document up until the point of the - * latest applied update. The fully-updated HTML document - * will comprise this value plus the part of the input document - * which follows that latest update. - * - * @see $bytes_already_copied - * - * @since 6.2.0 - * @var string - */ - private $output_buffer = ''; - /** * How many bytes from the original HTML document have been read and parsed. * @@ -346,23 +331,6 @@ class WP_HTML_Tag_Processor { */ private $bytes_already_parsed = 0; - /** - * How many bytes from the input HTML document have already been - * copied into the output buffer. - * - * Lexical updates are enqueued and processed in batches. Prior - * to any given update in the input document, there might exist - * a span of HTML unaffected by any changes. This span ought to - * be copied verbatim into the output buffer before applying the - * following update. This value will point to the starting byte - * offset in the input document where that unaffected span of - * HTML starts. - * - * @since 6.2.0 - * @var int - */ - private $bytes_already_copied = 0; - /** * Byte offset in input document where current tag name starts. * @@ -421,23 +389,23 @@ class WP_HTML_Tag_Processor { * * Example: * ```php - * // supposing the parser is working through this content - * // and stops after recognizing the `id` attribute - * //
- * // ^ parsing will continue from this point - * $this->attributes = array( - * 'id' => new WP_HTML_Attribute_Match( 'id', null, 6, 17 ) - * ); - * - * // when picking up parsing again, or when asking to find the - * // `class` attribute we will continue and add to this array - * $this->attributes = array( - * 'id' => new WP_HTML_Attribute_Match( 'id', null, 6, 17 ), - * 'class' => new WP_HTML_Attribute_Match( 'class', 'outline', 18, 32 ) - * ); - * - * // Note that only the `class` attribute value is stored in the index. - * // That's because it is the only value used by this class at the moment. + * // supposing the parser is working through this content + * // and stops after recognizing the `id` attribute + * //
+ * // ^ parsing will continue from this point + * $this->attributes = array( + * 'id' => new WP_HTML_Attribute_Match( 'id', null, 6, 17 ) + * ); + * + * // when picking up parsing again, or when asking to find the + * // `class` attribute we will continue and add to this array + * $this->attributes = array( + * 'id' => new WP_HTML_Attribute_Match( 'id', null, 6, 17 ), + * 'class' => new WP_HTML_Attribute_Match( 'class', 'outline', 18, 32 ) + * ); + * + * // Note that only the `class` attribute value is stored in the index. + * // That's because it is the only value used by this class at the moment. * ``` * * @since 6.2.0 @@ -458,12 +426,12 @@ class WP_HTML_Tag_Processor { * * Example: * ```php - * // Add the `wp-block-group` class, remove the `wp-group` class. - * $classname_updates = array( - * // Indexed by a comparable class name - * 'wp-block-group' => WP_HTML_Tag_Processor::ADD_CLASS, - * 'wp-group' => WP_HTML_Tag_Processor::REMOVE_CLASS - * ); + * // Add the `wp-block-group` class, remove the `wp-group` class. + * $classname_updates = array( + * // Indexed by a comparable class name + * 'wp-block-group' => WP_HTML_Tag_Processor::ADD_CLASS, + * 'wp-group' => WP_HTML_Tag_Processor::REMOVE_CLASS + * ); * ``` * * @since 6.2.0 @@ -512,16 +480,16 @@ class WP_HTML_Tag_Processor { * * Example: * ```php - * // Replace an attribute stored with a new value, indices - * // sourced from the lazily-parsed HTML recognizer. - * $start = $attributes['src']->start; - * $end = $attributes['src']->end; - * $modifications[] = new WP_HTML_Text_Replacement( $start, $end, $new_value ); - * - * // Correspondingly, something like this will appear in this array. - * $lexical_updates = array( - * WP_HTML_Text_Replacement( 14, 28, 'https://my-site.my-domain/wp-content/uploads/2014/08/kittens.jpg' ) - * ); + * // Replace an attribute stored with a new value, indices + * // sourced from the lazily-parsed HTML recognizer. + * $start = $attributes['src']->start; + * $end = $attributes['src']->end; + * $modifications[] = new WP_HTML_Text_Replacement( $start, $end, $new_value ); + * + * // Correspondingly, something like this will appear in this array. + * $lexical_updates = array( + * WP_HTML_Text_Replacement( 14, 28, 'https://my-site.my-domain/wp-content/uploads/2014/08/kittens.jpg' ) + * ); * ``` * * @since 6.2.0 @@ -532,9 +500,10 @@ class WP_HTML_Tag_Processor { /** * Tracks and limits `seek()` calls to prevent accidental infinite loops. * - * @see seek * @since 6.2.0 * @var int + * + * @see WP_HTML_Tag_Processor::seek() */ protected $seek_count = 0; @@ -754,9 +723,10 @@ public function release_bookmark( $name ) { /** * Skips contents of title and textarea tags. * - * @see https://html.spec.whatwg.org/multipage/parsing.html#rcdata-state * @since 6.2.0 * + * @see https://html.spec.whatwg.org/multipage/parsing.html#rcdata-state + * * @param string $tag_name – the lowercase tag name which will close the RCDATA region. * @return bool Whether an end to the RCDATA region was found before the end of the document. */ @@ -1303,8 +1273,7 @@ private function skip_whitespace() { * @return void */ private function after_tag() { - $this->class_name_updates_to_attributes_updates(); - $this->apply_attributes_updates(); + $this->get_updated_html(); $this->tag_name_starts_at = null; $this->tag_name_length = null; $this->tag_ends_at = null; @@ -1316,11 +1285,11 @@ private function after_tag() { * Converts class name updates into tag attributes updates * (they are accumulated in different data formats for performance). * - * @see $lexical_updates - * @see $classname_updates - * * @since 6.2.0 * + * @see WP_HTML_Tag_Processor::$lexical_updates + * @see WP_HTML_Tag_Processor::$classname_updates + * * @return void */ private function class_name_updates_to_attributes_updates() { @@ -1460,15 +1429,19 @@ private function class_name_updates_to_attributes_updates() { * Applies attribute updates to HTML document. * * @since 6.2.0 + * @since 6.2.1 Accumulates shift for internal cursor and passed pointer. * @since 6.3.0 Invalidate any bookmarks whose targets are overwritten. * - * @return void + * @param int $shift_this_point Accumulate and return shift for this position. + * @return int How many bytes the given pointer moved in response to the updates. */ - private function apply_attributes_updates() { + private function apply_attributes_updates( $shift_this_point = 0 ) { if ( ! count( $this->lexical_updates ) ) { - return; + return 0; } + $accumulated_shift_for_given_point = 0; + /* * Attribute updates can be enqueued in any order but updates * to the document must occur in lexical order; that is, each @@ -1481,12 +1454,28 @@ private function apply_attributes_updates() { */ usort( $this->lexical_updates, array( self::class, 'sort_start_ascending' ) ); + $bytes_already_copied = 0; + $output_buffer = ''; foreach ( $this->lexical_updates as $diff ) { - $this->output_buffer .= substr( $this->html, $this->bytes_already_copied, $diff->start - $this->bytes_already_copied ); - $this->output_buffer .= $diff->text; - $this->bytes_already_copied = $diff->end; + $shift = strlen( $diff->text ) - ( $diff->end - $diff->start ); + + // Adjust the cursor position by however much an update affects it. + if ( $diff->start <= $this->bytes_already_parsed ) { + $this->bytes_already_parsed += $shift; + } + + // Accumulate shift of the given pointer within this function call. + if ( $diff->start <= $shift_this_point ) { + $accumulated_shift_for_given_point += $shift; + } + + $output_buffer .= substr( $this->html, $bytes_already_copied, $diff->start - $bytes_already_copied ); + $output_buffer .= $diff->text; + $bytes_already_copied = $diff->end; } + $this->html = $output_buffer . substr( $this->html, $bytes_already_copied ); + /* * Adjust bookmark locations to account for how the text * replacements adjust offsets in the input document. @@ -1527,6 +1516,8 @@ private function apply_attributes_updates() { } $this->lexical_updates = array(); + + return $accumulated_shift_for_given_point; } /** @@ -1576,8 +1567,6 @@ public function seek( $bookmark_name ) { // Point this tag processor before the sought tag opener and consume it. $this->bytes_already_parsed = $this->bookmarks[ $bookmark_name ]->start; - $this->bytes_already_copied = $this->bytes_already_parsed; - $this->output_buffer = substr( $this->html, 0, $this->bytes_already_copied ); return $this->next_tag( array( 'tag_closers' => 'visit' ) ); } @@ -1676,14 +1665,14 @@ private function get_enqueued_attribute_value( $comparable_name ) { * * Example: * ```php - * $p = new WP_HTML_Tag_Processor( '
Test
' ); - * $p->next_tag( array( 'class_name' => 'test' ) ) === true; - * $p->get_attribute( 'data-test-id' ) === '14'; - * $p->get_attribute( 'enabled' ) === true; - * $p->get_attribute( 'aria-label' ) === null; - * - * $p->next_tag() === false; - * $p->get_attribute( 'class' ) === null; + * $p = new WP_HTML_Tag_Processor( '
Test
' ); + * $p->next_tag( array( 'class_name' => 'test' ) ) === true; + * $p->get_attribute( 'data-test-id' ) === '14'; + * $p->get_attribute( 'enabled' ) === true; + * $p->get_attribute( 'aria-label' ) === null; + * + * $p->next_tag() === false; + * $p->get_attribute( 'class' ) === null; * ``` * * @since 6.2.0 @@ -1755,20 +1744,20 @@ public function get_attribute( $name ) { * > case-insensitive match for each other. * - HTML 5 spec * - * @see https://html.spec.whatwg.org/multipage/syntax.html#attributes-2:ascii-case-insensitive - * * Example: * ```php - * $p = new WP_HTML_Tag_Processor( '
Test
' ); - * $p->next_tag( array( 'class_name' => 'test' ) ) === true; - * $p->get_attribute_names_with_prefix( 'data-' ) === array( 'data-enabled', 'data-test-id' ); + * $p = new WP_HTML_Tag_Processor( '
Test
' ); + * $p->next_tag( array( 'class_name' => 'test' ) ) === true; + * $p->get_attribute_names_with_prefix( 'data-' ) === array( 'data-enabled', 'data-test-id' ); * - * $p->next_tag() === false; - * $p->get_attribute_names_with_prefix( 'data-' ) === null; + * $p->next_tag() === false; + * $p->get_attribute_names_with_prefix( 'data-' ) === null; * ``` * * @since 6.2.0 * + * @see https://html.spec.whatwg.org/multipage/syntax.html#attributes-2:ascii-case-insensitive + * * @param string $prefix Prefix of requested attribute names. * @return array|null List of attribute names, or `null` when no tag opener is matched. */ @@ -1793,12 +1782,12 @@ function get_attribute_names_with_prefix( $prefix ) { * * Example: * ```php - * $p = new WP_HTML_Tag_Processor( '
Test
' ); - * $p->next_tag() === true; - * $p->get_tag() === 'DIV'; + * $p = new WP_HTML_Tag_Processor( '
Test
' ); + * $p->next_tag() === true; + * $p->get_tag() === 'DIV'; * - * $p->next_tag() === false; - * $p->get_tag() === null; + * $p->next_tag() === false; + * $p->get_tag() === null; * ``` * * @since 6.2.0 @@ -1845,12 +1834,12 @@ public function has_self_closing_flag() { * * Example: * ```php - * $p = new WP_HTML_Tag_Processor( '
' ); - * $p->next_tag( array( 'tag_name' => 'div', 'tag_closers' => 'visit' ) ); - * $p->is_tag_closer() === false; + * $p = new WP_HTML_Tag_Processor( '
' ); + * $p->next_tag( array( 'tag_name' => 'div', 'tag_closers' => 'visit' ) ); + * $p->is_tag_closer() === false; * - * $p->next_tag( array( 'tag_name' => 'div', 'tag_closers' => 'visit' ) ); - * $p->is_tag_closer() === true; + * $p->next_tag( array( 'tag_name' => 'div', 'tag_closers' => 'visit' ) ); + * $p->is_tag_closer() === true; * ``` * * @since 6.2.0 @@ -2110,7 +2099,8 @@ public function remove_class( $class_name ) { * Returns the string representation of the HTML Tag Processor. * * @since 6.2.0 - * @see get_updated_html + * + * @see WP_HTML_Tag_Processor::get_updated_html() * * @return string The processed HTML. */ @@ -2122,6 +2112,7 @@ public function __toString() { * Returns the string representation of the HTML Tag Processor. * * @since 6.2.0 + * @since 6.2.1 Shifts the internal cursor corresponding to the applied updates. * * @return string The processed HTML. */ @@ -2132,46 +2123,24 @@ public function get_updated_html() { * When there is nothing more to update and nothing has already been * updated, return the original document and avoid a string copy. */ - if ( $requires_no_updating && 0 === $this->bytes_already_copied ) { + if ( $requires_no_updating ) { return $this->html; } /* - * If there are no updates left to apply, but some have already - * been applied, then finish by copying the rest of the input - * to the end of the updated document and return. + * Keep track of the position right before the current tag. This will + * be necessary for reparsing the current tag after updating the HTML. */ - if ( $requires_no_updating && $this->bytes_already_copied > 0 ) { - $this->html = $this->output_buffer . substr( $this->html, $this->bytes_already_copied ); - $this->bytes_already_copied = strlen( $this->output_buffer ); - return $this->output_buffer . substr( $this->html, $this->bytes_already_copied ); - } - - // Apply the updates, rewind to before the current tag, and reparse the attributes. - $content_up_to_opened_tag_name = $this->output_buffer . substr( - $this->html, - $this->bytes_already_copied, - $this->tag_name_starts_at + $this->tag_name_length - $this->bytes_already_copied - ); + $before_current_tag = $this->tag_name_starts_at - 1; /* - * 1. Apply the edits by flushing them to the output buffer and updating the copied byte count. - * - * Note: `apply_attributes_updates()` modifies `$this->output_buffer`. + * 1. Apply the enqueued edits and update all the pointers to reflect those changes. */ $this->class_name_updates_to_attributes_updates(); - $this->apply_attributes_updates(); + $before_current_tag += $this->apply_attributes_updates( $before_current_tag ); /* - * 2. Replace the original HTML with the now-updated HTML so that it's possible to - * seek to a previous location and have a consistent view of the updated document. - */ - $this->html = $this->output_buffer . substr( $this->html, $this->bytes_already_copied ); - $this->output_buffer = $content_up_to_opened_tag_name; - $this->bytes_already_copied = strlen( $this->output_buffer ); - - /* - * 3. Point this tag processor at the original tag opener and consume it + * 2. Rewind to before the current tag and reparse to get updated attributes. * * At this point the internal cursor points to the end of the tag name. * Rewind before the tag name starts so that it's as if the cursor didn't @@ -2183,9 +2152,19 @@ public function get_updated_html() { * ^ | back up by the length of the tag name plus the opening < * \<-/ back up by strlen("em") + 1 ==> 3 */ - $this->bytes_already_parsed = strlen( $content_up_to_opened_tag_name ) - $this->tag_name_length - 1; + + // Store existing state so it can be restored after reparsing. + $previous_parsed_byte_count = $this->bytes_already_parsed; + $previous_query = $this->last_query; + + // Reparse attributes. + $this->bytes_already_parsed = $before_current_tag; $this->next_tag(); + // Restore previous state. + $this->bytes_already_parsed = $previous_parsed_byte_count; + $this->parse_query( $previous_query ); + return $this->html; } diff --git a/lib/compat/wordpress-6.2/script-loader.php b/lib/compat/wordpress-6.2/script-loader.php index 149a6a18e1450..6ed69244726d3 100644 --- a/lib/compat/wordpress-6.2/script-loader.php +++ b/lib/compat/wordpress-6.2/script-loader.php @@ -129,28 +129,11 @@ function gutenberg_resolve_assets_override() { $scripts = ob_get_clean(); - /* - * Generate font @font-face styles for the site editor iframe. - * Use the registered font families for printing. - */ - if ( class_exists( 'WP_Fonts' ) ) { - $wp_fonts = wp_fonts(); - $registered = $wp_fonts->get_registered_font_families(); - if ( ! empty( $registered ) ) { - $queue = $wp_fonts->queue; - $done = $wp_fonts->done; - - $wp_fonts->done = array(); - $wp_fonts->queue = $registered; - - ob_start(); - $wp_fonts->do_items(); - $styles .= ob_get_clean(); - - // Reset the Web Fonts API. - $wp_fonts->done = $done; - $wp_fonts->queue = $queue; - } + // Generate font @font-face styles. + if ( function_exists( 'wp_print_fonts' ) ) { + ob_start(); + wp_print_fonts( true ); + $styles .= ob_get_clean(); } return array( @@ -169,25 +152,3 @@ function( $settings ) { }, 100 ); - -/** - * Enqueues the global styles custom css. - * - * @since 6.2.0 - */ -function gutenberg_enqueue_global_styles_custom_css() { - if ( ! wp_is_block_theme() ) { - return; - } - - // Don't enqueue Customizer's custom CSS separately. - remove_action( 'wp_head', 'wp_custom_css_cb', 101 ); - - $custom_css = wp_get_custom_css(); - $custom_css .= gutenberg_get_global_styles_custom_css(); - - if ( ! empty( $custom_css ) ) { - wp_add_inline_style( 'global-styles', $custom_css ); - } -} -add_action( 'wp_enqueue_scripts', 'gutenberg_enqueue_global_styles_custom_css' ); diff --git a/lib/compat/wordpress-6.3/get-global-styles-and-settings.php b/lib/compat/wordpress-6.3/get-global-styles-and-settings.php index bb489664e1eea..609d9b3de38a1 100644 --- a/lib/compat/wordpress-6.3/get-global-styles-and-settings.php +++ b/lib/compat/wordpress-6.3/get-global-styles-and-settings.php @@ -124,3 +124,37 @@ function wp_get_block_css_selector( $block_type, $target = 'root', $fallback = f function gutenberg_get_remote_theme_patterns() { return WP_Theme_JSON_Resolver_Gutenberg::get_theme_data( array(), array( 'with_supports' => false ) )->get_patterns(); } + +/** + * Gets the styles resulting of merging core, theme, and user data. + * + * @since 5.9.0 + * @since 6.3.0 the internal link format "var:preset|color|secondary" is resolved + * to "var(--wp--preset--font-size--small)" so consumers don't have to. + * + * @param array $path Path to the specific style to retrieve. Optional. + * If empty, will return all styles. + * @param array $context { + * Metadata to know where to retrieve the $path from. Optional. + * + * @type string $block_name Which block to retrieve the styles from. + * If empty, it'll return the styles for the global context. + * @type string $origin Which origin to take data from. + * Valid values are 'all' (core, theme, and user) or 'base' (core and theme). + * If empty or unknown, 'all' is used. + * } + * @return array The styles to retrieve. + */ +function gutenberg_get_global_styles( $path = array(), $context = array() ) { + if ( ! empty( $context['block_name'] ) ) { + $path = array_merge( array( 'blocks', $context['block_name'] ), $path ); + } + + $origin = 'custom'; + if ( isset( $context['origin'] ) && 'base' === $context['origin'] ) { + $origin = 'theme'; + } + $styles = WP_Theme_JSON_Resolver_Gutenberg::get_merged_data( $origin )->get_raw_data()['styles']; + + return _wp_array_get( $styles, $path, $styles ); +} 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 65fcefe8ac9c8..5b38484f659ac 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 @@ -39,10 +39,10 @@ * * Example: * ```php - * $tags = new WP_HTML_Tag_Processor( $html ); - * if ( $tags->next_tag( 'option' ) ) { - * $tags->set_attribute( 'selected', true ); - * } + * $tags = new WP_HTML_Tag_Processor( $html ); + * if ( $tags->next_tag( 'option' ) ) { + * $tags->set_attribute( 'selected', true ); + * } * ``` * * ### Finding tags @@ -55,7 +55,7 @@ * * If you want to _find whatever the next tag is_: * ```php - * $tags->next_tag(); + * $tags->next_tag(); * ``` * * | Goal | Query | @@ -88,17 +88,17 @@ * * Example: * ```php - * // Paint up to the first five DIV or SPAN tags marked with the "jazzy" style. - * $remaining_count = 5; - * while ( $remaining_count > 0 && $tags->next_tag() ) { - * if ( - * ( 'DIV' === $tags->get_tag() || 'SPAN' === $tags->get_tag() ) && - * 'jazzy' === $tags->get_attribute( 'data-style' ) - * ) { - * $tags->add_class( 'theme-style-everest-jazz' ); - * $remaining_count--; - * } + * // Paint up to the first five DIV or SPAN tags marked with the "jazzy" style. + * $remaining_count = 5; + * while ( $remaining_count > 0 && $tags->next_tag() ) { + * if ( + * ( 'DIV' === $tags->get_tag() || 'SPAN' === $tags->get_tag() ) && + * 'jazzy' === $tags->get_attribute( 'data-style' ) + * ) { + * $tags->add_class( 'theme-style-everest-jazz' ); + * $remaining_count--; * } + * } * ``` * * `get_attribute()` will return `null` if the attribute wasn't present @@ -117,10 +117,10 @@ * * Example: * ```php - * if ( $tags->next_tag( array( 'class' => 'wp-group-block' ) ) ) { - * $tags->set_attribute( 'title', 'This groups the contained content.' ); - * $tags->remove_attribute( 'data-test-id' ); - * } + * if ( $tags->next_tag( array( 'class' => 'wp-group-block' ) ) ) { + * $tags->set_attribute( 'title', 'This groups the contained content.' ); + * $tags->remove_attribute( 'data-test-id' ); + * } * ``` * * If `set_attribute()` is called for an existing attribute it will @@ -142,29 +142,29 @@ * * Example: * ```php - * // from `Yippee!` - * // to `Yippee!` - * $tags->add_class( 'is-active' ); + * // from `Yippee!` + * // to `Yippee!` + * $tags->add_class( 'is-active' ); * - * // from `Yippee!` - * // to `Yippee!` - * $tags->add_class( 'is-active' ); + * // from `Yippee!` + * // to `Yippee!` + * $tags->add_class( 'is-active' ); * - * // from `Yippee!` - * // to `Yippee!` - * $tags->add_class( 'is-active' ); + * // from `Yippee!` + * // to `Yippee!` + * $tags->add_class( 'is-active' ); * - * // from `` - * // to ` - * $tags->remove_class( 'rugby' ); + * // from `` + * // to ` + * $tags->remove_class( 'rugby' ); * - * // from `` - * // to ` - * $tags->remove_class( 'rugby' ); + * // from `` + * // to ` + * $tags->remove_class( 'rugby' ); * - * // from `` - * // to ` - * $tags->remove_class( 'rugby' ); + * // from `` + * // to ` + * $tags->remove_class( 'rugby' ); * ``` * * When class changes are enqueued but a direct change to `class` is made via @@ -185,24 +185,24 @@ * bookmark and update it frequently, such as within a loop. * * ```php - * $total_todos = 0; - * while ( $p->next_tag( array( 'tag_name' => 'UL', 'class_name' => 'todo' ) ) ) { - * $p->set_bookmark( 'list-start' ); - * while ( $p->next_tag( array( 'tag_closers' => 'visit' ) ) ) { - * if ( 'UL' === $p->get_tag() && $p->is_tag_closer() ) { - * $p->set_bookmark( 'list-end' ); - * $p->seek( 'list-start' ); - * $p->set_attribute( 'data-contained-todos', (string) $total_todos ); - * $total_todos = 0; - * $p->seek( 'list-end' ); - * break; - * } + * $total_todos = 0; + * while ( $p->next_tag( array( 'tag_name' => 'UL', 'class_name' => 'todo' ) ) ) { + * $p->set_bookmark( 'list-start' ); + * while ( $p->next_tag( array( 'tag_closers' => 'visit' ) ) ) { + * if ( 'UL' === $p->get_tag() && $p->is_tag_closer() ) { + * $p->set_bookmark( 'list-end' ); + * $p->seek( 'list-start' ); + * $p->set_attribute( 'data-contained-todos', (string) $total_todos ); + * $total_todos = 0; + * $p->seek( 'list-end' ); + * break; + * } * - * if ( 'LI' === $p->get_tag() && ! $p->is_tag_closer() ) { - * $total_todos++; - * } + * if ( 'LI' === $p->get_tag() && ! $p->is_tag_closer() ) { + * $total_todos++; * } * } + * } * ``` * * ## Design and limitations @@ -229,11 +229,11 @@ * The Tag Processor's design incorporates a "garbage-in-garbage-out" philosophy. * HTML5 specifies that certain invalid content be transformed into different forms * for display, such as removing null bytes from an input document and replacing - * invalid characters with the Unicode replacement character U+FFFD �. Where errors - * or transformations exist within the HTML5 specification, the Tag Processor leaves - * those invalid inputs untouched, passing them through to the final browser to handle. - * While this implies that certain operations will be non-spec-compliant, such as - * reading the value of an attribute with invalid content, it also preserves a + * invalid characters with the Unicode replacement character `U+FFFD` (visually "�"). + * Where errors or transformations exist within the HTML5 specification, the Tag Processor + * leaves those invalid inputs untouched, passing them through to the final browser + * to handle. While this implies that certain operations will be non-spec-compliant, + * such as reading the value of an attribute with invalid content, it also preserves a * simplicity and efficiency for handling those error cases. * * Most operations within the Tag Processor are designed to minimize the difference @@ -253,9 +253,10 @@ class Gutenberg_HTML_Tag_Processor_6_3 { * The maximum number of bookmarks allowed to exist at * any given time. * - * @see set_bookmark() * @since 6.2.0 * @var int + * + * @see WP_HTML_Tag_Processor::set_bookmark() */ const MAX_BOOKMARKS = 10; @@ -263,9 +264,10 @@ class Gutenberg_HTML_Tag_Processor_6_3 { * Maximum number of times seek() can be called. * Prevents accidental infinite loops. * - * @see seek() * @since 6.2.0 * @var int + * + * @see WP_HTML_Tag_Processor::seek() */ const MAX_SEEK_OPS = 1000; @@ -317,23 +319,6 @@ class Gutenberg_HTML_Tag_Processor_6_3 { */ private $stop_on_tag_closers; - /** - * Holds updated HTML as updates are applied. - * - * Updates and unmodified portions of the input document are - * appended to this value as they are applied. It will hold - * a copy of the updated document up until the point of the - * latest applied update. The fully-updated HTML document - * will comprise this value plus the part of the input document - * which follows that latest update. - * - * @see $bytes_already_copied - * - * @since 6.2.0 - * @var string - */ - private $output_buffer = ''; - /** * How many bytes from the original HTML document have been read and parsed. * @@ -346,23 +331,6 @@ class Gutenberg_HTML_Tag_Processor_6_3 { */ private $bytes_already_parsed = 0; - /** - * How many bytes from the input HTML document have already been - * copied into the output buffer. - * - * Lexical updates are enqueued and processed in batches. Prior - * to any given update in the input document, there might exist - * a span of HTML unaffected by any changes. This span ought to - * be copied verbatim into the output buffer before applying the - * following update. This value will point to the starting byte - * offset in the input document where that unaffected span of - * HTML starts. - * - * @since 6.2.0 - * @var int - */ - private $bytes_already_copied = 0; - /** * Byte offset in input document where current tag name starts. * @@ -421,23 +389,23 @@ class Gutenberg_HTML_Tag_Processor_6_3 { * * Example: * ```php - * // supposing the parser is working through this content - * // and stops after recognizing the `id` attribute - * //
- * // ^ parsing will continue from this point - * $this->attributes = array( - * 'id' => new WP_HTML_Attribute_Match( 'id', null, 6, 17 ) - * ); - * - * // when picking up parsing again, or when asking to find the - * // `class` attribute we will continue and add to this array - * $this->attributes = array( - * 'id' => new WP_HTML_Attribute_Match( 'id', null, 6, 17 ), - * 'class' => new WP_HTML_Attribute_Match( 'class', 'outline', 18, 32 ) - * ); - * - * // Note that only the `class` attribute value is stored in the index. - * // That's because it is the only value used by this class at the moment. + * // supposing the parser is working through this content + * // and stops after recognizing the `id` attribute + * //
+ * // ^ parsing will continue from this point + * $this->attributes = array( + * 'id' => new WP_HTML_Attribute_Match( 'id', null, 6, 17 ) + * ); + * + * // when picking up parsing again, or when asking to find the + * // `class` attribute we will continue and add to this array + * $this->attributes = array( + * 'id' => new WP_HTML_Attribute_Match( 'id', null, 6, 17 ), + * 'class' => new WP_HTML_Attribute_Match( 'class', 'outline', 18, 32 ) + * ); + * + * // Note that only the `class` attribute value is stored in the index. + * // That's because it is the only value used by this class at the moment. * ``` * * @since 6.2.0 @@ -458,12 +426,12 @@ class Gutenberg_HTML_Tag_Processor_6_3 { * * Example: * ```php - * // Add the `wp-block-group` class, remove the `wp-group` class. - * $classname_updates = array( - * // Indexed by a comparable class name - * 'wp-block-group' => WP_HTML_Tag_Processor::ADD_CLASS, - * 'wp-group' => WP_HTML_Tag_Processor::REMOVE_CLASS - * ); + * // Add the `wp-block-group` class, remove the `wp-group` class. + * $classname_updates = array( + * // Indexed by a comparable class name + * 'wp-block-group' => WP_HTML_Tag_Processor::ADD_CLASS, + * 'wp-group' => WP_HTML_Tag_Processor::REMOVE_CLASS + * ); * ``` * * @since 6.2.0 @@ -512,16 +480,16 @@ class Gutenberg_HTML_Tag_Processor_6_3 { * * Example: * ```php - * // Replace an attribute stored with a new value, indices - * // sourced from the lazily-parsed HTML recognizer. - * $start = $attributes['src']->start; - * $end = $attributes['src']->end; - * $modifications[] = new WP_HTML_Text_Replacement( $start, $end, $new_value ); - * - * // Correspondingly, something like this will appear in this array. - * $lexical_updates = array( - * WP_HTML_Text_Replacement( 14, 28, 'https://my-site.my-domain/wp-content/uploads/2014/08/kittens.jpg' ) - * ); + * // Replace an attribute stored with a new value, indices + * // sourced from the lazily-parsed HTML recognizer. + * $start = $attributes['src']->start; + * $end = $attributes['src']->end; + * $modifications[] = new WP_HTML_Text_Replacement( $start, $end, $new_value ); + * + * // Correspondingly, something like this will appear in this array. + * $lexical_updates = array( + * WP_HTML_Text_Replacement( 14, 28, 'https://my-site.my-domain/wp-content/uploads/2014/08/kittens.jpg' ) + * ); * ``` * * @since 6.2.0 @@ -532,9 +500,10 @@ class Gutenberg_HTML_Tag_Processor_6_3 { /** * Tracks and limits `seek()` calls to prevent accidental infinite loops. * - * @see seek * @since 6.2.0 * @var int + * + * @see WP_HTML_Tag_Processor::seek() */ protected $seek_count = 0; @@ -754,9 +723,10 @@ public function release_bookmark( $name ) { /** * Skips contents of title and textarea tags. * - * @see https://html.spec.whatwg.org/multipage/parsing.html#rcdata-state * @since 6.2.0 * + * @see https://html.spec.whatwg.org/multipage/parsing.html#rcdata-state + * * @param string $tag_name – the lowercase tag name which will close the RCDATA region. * @return bool Whether an end to the RCDATA region was found before the end of the document. */ @@ -1303,8 +1273,7 @@ private function skip_whitespace() { * @return void */ private function after_tag() { - $this->class_name_updates_to_attributes_updates(); - $this->apply_attributes_updates(); + $this->get_updated_html(); $this->tag_name_starts_at = null; $this->tag_name_length = null; $this->tag_ends_at = null; @@ -1316,11 +1285,11 @@ private function after_tag() { * Converts class name updates into tag attributes updates * (they are accumulated in different data formats for performance). * - * @see $lexical_updates - * @see $classname_updates - * * @since 6.2.0 * + * @see WP_HTML_Tag_Processor::$lexical_updates + * @see WP_HTML_Tag_Processor::$classname_updates + * * @return void */ private function class_name_updates_to_attributes_updates() { @@ -1460,15 +1429,19 @@ private function class_name_updates_to_attributes_updates() { * Applies attribute updates to HTML document. * * @since 6.2.0 + * @since 6.2.1 Accumulates shift for internal cursor and passed pointer. * @since 6.3.0 Invalidate any bookmarks whose targets are overwritten. * - * @return void + * @param int $shift_this_point Accumulate and return shift for this position. + * @return int How many bytes the given pointer moved in response to the updates. */ - private function apply_attributes_updates() { + private function apply_attributes_updates( $shift_this_point = 0 ) { if ( ! count( $this->lexical_updates ) ) { - return; + return 0; } + $accumulated_shift_for_given_point = 0; + /* * Attribute updates can be enqueued in any order but updates * to the document must occur in lexical order; that is, each @@ -1481,12 +1454,28 @@ private function apply_attributes_updates() { */ usort( $this->lexical_updates, array( self::class, 'sort_start_ascending' ) ); + $bytes_already_copied = 0; + $output_buffer = ''; foreach ( $this->lexical_updates as $diff ) { - $this->output_buffer .= substr( $this->html, $this->bytes_already_copied, $diff->start - $this->bytes_already_copied ); - $this->output_buffer .= $diff->text; - $this->bytes_already_copied = $diff->end; + $shift = strlen( $diff->text ) - ( $diff->end - $diff->start ); + + // Adjust the cursor position by however much an update affects it. + if ( $diff->start <= $this->bytes_already_parsed ) { + $this->bytes_already_parsed += $shift; + } + + // Accumulate shift of the given pointer within this function call. + if ( $diff->start <= $shift_this_point ) { + $accumulated_shift_for_given_point += $shift; + } + + $output_buffer .= substr( $this->html, $bytes_already_copied, $diff->start - $bytes_already_copied ); + $output_buffer .= $diff->text; + $bytes_already_copied = $diff->end; } + $this->html = $output_buffer . substr( $this->html, $bytes_already_copied ); + /* * Adjust bookmark locations to account for how the text * replacements adjust offsets in the input document. @@ -1527,6 +1516,8 @@ private function apply_attributes_updates() { } $this->lexical_updates = array(); + + return $accumulated_shift_for_given_point; } /** @@ -1576,8 +1567,6 @@ public function seek( $bookmark_name ) { // Point this tag processor before the sought tag opener and consume it. $this->bytes_already_parsed = $this->bookmarks[ $bookmark_name ]->start; - $this->bytes_already_copied = $this->bytes_already_parsed; - $this->output_buffer = substr( $this->html, 0, $this->bytes_already_copied ); return $this->next_tag( array( 'tag_closers' => 'visit' ) ); } @@ -1676,14 +1665,14 @@ private function get_enqueued_attribute_value( $comparable_name ) { * * Example: * ```php - * $p = new WP_HTML_Tag_Processor( '
Test
' ); - * $p->next_tag( array( 'class_name' => 'test' ) ) === true; - * $p->get_attribute( 'data-test-id' ) === '14'; - * $p->get_attribute( 'enabled' ) === true; - * $p->get_attribute( 'aria-label' ) === null; - * - * $p->next_tag() === false; - * $p->get_attribute( 'class' ) === null; + * $p = new WP_HTML_Tag_Processor( '
Test
' ); + * $p->next_tag( array( 'class_name' => 'test' ) ) === true; + * $p->get_attribute( 'data-test-id' ) === '14'; + * $p->get_attribute( 'enabled' ) === true; + * $p->get_attribute( 'aria-label' ) === null; + * + * $p->next_tag() === false; + * $p->get_attribute( 'class' ) === null; * ``` * * @since 6.2.0 @@ -1755,20 +1744,20 @@ public function get_attribute( $name ) { * > case-insensitive match for each other. * - HTML 5 spec * - * @see https://html.spec.whatwg.org/multipage/syntax.html#attributes-2:ascii-case-insensitive - * * Example: * ```php - * $p = new WP_HTML_Tag_Processor( '
Test
' ); - * $p->next_tag( array( 'class_name' => 'test' ) ) === true; - * $p->get_attribute_names_with_prefix( 'data-' ) === array( 'data-enabled', 'data-test-id' ); + * $p = new WP_HTML_Tag_Processor( '
Test
' ); + * $p->next_tag( array( 'class_name' => 'test' ) ) === true; + * $p->get_attribute_names_with_prefix( 'data-' ) === array( 'data-enabled', 'data-test-id' ); * - * $p->next_tag() === false; - * $p->get_attribute_names_with_prefix( 'data-' ) === null; + * $p->next_tag() === false; + * $p->get_attribute_names_with_prefix( 'data-' ) === null; * ``` * * @since 6.2.0 * + * @see https://html.spec.whatwg.org/multipage/syntax.html#attributes-2:ascii-case-insensitive + * * @param string $prefix Prefix of requested attribute names. * @return array|null List of attribute names, or `null` when no tag opener is matched. */ @@ -1793,12 +1782,12 @@ function get_attribute_names_with_prefix( $prefix ) { * * Example: * ```php - * $p = new WP_HTML_Tag_Processor( '
Test
' ); - * $p->next_tag() === true; - * $p->get_tag() === 'DIV'; + * $p = new WP_HTML_Tag_Processor( '
Test
' ); + * $p->next_tag() === true; + * $p->get_tag() === 'DIV'; * - * $p->next_tag() === false; - * $p->get_tag() === null; + * $p->next_tag() === false; + * $p->get_tag() === null; * ``` * * @since 6.2.0 @@ -1845,12 +1834,12 @@ public function has_self_closing_flag() { * * Example: * ```php - * $p = new WP_HTML_Tag_Processor( '
' ); - * $p->next_tag( array( 'tag_name' => 'div', 'tag_closers' => 'visit' ) ); - * $p->is_tag_closer() === false; + * $p = new WP_HTML_Tag_Processor( '
' ); + * $p->next_tag( array( 'tag_name' => 'div', 'tag_closers' => 'visit' ) ); + * $p->is_tag_closer() === false; * - * $p->next_tag( array( 'tag_name' => 'div', 'tag_closers' => 'visit' ) ); - * $p->is_tag_closer() === true; + * $p->next_tag( array( 'tag_name' => 'div', 'tag_closers' => 'visit' ) ); + * $p->is_tag_closer() === true; * ``` * * @since 6.2.0 @@ -2110,7 +2099,8 @@ public function remove_class( $class_name ) { * Returns the string representation of the HTML Tag Processor. * * @since 6.2.0 - * @see get_updated_html + * + * @see WP_HTML_Tag_Processor::get_updated_html() * * @return string The processed HTML. */ @@ -2122,6 +2112,7 @@ public function __toString() { * Returns the string representation of the HTML Tag Processor. * * @since 6.2.0 + * @since 6.2.1 Shifts the internal cursor corresponding to the applied updates. * * @return string The processed HTML. */ @@ -2132,46 +2123,24 @@ public function get_updated_html() { * When there is nothing more to update and nothing has already been * updated, return the original document and avoid a string copy. */ - if ( $requires_no_updating && 0 === $this->bytes_already_copied ) { + if ( $requires_no_updating ) { return $this->html; } /* - * If there are no updates left to apply, but some have already - * been applied, then finish by copying the rest of the input - * to the end of the updated document and return. + * Keep track of the position right before the current tag. This will + * be necessary for reparsing the current tag after updating the HTML. */ - if ( $requires_no_updating && $this->bytes_already_copied > 0 ) { - $this->html = $this->output_buffer . substr( $this->html, $this->bytes_already_copied ); - $this->bytes_already_copied = strlen( $this->output_buffer ); - return $this->output_buffer . substr( $this->html, $this->bytes_already_copied ); - } - - // Apply the updates, rewind to before the current tag, and reparse the attributes. - $content_up_to_opened_tag_name = $this->output_buffer . substr( - $this->html, - $this->bytes_already_copied, - $this->tag_name_starts_at + $this->tag_name_length - $this->bytes_already_copied - ); + $before_current_tag = $this->tag_name_starts_at - 1; /* - * 1. Apply the edits by flushing them to the output buffer and updating the copied byte count. - * - * Note: `apply_attributes_updates()` modifies `$this->output_buffer`. + * 1. Apply the enqueued edits and update all the pointers to reflect those changes. */ $this->class_name_updates_to_attributes_updates(); - $this->apply_attributes_updates(); + $before_current_tag += $this->apply_attributes_updates( $before_current_tag ); /* - * 2. Replace the original HTML with the now-updated HTML so that it's possible to - * seek to a previous location and have a consistent view of the updated document. - */ - $this->html = $this->output_buffer . substr( $this->html, $this->bytes_already_copied ); - $this->output_buffer = $content_up_to_opened_tag_name; - $this->bytes_already_copied = strlen( $this->output_buffer ); - - /* - * 3. Point this tag processor at the original tag opener and consume it + * 2. Rewind to before the current tag and reparse to get updated attributes. * * At this point the internal cursor points to the end of the tag name. * Rewind before the tag name starts so that it's as if the cursor didn't @@ -2183,9 +2152,19 @@ public function get_updated_html() { * ^ | back up by the length of the tag name plus the opening < * \<-/ back up by strlen("em") + 1 ==> 3 */ - $this->bytes_already_parsed = strlen( $content_up_to_opened_tag_name ) - $this->tag_name_length - 1; + + // Store existing state so it can be restored after reparsing. + $previous_parsed_byte_count = $this->bytes_already_parsed; + $previous_query = $this->last_query; + + // Reparse attributes. + $this->bytes_already_parsed = $before_current_tag; $this->next_tag(); + // Restore previous state. + $this->bytes_already_parsed = $previous_parsed_byte_count; + $this->parse_query( $previous_query ); + return $this->html; } diff --git a/lib/compat/wordpress-6.3/navigation-block-preloading.php b/lib/compat/wordpress-6.3/navigation-block-preloading.php new file mode 100644 index 0000000000000..82fe81b236a59 --- /dev/null +++ b/lib/compat/wordpress-6.3/navigation-block-preloading.php @@ -0,0 +1,63 @@ +name ) && 'core/edit-site' !== $context->name ) { + return $preload_paths; + } + + $navigation_rest_route = rest_get_route_for_post_type_items( + 'wp_navigation' + ); + + // Preload the OPTIONS request for all Navigation posts request. + $preload_paths[] = array( $navigation_rest_route, 'OPTIONS' ); + + // Preload the GET request for ALL 'published' or 'draft' Navigation posts. + $preload_paths[] = array( + add_query_arg( + array( + 'context' => 'edit', + 'per_page' => 100, + '_locale' => 'user', + // array indices are required to avoid query being encoded and not matching in cache. + 'status[0]' => 'publish', + 'status[1]' => 'draft', + ), + $navigation_rest_route + ), + 'GET', + ); + + // Preload request for Browse Mode sidebar "Navigation" section. + $preload_paths[] = array( + add_query_arg( + array( + 'context' => 'edit', + 'per_page' => 1, + 'status' => 'publish', + 'order' => 'desc', + 'orderby' => 'date', + ), + $navigation_rest_route + ), + 'GET', + ); + + return $preload_paths; +} +add_filter( 'block_editor_rest_api_preload_paths', 'gutenberg_preload_navigation_posts', 10, 2 ); diff --git a/lib/compat/wordpress-6.3/script-loader.php b/lib/compat/wordpress-6.3/script-loader.php index c735f3b8a792a..8b00e10d09b66 100644 --- a/lib/compat/wordpress-6.3/script-loader.php +++ b/lib/compat/wordpress-6.3/script-loader.php @@ -56,7 +56,7 @@ function _gutenberg_get_iframed_editor_assets() { ob_start(); wp_print_styles(); - wp_print_fonts(); + wp_print_fonts( true ); $styles = ob_get_clean(); ob_start(); diff --git a/lib/compat/wordpress-6.3/theme-previews.php b/lib/compat/wordpress-6.3/theme-previews.php index 5671274925765..e73c13daa7cfb 100644 --- a/lib/compat/wordpress-6.3/theme-previews.php +++ b/lib/compat/wordpress-6.3/theme-previews.php @@ -6,32 +6,27 @@ */ /** - * Filters the blog option to return the directory for the previewed theme. + * Filters the blog option to return the path for the previewed theme. * - * @param string $current_stylesheet The current theme directory. - * @return string The previewed theme directory. + * @param string $current_stylesheet The current theme's stylesheet or template path. + * @return string The previewed theme's stylesheet or template path. */ -function gutenberg_theme_preview_stylesheet( $current_stylesheet = null ) { - $preview_stylesheet = ! empty( $_GET['theme_preview'] ) ? $_GET['theme_preview'] : null; - $wp_theme = wp_get_theme( $preview_stylesheet ); - if ( ! is_wp_error( $wp_theme->errors() ) ) { - return sanitize_text_field( $preview_stylesheet ); +function gutenberg_get_theme_preview_path( $current_stylesheet = null ) { + // Don't allow non-admins to preview themes. + if ( ! current_user_can( 'switch_themes' ) ) { + return; } - return $current_stylesheet; -} - -/** - * Filters the blog option to return the parent theme directory for the previewed theme. - * - * @param string $current_stylesheet The current theme directory. - * @return string The previewed theme directory. - */ -function gutenberg_theme_preview_template( $current_stylesheet = null ) { $preview_stylesheet = ! empty( $_GET['theme_preview'] ) ? $_GET['theme_preview'] : null; $wp_theme = wp_get_theme( $preview_stylesheet ); if ( ! is_wp_error( $wp_theme->errors() ) ) { - return sanitize_text_field( $wp_theme->get_template() ); + if ( current_filter() === 'template' ) { + $theme_path = $wp_theme->get_template(); + } else { + $theme_path = $wp_theme->get_stylesheet(); + } + + return sanitize_text_field( $theme_path ); } return $current_stylesheet; @@ -41,6 +36,11 @@ function gutenberg_theme_preview_template( $current_stylesheet = null ) { * Adds a middleware to the REST API to set the theme for the preview. */ function gutenberg_attach_theme_preview_middleware() { + // Don't allow non-admins to preview themes. + if ( ! current_user_can( 'switch_themes' ) ) { + return; + } + wp_add_inline_script( 'wp-api-fetch', sprintf( @@ -104,7 +104,7 @@ function addLivePreviewButton() { * Adds a nonce for the theme activation link. */ function block_theme_activate_nonce() { - $nonce_handle = 'switch-theme_' . gutenberg_theme_preview_stylesheet(); + $nonce_handle = 'switch-theme_' . gutenberg_get_theme_preview_path(); ?>