diff --git a/.eslintrc.js b/.eslintrc.js index 4063bb42cf32ab..53e8cf888a18ed 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -88,6 +88,7 @@ const restrictedImports = [ 'invoke', 'isArray', 'isBoolean', + 'isEmpty', 'isEqual', 'isFinite', 'isFunction', diff --git a/README.md b/README.md index 8ac17b8574c52f..5ba112319b405c 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ Welcome to the development hub for the WordPress Gutenberg project! The block editor introduces a modular approach to pages and posts: each piece of content in the editor, from a paragraph to an image gallery to a headline, is its own block. And just like physical blocks, WordPress blocks can be added, arranged, and rearranged, allowing WordPress users to create media-rich pages in a visually intuitive way -- and without work-arounds like shortcodes or custom HTML. -The block editor first became available in December 2018, and we're still hard at work refining the experience, creating more and better blocks, and laying the groundwork for the next three phases of work. The Gutenberg plugin gives you the latest version of the block editor so you can join us in testing bleeding-edge features, start playing with blocks, and maybe get inspired to build your own. +The block editor first became available in December 2018, and we're still hard at work refining the experience, creating more and better blocks, and laying the groundwork for the next three phases of work. The Gutenberg plugin gives you the latest version of the block editor, so you can join us in testing bleeding-edge features, start playing with blocks, and maybe get inspired to build your own. Check out the [Ways to keep up with Gutenberg & Full Site Editing (FSE)](https://make.wordpress.org/core/2020/05/20/ways-to-keep-up-with-full-site-editing-fse/) @@ -31,7 +31,7 @@ Get hands on: check out the [block editor live demo](https://wordpress.org/guten - **User Documentation:** See the [WordPress Editor documentation](https://wordpress.org/documentation/article/wordpress-block-editor/) for detailed docs on using the editor as an author creating posts and pages. -- **User Support:** If you have run into an issue, you should check the [Support Forums first](https://wordpress.org/support/forums/). The forums are a great place to get help. If you have a bug to report, please [submit it to the Gutenberg repository](https://github.com/wordpress/gutenberg/issues). Please search prior to creating a new bug to confirm its not a duplicate. +- **User Support:** If you have run into an issue, you should check the [Support Forums first](https://wordpress.org/support/forums/). The forums are a great place to get help. If you have a bug to report, please [submit it to the Gutenberg repository](https://github.com/wordpress/gutenberg/issues). Please search prior to creating a new bug to confirm it's not a duplicate. ### Developing for Gutenberg @@ -41,7 +41,7 @@ Review the [Create a Block tutorial](/docs/getting-started/create-block/README.m ### Contribute to Gutenberg -Gutenberg is an open-source project and welcomes all contributors from code to design, and from documentation to triage. The project is built by many contributors and volunteers and we'd love your help building it. +Gutenberg is an open-source project and welcomes all contributors from code to design, and from documentation to triage. The project is built by many contributors and volunteers, and we'd love your help building it. See the [Contributors Handbook](https://developer.wordpress.org/block-editor/contributors/) for all the details on how you can contribute. diff --git a/bin/generate-public-grammar.js b/bin/generate-public-grammar.js deleted file mode 100755 index d66577adbc4d02..00000000000000 --- a/bin/generate-public-grammar.js +++ /dev/null @@ -1,121 +0,0 @@ -#!/usr/bin/env node - -/** - * Internal dependencies - */ -const parser = require( '../node_modules/pegjs/lib/parser.js' ); - -/** - * External dependencies - */ -const fs = require( 'fs' ); -const path = require( 'path' ); -const grammarSource = fs.readFileSync( - './packages/block-serialization-spec-parser/grammar.pegjs', - 'utf8' -); -const grammar = parser.parse( grammarSource ); - -function escape( text ) { - return text - .replace( /\t/g, '\\t' ) - .replace( /\r/g, '\\r' ) - .replace( /\n/g, '\\n' ) - .replace( /\&/g, '&' ) - .replace( /= 0 - ); -} - -function flattenUnary( expression ) { - const shouldWrap = isGroup( expression ); - const inner = flatten( expression ); - return shouldWrap ? '(' + inner + ')' : inner; -} - -function flatten( expression ) { - switch ( expression.type ) { - // Terminal - case 'any': - return '.'; - case 'rule_ref': - return expression.name; - case 'literal': - return '"' + escape( expression.value ) + '"'; - case 'class': - return ( - '[' + - ( expression.inverted ? '^' : '' ) + - expression.parts - .map( ( part ) => - escape( - Array.isArray( part ) ? part.join( '-' ) : part - ) - ) - .join( '' ) + - ']' + - ( expression.ignoreCase ? 'i' : '' ) - ); - - // Unary - case 'zero_or_more': - return flattenUnary( expression.expression ) + '*'; - case 'one_or_more': - return flattenUnary( expression.expression ) + '+'; - case 'optional': - return flattenUnary( expression.expression ) + '?'; - case 'simple_not': - return '!' + flattenUnary( expression.expression ); - - // Other groups - case 'sequence': - return expression.elements.map( flatten ).join( ' ' ); - case 'choice': - const sep = expression.isRuleTop ? '\n / ' : ' / '; - return expression.alternatives.map( flatten ).join( sep ); - case 'group': - return '(' + flatten( expression.expression ) + ')'; - case 'text': - // Avoid double parentheses - const inner = flatten( expression.expression ); - const shouldWrap = inner.indexOf( '(' ) !== 0; - return shouldWrap ? '$(' + inner + ')' : '$' + inner; - case 'action': - case 'labeled': - case 'named': - return flatten( expression.expression ); - - // Top-level formatting - case 'grammar': - return `
${ expression.rules.map( flatten ).join( '' ) }
`; - case 'rule': - expression.expression.isRuleTop = true; - const displayName = - expression.expression.type === 'named' - ? expression.expression.name - : ''; - return ( - `
${ displayName }
` + - `
${ expression.name }
= ` + - `${ flatten( expression.expression ) }
` - ); - - default: - throw new Error( JSON.stringify( expression ) ); - } -} - -fs.writeFileSync( - path.join( __dirname, '..', 'docs', 'contributors', 'grammar.md' ), - ` -# Block Grammar - -${ flatten( grammar ) } -` -); diff --git a/bin/packages/get-packages.js b/bin/packages/get-packages.js index 695eee03c440e2..42ba08afed6f68 100644 --- a/bin/packages/get-packages.js +++ b/bin/packages/get-packages.js @@ -3,7 +3,6 @@ */ const fs = require( 'fs' ); const path = require( 'path' ); -const { isEmpty } = require( 'lodash' ); /** * Absolute path to packages directory. @@ -43,7 +42,7 @@ function hasModuleField( file ) { return false; } - return ! isEmpty( pkg.module ); + return !! pkg.module; } /** diff --git a/changelog.txt b/changelog.txt index 5e96e8b0959996..4cdd8690b3740f 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,312 @@ == Changelog == += 15.9.1 = + + + +## Changelog + +### Bug Fixes + +#### Fonts API +- [Fonts API] Make local font asset file URL absolute. ([51178](https://github.com/WordPress/gutenberg/pull/51178)) + +#### Block Library +- Social Icons: Add color classes so icon colors correctly reflect changes in Global Styles. ([51020](https://github.com/WordPress/gutenberg/pull/51020)) + + +## Contributors + +The following contributors merged PRs in this release: + +@hellofromtonya @ndiego + + += 15.9.0 = + +## Changelog + +### Enhancements + +#### Block Library +- Add block variations transformation in block switcher. ([50139](https://github.com/WordPress/gutenberg/pull/50139)) +- Code block: Add wide align support. ([50710](https://github.com/WordPress/gutenberg/pull/50710)) +- Post Title edit: Adjust the logic, so it avoids unnecessary OPTIONS requests. ([49839](https://github.com/WordPress/gutenberg/pull/49839)) +- Pattern block: Add experimental flag and syncStatus attrib to allow testing of partial syncing. ([50533](https://github.com/WordPress/gutenberg/pull/50533)) +- Pattern block: Add slug as classname to pattern block wrapper. ([50641](https://github.com/WordPress/gutenberg/pull/50641)) +- Removes the Post Content block from the inserter in the post editor. ([50620](https://github.com/WordPress/gutenberg/pull/50620)) +- Navigation: Handle empty menus in Navigation Browse Mode. ([50870](https://github.com/WordPress/gutenberg/pull/50870)) +- Navigation: browse mode list all Navigation Menus. ([50840](https://github.com/WordPress/gutenberg/pull/50840)) +- Navigation: remove all edit functionality in Browse Mode. ([50788](https://github.com/WordPress/gutenberg/pull/50788)) +- Navigation: Use the ListView in the Navigation block inspector controls. ([49417](https://github.com/WordPress/gutenberg/pull/49417)) +- Navigation: Respect showAppender when there are no items in list view. ([50711](https://github.com/WordPress/gutenberg/pull/50711)) + +#### Command Tool +- Command tool available without the experimental flag. ([50781](https://github.com/WordPress/gutenberg/pull/50781)) +- Add contextual commands. ([50543](https://github.com/WordPress/gutenberg/pull/50543)) +- Marks the commands APIs as public. ([50691](https://github.com/WordPress/gutenberg/pull/50691)) +- Update the document title in the site editor to open the command tool. ([50369](https://github.com/WordPress/gutenberg/pull/50369)) + +#### Components +- Add an outline when the color picker select box is focused. ([50609](https://github.com/WordPress/gutenberg/pull/50609)) +- Button: Update disabled state to be without background. ([50496](https://github.com/WordPress/gutenberg/pull/50496)) +- Update tooltip colors. ([50792](https://github.com/WordPress/gutenberg/pull/50792)) + +#### Site Editor +- Editor canvas container: Include resizeable iframe in component. ([50682](https://github.com/WordPress/gutenberg/pull/50682)) +- Snackbar: Make sure only one template deleted displays at once. ([50625](https://github.com/WordPress/gutenberg/pull/50625)) +- Snackbar: Simplify the template revert. ([50626](https://github.com/WordPress/gutenberg/pull/50626)) +(https://github.com/WordPress/gutenberg/pull/50369)) +- Update the add template menu. ([50595](https://github.com/WordPress/gutenberg/pull/50595)) +- Browse Mode: Add snackbar notices. ([50794](https://github.com/WordPress/gutenberg/pull/50794)) +- Site Editor navigation: Add corresponding area icon to template part menu items. ([50791](https://github.com/WordPress/gutenberg/pull/50791)) +- Update frame resizing. ([49910](https://github.com/WordPress/gutenberg/pull/49910)) +- Always show the `Styles` navigation item. ([50573](https://github.com/WordPress/gutenberg/pull/50573)) +- Sort template parts by type in navigation screen. ([50841](https://github.com/WordPress/gutenberg/pull/50841)) +- Site editor: Update custom post types with _edit_link. ([50563](https://github.com/WordPress/gutenberg/pull/50563)) + +#### Interactivity API +- Image: Add lightbox using directives. ([50373](https://github.com/WordPress/gutenberg/pull/50373)) +- File: Add experimental integration with Interactivity API. ([50377](https://github.com/WordPress/gutenberg/pull/50377)) +- Support negation operator in selectors. ([50732](https://github.com/WordPress/gutenberg/pull/50732)) + +#### Block Editor +- Add `lang` and `dir` attributes to text-formatting tools. ([49985](https://github.com/WordPress/gutenberg/pull/49985)) +- Use `bdo` element when defining the language of some text. ([50632](https://github.com/WordPress/gutenberg/pull/50632)) +- Block inserter: Improve alignment of block inserter search and close icons. ([50439](https://github.com/WordPress/gutenberg/pull/50439)) +- Show visual cue when dragging over empty group block. ([50826](https://github.com/WordPress/gutenberg/pull/50826)) +- Add ability to prevent editing blocks using useBlockEditingMode(). ([50643](https://github.com/WordPress/gutenberg/pull/50643)) +- Remove `unwrap` from transforms and add `ungroup` to more blocks. ([50385](https://github.com/WordPress/gutenberg/pull/50385)) +- Add new API to allow inserter items to be prioritised. ([50510](https://github.com/WordPress/gutenberg/pull/50510)) +- Integrate `prioritizedInserterBlocks` API to slash inserter. ([50658](https://github.com/WordPress/gutenberg/pull/50658)) + +#### Global Styles +- Custom CSS: Force display of in custom css input boxes to LTR. ([50768](https://github.com/WordPress/gutenberg/pull/50768)) +- Styles Navigation Screen: Add Style Book. ([50566](https://github.com/WordPress/gutenberg/pull/50566)) + +#### Data Layer +- Data: Improve `hasResolvingSelectors` redux metadata selector. ([50865](https://github.com/WordPress/gutenberg/pull/50865)) + +#### List View +- Remove fade in/out animation for block settings menu icon button. ([50823](https://github.com/WordPress/gutenberg/pull/50823)) + +#### Full Site Editing +- Template editing: Improve revert notices. ([50302](https://github.com/WordPress/gutenberg/pull/50302)) +- Template pattern modal: Remove internal modal classnames. ([50655](https://github.com/WordPress/gutenberg/pull/50655)) +- Library: Rename template parts to library. ([50769](https://github.com/WordPress/gutenberg/pull/50769)) + +#### Accessibility +- Modals: Update the Cancel action's button design. ([50544](https://github.com/WordPress/gutenberg/pull/50544)) +- Writing flow: Improve keyboard navigation on certain input types. ([43667](https://github.com/WordPress/gutenberg/pull/43667)) + +#### Icons +- Add new `HeadingLevel` icons. ([50856](https://github.com/WordPress/gutenberg/pull/50856)) +- Smaller external link icon. ([50728](https://github.com/WordPress/gutenberg/pull/50728)) + +### Bug Fixes + +#### Block Library +- Ensure multiple pattern blocks with the same slug each create unique blocks. ([50629](https://github.com/WordPress/gutenberg/pull/50629)) +- Fix inconsistent Link UI in Nav block list view editor. ([50774](https://github.com/WordPress/gutenberg/pull/50774)) +- Pattern block: Update frontend render code to match the new version of syncStatus attrib. ([50646](https://github.com/WordPress/gutenberg/pull/50646)) +- Revert "Browse Mode: Add snackbar notices (#50794)". ([50937](https://github.com/WordPress/gutenberg/pull/50937)) +- Update `rel` and `title` labels for navigation and submenu links. ([50214](https://github.com/WordPress/gutenberg/pull/50214)) +- Social Link: Remove block on `DELETE` if empty URL. ([50903](https://github.com/WordPress/gutenberg/pull/50903)) +- Social Link: Add color classes so icon colors correctly reflect changes in Global Styles. ([51020](https://github.com/WordPress/gutenberg/pull/51020)) +- Navigation: Duplicate LeafMoreMenu into the navigation block and the global sidebar navigation. ([50489](https://github.com/WordPress/gutenberg/pull/50489)) +- Post Comments From: Prevent hidden input fields from being focusable in Safari. ([50834](https://github.com/WordPress/gutenberg/pull/50834)) +- Image: Improve the image block lightbox translations, labelling, and escaping. ([50962](https://github.com/WordPress/gutenberg/pull/50962)) + +#### Accessibility +- Fix Multiple Tooltips from Focus Toolbar Shortcut on Site Editor. ([50349](https://github.com/WordPress/gutenberg/pull/50349)) +- Fix accessibility issues navigation block experiment. ([50786](https://github.com/WordPress/gutenberg/pull/50786)) +- Fix accessibility of the Classic block modal dialog. ([50384](https://github.com/WordPress/gutenberg/pull/50384)) +- Fix labelling, description, and focus style of the block transform to pattern previews. ([50577](https://github.com/WordPress/gutenberg/pull/50577)) +- ToggleGroupControl: Fix focus and selected style to support Windows High Contrast mode. ([50785](https://github.com/WordPress/gutenberg/pull/50785)) + +#### Global Styles +- Add back the global styles logic that forces the solid border when color or width applied. ([50498](https://github.com/WordPress/gutenberg/pull/50498)) +- Dimensions Panel: Fix resetting of axial spacing controls. ([50654](https://github.com/WordPress/gutenberg/pull/50654)) +- Global Styles: Enable deep linking to the selected block only in the `Blocks` screen. ([50708](https://github.com/WordPress/gutenberg/pull/50708)) +- Global styles revisions: Highlight currently-loaded revision. ([50725](https://github.com/WordPress/gutenberg/pull/50725)) +- Better error message when theme.json styles use a duotone preset not in settings. ([50714](https://github.com/WordPress/gutenberg/pull/50714)) +- Fix custom duotone filters in frontend. ([50678](https://github.com/WordPress/gutenberg/pull/50678)) + +#### Command Tool +- Command tool: Fix contextual commands selectors. ([50829](https://github.com/WordPress/gutenberg/pull/50829)) +- Command tool: Add searchLabel property to commands. ([50663](https://github.com/WordPress/gutenberg/pull/50663)) + +#### Components +- Add transparent outline to input control BackdropUI focus style. ([50772](https://github.com/WordPress/gutenberg/pull/50772)) +- Update border and focus style of the Input selector in ColorPicker Component. ([50703](https://github.com/WordPress/gutenberg/pull/50703)) + +#### Site Editor +- Fix custom template creation regression. ([50797](https://github.com/WordPress/gutenberg/pull/50797)) +- Remove the loader from sidebar navigation screen. ([50326](https://github.com/WordPress/gutenberg/pull/50326)) +- Update site editor sidebar alignment. ([50561](https://github.com/WordPress/gutenberg/pull/50561)) +- Fix `useEditedEntityRecord()` loading state. ([50730](https://github.com/WordPress/gutenberg/pull/50730)) +- Fix width of Template Parts view. ([50836](https://github.com/WordPress/gutenberg/pull/50836)) +- Process template part shortcodes before blocks. ([50801](https://github.com/WordPress/gutenberg/pull/50801)) +- Convert device type margin styles into non-shorthand syntax. ([50441](https://github.com/WordPress/gutenberg/pull/50441)) +- Browse mode Navigation: Fix broken submenu items. ([50551](https://github.com/WordPress/gutenberg/pull/50551)) + +#### Inspector Controls +- Template revisions: Require 2 revisions before showing the revisions UI. ([50762](https://github.com/WordPress/gutenberg/pull/50762)) + +#### Block Editor +- List block: Fix merging nested list into paragraph. ([50634](https://github.com/WordPress/gutenberg/pull/50634)) +- Add grab cursor style for Block mover drag handle button. ([50808](https://github.com/WordPress/gutenberg/pull/50808)) +- Fix gutenberg_get_block_editor_settings overriding other hooks. ([50760](https://github.com/WordPress/gutenberg/pull/50760)) +- Iframe: Use src instead of srcDoc. ([50875](https://github.com/WordPress/gutenberg/pull/50875)) +- Don't use global 'select' in the Behaviors controls component. ([51028](https://github.com/WordPress/gutenberg/pull/51028)) +- Lightbox UI appearing with interactivity experiment disabled. ([51025](https://github.com/WordPress/gutenberg/pull/51025)) +- Move "No Behaviors" to be the first option in the list of behaviors. ([50979](https://github.com/WordPress/gutenberg/pull/50979)) +- Revert "Browse Mode: Add snackbar notices. ([50937](https://github.com/WordPress/gutenberg/pull/50937)) + +#### Rich Text +- File block: Fix editing of empty file name. ([50607](https://github.com/WordPress/gutenberg/pull/50607)) + +#### List View +- Ensure settings menu is visible when focused. ([50572](https://github.com/WordPress/gutenberg/pull/50572)) + +#### Layout +- Navigation: Fix warning when stretch justification is used. ([50568](https://github.com/WordPress/gutenberg/pull/50568)) + +#### Tests +- Fix release performance tests. ([50699](https://github.com/WordPress/gutenberg/pull/50699)) + +#### Patterns +- Library: Revert description change until new grid view lands. ([51039](https://github.com/WordPress/gutenberg/pull/51039)) + +### Performance + +#### Block Library +- Nav block: Improve loading UX by preloading Navigation menu requests. ([48683](https://github.com/WordPress/gutenberg/pull/48683)) +- Inner blocks: Reduce tree depth to improve performance. ([50447](https://github.com/WordPress/gutenberg/pull/50447)) + +#### Site Editor +- Edit Site: Optimize loading `useSelect` call. ([50546](https://github.com/WordPress/gutenberg/pull/50546)) + + +### Experiments + +#### Components +- Add new experimental version of DropdownMenu. ([49473](https://github.com/WordPress/gutenberg/pull/49473)) +- Behaviors UI. ([49972](https://github.com/WordPress/gutenberg/pull/49972)) + + +### Documentation + +- Add link for more details about block variations' example. ([50909](https://github.com/WordPress/gutenberg/pull/50909)) +- Components: Back-add changelog for TypeScript types. ([50881](https://github.com/WordPress/gutenberg/pull/50881)) +- Add parent and experimental status to the core block reference. ([48269](https://github.com/WordPress/gutenberg/pull/48269)) +- Fix syntax highlighting of curating the editor experience guide. ([50902](https://github.com/WordPress/gutenberg/pull/50902)) +- Minor updates to theme.json schema pages. ([50742](https://github.com/WordPress/gutenberg/pull/50742)) +- Update PHP docblock for `WP_Theme_JSON_Gutenberg::Get_property_value`. ([50527](https://github.com/WordPress/gutenberg/pull/50527)) +- Mobile app: Fix change log typo. ([50737](https://github.com/WordPress/gutenberg/pull/50737)) +- Icons: Update README.md to include a link to the documentation. ([50606](https://github.com/WordPress/gutenberg/pull/50606)) + + +### Code Quality + +#### Block Library +- Cover: Unlock private APIs outside of the component. ([50686](https://github.com/WordPress/gutenberg/pull/50686)) +- Fix column block category. ([46048](https://github.com/WordPress/gutenberg/pull/46048)) +- Freeform: Move modal styles to the correct file. ([50858](https://github.com/WordPress/gutenberg/pull/50858)) +- Navigation: Remove the check for draft navigation menus from the UnsavedInnerBlocks component. ([49161](https://github.com/WordPress/gutenberg/pull/49161)) +- Navigation: Unlock private APIs outside of the component. ([50509](https://github.com/WordPress/gutenberg/pull/50509)) +- Remove OffCanvasEditor. ([50705](https://github.com/WordPress/gutenberg/pull/50705)) +- Comments: Replace get_comments() with get_comments_number(). ([50798](https://github.com/WordPress/gutenberg/pull/50798)) +- Lodash: Remove from Gallery block. ([50591](https://github.com/WordPress/gutenberg/pull/50591)) +- Lodash: Remove from Image block. ([50592](https://github.com/WordPress/gutenberg/pull/50592)) +- Lodash: Remove from Latest Posts block. ([50593](https://github.com/WordPress/gutenberg/pull/50593)) +- Lodash: Remove from Media & Text block. ([50587](https://github.com/WordPress/gutenberg/pull/50587)) +- Lodash: Remove from template part block. ([50586](https://github.com/WordPress/gutenberg/pull/50586)) +- Lodash: Remove unnecessary mock from Buttons tests. ([50588](https://github.com/WordPress/gutenberg/pull/50588)) + +#### Block Editor +- Block Editor: Remove unused 'useIsDimensionsSupportValid' method. ([50735](https://github.com/WordPress/gutenberg/pull/50735)) +- Block styles: Remove unused prop from inserter preview component. ([50622](https://github.com/WordPress/gutenberg/pull/50622)) + +#### Post Editor +- Edit Post: Unlock useShouldContextualToolbarShow outside of the component. ([50612](https://github.com/WordPress/gutenberg/pull/50612)) +- FlatTermSelector: Fix the 'useSelect' missing dependency. ([50872](https://github.com/WordPress/gutenberg/pull/50872)) + +#### Site Editor +- Use the keyboard shortcuts package for the title bar. ([50873](https://github.com/WordPress/gutenberg/pull/50873)) +- Simplify variation selectors. ([50687](https://github.com/WordPress/gutenberg/pull/50687)) +- Unlock private APIs outside of the component. ([50534](https://github.com/WordPress/gutenberg/pull/50534)) +- Remove unused 'NavigateToLink' component. ([50908](https://github.com/WordPress/gutenberg/pull/50908)) +- Move `gutenberg_get_remote_theme_patterns`. ([50597](https://github.com/WordPress/gutenberg/pull/50597)) + +#### Interactivity API +- Polish experimental navigation block. ([50670](https://github.com/WordPress/gutenberg/pull/50670)) + +#### Components +- DropdownMenu: Refactor to TypeScript. ([50187](https://github.com/WordPress/gutenberg/pull/50187)) + +#### npm Packages +- chore: Update memize to v2. ([50172](https://github.com/WordPress/gutenberg/pull/50172)) + +#### Global Styles +- Global styles revisions: Remove unused private var. ([50763](https://github.com/WordPress/gutenberg/pull/50763)) +- Introduce `prepend_to_selector()` to avoid additional if checks and follow single responsibility principle. ([50266](https://github.com/WordPress/gutenberg/pull/50266)) +- Move `gutenberg_get_global_styles` function. ([50596](https://github.com/WordPress/gutenberg/pull/50596)) + + +### Tools + +#### Testing +- Combine frontend navigation Page list block tests into one test to speed up end-to-end tests. ([50681](https://github.com/WordPress/gutenberg/pull/50681)) +- Command tool: Enable end-to-end tests. ([50833](https://github.com/WordPress/gutenberg/pull/50833)) +- Create pages before navigation tests requiring link control to find page results. ([50680](https://github.com/WordPress/gutenberg/pull/50680)) +- Enable iframe-inline-styles end-to-end test. ([50548](https://github.com/WordPress/gutenberg/pull/50548)) +- Fix coding-standards issues. ([50656](https://github.com/WordPress/gutenberg/pull/50656)) +- Fix flaky media inserter drag-and-dropping end-to-end test. ([50740](https://github.com/WordPress/gutenberg/pull/50740)) +- Fix flaky template revert end-to-end tests. ([50851](https://github.com/WordPress/gutenberg/pull/50851)) +- In CI, verify that PHPunit is actually running. ([50442](https://github.com/WordPress/gutenberg/pull/50442)) +- Migrate Cover Block tests to Playwright. ([45784](https://github.com/WordPress/gutenberg/pull/45784)) +- Remove redundant calls to disable the Styles welcome guide. ([50871](https://github.com/WordPress/gutenberg/pull/50871)) +- Remove unintentionally added test artifact. ([50795](https://github.com/WordPress/gutenberg/pull/50795)) +- Revert "Enqueue the registered assets (#50185)". ([50537](https://github.com/WordPress/gutenberg/pull/50537)) +- Mobile - end-to-end test - Update code to use the new navigateUp helper. ([50736](https://github.com/WordPress/gutenberg/pull/50736)) +- Playwright Utils: Use 'set' to disable the Styles welcome guide. ([50852](https://github.com/WordPress/gutenberg/pull/50852)) + + +#### Build Tooling +- DateTime: Remove deprecated props (and fix static analysis action in trunk). ([50724](https://github.com/WordPress/gutenberg/pull/50724)) +- Update `runtime` test field in WebPack configuration to support Windows. ([50727](https://github.com/WordPress/gutenberg/pull/50727)) +- Removed `gutenberg` Directory Name Expectation. ([50894](https://github.com/WordPress/gutenberg/pull/50894)) +- Reworked `run` Command Parsing. ([50559](https://github.com/WordPress/gutenberg/pull/50559)) + +#### wp-env +- Add `t-hamano` as codeowner for `env` package. ([50817](https://github.com/WordPress/gutenberg/pull/50817)) +- Check `.wp-env.json` For Unknown Options. ([50642](https://github.com/WordPress/gutenberg/pull/50642)) +- Expanded `wp-env` Lifecycle Scripts. ([50570](https://github.com/WordPress/gutenberg/pull/50570)) +- Fixed `wp-env start` On Windows. ([50895](https://github.com/WordPress/gutenberg/pull/50895)) +- Add @ObliviousHarmony to wp-env codeowners. ([50530](https://github.com/WordPress/gutenberg/pull/50530)) + + +## First time contributors + +The following PRs were merged by first time contributors: + +- @bacoords: Update README.md to include a link to the documentation. ([50606](https://github.com/WordPress/gutenberg/pull/50606)) +- @falgunihdesai: Update border and focus style of the Input selector in ColorPicker Component. ([50703](https://github.com/WordPress/gutenberg/pull/50703)) +- @kmanijak: Adjust the logic of Post Title edit, so it avoids unnecessary OPTIONS requests. ([49839](https://github.com/WordPress/gutenberg/pull/49839)) +- @kutsu123: Add grab cursor style for Block mover drag handle button. ([50808](https://github.com/WordPress/gutenberg/pull/50808)) +- @megane9988: Add an outline when the color picker select box is focused. ([50609](https://github.com/WordPress/gutenberg/pull/50609)) +- @SaxonF: Update site editor sidebar alignment. ([50561](https://github.com/WordPress/gutenberg/pull/50561)) +- @worldomonation: Migrate Cover Block tests to Playwright. ([45784](https://github.com/WordPress/gutenberg/pull/45784)) + + +## Contributors + +The following contributors merged PRs in this release: + +@aaronrobertshaw @afercia @ajlende @andrewserong @antpb @aristath @artemiomorales @bacoords @carolinan @chad1008 @ciampo @dcalhoun @derekblank @ellatrix @fabiankaegy @falgunihdesai @felixarntz @fluiddot @geriux @getdave @glendaviesnz @gziolo @jameskoster @jasmussen @jeryj @jhnstn @johnhooks @juanfra @kevin940726 @kmanijak @kutsu123 @MaggieCabrera @Mamaduka @mboynes @mburridge @megane9988 @michalczaplinski @mirka @n2erjo00 @noahtallen @noisysocks @ntsekouras @oandregal @ObliviousHarmony @ramonjd @richtabor @samnajian @SantosGuillamot @SaxonF @scruffian @shimotmk @SiobhyB @t-hamano @talldan @tyxla @worldomonation @WunderBart @youknowriad + + = 15.8.1 = diff --git a/docs/contributors/code/coding-guidelines.md b/docs/contributors/code/coding-guidelines.md index 1954020c1a3eb1..ac89ef7f7dc873 100644 --- a/docs/contributors/code/coding-guidelines.md +++ b/docs/contributors/code/coding-guidelines.md @@ -771,9 +771,9 @@ Documenting a function component should be treated the same as any other functio * * @return {?string} Block title. */ -```` +``` -For class components, there is no recommendation for documenting the props of the component. Gutenberg does not use or endorse the [`propTypes` static class member](https://reactjs.org/docs/typechecking-with-proptypes.html). +For class components, there is no recommendation for documenting the props of the component. Gutenberg does not use or endorse the [`propTypes` static class member](https://react.dev/reference/react/Component#static-proptypes). ## PHP diff --git a/docs/contributors/code/grammar.md b/docs/contributors/code/grammar.md deleted file mode 100644 index ae59259932f91e..00000000000000 --- a/docs/contributors/code/grammar.md +++ /dev/null @@ -1,5 +0,0 @@ -# Block Grammar - -
Block_List
= $(!Block .)* (Block $(!Block .)*)* $(.*)
Block
= Block_Void - / Block_Balanced
Block_Void
= "<!--" __ "wp:" Block_Name __ (Block_Attributes __)? "/-->"
Block_Balanced
= Block_Start (Block / $(!Block !Block_End .)+)* Block_End
Block_Start
= "<!--" __ "wp:" Block_Name __ (Block_Attributes __)? "-->"
Block_End
= "<!--" __ "/wp:" Block_Name __ "-->"
Block_Name
= Namespaced_Block_Name - / Core_Block_Name
Namespaced_Block_Name
= $(Block_Name_Part "/" Block_Name_Part)
Core_Block_Name
= $(Block_Name_Part)
Block_Name_Part
= $([a-z] [a-z0-9_-]*)
JSON-encoded attributes embedded in a block's opening comment
Block_Attributes
= $("{" (!("}" __ "" "/"? "-->") .)* "}")
__
= [ \t\r\n]+
diff --git a/docs/contributors/code/scripts.md b/docs/contributors/code/scripts.md index d4ce263c80ad14..5cd7efd2fffdad 100644 --- a/docs/contributors/code/scripts.md +++ b/docs/contributors/code/scripts.md @@ -2,7 +2,7 @@ The editor provides several vendor and internal scripts to plugin developers. Script names, handles, and descriptions are documented in the table below. -## WP Scripts +## WordPress scripts The editor includes a number of packages to enable various pieces of functionality. Plugin developers can utilize them to create blocks, editor plugins, or generic plugins. @@ -40,7 +40,7 @@ The editor includes a number of packages to enable various pieces of functionali | [Viewport](/packages/viewport/README.md) | wp-viewport | Module for responding to changes in the browser viewport size | | [Wordcount](/packages/wordcount/README.md) | wp-wordcount | WordPress word count utility | -## Vendor Scripts +## Vendor scripts The editor also uses some popular third-party packages and scripts. Plugin developers can use these scripts as well without bundling them in their code (and increasing file sizes). @@ -51,9 +51,10 @@ The editor also uses some popular third-party packages and scripts. Plugin devel | [Moment](https://momentjs.com/) | moment | Parse, validate, manipulate, and display dates and times in JavaScript | | [Lodash](https://lodash.com) | lodash | Lodash is a JavaScript library which provides utility functions for common programming tasks | -## Polyfill Scripts +## Polyfill scripts The editor also provides polyfills for certain features that may not be available in all modern browsers. + It is recommended to use the main `wp-polyfill` script handle which takes care of loading all the below mentioned polyfills. | Script Name | Handle | Description | @@ -67,12 +68,6 @@ It is recommended to use the main `wp-polyfill` script handle which takes care o ## Bundling and code sharing -When using a JavaScript bundler like [webpack](https://webpack.js.org/), the scripts mentioned here -can be excluded from the bundle and provided by WordPress in the form of script dependencies [see -`wp_enqueue_script`](https://developer.wordpress.org/reference/functions/wp_enqueue_script/#default-scripts-included-and-registered-by-wordpress). +When using a JavaScript bundler like [webpack](https://webpack.js.org/), the scripts mentioned here can be excluded from the bundle and provided by WordPress in the form of script dependencies see [`wp_enqueue_script`](https://developer.wordpress.org/reference/functions/wp_enqueue_script/#default-scripts-included-and-registered-by-wordpress). -The -[`@wordpress/dependency-extraction-webpack-plugin`](https://github.com/WordPress/gutenberg/tree/HEAD/packages/dependency-extraction-webpack-plugin) -provides a webpack plugin to help extract WordPress dependencies from bundles. `@wordpress/scripts` -[`build`](https://github.com/WordPress/gutenberg/tree/HEAD/packages/scripts#build) script includes -the plugin by default. +The [`@wordpress/dependency-extraction-webpack-plugin`](https://github.com/WordPress/gutenberg/tree/HEAD/packages/dependency-extraction-webpack-plugin) provides a webpack plugin to help extract WordPress dependencies from bundles. The `@wordpress/scripts` [`build`](https://github.com/WordPress/gutenberg/tree/HEAD/packages/scripts#build) script includes the plugin by default. diff --git a/docs/contributors/roadmap.md b/docs/contributors/roadmap.md deleted file mode 100644 index ae7aa5ea797731..00000000000000 --- a/docs/contributors/roadmap.md +++ /dev/null @@ -1,31 +0,0 @@ -# Upcoming Projects & Roadmap - -_Complementary to [Phase 2 Scope](https://github.com/WordPress/gutenberg/issues/13113)._ - -This document outlines some of the features currently in development or being considered for the project. It should not be confused with the product roadmap for WordPress itself, even if some areas naturally overlap. The main purpose of it is to give visibility to some of the key problems remaining to be solved and as an invitation for those wanting to collaborate on some of the more complex issues to learn about what needs help. - -Gutenberg is already in use by millions of sites through WordPress, so in order to make substantial changes to the design or updating specifications it is advisable to consider a discussion process ("Request for Comments") showing both an understanding of the impact, both positives and negatives, trade offs and opportunities. - -## Projects - -- **Block Registry** — define an entry point for block identification. ([See active RFC](https://github.com/WordPress/gutenberg/pull/13693).) -- **Live Component Library** — a place to visualize and interact with the UI components and block tools included in the packages. -- **Modular Editor** — allow loading the block editor in several contexts without a dependency to a post object. (Ongoing [pending tasks](https://github.com/WordPress/gutenberg/issues/14043).) -- **Better Validation** — continue to refine the mechanisms used in validating editor content. (See in depth overview at [#11440](https://github.com/WordPress/gutenberg/issues/11440) and [#7604](https://github.com/WordPress/gutenberg/issues/7604).) -- **Block Areas** — build support for areas of blocks that fall outside the content (including relationship with templates, registration, storage, and so on). ([See overview](https://github.com/WordPress/gutenberg/issues/13489).) -- **Multi-Block Editing** — allow modifying attributes of multiple blocks of the same kind at once. -- **Rich Text Roadmap** — continue to develop the capabilities of the rich text package. ([See overview](https://github.com/WordPress/gutenberg/issues/13778).) -- **Common Block Functionality** — coalesce into a preferred mechanism for creating and sharing chunks of functionality (block alignment, color tools, etc) across blocks with a simple and intuitive code interface. (Suggested exploration: React Hooks, [see overview](https://github.com/WordPress/gutenberg/issues/15450).) -- **Responsive Images** — propose mechanisms for handling flexible image sources that can be optimized for loading and takes into account their placement on a page (within main content, a column, sidebar, etc). -- **Async Loading** — propose a strategy for loading block code only when necessary in the editor without overhead for the developer or disrupting the user experience. -- **Styles** — continue to develop the mechanisms for managing block styles and other styling solutions. (See overview at [#7551](https://github.com/WordPress/gutenberg/issues/7551) and [#9534](https://github.com/WordPress/gutenberg/issues/9534).) -- **Bundling Front-end Assets** — explore ways in which front-end styles for blocks could be assembled based on which blocks are used in a given page response. ([See overview](https://github.com/WordPress/gutenberg/issues/5445).) -- **Transforms API** — improve the transform API to allow advanced use-cases: support for async-transforms, access to the block editor settings and bring consistency between the different types of transforms. ([See related issue](https://github.com/WordPress/gutenberg/issues/14755).) - -## Timeline - -The projects outlined above indicate areas of interest but not necessarily development priorities. Sometimes, a product need will accelerate a resolution (as is the case of the block registry), other times community interest might be the driving force. - -- 2019 Q1: Block Registry — First phase. Required for plugin directory "meta" project. -- 2019 Q2: Modular Editor — Requirement for most of phase 2. -- 2019 Q3: Block Areas. diff --git a/docs/explanations/architecture/README.md b/docs/explanations/architecture/README.md index 774df183618d4a..2cecdfd70e2d6f 100644 --- a/docs/explanations/architecture/README.md +++ b/docs/explanations/architecture/README.md @@ -6,6 +6,7 @@ Let’s look at the big picture and the architectural and UX principles of the b - [Key concepts](/docs/explanations/architecture/key-concepts.md). - [Data format and data flow](/docs/explanations/architecture/data-flow.md). +- [Entities and undo/redo](/docs/explanations/architecture/entities.md). - [Site editing templates](/docs/explanations/architecture/full-site-editing-templates.md). - [Styles in the editor](/docs/explanations/architecture/styles.md). - [Performance](/docs/explanations/architecture/performance.md). diff --git a/docs/explanations/architecture/entities.md b/docs/explanations/architecture/entities.md new file mode 100644 index 00000000000000..1e037ed5b2824f --- /dev/null +++ b/docs/explanations/architecture/entities.md @@ -0,0 +1,63 @@ +# Entities and Undo/Redo. + +The WordPress editors, whether it's the post or site editor, manipulate what we call entity records. These are objects that represent a post, a page, a user, a term, a template, etc. They are the data that is stored in the database and that is manipulated by the editor. Each editor can fetch, edit and save multiple entity records at the same time. + +For instance, when opening a page in the site editor: + - you can edit properties of the page itself (title, content...) + - you can edit properties of the template of the page (content of the template, design...) + - you can edit properties of template parts (header, footer) used with the template. + +The editor keeps track of all these modifications and orchestrates the saving of all these modified records. This happens within the `@wordpress/core-data` package. + + +## Editing entities + +To be able to edit an entity, you need to first fetch it and load it into the `core-data` store. For example, the following code loads the post with ID 1 into the store. (The entity is the post, the post 1 is the entity record). + +````js +wp.data.dispatch( 'core' ).getEntityRecord( 'postType', 'post', 1 ); +```` + +Once the entity is loaded, you can edit it. For example, the following code sets the title of the post to "Hello World". For each fetched entity record, the `core-data` store keeps track of: + - the "persisted" record: The last state of the record as it was fetched from the backend. + - A list of "edits": Unsaved local modifications for one or several properties of the record. + +The package also exposes a set of actions to manipulate the fetched entity records. + +To edit an entity record, you can call `editEntityRecord`, which takes the entity type, the entity ID and the new entity record as parameters. The following example sets the title of the post with ID 1 to "Hello World". + +````js +wp.data.dispatch( 'core' ).editEntityRecord( 'postType', 'post', 1, { title: 'Hello World' } ); +```` + +Once you have edited an entity record, you can save it. The following code saves the post with ID 1. + +````js +wp.data.dispatch( 'core' ).saveEditedEntityRecord( 'postType', 'post', 1 ); +```` + +## Undo/Redo + +Since the WordPress editors allow multiple entity records to be edited at the same time, the `core-data` package keeps track of all the entity records that have been fetched and edited in a common undo/redo stack. Each step in the undo/redo stack contains a list of "edits" that should be undone or redone at the same time when calling the `undo` or `redo` action. + +And to be able to perform both undo and redo operations propertly, each modification in the list of edits contains the following information: + + - Entity kind and name: Each entity in core-data is identified by the pair _(kind, name)_. This corresponds to the identifier of the modified entity. + - Entity Record ID: The ID of the modified record. + - Property: The name of the modified property. + - From: The previous value of the property (needed to apply the undo operation). + - To: The new value of the property (needed to apply the redo operation). + +For example, let's say a user edits the title of a post, followed by a modification to the post slug, and then a modification of the title of a reusable block used with the post. The following information is stored in the undo/redo stack: + + - `[ { kind: 'postType', name: 'post', id: 1, property: 'title', from: '', to: 'Hello World' } ]` + - `[ { kind: 'postType', name: 'post', id: 1, property: 'slug', from: 'Previous slug', to: 'This is the slug of the hello world post' } ]` + - `[ { kind: 'postType', name: 'wp_block', id: 2, property: 'title', from: 'Reusable Block', to: 'Awesome Reusable Block' } ]` + +The store also keep tracks of a "pointer" to the current "undo/redo" step. By default, the pointer always points to the last item in the stack. This pointer is updated when the user performs an undo or redo operation. + +### Transient changes + +The undo/redo core behavior also supports what we call "transient modifications". These are modifications that are not stored in the undo/redo stack right away. For instance, when a user starts typing in a text field, the value of the field is modified in the store, but this modification is not stored in the undo/redo stack until after the user moves to the next word or after a few milliseconds. This is done to avoid creating a new undo/redo step for each character typed by the user. + +So by default, `core-data` store considers all modifications to properties that are marked as "transient" (like the `blocks` property in the post entity) as transient modifications. It keeps these modifications outside the undo/redo stack in what is called a "cache" of modifications and these modifications are only stored in the undo/redo stack when we explicitely call `__unstableCreateUndoLevel` or when the next non-transient modification is performed. diff --git a/docs/getting-started/create-block/block-anatomy.md b/docs/getting-started/create-block/block-anatomy.md index 83dbcf14696325..d53b1c9d6f5ebd 100644 --- a/docs/getting-started/create-block/block-anatomy.md +++ b/docs/getting-started/create-block/block-anatomy.md @@ -44,7 +44,7 @@ Most of the properties are set in the `src/block.json` file. ```json { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "create-block/gutenpride", "version": "0.1.0", "title": "Gutenpride", diff --git a/docs/getting-started/create-block/wp-plugin.md b/docs/getting-started/create-block/wp-plugin.md index 33142659680b94..465060daba7c38 100644 --- a/docs/getting-started/create-block/wp-plugin.md +++ b/docs/getting-started/create-block/wp-plugin.md @@ -104,7 +104,7 @@ The `register_block_type` function registers the block we are going to create an ```json { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "create-block/gutenpride", "version": "0.1.0", "title": "Gutenpride", diff --git a/docs/how-to-guides/block-tutorial/applying-styles-with-stylesheets.md b/docs/how-to-guides/block-tutorial/applying-styles-with-stylesheets.md index e32054c167ca55..fc8dc01531c5d9 100644 --- a/docs/how-to-guides/block-tutorial/applying-styles-with-stylesheets.md +++ b/docs/how-to-guides/block-tutorial/applying-styles-with-stylesheets.md @@ -197,11 +197,15 @@ Like scripts, you can enqueue your block's styles using the `block.json` file. Use the `editorStyle` property to a CSS file you want to load in the editor view, and use the `style` property for a CSS file you want to load on the frontend when the block is used. +It is worth noting that, if the editor content is iframed, both of these will +load in the iframe. `editorStyle` will also load outside the iframe, so it can +be used for editor content as well as UI. + For example: ```json { - "apiVersion": 2, + "apiVersion": 3, "name": "gutenberg-examples/example-02-stylesheets", "title": "Example: Stylesheets", "icon": "universal-access-alt", diff --git a/docs/how-to-guides/block-tutorial/block-controls-toolbar-and-sidebar.md b/docs/how-to-guides/block-tutorial/block-controls-toolbar-and-sidebar.md index cd110973b124f2..93e5e54d848690 100644 --- a/docs/how-to-guides/block-tutorial/block-controls-toolbar-and-sidebar.md +++ b/docs/how-to-guides/block-tutorial/block-controls-toolbar-and-sidebar.md @@ -24,7 +24,7 @@ import { } from '@wordpress/block-editor'; registerBlockType( 'gutenberg-examples/example-04-controls-esnext', { - apiVersion: 2, + apiVersion: 3, title: 'Example: Controls (esnext)', icon: 'universal-access-alt', category: 'design', @@ -208,7 +208,7 @@ import { } from '@wordpress/block-editor'; registerBlockType( 'create-block/gutenpride', { - apiVersion: 2, + apiVersion: 3, attributes: { message: { type: 'string', diff --git a/docs/how-to-guides/block-tutorial/block-supports-in-dynamic-blocks.md b/docs/how-to-guides/block-tutorial/block-supports-in-dynamic-blocks.md index b458b135104f90..dc022622c80c20 100644 --- a/docs/how-to-guides/block-tutorial/block-supports-in-dynamic-blocks.md +++ b/docs/how-to-guides/block-tutorial/block-supports-in-dynamic-blocks.md @@ -20,7 +20,7 @@ import { } from '@wordpress/block-editor'; registerBlockType( 'gutenberg-examples/example-dynamic', { - apiVersion: 2, + apiVersion: 3, title: 'Example: last post title', icon: 'megaphone', category: 'widgets', @@ -119,7 +119,7 @@ function gutenberg_examples_dynamic() { register_block_type( 'gutenberg-examples/example-dynamic', array( - 'api_version' => 2, + 'api_version' => 3, 'category' => 'widgets', 'attributes' => array( 'bgColor' => array( 'type' => 'string' ), @@ -144,7 +144,7 @@ import { useSelect } from '@wordpress/data'; import { useBlockProps } from '@wordpress/block-editor'; registerBlockType( 'gutenberg-examples/example-dynamic-block-supports', { - apiVersion: 2, + apiVersion: 3, title: 'Example: last post title(block supports)', icon: 'megaphone', category: 'widgets', @@ -195,7 +195,7 @@ function gutenberg_examples_dynamic_block_supports() { register_block_type( 'gutenberg-examples/example-dynamic-block-supports', array( - 'api_version' => 2, + 'api_version' => 3, 'category' => 'widgets', 'supports' => array( 'color' => true ), 'render_callback' => 'gutenberg_examples_dynamic_block_supports_render_callback', diff --git a/docs/how-to-guides/block-tutorial/block-supports-in-static-blocks.md b/docs/how-to-guides/block-tutorial/block-supports-in-static-blocks.md index ee478602fd1e9b..b343280cae43f9 100644 --- a/docs/how-to-guides/block-tutorial/block-supports-in-static-blocks.md +++ b/docs/how-to-guides/block-tutorial/block-supports-in-static-blocks.md @@ -16,7 +16,7 @@ import { registerBlockType } from '@wordpress/blocks'; import { useBlockProps, RichText } from '@wordpress/block-editor'; registerBlockType( 'gutenberg-examples/example-03-editable-esnext', { - apiVersion: 2, + apiVersion: 3, title: 'Example: Basic with block supports', icon: 'universal-access-alt', category: 'design', @@ -73,7 +73,7 @@ registerBlockType( 'gutenberg-examples/example-03-editable-esnext', { var useBlockProps = blockEditor.useBlockProps; blocks.registerBlockType( 'gutenberg-examples/example-03-editable', { - apiVersion: 2, + apiVersion: 3, title: 'Example: Basic with block supports', icon: 'universal-access-alt', category: 'design', @@ -127,7 +127,7 @@ Now, let's alter the block.json file for that block, and add the supports key. ( ```json { - "apiVersion": 2, + "apiVersion": 3, "name": "gutenberg-examples/example-03-editable-esnext", "title": "Example: Basic with block supports", "icon": "universal-access-alt", diff --git a/docs/how-to-guides/block-tutorial/creating-dynamic-blocks.md b/docs/how-to-guides/block-tutorial/creating-dynamic-blocks.md index 9f5eff3883b6a7..9d1e4dbdf52553 100644 --- a/docs/how-to-guides/block-tutorial/creating-dynamic-blocks.md +++ b/docs/how-to-guides/block-tutorial/creating-dynamic-blocks.md @@ -26,7 +26,7 @@ import { useSelect } from '@wordpress/data'; import { useBlockProps } from '@wordpress/block-editor'; registerBlockType( 'gutenberg-examples/example-dynamic', { - apiVersion: 2, + apiVersion: 3, title: 'Example: last post', icon: 'megaphone', category: 'widgets', @@ -62,7 +62,7 @@ registerBlockType( 'gutenberg-examples/example-dynamic', { useBlockProps = blockEditor.useBlockProps; registerBlockType( 'gutenberg-examples/example-dynamic', { - apiVersion: 2, + apiVersion: 3, title: 'Example: last post', icon: 'megaphone', category: 'widgets', @@ -132,7 +132,7 @@ function gutenberg_examples_dynamic() { ); register_block_type( 'gutenberg-examples/example-dynamic', array( - 'api_version' => 2, + 'api_version' => 3, 'editor_script' => 'gutenberg-examples-dynamic', 'render_callback' => 'gutenberg_examples_dynamic_render_callback' ) ); @@ -165,7 +165,7 @@ import ServerSideRender from '@wordpress/server-side-render'; import { useBlockProps } from '@wordpress/block-editor'; registerBlockType( 'gutenberg-examples/example-dynamic', { - apiVersion: 2, + apiVersion: 3, title: 'Example: last post', icon: 'megaphone', category: 'widgets', @@ -194,7 +194,7 @@ registerBlockType( 'gutenberg-examples/example-dynamic', { useBlockProps = blockEditor.useBlockProps; registerBlockType( 'gutenberg-examples/example-dynamic', { - apiVersion: 2, + apiVersion: 3, title: 'Example: last post', icon: 'megaphone', category: 'widgets', diff --git a/docs/how-to-guides/block-tutorial/introducing-attributes-and-editable-fields.md b/docs/how-to-guides/block-tutorial/introducing-attributes-and-editable-fields.md index b0def1aff4d08e..8f4c54451cdb2f 100644 --- a/docs/how-to-guides/block-tutorial/introducing-attributes-and-editable-fields.md +++ b/docs/how-to-guides/block-tutorial/introducing-attributes-and-editable-fields.md @@ -60,7 +60,7 @@ import { registerBlockType } from '@wordpress/blocks'; import { useBlockProps, RichText } from '@wordpress/block-editor'; registerBlockType( 'gutenberg-examples/example-03-editable-esnext', { - apiVersion: 2, + apiVersion: 3, title: 'Example: Editable (esnext)', icon: 'universal-access-alt', category: 'design', @@ -117,7 +117,7 @@ registerBlockType( 'gutenberg-examples/example-03-editable-esnext', { var useBlockProps = blockEditor.useBlockProps; blocks.registerBlockType( 'gutenberg-examples/example-03-editable', { - apiVersion: 2, + apiVersion: 3, title: 'Example: Editable', icon: 'universal-access-alt', category: 'design', diff --git a/docs/how-to-guides/block-tutorial/writing-your-first-block-type.md b/docs/how-to-guides/block-tutorial/writing-your-first-block-type.md index 83a3cd156251bf..40f9dcfcfb5fd9 100644 --- a/docs/how-to-guides/block-tutorial/writing-your-first-block-type.md +++ b/docs/how-to-guides/block-tutorial/writing-your-first-block-type.md @@ -43,7 +43,7 @@ Create a basic `block.json` file there: ```json { - "apiVersion": 2, + "apiVersion": 3, "title": "Example: Basic (ESNext)", "name": "gutenberg-examples/example-01-basic-esnext", "category": "layout", @@ -56,7 +56,7 @@ Create a basic `block.json` file there: ```json { - "apiVersion": 2, + "apiVersion": 3, "title": "Example: Basic", "name": "gutenberg-examples/example-01-basic", "category": "layout", diff --git a/docs/how-to-guides/curating-the-editor-experience.md b/docs/how-to-guides/curating-the-editor-experience.md index 795f0db59eaf7f..51054655f51aac 100644 --- a/docs/how-to-guides/curating-the-editor-experience.md +++ b/docs/how-to-guides/curating-the-editor-experience.md @@ -343,7 +343,7 @@ addFilter( 'blockEditor.useSetting.before', 'example/useSetting.before', ( settingValue, settingName, clientId, blockName ) => { - if ( blockName === Media & Text block'core/column' && settingName === 'spacing.units' ) { + if ( blockName === 'core/column' && settingName === 'spacing.units' ) { return [ 'px' ]; } return settingValue; diff --git a/docs/how-to-guides/internationalization.md b/docs/how-to-guides/internationalization.md index fa28b78b376904..af68da27193355 100644 --- a/docs/how-to-guides/internationalization.md +++ b/docs/how-to-guides/internationalization.md @@ -28,7 +28,7 @@ function myguten_block_init() { ); register_block_type( 'myguten/simple', array( - 'api_version' => 2, + 'api_version' => 3, 'editor_script' => 'myguten-script', ) ); } @@ -46,7 +46,7 @@ import { registerBlockType } from '@wordpress/blocks'; import { useBlockProps } from '@wordpress/block-editor'; registerBlockType( 'myguten/simple', { - apiVersion: 2, + apiVersion: 3, title: __( 'Simple Block', 'myguten' ), category: 'widgets', diff --git a/docs/how-to-guides/metabox.md b/docs/how-to-guides/metabox.md index 382afd602ed3de..7a8686968d2cf2 100644 --- a/docs/how-to-guides/metabox.md +++ b/docs/how-to-guides/metabox.md @@ -152,7 +152,7 @@ function myguten_render_paragraph( $block_attributes, $content ) { } register_block_type( 'core/paragraph', array( - 'api_version' => 2, + 'api_version' => 3, 'render_callback' => 'myguten_render_paragraph', ) ); ``` diff --git a/docs/manifest.json b/docs/manifest.json index d6759f051a6791..8a21bc38a54189 100644 --- a/docs/manifest.json +++ b/docs/manifest.json @@ -2039,6 +2039,12 @@ "markdown_source": "../docs/explanations/architecture/data-flow.md", "parent": "architecture" }, + { + "title": "Entities and Undo/Redo.", + "slug": "entities", + "markdown_source": "../docs/explanations/architecture/entities.md", + "parent": "architecture" + }, { "title": "Modularity", "slug": "modularity", @@ -2165,12 +2171,6 @@ "markdown_source": "../docs/contributors/code/e2e/overusing-snapshots.md", "parent": "e2e" }, - { - "title": "Block Grammar", - "slug": "grammar", - "markdown_source": "../docs/contributors/code/grammar.md", - "parent": "code" - }, { "title": "Scripts", "slug": "scripts", @@ -2308,11 +2308,5 @@ "slug": "versions-in-wordpress", "markdown_source": "../docs/contributors/versions-in-wordpress.md", "parent": "contributors" - }, - { - "title": "Upcoming Projects & Roadmap", - "slug": "roadmap", - "markdown_source": "../docs/contributors/roadmap.md", - "parent": "contributors" } ] diff --git a/docs/reference-guides/block-api/block-edit-save.md b/docs/reference-guides/block-api/block-edit-save.md index f585d734547277..843a8d5be12d3c 100644 --- a/docs/reference-guides/block-api/block-edit-save.md +++ b/docs/reference-guides/block-api/block-edit-save.md @@ -14,7 +14,7 @@ import { useBlockProps } from '@wordpress/block-editor'; // ... const blockSettings = { - apiVersion: 2, + apiVersion: 3, // ... @@ -30,7 +30,7 @@ const blockSettings = { ```js var blockSettings = { - apiVersion: 2, + apiVersion: 3, // ... @@ -58,7 +58,7 @@ import { useBlockProps } from '@wordpress/block-editor'; // ... const blockSettings = { - apiVersion: 2, + apiVersion: 3, // ... @@ -76,7 +76,7 @@ const blockSettings = { ```js var blockSettings = { - apiVersion: 2, + apiVersion: 3, // ... diff --git a/docs/reference-guides/block-api/block-metadata.md b/docs/reference-guides/block-api/block-metadata.md index 9bfdce9279ff24..216509ab1df133 100644 --- a/docs/reference-guides/block-api/block-metadata.md +++ b/docs/reference-guides/block-api/block-metadata.md @@ -7,7 +7,7 @@ Starting in WordPress 5.8 release, we recommend using the `block.json` metadata ```json { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "my-plugin/notice", "title": "Notice", "category": "text", @@ -150,10 +150,10 @@ This section describes all the properties that can be added to the `block.json` - Default: `1` ```json -{ "apiVersion": 2 } +{ "apiVersion": 3 } ``` -The version of the Block API used by the block. The most recent version is `2` and it was introduced in WordPress 5.6. +The version of the Block API used by the block. The most recent version is `3` and it was introduced in WordPress 6.3. See the [the API versions documentation](/docs/reference-guides/block-api/block-api-versions.md) for more details. diff --git a/docs/reference-guides/core-blocks.md b/docs/reference-guides/core-blocks.md index b84d8edb8e9d98..5199ce7c7b8cc9 100644 --- a/docs/reference-guides/core-blocks.md +++ b/docs/reference-guides/core-blocks.md @@ -247,7 +247,6 @@ Add an image or video with a text overlay. ([Source](https://github.com/WordPres Hide and show additional content. ([Source](https://github.com/WordPress/gutenberg/tree/trunk/packages/block-library/src/details)) - **Name:** core/details -- **Experimental:** true - **Category:** text - **Supports:** align (full, wide), color (background, gradients, link, text), spacing (margin, padding), typography (fontSize, lineHeight), ~~html~~ - **Attributes:** showContent, summary @@ -331,8 +330,8 @@ Insert an image to make a visual statement. ([Source](https://github.com/WordPre - **Name:** core/image - **Category:** media -- **Supports:** anchor, color (~~background~~, ~~text~~), filter (duotone) -- **Attributes:** align, alt, behaviors, caption, height, href, id, linkClass, linkDestination, linkTarget, rel, sizeSlug, title, url, width +- **Supports:** anchor, behaviors (lightbox), color (~~background~~, ~~text~~), filter (duotone) +- **Attributes:** align, alt, caption, height, href, id, linkClass, linkDestination, linkTarget, rel, sizeSlug, title, url, width ## Latest Comments @@ -567,9 +566,9 @@ Add the date of this post. ([Source](https://github.com/WordPress/gutenberg/tree - **Supports:** anchor, color (background, gradients, link, text), spacing (margin, padding), typography (fontSize, lineHeight), ~~html~~ - **Attributes:** displayType, format, isLink, textAlign -## Post Excerpt +## Excerpt -Display a post's excerpt. ([Source](https://github.com/WordPress/gutenberg/tree/trunk/packages/block-library/src/post-excerpt)) +Display the excerpt. ([Source](https://github.com/WordPress/gutenberg/tree/trunk/packages/block-library/src/post-excerpt)) - **Name:** core/post-excerpt - **Category:** theme @@ -601,7 +600,7 @@ Contains the block elements used to render a post, like the title, date, feature - **Name:** core/post-template - **Category:** theme - **Parent:** core/query -- **Supports:** align (full, wide), anchor, color (background, gradients, link, text), typography (fontSize, lineHeight), ~~html~~, ~~reusable~~ +- **Supports:** align (full, wide), anchor, color (background, gradients, link, text), spacing (blockGap), typography (fontSize, lineHeight), ~~html~~, ~~reusable~~ - **Attributes:** ## Post Terms @@ -623,7 +622,7 @@ Show minutes required to finish reading the post. ([Source](https://github.com/W - **Supports:** color (background, gradients, text), spacing (margin, padding), typography (fontSize, lineHeight), ~~html~~ - **Attributes:** textAlign -## Post Title +## Title Displays the title of a post, page, or any other content-type. ([Source](https://github.com/WordPress/gutenberg/tree/trunk/packages/block-library/src/post-title)) @@ -657,7 +656,7 @@ An advanced block that allows displaying post types based on different query par - **Name:** core/query - **Category:** theme - **Supports:** align (full, wide), anchor, ~~html~~ -- **Attributes:** displayLayout, namespace, query, queryId, tagName +- **Attributes:** namespace, query, queryId, tagName ## No results @@ -677,7 +676,7 @@ Displays a paginated navigation to next/previous set of posts, when applicable. - **Category:** theme - **Parent:** core/query - **Supports:** align, anchor, color (background, gradients, link, text), typography (fontSize, lineHeight), ~~html~~, ~~reusable~~ -- **Attributes:** paginationArrow +- **Attributes:** paginationArrow, showLabel ## Next Page @@ -752,7 +751,7 @@ Help visitors find your content. ([Source](https://github.com/WordPress/gutenber - **Name:** core/search - **Category:** widgets - **Supports:** align (center, left, right), anchor, color (background, gradients, text), typography (fontSize, lineHeight), ~~html~~ -- **Attributes:** buttonPosition, buttonText, buttonUseIcon, label, placeholder, query, showLabel, width, widthUnit +- **Attributes:** buttonBehavior, buttonPosition, buttonText, buttonUseIcon, isSearchFieldHidden, label, placeholder, query, showLabel, width, widthUnit ## Separator diff --git a/docs/reference-guides/data/data-core-edit-site.md b/docs/reference-guides/data/data-core-edit-site.md index 0dad03bbc8ca2a..523bb8d2bbff5f 100644 --- a/docs/reference-guides/data/data-core-edit-site.md +++ b/docs/reference-guides/data/data-core-edit-site.md @@ -131,6 +131,18 @@ _Returns_ - `Object`: Settings. +### hasPageContentLock + +Whether or not the editor is locked so that only page content can be edited. + +_Parameters_ + +- _state_ `Object`: Global application state. + +_Returns_ + +- `boolean`: Whether or not the editor is locked. + ### isFeatureActive > **Deprecated** @@ -174,6 +186,22 @@ _Returns_ > **Deprecated** +### isPage + +Whether or not the editor has a page loaded into it. + +_Related_ + +- setPage + +_Parameters_ + +- _state_ `Object`: Global application state. + +_Returns_ + +- `boolean`: Whether or not the editor has a page loaded into it. + ### isSaveViewOpened Returns the current opened/closed state of the save panel. @@ -252,6 +280,14 @@ _Returns_ - `number`: The resolved template ID for the page route. +### setHasPageContentLock + +Sets whether or not the editor is locked so that only page content can be edited. + +_Parameters_ + +- _hasPageContentLock_ `boolean`: True to enable lock, false to disable. + ### setHomeTemplateId > **Deprecated** diff --git a/docs/reference-guides/data/data-core-notices.md b/docs/reference-guides/data/data-core-notices.md index c5e3bc017a9146..e11e6f226169f9 100644 --- a/docs/reference-guides/data/data-core-notices.md +++ b/docs/reference-guides/data/data-core-notices.md @@ -261,6 +261,53 @@ _Returns_ - `Object`: Action object. +### removeAllNotices + +Removes all notices from a given context. Defaults to the default context. + +_Usage_ + +```js +import { __ } from '@wordpress/i18n'; +import { useDispatch, useSelect } from '@wordpress/data'; +import { store as noticesStore } from '@wordpress/notices'; +import { Button } from '@wordpress/components'; + +export const ExampleComponent = () => { + const notices = useSelect( ( select ) => + select( noticesStore ).getNotices() + ); + const { removeNotices } = useDispatch( noticesStore ); + return ( + <> + + + + + ); +}; +``` + +_Parameters_ + +- _noticeType_ `string`: The context to remove all notices from. +- _context_ `string`: The context to remove all notices from. + +_Returns_ + +- `Object`: Action object. + ### removeNotice Returns an action object used in signalling that a notice is to be removed. @@ -309,4 +356,49 @@ _Returns_ - `Object`: Action object. +### removeNotices + +Returns an action object used in signalling that several notices are to be removed. + +_Usage_ + +```js +import { __ } from '@wordpress/i18n'; +import { useDispatch, useSelect } from '@wordpress/data'; +import { store as noticesStore } from '@wordpress/notices'; +import { Button } from '@wordpress/components'; + +const ExampleComponent = () => { + const notices = useSelect( ( select ) => + select( noticesStore ).getNotices() + ); + const { removeNotices } = useDispatch( noticesStore ); + return ( + <> + + + + ); +}; +``` + +_Parameters_ + +- _ids_ `string[]`: List of unique notice identifiers. +- _context_ `[string]`: Optional context (grouping) in which the notices are intended to appear. Defaults to default context. + +_Returns_ + +- `Object`: Action object. + diff --git a/docs/reference-guides/data/data-core.md b/docs/reference-guides/data/data-core.md index 1ee04e09550e2d..8db3a26dd09772 100644 --- a/docs/reference-guides/data/data-core.md +++ b/docs/reference-guides/data/data-core.md @@ -358,6 +358,8 @@ _Returns_ ### getRedoEdit +> **Deprecated** since 6.3 + Returns the next edit from the current undo offset for the entity records edits history, if any. _Parameters_ @@ -401,6 +403,8 @@ _Returns_ ### getUndoEdit +> **Deprecated** since 6.3 + Returns the previous edit from the current undo offset for the entity records edits history, if any. _Parameters_ diff --git a/docs/toc.json b/docs/toc.json index 7b48e68cbab564..085bbb536ece2b 100644 --- a/docs/toc.json +++ b/docs/toc.json @@ -302,6 +302,7 @@ "docs/explanations/architecture/README.md": [ { "docs/explanations/architecture/key-concepts.md": [] }, { "docs/explanations/architecture/data-flow.md": [] }, + { "docs/explanations/architecture/entities.md": [] }, { "docs/explanations/architecture/modularity.md": [] }, { "docs/explanations/architecture/performance.md": [] }, { @@ -350,7 +351,6 @@ } ] }, - { "docs/contributors/code/grammar.md": [] }, { "docs/contributors/code/scripts.md": [] }, { "docs/contributors/code/managing-packages.md": [] }, { @@ -399,8 +399,7 @@ { "docs/contributors/accessibility-testing.md": [] }, { "docs/contributors/repository-management.md": [] }, { "docs/contributors/folder-structure.md": [] }, - { "docs/contributors/versions-in-wordpress.md": [] }, - { "docs/contributors/roadmap.md": [] } + { "docs/contributors/versions-in-wordpress.md": [] } ] } ] diff --git a/gutenberg.php b/gutenberg.php index 9c9e324756258d..1200a0b24d55c3 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.9.0-rc.1 + * Version: 16.0.0-rc.1 * Author: Gutenberg Team * Text Domain: gutenberg * diff --git a/lib/block-supports/behaviors.php b/lib/block-supports/behaviors.php new file mode 100644 index 00000000000000..55a3419e466fbb --- /dev/null +++ b/lib/block-supports/behaviors.php @@ -0,0 +1,143 @@ +attributes ) { + $block_type->attributes = array(); + } + + $block_type->attributes['behaviors'] = array( + 'type' => 'object', + ); + + // If it supports the lightbox behavior, add the hook to that block. + // In the future, this should be a loop with all the behaviors. + $has_lightbox_support = block_has_support( $block_type, array( 'behaviors', 'lightbox' ), false ); + if ( $has_lightbox_support ) { + // Use priority 15 to run this hook after other hooks/plugins. + // They could use the `render_block_{$this->name}` filter to modify the markup. + add_filter( 'render_block_' . $block_type->name, 'gutenberg_render_behaviors_support_lightbox', 15, 2 ); + } +} + +/** + * Add the directives and layout needed for the lightbox behavior. + * This functions shouldn't be in this file. It should be moved to a package (or somewhere else), where all the behaviors logic is defined. + * + * @param string $block_content Rendered block content. + * @param array $block Block object. + * @return string Filtered block content. + */ +function gutenberg_render_behaviors_support_lightbox( $block_content, $block ) { + $experiments = get_option( 'gutenberg-experiments' ); + $link_destination = isset( $block['attrs']['linkDestination'] ) ? $block['attrs']['linkDestination'] : 'none'; + // Get the lightbox setting from the block attributes. + if ( isset( $block['attrs']['behaviors']['lightbox'] ) ) { + $lightbox = $block['attrs']['behaviors']['lightbox']; + // If the lightbox setting is not set in the block attributes, get it from the theme.json file. + } else { + $theme_data = WP_Theme_JSON_Resolver_Gutenberg::get_merged_data()->get_data(); + if ( isset( $theme_data['behaviors']['blocks'][ $block['blockName'] ]['lightbox'] ) ) { + $lightbox = $theme_data['behaviors']['blocks'][ $block['blockName'] ]['lightbox']; + } else { + $lightbox = false; + } + } + + if ( ! $lightbox || 'none' !== $link_destination || empty( $experiments['gutenberg-interactivity-api-core-blocks'] ) ) { + return $block_content; + } + + $processor = new WP_HTML_Tag_Processor( $block_content ); + + $aria_label = __( 'Enlarge image', 'gutenberg' ); + + $alt_attribute = trim( $processor->get_attribute( 'alt' ) ); + + if ( $alt_attribute ) { + /* translators: %s: Image alt text. */ + $aria_label = sprintf( __( 'Enlarge image: %s', 'gutenberg' ), $alt_attribute ); + } + $content = $processor->get_updated_html(); + + $w = new WP_HTML_Tag_Processor( $content ); + $w->next_tag( 'figure' ); + $w->add_class( 'wp-lightbox-container' ); + $w->set_attribute( 'data-wp-interactive', true ); + $w->set_attribute( 'data-wp-context', '{ "core": { "image": { "initialized": false, "lightboxEnabled": false } } }' ); + $body_content = $w->get_updated_html(); + + // Wrap the image in the body content with a button. + $img = null; + preg_match( '/]+>/', $content, $img ); + $button = '
+ ' + . $img[0] . + '
'; + $body_content = preg_replace( '/]+>/', $button, $body_content ); + + // Add directive to expand modal image if appropriate. + $m = new WP_HTML_Tag_Processor( $content ); + $m->next_tag( 'img' ); + if ( isset( $block['attrs']['id'] ) ) { + $img_src = wp_get_attachment_url( $block['attrs']['id'] ); + } else { + $img_src = $m->get_attribute( 'src' ); + } + $m->set_attribute( 'data-wp-context', '{ "core": { "image": { "imageSrc": "' . $img_src . '"} } }' ); + $m->set_attribute( 'data-wp-bind--src', 'selectors.core.image.imageSrc' ); + $modal_content = $m->get_updated_html(); + + $background_color = esc_attr( wp_get_global_styles( array( 'color', 'background' ) ) ); + + $close_button_icon = ''; + $close_button_color = esc_attr( wp_get_global_styles( array( 'color', 'text' ) ) ); + $dialog_label = $alt_attribute ? esc_attr( $alt_attribute ) : esc_attr__( 'Image', 'gutenberg' ); + $close_button_label = esc_attr__( 'Close', 'gutenberg' ); + + $lightbox_html = << + + $modal_content +
+ +HTML; + + return str_replace( '', $lightbox_html . '', $body_content ); +} + +// Register the block support. +WP_Block_Supports::get_instance()->register( + 'behaviors', + array( + 'register_attribute' => 'gutenberg_register_behaviors_support', + ) +); diff --git a/lib/block-supports/layout.php b/lib/block-supports/layout.php index 87cc4a6cc5f18f..fb3098d06f7432 100644 --- a/lib/block-supports/layout.php +++ b/lib/block-supports/layout.php @@ -280,12 +280,19 @@ function gutenberg_get_layout_style( $selector, $layout, $has_block_gap_support } } } elseif ( 'grid' === $layout_type ) { - $minimum_column_width = ! empty( $layout['minimumColumnWidth'] ) ? $layout['minimumColumnWidth'] : '12rem'; + if ( ! empty( $layout['columnCount'] ) ) { + $layout_styles[] = array( + 'selector' => $selector, + 'declarations' => array( 'grid-template-columns' => 'repeat(' . $layout['columnCount'] . ', minmax(0, 1fr))' ), + ); + } else { + $minimum_column_width = ! empty( $layout['minimumColumnWidth'] ) ? $layout['minimumColumnWidth'] : '12rem'; - $layout_styles[] = array( - 'selector' => $selector, - 'declarations' => array( 'grid-template-columns' => 'repeat(auto-fill, minmax(min(' . $minimum_column_width . ', 100%), 1fr))' ), - ); + $layout_styles[] = array( + 'selector' => $selector, + 'declarations' => array( 'grid-template-columns' => 'repeat(auto-fill, minmax(min(' . $minimum_column_width . ', 100%), 1fr))' ), + ); + } if ( $has_block_gap_support && isset( $gap_value ) ) { $combined_gap_value = ''; @@ -590,7 +597,7 @@ function gutenberg_restore_group_inner_container( $block_content, $block ) { ); $updated_content = preg_replace_callback( $replace_regex, - function( $matches ) { + static function( $matches ) { return $matches[1] . '
' . $matches[2] . '
' . $matches[3]; }, $block_content diff --git a/lib/blocks.php b/lib/blocks.php index bbee108b71c5f5..fdbc555a2f9443 100644 --- a/lib/blocks.php +++ b/lib/blocks.php @@ -77,6 +77,7 @@ function gutenberg_reregister_core_block_types() { 'navigation-link.php' => 'core/navigation-link', 'navigation-submenu.php' => 'core/navigation-submenu', 'page-list.php' => 'core/page-list', + 'page-list-item.php' => 'core/page-list-item', 'pattern.php' => 'core/pattern', 'post-author.php' => 'core/post-author', 'post-author-name.php' => 'core/post-author-name', @@ -239,7 +240,7 @@ function gutenberg_register_core_block_assets( $block_name ) { if ( ! $stylesheet_removed ) { add_action( 'wp_enqueue_scripts', - function() { + static function() { wp_dequeue_style( 'wp-block-library-theme' ); } ); diff --git a/lib/class-wp-theme-json-gutenberg.php b/lib/class-wp-theme-json-gutenberg.php index c27572e735ee1e..5cb11c2d7aaf94 100644 --- a/lib/class-wp-theme-json-gutenberg.php +++ b/lib/class-wp-theme-json-gutenberg.php @@ -1073,11 +1073,13 @@ public function get_stylesheet( $types = array( 'variables', 'styles', 'presets' } $stylesheet .= $this->get_block_classes( $style_nodes ); } elseif ( in_array( 'base-layout-styles', $types, true ) ) { - $root_selector = static::ROOT_BLOCK_SELECTOR; - $columns_selector = '.wp-block-columns'; + $root_selector = static::ROOT_BLOCK_SELECTOR; + $columns_selector = '.wp-block-columns'; + $post_template_selector = '.wp-block-post-template'; if ( ! empty( $options['scope'] ) ) { - $root_selector = static::scope_selector( $options['scope'], $root_selector ); - $columns_selector = static::scope_selector( $options['scope'], $columns_selector ); + $root_selector = static::scope_selector( $options['scope'], $root_selector ); + $columns_selector = static::scope_selector( $options['scope'], $columns_selector ); + $post_template_selector = static::scope_selector( $options['scope'], $post_template_selector ); } if ( ! empty( $options['root_selector'] ) ) { $root_selector = $options['root_selector']; @@ -1094,6 +1096,11 @@ public function get_stylesheet( $types = array( 'variables', 'styles', 'presets' 'selector' => $columns_selector, 'name' => 'core/columns', ), + array( + 'path' => array( 'styles', 'blocks', 'core/post-template' ), + 'selector' => $post_template_selector, + 'name' => 'core/post-template', + ), ); foreach ( $base_styles_nodes as $base_style_node ) { @@ -1298,7 +1305,7 @@ protected function get_layout_styles( $block_metadata ) { if ( null !== $block_gap_value && false !== $block_gap_value && '' !== $block_gap_value ) { foreach ( $layout_definitions as $layout_definition_key => $layout_definition ) { // Allow outputting fallback gap styles for flex layout type when block gap support isn't available. - if ( ! $has_block_gap_support && 'flex' !== $layout_definition_key ) { + if ( ! $has_block_gap_support && 'flex' !== $layout_definition_key && 'grid' !== $layout_definition_key ) { continue; } @@ -2365,7 +2372,7 @@ static function( $split_selector ) use ( $clean_style_variation_selector ) { $pseudo_matches = array_values( array_filter( $element_pseudo_allowed, - function( $pseudo_selector ) use ( $selector ) { + static function( $pseudo_selector ) use ( $selector ) { return str_contains( $selector, $pseudo_selector ); } ) diff --git a/lib/class-wp-theme-json-resolver-gutenberg.php b/lib/class-wp-theme-json-resolver-gutenberg.php index 2c61de7c5e24c2..33fd4defd51917 100644 --- a/lib/class-wp-theme-json-resolver-gutenberg.php +++ b/lib/class-wp-theme-json-resolver-gutenberg.php @@ -275,7 +275,7 @@ public static function get_theme_data( $deprecated = array(), $options = array() } // BEGIN OF EXPERIMENTAL CODE. Not to backport to core. - static::$theme = gutenberg_add_registered_fonts_to_theme_json( static::$theme ); + static::$theme = WP_Fonts_Resolver::add_missing_fonts_to_theme_json( static::$theme ); // END OF EXPERIMENTAL CODE. } diff --git a/lib/compat/wordpress-6.2/script-loader.php b/lib/compat/wordpress-6.2/script-loader.php index 6ed69244726d33..37c1ced3c8cfcd 100644 --- a/lib/compat/wordpress-6.2/script-loader.php +++ b/lib/compat/wordpress-6.2/script-loader.php @@ -64,89 +64,10 @@ static function () use ( $style ) { ); } -/** - * Sets the content assets for the block editor. - * - * Note for core merge: see inline comment on what's been updated. - */ -function gutenberg_resolve_assets_override() { - global $pagenow; - - $script_handles = array( - 'wp-polyfill', - ); - // Note for core merge: only 'wp-edit-blocks' should be in this array. - $style_handles = array( - 'wp-edit-blocks', - ); - - if ( current_theme_supports( 'wp-block-styles' ) ) { - $style_handles[] = 'wp-block-library-theme'; - } - - if ( 'widgets.php' === $pagenow || 'customize.php' === $pagenow ) { - $style_handles[] = 'wp-widgets'; - $style_handles[] = 'wp-edit-widgets'; - } - - $block_registry = WP_Block_Type_Registry::get_instance(); - - foreach ( $block_registry->get_all_registered() as $block_type ) { - // In older WordPress versions, like 6.0, these properties are not defined. - if ( isset( $block_type->style_handles ) && is_array( $block_type->style_handles ) ) { - $style_handles = array_merge( $style_handles, $block_type->style_handles ); - } - - if ( isset( $block_type->editor_style_handles ) && is_array( $block_type->editor_style_handles ) ) { - $style_handles = array_merge( $style_handles, $block_type->editor_style_handles ); - } - - if ( isset( $block_type->script_handles ) && is_array( $block_type->script_handles ) ) { - $script_handles = array_merge( $script_handles, $block_type->script_handles ); - } - } - - $style_handles = array_unique( $style_handles ); - $done = wp_styles()->done; - - ob_start(); - - // We do not need reset styles for the iframed editor. - wp_styles()->done = array( 'wp-reset-editor-styles' ); - wp_styles()->do_items( $style_handles ); - wp_styles()->done = $done; - - $styles = ob_get_clean(); - - $script_handles = array_unique( $script_handles ); - $done = wp_scripts()->done; - - ob_start(); - - wp_scripts()->done = array(); - wp_scripts()->do_items( $script_handles ); - wp_scripts()->done = $done; - - $scripts = ob_get_clean(); - - // Generate font @font-face styles. - if ( function_exists( 'wp_print_fonts' ) ) { - ob_start(); - wp_print_fonts( true ); - $styles .= ob_get_clean(); - } - - return array( - 'styles' => $styles, - 'scripts' => $scripts, - ); -} - add_filter( 'block_editor_settings_all', - function( $settings ) { + static function( $settings ) { // We must override what core is passing now. - $settings['__unstableResolvedAssets'] = gutenberg_resolve_assets_override(); $settings['__unstableIsBlockBasedTheme'] = wp_is_block_theme(); return $settings; }, diff --git a/lib/compat/wordpress-6.3/script-loader.php b/lib/compat/wordpress-6.3/script-loader.php index 8b00e10d09b660..c515eb10fdc6bb 100644 --- a/lib/compat/wordpress-6.3/script-loader.php +++ b/lib/compat/wordpress-6.3/script-loader.php @@ -27,7 +27,7 @@ * } */ function _gutenberg_get_iframed_editor_assets() { - global $wp_styles, $wp_scripts; + global $wp_styles, $wp_scripts, $pagenow; // Keep track of the styles and scripts instance to restore later. $current_wp_styles = $wp_styles; @@ -42,18 +42,43 @@ function _gutenberg_get_iframed_editor_assets() { $wp_styles->registered = $current_wp_styles->registered; $wp_scripts->registered = $current_wp_scripts->registered; - wp_enqueue_style( 'wp-block-editor-content' ); - // To do: investigate why this is not enqueued through enqueue_block_assets, - // as styles for non-core blocks are. - wp_enqueue_style( 'wp-block-library' ); + // We generally do not need reset styles for the iframed editor. + // However, if it's a classic theme, margins will be added to every block, + // which is reset specifically for list items, so classic themes rely on + // these reset styles. + $wp_styles->done = + wp_theme_has_theme_json() ? array( 'wp-reset-editor-styles' ) : array(); + wp_enqueue_script( 'wp-polyfill' ); + // Enqueue the `editorStyle` handles for all core block, and dependencies. + wp_enqueue_style( 'wp-edit-blocks' ); + + if ( 'site-editor.php' === $pagenow ) { + wp_enqueue_style( 'wp-edit-site' ); + } + + if ( current_theme_supports( 'wp-block-styles' ) ) { + wp_enqueue_style( 'wp-block-library-theme' ); + } - // We don't want to load EDITOR scripts and styles in the iframe, only - // assets for the content. + // We don't want to load EDITOR scripts in the iframe, only enqueue + // front-end assets for the content. add_filter( 'should_load_block_editor_scripts_and_styles', '__return_false' ); do_action( 'enqueue_block_assets' ); remove_filter( 'should_load_block_editor_scripts_and_styles', '__return_false' ); + $block_registry = WP_Block_Type_Registry::get_instance(); + + // Additionally, do enqueue `editorStyle` assets for all blocks, which + // contains editor-only styling for blocks (editor content). + foreach ( $block_registry->get_all_registered() as $block_type ) { + if ( isset( $block_type->editor_style_handles ) && is_array( $block_type->editor_style_handles ) ) { + foreach ( $block_type->editor_style_handles as $style_handle ) { + wp_enqueue_style( $style_handle ); + } + } + } + ob_start(); wp_print_styles(); wp_print_fonts( true ); @@ -76,10 +101,9 @@ function _gutenberg_get_iframed_editor_assets() { add_filter( 'block_editor_settings_all', - function( $settings ) { + static function( $settings ) { // We must override what core is passing now. $settings['__unstableResolvedAssets'] = _gutenberg_get_iframed_editor_assets(); return $settings; - }, - 100 + } ); diff --git a/lib/compat/wordpress-6.3/theme-previews.php b/lib/compat/wordpress-6.3/theme-previews.php index e73c13daa7cfb5..5a6f282d301bc5 100644 --- a/lib/compat/wordpress-6.3/theme-previews.php +++ b/lib/compat/wordpress-6.3/theme-previews.php @@ -14,7 +14,7 @@ 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; } $preview_stylesheet = ! empty( $_GET['theme_preview'] ) ? $_GET['theme_preview'] : null; diff --git a/lib/experimental/editor-settings.php b/lib/experimental/editor-settings.php index 96cd4e48440394..f0b16eeb7f257a 100644 --- a/lib/experimental/editor-settings.php +++ b/lib/experimental/editor-settings.php @@ -86,15 +86,12 @@ function gutenberg_enable_experiments() { if ( $gutenberg_experiments && array_key_exists( 'gutenberg-group-grid-variation', $gutenberg_experiments ) ) { wp_add_inline_script( 'wp-block-editor', 'window.__experimentalEnableGroupGridVariation = true', 'before' ); } - if ( $gutenberg_experiments && array_key_exists( 'gutenberg-details-blocks', $gutenberg_experiments ) ) { - wp_add_inline_script( 'wp-block-editor', 'window.__experimentalEnableDetailsBlocks = true', 'before' ); - } - if ( $gutenberg_experiments && array_key_exists( 'gutenberg-theme-previews', $gutenberg_experiments ) ) { - wp_add_inline_script( 'wp-block-editor', 'window.__experimentalEnableThemePreviews = true', 'before' ); - } if ( $gutenberg_experiments && array_key_exists( 'gutenberg-pattern-enhancements', $gutenberg_experiments ) ) { wp_add_inline_script( 'wp-block-editor', 'window.__experimentalEnablePatternEnhancements = true', 'before' ); } + if ( $gutenberg_experiments && array_key_exists( 'gutenberg-interactivity-api-core-blocks', $gutenberg_experiments ) ) { + wp_add_inline_script( 'wp-block-editor', 'window.__experimentalInteractivityAPI = true', 'before' ); + } } diff --git a/lib/experimental/fonts-api/class-wp-fonts-provider-local.php b/lib/experimental/fonts-api/class-wp-fonts-provider-local.php index a5dbdb707e41ff..019861a9ae191f 100644 --- a/lib/experimental/fonts-api/class-wp-fonts-provider-local.php +++ b/lib/experimental/fonts-api/class-wp-fonts-provider-local.php @@ -207,11 +207,6 @@ private function compile_src( array $value ) { $src = ''; foreach ( $value as $item ) { - - if ( str_starts_with( $item['url'], get_site_url() ) ) { - $item['url'] = wp_make_link_relative( $item['url'] ); - } - $src .= ( 'data' === $item['format'] ) ? ", url({$item['url']})" : ", url('{$item['url']}') format('{$item['format']}')"; diff --git a/lib/experimental/fonts-api/class-wp-fonts-resolver.php b/lib/experimental/fonts-api/class-wp-fonts-resolver.php index d3d0ecba992b88..144f7b30acc153 100644 --- a/lib/experimental/fonts-api/class-wp-fonts-resolver.php +++ b/lib/experimental/fonts-api/class-wp-fonts-resolver.php @@ -106,4 +106,293 @@ private static function get_value_from_style( $style, $preset_type = 'font-famil $length = strpos( $style, $ending_pattern ) - $offset; return substr( $style, $offset, $length ); } + + /** + * Register fonts defined in theme.json. + * + * @since X.X.X + */ + public static function register_fonts_from_theme_json() { + + $settings = static::get_settings(); + // Bail out early if there are no settings for fonts. + if ( empty( $settings['typography'] ) || empty( $settings['typography']['fontFamilies'] ) ) { + return; + } + + list( $fonts, $handles ) = static::parse_font_families( $settings ); + + wp_register_fonts( $fonts ); + wp_enqueue_fonts( $handles ); + } + + /** + * Add missing fonts to the global styles. + * + * @since X.X.X + * + * @param WP_Theme_JSON_Gutenberg|WP_Theme_JSON $data The global styles. + * @return WP_Theme_JSON_Gutenberg|WP_Theme_JSON The global styles with missing fonts. + */ + public static function add_missing_fonts_to_theme_json( $data ) { + $font_families_registered = wp_fonts()->get_registered_font_families(); + + $raw_data = $data->get_raw_data(); + + $font_families_from_theme = ! empty( $raw_data['settings']['typography']['fontFamilies']['theme'] ) + ? $raw_data['settings']['typography']['fontFamilies']['theme'] + : array(); + + // Find missing fonts that are not in the theme's theme.json. + $to_add = array(); + if ( ! empty( $font_families_registered ) ) { + $to_add = array_diff( $font_families_registered, static::get_font_families( $font_families_from_theme ) ); + } + + // Bail out early if there are no missing fonts. + if ( empty( $to_add ) ) { + return $data; + } + + /* + * Make sure the path to settings.typography.fontFamilies.theme exists + * before adding missing fonts. + */ + if ( empty( $raw_data['settings'] ) ) { + $raw_data['settings'] = array(); + } + $raw_data['settings'] = static::set_tyopgraphy_settings_array_structure( $raw_data['settings'] ); + + foreach ( $to_add as $font_family_handle ) { + $raw_data['settings']['typography']['fontFamilies']['theme'][] = wp_fonts()->to_theme_json( $font_family_handle ); + } + + return new WP_Theme_JSON_Gutenberg( $raw_data ); + } + + /** + * Returns theme's settings and adds fonts defined in variations. + * + * @since X.X.X + * + * @return array An array containing theme's settings. + */ + private static function get_settings() { + // Get settings. + $settings = WP_Theme_JSON_Resolver_Gutenberg::get_merged_data()->get_settings(); + + if ( ! is_admin() && ! ( defined( 'REST_REQUEST' ) && REST_REQUEST ) ) { + return $settings; + } + + // If in the editor, add fonts defined in variations. + $variations = WP_Theme_JSON_Resolver_Gutenberg::get_style_variations(); + $set_theme_structure = true; + + foreach ( $variations as $variation ) { + + // Skip if settings.typography.fontFamilies are not defined in the variation. + if ( empty( $variation['settings']['typography']['fontFamilies'] ) ) { + continue; + } + + // One time, set any missing parts of the array structure. + if ( $set_theme_structure ) { + $set_theme_structure = false; + $settings = static::set_tyopgraphy_settings_array_structure( $settings ); + } + + // Merge the variation settings with the global settings. + $settings['typography']['fontFamilies']['theme'] = array_merge( + $settings['typography']['fontFamilies']['theme'], + $variation['settings']['typography']['fontFamilies']['theme'] + ); + + // Make sure there are no duplicates. + $settings['typography']['fontFamilies'] = array_unique( $settings['typography']['fontFamilies'] ); + } + + return $settings; + } + + /** + * Converts a list of font families into font handles and returns them as an array. + * + * @since X.X.X + * + * @param array $families_data An array of font families data. + * @return array An array containing font handles. + */ + private static function get_font_families( $families_data ) { + $families = array(); + foreach ( $families_data as $family ) { + $font_family = WP_Fonts_Utils::get_font_family_from_variation( $family ); + $handle = WP_Fonts_Utils::convert_font_family_into_handle( $font_family ); + if ( ! empty( $handle ) ) { + $families[ $handle ] = true; + } + } + + return ! empty( $families ) ? array_keys( $families ) : array(); + } + + /** + * Parse font families from theme.json. + * + * @since X.X.X + * + * @param array $settings Font settings to parse. + * @return array Returns an array that contains font data and corresponding handles. + */ + private static function parse_font_families( array $settings ) { + $handles = array(); + $fonts = array(); + + // Look for fontFamilies. + foreach ( $settings['typography']['fontFamilies'] as $font_families ) { + foreach ( $font_families as $font_family ) { + + // Skip if fontFace is not defined. + if ( empty( $font_family['fontFace'] ) ) { + continue; + } + + $font_family['fontFace'] = (array) $font_family['fontFace']; + $font_family_slug = isset( $font_family['slug'] ) ? $font_family['slug'] : ''; + + foreach ( $font_family['fontFace'] as $font_face ) { + // Skip if the font was registered through the Fonts API. + if ( isset( $font_face['origin'] ) && WP_Fonts::REGISTERED_ORIGIN === $font_face['origin'] ) { + continue; + } + + // For each font "src", convert the "file:./" placeholder into a theme font file URI. + if ( ! empty( $font_face['src'] ) ) { + $font_face['src'] = static::to_theme_file_uri( (array) $font_face['src'] ); + } + + // Convert font-face properties into kebab-case. + $font_face = static::to_kebab_case( $font_face ); + + // Convert font-face properties into kebab-case. + $font_face = static::to_kebab_case( $font_face ); + + $font_family_handle = static::get_font_family_handle( $font_family_slug, $font_face ); + + // Skip if no font-family handle was found. + if ( null === $font_family_handle ) { + continue; + } + + $handles[] = $font_family_handle; + if ( ! array_key_exists( $font_family_handle, $fonts ) ) { + $fonts[ $font_family_handle ] = array(); + } + + $fonts[ $font_family_handle ][] = $font_face; + } + } + } + + return array( $fonts, $handles ); + } + + /** + * Sets the typography.fontFamilies.theme structure in the given array, if not already set. + * if not already set. + * + * @since X.X.X + * + * @param array $data The target array to process. + * @return array Data array with typography.fontFamilies.theme structure set. + */ + private static function set_tyopgraphy_settings_array_structure( array $data ) { + if ( empty( $data['typography'] ) ) { + $data['typography'] = array(); + } + if ( empty( $data['typography']['fontFamilies'] ) ) { + $data['typography']['fontFamilies'] = array(); + } + if ( empty( $data['typography']['fontFamilies']['theme'] ) ) { + $data['typography']['fontFamilies']['theme'] = array(); + } + + return $data; + } + + /** + * Converts each 'file:./' placeholder into a URI to the font file in the theme. + * + * The 'file:./' is specified in the theme's `theme.json` as a placeholder to be + * replaced with the URI to the font file's location in the theme. When a "src" + * beings with this placeholder, it is replaced, converting the src into a URI. + * + * @since X.X.X + * + * @param array $src An array of font file sources to process. + * @return array An array of font file src URI(s). + */ + private static function to_theme_file_uri( array $src ) { + $placeholder = 'file:./'; + + foreach ( $src as $src_key => $src_url ) { + // Skip if the src doesn't start with the placeholder, as there's nothing to replace. + if ( ! str_starts_with( $src_url, $placeholder ) ) { + continue; + } + + $src_file = str_replace( $placeholder, '', $src_url ); + $src[ $src_key ] = get_theme_file_uri( $src_file ); + } + + return $src; + } + + /** + * Converts all first dimension keys into kebab-case. + * + * @since X.X.X + * + * @param array $data The array to process. + */ + private static function to_kebab_case( array $data ) { + foreach ( $data as $key => $value ) { + $kebab_case = _wp_to_kebab_case( $key ); + $data[ $kebab_case ] = $value; + if ( $kebab_case !== $key ) { + unset( $data[ $key ] ); + } + } + + return $data; + } + + /** + * Gets the font-family handle if defined in the "slug" or font-face variation. + * + * @since X.X.X + * + * @param string $font_family_slug Font-family "slug". + * @param array $font_face Font-face (variation) to search. + * @return string|null Font-family handle on success, else null if not found. + */ + private static function get_font_family_handle( $font_family_slug, array $font_face ) { + $font_family_handle = WP_Fonts_Utils::get_font_family_from_variation( $font_face ); + + // Use the defined slug if no handle found. + if ( empty( $font_family_handle ) ) { + $font_family_handle = $font_family_slug; + } + + if ( ! empty( $font_family_handle ) ) { + $font_family_handle = WP_Fonts_Utils::convert_font_family_into_handle( $font_family_handle ); + } + + if ( empty( $font_family_handle ) ) { + _doing_it_wrong( __FUNCTION__, __( 'Font family not defined in the variation or "slug".', 'gutenberg' ), '6.1.0' ); + return null; + } + + return $font_family_handle; + } } diff --git a/lib/experimental/fonts-api/class-wp-fonts.php b/lib/experimental/fonts-api/class-wp-fonts.php index cbabd3d85d36d7..5ce85bab315094 100644 --- a/lib/experimental/fonts-api/class-wp-fonts.php +++ b/lib/experimental/fonts-api/class-wp-fonts.php @@ -18,6 +18,15 @@ */ class WP_Fonts extends WP_Dependencies { + /** + * Registered "origin", indicating the font is registered in the API. + * + * @since X.X.X + * + * @var string + */ + const REGISTERED_ORIGIN = 'gutenberg_wp_fonts_api'; + /** * An array of registered providers. * @@ -731,7 +740,7 @@ public function to_theme_json( $font_family_handle ) { } $variation_obj = $this->registered[ $variation_handle ]; - $variation_properties = array( 'origin' => 'gutenberg_wp_fonts_api' ); + $variation_properties = array( 'origin' => static::REGISTERED_ORIGIN ); foreach ( $variation_obj->extra['font-properties'] as $property_name => $property_value ) { $property_in_camelcase = lcfirst( str_replace( '-', '', ucwords( $property_name, '-' ) ) ); $variation_properties[ $property_in_camelcase ] = $property_value; diff --git a/lib/experimental/fonts-api/fonts-api.php b/lib/experimental/fonts-api/fonts-api.php index 7075f20f76a217..841efeda47a953 100644 --- a/lib/experimental/fonts-api/fonts-api.php +++ b/lib/experimental/fonts-api/fonts-api.php @@ -230,7 +230,7 @@ function wp_print_fonts( $handles = false ) { */ add_filter( 'mime_types', - function( $mime_types ) { + static function( $mime_types ) { // Webfonts formats. $mime_types['woff2'] = 'font/woff2'; $mime_types['woff'] = 'font/woff'; @@ -241,3 +241,12 @@ function( $mime_types ) { return $mime_types; } ); + +/* + * To make sure blocks are registered before any Theme_JSON operations take place, a priority of 21 is used. + * + * Why 21? + * Blocks are registered via the "init" hook with a priority value of `20`, which is dynamically added + * during the build. See: tools/webpack/blocks.js. + */ +add_action( 'init', 'WP_Fonts_Resolver::register_fonts_from_theme_json', 21 ); diff --git a/lib/experimental/fonts-api/register-fonts-from-theme-json.php b/lib/experimental/fonts-api/register-fonts-from-theme-json.php deleted file mode 100644 index 5831217b3cd88f..00000000000000 --- a/lib/experimental/fonts-api/register-fonts-from-theme-json.php +++ /dev/null @@ -1,189 +0,0 @@ -get_settings(); - - // If in the editor, add webfonts defined in variations. - if ( is_admin() || ( defined( 'REST_REQUEST' ) && REST_REQUEST ) ) { - $variations = WP_Theme_JSON_Resolver_Gutenberg::get_style_variations(); - - foreach ( $variations as $variation ) { - - // Sanity check: Skip if fontFamilies are not defined in the variation. - if ( - empty( $variation['settings'] ) || - empty( $variation['settings']['typography'] ) || - empty( $variation['settings']['typography']['fontFamilies'] ) - ) { - continue; - } - - // Merge the variation settings with the global settings. - $settings['typography'] = empty( $settings['typography'] ) ? array() : $settings['typography']; - $settings['typography']['fontFamilies'] = empty( $settings['typography']['fontFamilies'] ) ? array() : $settings['typography']['fontFamilies']; - $settings['typography']['fontFamilies']['theme'] = empty( $settings['typography']['fontFamilies'] ) ? array() : $settings['typography']['fontFamilies']['theme']; - $settings['typography']['fontFamilies']['theme'] = array_merge( $settings['typography']['fontFamilies']['theme'], $variation['settings']['typography']['fontFamilies']['theme'] ); - - // Make sure there are no duplicates. - $settings['typography']['fontFamilies'] = array_unique( $settings['typography']['fontFamilies'] ); - } - } - - // Bail out early if there are no settings for webfonts. - if ( empty( $settings['typography'] ) || empty( $settings['typography']['fontFamilies'] ) ) { - return; - } - - $fonts = array(); - $handles = array(); - - // Look for fontFamilies. - foreach ( $settings['typography']['fontFamilies'] as $font_families ) { - foreach ( $font_families as $font_family ) { - - // Skip if fontFace is not defined. - if ( empty( $font_family['fontFace'] ) ) { - continue; - } - - $font_family['fontFace'] = (array) $font_family['fontFace']; - - foreach ( $font_family['fontFace'] as $font_face ) { - // Skip if the font was registered through the Fonts API. - if ( isset( $font_face['origin'] ) && 'gutenberg_wp_fonts_api' === $font_face['origin'] ) { - continue; - } - - // Check if webfonts have a "src" param, and if they do account for the use of "file:./". - if ( ! empty( $font_face['src'] ) ) { - $font_face['src'] = (array) $font_face['src']; - - foreach ( $font_face['src'] as $src_key => $url ) { - // Tweak the URL to be relative to the theme root. - if ( ! str_starts_with( $url, 'file:./' ) ) { - continue; - } - $font_face['src'][ $src_key ] = get_theme_file_uri( str_replace( 'file:./', '', $url ) ); - } - } - - // Convert keys to kebab-case. - foreach ( $font_face as $property => $value ) { - $kebab_case = _wp_to_kebab_case( $property ); - $font_face[ $kebab_case ] = $value; - if ( $kebab_case !== $property ) { - unset( $font_face[ $property ] ); - } - } - - $font_family_handle = WP_Fonts_Utils::get_font_family_from_variation( $font_face ); - if ( empty( $font_family_handle ) && isset( $font_family['slug'] ) ) { - $font_family_handle = $font_family['slug']; - } - if ( ! empty( $font_family_handle ) ) { - $font_family_handle = WP_Fonts_Utils::convert_font_family_into_handle( $font_family_handle ); - } - if ( empty( $font_family_handle ) ) { - _doing_it_wrong( __FUNCTION__, __( 'Font family not defined in the variation or "slug".', 'gutenberg' ), '6.1.0' ); - } - - $handles[] = $font_family_handle; - if ( ! array_key_exists( $font_family_handle, $fonts ) ) { - $fonts[ $font_family_handle ] = array(); - } - - $fonts[ $font_family_handle ][] = $font_face; - } - } - } - - wp_register_fonts( $fonts ); - wp_enqueue_fonts( $handles ); - } -} - -if ( ! function_exists( 'gutenberg_add_registered_fonts_to_theme_json' ) ) { - /** - * Add missing fonts data to the global styles. - * - * @param array $data The global styles. - * @return array The global styles with missing fonts data. - */ - function gutenberg_add_registered_fonts_to_theme_json( $data ) { - $font_families_registered = wp_fonts()->get_registered_font_families(); - - $raw_data = $data->get_raw_data(); - - $font_families_from_theme = ! empty( $raw_data['settings']['typography']['fontFamilies']['theme'] ) - ? $raw_data['settings']['typography']['fontFamilies']['theme'] - : array(); - - /** - * Helper to get an array of the font-families. - * - * @param array $families_data The font-families data. - * @return array The font-families array. - */ - $get_families = static function ( $families_data ) { - $families = array(); - foreach ( $families_data as $family ) { - $font_family = WP_Fonts_Utils::get_font_family_from_variation( $family ); - $handle = WP_Fonts_Utils::convert_font_family_into_handle( $font_family ); - if ( ! empty( $handle ) ) { - $families[ $handle ] = true; - } - } - - return ! empty( $families ) ? array_keys( $families ) : array(); - }; - - // Find missing fonts that are not in the theme's theme.json. - $to_add = array(); - if ( ! empty( $font_families_registered ) ) { - $to_add = array_diff( $font_families_registered, $get_families( $font_families_from_theme ) ); - } - - // Bail out early if there are no missing fonts. - if ( empty( $to_add ) ) { - return $data; - } - - // Make sure the path to settings.typography.fontFamilies.theme exists - // before adding missing fonts. - if ( empty( $raw_data['settings'] ) ) { - $raw_data['settings'] = array(); - } - if ( empty( $raw_data['settings']['typography'] ) ) { - $raw_data['settings']['typography'] = array(); - } - if ( empty( $raw_data['settings']['typography']['fontFamilies'] ) ) { - $raw_data['settings']['typography']['fontFamilies'] = array(); - } - if ( empty( $raw_data['settings']['typography']['fontFamilies'] ) ) { - $raw_data['settings']['typography']['fontFamilies']['theme'] = array(); - } - - foreach ( $to_add as $font_family_handle ) { - $raw_data['settings']['typography']['fontFamilies']['theme'][] = wp_fonts()->to_theme_json( $font_family_handle ); - } - - return new WP_Theme_JSON_Gutenberg( $raw_data ); - } -} - -// `gutenberg_register_fonts_from_theme_json()` calls `WP_Theme_JSON_Resolver_Gutenberg::get_merged_data()`, which instantiates `WP_Theme_JSON_Gutenberg()`; -// Gutenberg server-side blocks are registered via the init hook with a priority value of `20`. E.g., `add_action( 'init', 'register_block_core_image', 20 )`; -// This priority value is added dynamically during the build. See: tools/webpack/blocks.js. -// We want to make sure Gutenberg blocks are re-registered before any Theme_JSON operations take place -// so that we have access to updated merged data. -add_action( 'init', 'gutenberg_register_fonts_from_theme_json', 21 ); diff --git a/lib/experimental/interactivity-api/blocks.php b/lib/experimental/interactivity-api/blocks.php index 3ad6d13d660fb1..0087f95cbf1449 100644 --- a/lib/experimental/interactivity-api/blocks.php +++ b/lib/experimental/interactivity-api/blocks.php @@ -1,222 +1,12 @@ attributes['displayPreview'] ) ) { - return $block_content; - } - $processor = new WP_HTML_Tag_Processor( $block_content ); - $processor->next_tag(); - $processor->set_attribute( 'data-wp-island', '' ); - $processor->next_tag( 'object' ); - $processor->set_attribute( 'data-wp-bind.hidden', '!selectors.core.file.hasPdfPreview' ); - $processor->set_attribute( 'hidden', true ); - return $processor->get_updated_html(); -} -add_filter( 'render_block_core/file', 'gutenberg_block_core_file_add_directives_to_content', 10, 3 ); - -/** - * Add Interactivity API directives to the navigation block markup using the Tag Processor - * The final HTML of the navigation block will look similar to this: - * - * - * - * @param string $block_content Markup of the navigation block. - * - * @return string Navigation block markup with the proper directives - */ -function gutenberg_block_core_navigation_add_directives_to_markup( $block_content ) { - $w = new WP_HTML_Tag_Processor( $block_content ); - // Add directives to the `