diff --git a/changelog.txt b/changelog.txt
index 2356249f0b9f5e..92fa2690b15d68 100644
--- a/changelog.txt
+++ b/changelog.txt
@@ -1,5 +1,316 @@
== Changelog ==
+= 17.2.0-rc.1 =
+
+
+
+## Changelog
+
+### Features
+
+#### Modules API
+- Interactivity API: Use modules instead of scripts in the frontend. ([56143](https://github.com/WordPress/gutenberg/pull/56143))
+
+
+### Enhancements
+
+- Add translator comments for strings containing date formats. ([56531](https://github.com/WordPress/gutenberg/pull/56531))
+- Block Settings: Only display parent block selector on small screens. ([56431](https://github.com/WordPress/gutenberg/pull/56431))
+- Block Theme Preview: Display the theme name on the activate button. ([55752](https://github.com/WordPress/gutenberg/pull/55752))
+- Core data revisions: Extend support to other post types. ([56353](https://github.com/WordPress/gutenberg/pull/56353))
+- Improve tooltip for parent blocks on the block toolbar. ([56146](https://github.com/WordPress/gutenberg/pull/56146))
+- Simplify template author token. ([56566](https://github.com/WordPress/gutenberg/pull/56566))
+- Style engine: Allow CSS var output for fontSize and fontFamily and update documentation. ([56528](https://github.com/WordPress/gutenberg/pull/56528))
+- Try: Change "Detach pattern" to "Detach". ([56323](https://github.com/WordPress/gutenberg/pull/56323))
+- useEntityRecord: Improve unit tests. ([56415](https://github.com/WordPress/gutenberg/pull/56415))
+
+#### Components
+- Add focus rings to focusable disabled buttons. ([56383](https://github.com/WordPress/gutenberg/pull/56383))
+- DropdownMenu V2 tweaks. ([56041](https://github.com/WordPress/gutenberg/pull/56041))
+- DropdownMenu V2: Add support for rendering in legacy popover slot. ([56342](https://github.com/WordPress/gutenberg/pull/56342))
+- FormToggle: Refine animation. ([56515](https://github.com/WordPress/gutenberg/pull/56515))
+- Slot: Add styles prop to bubblesVirtually version. ([56428](https://github.com/WordPress/gutenberg/pull/56428))
+- Tabs: Cleanup and improvements. ([56224](https://github.com/WordPress/gutenberg/pull/56224))
+- Try Ariakit Select for new CustomSelectControl component. ([55790](https://github.com/WordPress/gutenberg/pull/55790))
+
+#### Data Views
+- Data list view: Make filter row, table header, and pagination sticky. ([56157](https://github.com/WordPress/gutenberg/pull/56157))
+- Simplify dataviews view button. ([56485](https://github.com/WordPress/gutenberg/pull/56485))
+- Update data view menu item actions. ([56398](https://github.com/WordPress/gutenberg/pull/56398))
+
+#### Global Styles
+- Global style revisions: Redesign style revision items. ([55913](https://github.com/WordPress/gutenberg/pull/55913))
+- Global styles revisions: Migrate API call to getRevisions(). ([56349](https://github.com/WordPress/gutenberg/pull/56349))
+- Style Revisions: Remove style revisions dropdown menu. ([56454](https://github.com/WordPress/gutenberg/pull/56454))
+
+#### Site Editor
+- Add 'View site' action to 'Site updated' snackbar. ([52693](https://github.com/WordPress/gutenberg/pull/52693))
+- Add the Post Author component to the Page sidebar. ([56368](https://github.com/WordPress/gutenberg/pull/56368))
+- Redirect to main page menu if page record not found. ([56177](https://github.com/WordPress/gutenberg/pull/56177))
+
+#### Block Editor
+- Drag and drop: Allow dragging to the beginning and end of a document. ([56070](https://github.com/WordPress/gutenberg/pull/56070))
+- List View: Expand state if a block is dragged to within a collapsed block in the editor canvas. ([56493](https://github.com/WordPress/gutenberg/pull/56493))
+
+#### Layout
+- Add layout classes to legacy Group inner container. ([56130](https://github.com/WordPress/gutenberg/pull/56130))
+- Add setting to disable custom content size controls. ([56236](https://github.com/WordPress/gutenberg/pull/56236))
+
+#### Patterns
+- Small tweaks to CreatePatternModal. ([56016](https://github.com/WordPress/gutenberg/pull/56016))
+- Update Labels in Block Inserter (block patterns tab). ([55986](https://github.com/WordPress/gutenberg/pull/55986))
+
+#### Icons
+- Update trash icon. ([56569](https://github.com/WordPress/gutenberg/pull/56569))
+
+#### Block Library
+- Disable block renaming support for Nav Link block. ([56425](https://github.com/WordPress/gutenberg/pull/56425))
+
+#### Distraction Free
+- Add top toolbar to distraction free mode. ([56295](https://github.com/WordPress/gutenberg/pull/56295))
+
+#### CSS & Styling
+- Gallery Block: Use styled scrollbars for image captions. ([56252](https://github.com/WordPress/gutenberg/pull/56252))
+
+#### Typography
+- Font Library: Remove insecure properties. ([56230](https://github.com/WordPress/gutenberg/pull/56230))
+
+
+### New APIs
+
+- Revisions: Add new selectors to fetch entity revisions. ([54046](https://github.com/WordPress/gutenberg/pull/54046))
+
+#### Interactivity API
+- Migration to the new `store()` API. ([55459](https://github.com/WordPress/gutenberg/pull/55459))
+
+
+### Bug Fixes
+
+- Block Editor: Undeprecate the '__experimentalImageSizeControl' component. ([56414](https://github.com/WordPress/gutenberg/pull/56414))
+- Core data: Harmonize getRevision selector and resolver function signatures. ([56416](https://github.com/WordPress/gutenberg/pull/56416))
+- Editor styles: Scope without adding specificity. ([56564](https://github.com/WordPress/gutenberg/pull/56564))
+- Fix Restore Post title placeholder. ([56580](https://github.com/WordPress/gutenberg/pull/56580))
+- Post Schedule Panel: Remove text overflow ellipsis. ([56319](https://github.com/WordPress/gutenberg/pull/56319))
+- PostCSS style transformation: Fail gracefully instead of throwing an error. ([56093](https://github.com/WordPress/gutenberg/pull/56093))
+- Rich text: Pad multiple spaces through en/em replacement. ([56341](https://github.com/WordPress/gutenberg/pull/56341))
+- Site Editor Sidebar: Fix actions vertical alignment. ([56218](https://github.com/WordPress/gutenberg/pull/56218))
+- Site Editor: Add a fallback template showing the title and content for the post only mode. ([56509](https://github.com/WordPress/gutenberg/pull/56509))
+- useEntityRecord: Do not trigger REST API requests when disabled. ([56108](https://github.com/WordPress/gutenberg/pull/56108))
+
+#### Block Library
+- File block: Remove anchor tag when copy pasting to file name. ([56508](https://github.com/WordPress/gutenberg/pull/56508))
+- Fix label of columns inspector panel. ([56647](https://github.com/WordPress/gutenberg/pull/56647))
+- Post Template: Fix incorrect offset query. ([56440](https://github.com/WordPress/gutenberg/pull/56440))
+
+#### Block Editor
+- (RichText)(Workaround)(17.1.x) Fallback to a string arg in `collapseWhiteSpace()` if `value` is not a string. ([56570](https://github.com/WordPress/gutenberg/pull/56570))
+- Cover block: Pass dropZoneElement reference to fix dragging within cover block area. ([56312](https://github.com/WordPress/gutenberg/pull/56312))
+- useMovingAnimation: Clear translate3d rule when animation is finished. ([56410](https://github.com/WordPress/gutenberg/pull/56410))
+
+#### Components
+- Design Tools: Fix last ToolsPanelItem styling. ([56536](https://github.com/WordPress/gutenberg/pull/56536))
+- Fix FormTokenField suggestions broken scrollbar when `__experimentalExpandOnFocus` is defined. ([56426](https://github.com/WordPress/gutenberg/pull/56426))
+- Tabs: Fix flaky unit tests. ([55950](https://github.com/WordPress/gutenberg/pull/55950))
+
+#### Global Styles
+- Additional CSS: Fix on change validation. ([56434](https://github.com/WordPress/gutenberg/pull/56434))
+- Global styles revisions: Update isResolving flag. ([56491](https://github.com/WordPress/gutenberg/pull/56491))
+- Spacing: Fix block error if spacing unit array empty in theme.json. ([56306](https://github.com/WordPress/gutenberg/pull/56306))
+
+#### CSS & Styling
+- Reduce specificity of default Cover text color styles. ([56411](https://github.com/WordPress/gutenberg/pull/56411))
+- Restore Post Title visual styles in Code View mode. ([56582](https://github.com/WordPress/gutenberg/pull/56582))
+
+#### Saving
+- Editor: Reinstate anonymous callback for saved post state. ([56529](https://github.com/WordPress/gutenberg/pull/56529))
+
+#### Post Editor
+- Save post button: Avoid extra re-renders when enablng/disabling tooltip. ([56502](https://github.com/WordPress/gutenberg/pull/56502))
+
+#### Plugin
+- Update Readme.txt tested up to 6.4. ([56427](https://github.com/WordPress/gutenberg/pull/56427))
+
+#### Site Editor
+- Fix template resolution for templates assigned as home page. ([56418](https://github.com/WordPress/gutenberg/pull/56418))
+
+#### Patterns
+- Fix issue with template in replace template screen. ([56407](https://github.com/WordPress/gutenberg/pull/56407))
+
+#### Layout
+- Fix issue where layout classnames are injected for blocks without layout support. ([56187](https://github.com/WordPress/gutenberg/pull/56187))
+
+#### Typography
+- Font Library: Fix fonts not displaying correctly. ([55393](https://github.com/WordPress/gutenberg/pull/55393))
+
+#### Colors
+- Duotone: Backport from Core to fix filters in classic themes. ([54778](https://github.com/WordPress/gutenberg/pull/54778))
+
+
+### Accessibility
+
+- Migrating `StyleBook` to use updated `Composite` implementation. ([55344](https://github.com/WordPress/gutenberg/pull/55344))
+
+#### Data Views
+- DataViews: Make disabled pagination buttons focusable. ([56422](https://github.com/WordPress/gutenberg/pull/56422))
+
+#### Block Library
+- Image Block: Enable image block to be selected correctly when clicked. ([56043](https://github.com/WordPress/gutenberg/pull/56043))
+
+#### Post Editor
+- Tooltip: Don't render buttons tooltip when show button text labels is enabled. ([55842](https://github.com/WordPress/gutenberg/pull/55842))
+
+#### Components
+- Improve `Button` saving state accessibility. ([55547](https://github.com/WordPress/gutenberg/pull/55547))
+
+#### Patterns
+- Fix focus loss after converting to a synced pattern. ([55473](https://github.com/WordPress/gutenberg/pull/55473))
+
+
+### Performance
+
+- Avoid calling postcss when not needed. ([56601](https://github.com/WordPress/gutenberg/pull/56601))
+- Block Editor: Optimize 'Connections' inspector controls. ([56443](https://github.com/WordPress/gutenberg/pull/56443))
+
+#### Global Styles
+- Make search more responsive for block type list. ([56139](https://github.com/WordPress/gutenberg/pull/56139))
+
+
+### Experiments
+
+#### Data Views
+- DataViews: Document `view.layout`. ([56637](https://github.com/WordPress/gutenberg/pull/56637))
+- DataViews: Extract common constants to file. ([56251](https://github.com/WordPress/gutenberg/pull/56251))
+- DataViews: Rename `InFilter` component to `FilterSummary`. ([56506](https://github.com/WordPress/gutenberg/pull/56506))
+- DataViews: Scope names of V2 UI components. ([56503](https://github.com/WordPress/gutenberg/pull/56503))
+- DataViews: Update field API to generate filters based on type. ([55996](https://github.com/WordPress/gutenberg/pull/55996))
+- DataViews: Update filter component. ([56110](https://github.com/WordPress/gutenberg/pull/56110))
+- Dataviews: Add confirmation step before deleting a page. ([56504](https://github.com/WordPress/gutenberg/pull/56504))
+- Dataviews: Add preview and grid view in templates list. ([56382](https://github.com/WordPress/gutenberg/pull/56382))
+- Dataviews: Grid layout refinements. ([56441](https://github.com/WordPress/gutenberg/pull/56441))
+- Dataviews: Remove link from author. ([56467](https://github.com/WordPress/gutenberg/pull/56467))
+- Dataviews: Update item actions in grid view. ([56501](https://github.com/WordPress/gutenberg/pull/56501))
+- Fix data view menu item radius. ([56395](https://github.com/WordPress/gutenberg/pull/56395))
+
+#### Post Editor
+- Render html in post titles in visual mode and edit HTML in post title in code view. ([54718](https://github.com/WordPress/gutenberg/pull/54718))
+
+
+### Documentation
+
+- Add the attributes definition page to the create block tutorial of the platform documentation. ([56429](https://github.com/WordPress/gutenberg/pull/56429))
+- Add the transforms page to the create block tutorial of the platform documentation. ([56559](https://github.com/WordPress/gutenberg/pull/56559))
+- Add thee block supports page to the create block tutorial of the framework docs. ([56483](https://github.com/WordPress/gutenberg/pull/56483))
+- Added clarifications and examples to "Get started with wp-scripts". ([56298](https://github.com/WordPress/gutenberg/pull/56298))
+- Block Editor: Fix typo in `URLInput`'s `onKeyDown` prop documentation. ([56322](https://github.com/WordPress/gutenberg/pull/56322))
+- Bring back non-JS tabs in block editor handbook. ([56561](https://github.com/WordPress/gutenberg/pull/56561))
+- Docs: Fix incorrect build script description in script package. ([56332](https://github.com/WordPress/gutenberg/pull/56332))
+- Docs: Fundamentals of Block Development - File structure of a block. ([56551](https://github.com/WordPress/gutenberg/pull/56551))
+- Docs: Fundamentals of Block Development - Registration of a block. ([56334](https://github.com/WordPress/gutenberg/pull/56334))
+- Docs: Fundamentals of Block Development - The block wrapper. ([56596](https://github.com/WordPress/gutenberg/pull/56596))
+- Docs: Fundamentals of Block Development - Working with Javascript in the Block Editor. ([56553](https://github.com/WordPress/gutenberg/pull/56553))
+- Docs: Fundamentals of Block Development - block.json. ([56435](https://github.com/WordPress/gutenberg/pull/56435))
+- Docs: Improve downloadBlob example. ([56225](https://github.com/WordPress/gutenberg/pull/56225))
+- Documentation - Block Editor Handbook - Add end user documentation about Block Editor as a resource on the Landing Page of the Block Editor Handbook. ([49854](https://github.com/WordPress/gutenberg/pull/49854))
+- Fix overly complex code example in ComboboxControl readme. ([56365](https://github.com/WordPress/gutenberg/pull/56365))
+- Fix version in useSetting deprecation notice. ([56377](https://github.com/WordPress/gutenberg/pull/56377))
+- Fundamentals block development - landing and first pages. ([56584](https://github.com/WordPress/gutenberg/pull/56584))
+- Fundamentals of Block Development - fix save definition. ([56605](https://github.com/WordPress/gutenberg/pull/56605))
+- Link preview image to live example using WordPress Playground. ([56292](https://github.com/WordPress/gutenberg/pull/56292))
+- NavigableContainers: Fix doc typo in onKeyDown prop. ([56352](https://github.com/WordPress/gutenberg/pull/56352))
+- Release docs: Add new section about troubleshooting the release. ([56436](https://github.com/WordPress/gutenberg/pull/56436))
+- Remove all {% codetabs %} instances and any vanilla JS references. ([56121](https://github.com/WordPress/gutenberg/pull/56121))
+- Simplify code example in ToggleControl component readme. ([56389](https://github.com/WordPress/gutenberg/pull/56389))
+- Text and Heading: Improve documentation around default values and truncation logic. ([56518](https://github.com/WordPress/gutenberg/pull/56518))
+- Theme JSON schema: Add heading/button key to color definition. ([55674](https://github.com/WordPress/gutenberg/pull/55674))
+- Update for 6.4.1 for versions in WP. ([56216](https://github.com/WordPress/gutenberg/pull/56216))
+- Update references to the gutenberg-examples repo to the new block-development-examples. ([56119](https://github.com/WordPress/gutenberg/pull/56119))
+- Update template name in `create-block` command. ([56281](https://github.com/WordPress/gutenberg/pull/56281))
+- Update webpack options for wp-scripts in README.md. ([56314](https://github.com/WordPress/gutenberg/pull/56314))
+- `BoxControl`: Update story and refactor to Typescript. ([56462](https://github.com/WordPress/gutenberg/pull/56462))
+
+
+### Code Quality
+
+- Blocks pkg: Remove 'browser' dependencies. ([56433](https://github.com/WordPress/gutenberg/pull/56433))
+- DataViews: Code Quality remove some unused props from action. ([56477](https://github.com/WordPress/gutenberg/pull/56477))
+- Editor: Move the template focus modes to the editor store. ([56472](https://github.com/WordPress/gutenberg/pull/56472))
+- Extract a PostPanelRow component from the different sidebar panels. ([56238](https://github.com/WordPress/gutenberg/pull/56238))
+- Interactivity API: Add missing changelog entry for the new `store()` API. ([56611](https://github.com/WordPress/gutenberg/pull/56611))
+- Migrating block editor `BlockPatternsList` component. ([56210](https://github.com/WordPress/gutenberg/pull/56210))
+- Move the DisableNonContentBlocks component to the editor package. ([56423](https://github.com/WordPress/gutenberg/pull/56423))
+- Post Schedule Panel: Fix Sass deprecation warning for division. ([56412](https://github.com/WordPress/gutenberg/pull/56412))
+- Remove compatibility layer for WP 6.2. ([56464](https://github.com/WordPress/gutenberg/pull/56464))
+- Unify the PostSchedule component between site and post editors. ([56196](https://github.com/WordPress/gutenberg/pull/56196))
+- Update: Refactor useAddedBy to use authorText and originalSource fields. ([56568](https://github.com/WordPress/gutenberg/pull/56568))
+
+#### Block Library
+- Add align support to the image block - alternative. ([55954](https://github.com/WordPress/gutenberg/pull/55954))
+- Backmerge block renaming fixes/refactors from 6.4 branch into Gutenberg trunk. ([56386](https://github.com/WordPress/gutenberg/pull/56386))
+- Pattern placeholder: Remove duplicate 'useDispatch' hook. ([56397](https://github.com/WordPress/gutenberg/pull/56397))
+
+#### Components
+- Remove incorrect version from deprecated `__nextHasNoMarginBottom` prop of `AnglePickerControl` Component. ([56336](https://github.com/WordPress/gutenberg/pull/56336))
+- Revert "DropdownMenu V2: Add support for rendering in legacy popover slot". ([56484](https://github.com/WordPress/gutenberg/pull/56484))
+
+#### Data Views
+- Dataviews: Ensure items and fields are using a unique id. ([56366](https://github.com/WordPress/gutenberg/pull/56366))
+
+#### Block Editor
+- useInnerBlocksProps: Stabilise dropZoneElement prop. ([56313](https://github.com/WordPress/gutenberg/pull/56313))
+
+#### Design Tools
+- Fix: Theme.json font settings in unit test. ([56309](https://github.com/WordPress/gutenberg/pull/56309))
+
+
+### Tools
+
+- Workflows: Update 'days-before-stale' for flaky test report issues. ([56585](https://github.com/WordPress/gutenberg/pull/56585))
+- scripts: Update `jest-dev-server` to v9. ([56552](https://github.com/WordPress/gutenberg/pull/56552))
+
+#### Testing
+- Dataviews: Add first end-to-end tests. ([56634](https://github.com/WordPress/gutenberg/pull/56634))
+- Migrate 'align hook' end-to-end tests to Playwright. ([56480](https://github.com/WordPress/gutenberg/pull/56480))
+- Migrate 'block directory' end-to-end tests to Playwright. ([56593](https://github.com/WordPress/gutenberg/pull/56593))
+- Migrate 'block icons' end-to-end tests to Playwright. ([56610](https://github.com/WordPress/gutenberg/pull/56610))
+- Migrate 'custom taxonomies' end-to-end test to Playwright. ([56486](https://github.com/WordPress/gutenberg/pull/56486))
+- Migrate 'sidebar permalink' end-to-end tests to Playwright. ([56253](https://github.com/WordPress/gutenberg/pull/56253))
+- Migrate Is Typing Test to Playwright. ([56616](https://github.com/WordPress/gutenberg/pull/56616))
+- Page spec: Merging create page and toggle preview tests. ([56129](https://github.com/WordPress/gutenberg/pull/56129))
+- Playwright Utils: Fix the method of getting post ID in 'publishPost'. ([56421](https://github.com/WordPress/gutenberg/pull/56421))
+- end-to-end tests: Merge Puppeteer into single job, split Playwright further. ([56363](https://github.com/WordPress/gutenberg/pull/56363))
+
+#### Build Tooling
+- Create block: Update `interactive-template` to the new `store()` API. ([56613](https://github.com/WordPress/gutenberg/pull/56613))
+
+
+### Security
+
+- WP_Theme_JSON_Gutenberg: Add nested indexed array schema sanitization. ([56447](https://github.com/WordPress/gutenberg/pull/56447))
+
+
+### Various
+
+- Add: Author text and original source to wp_template_part. ([56567](https://github.com/WordPress/gutenberg/pull/56567))
+- Migrating `BlockPatternSetup` to use updated `Composite` implementation. ([55425](https://github.com/WordPress/gutenberg/pull/55425))
+- Migrating `InserterListbox` to use updated Composite implementation. ([56246](https://github.com/WordPress/gutenberg/pull/56246))
+
+#### Data Views
+- Dataviews: All Templates: Add filters to template author. ([56338](https://github.com/WordPress/gutenberg/pull/56338))
+- Dataviews: All templates: Add: Sorting to template author and add author_text to the rest API. ([56333](https://github.com/WordPress/gutenberg/pull/56333))
+
+#### HTML API
+- Backport updates from Core. ([56578](https://github.com/WordPress/gutenberg/pull/56578))
+
+
+
+
+## Contributors
+
+The following contributors merged PRs in this release:
+
+@aaronrobertshaw @afercia @andrewhayward @andrewserong @annezazu @apeatling @arthur791004 @bph @brookewp @chad1008 @chiilog @ciampo @DAreRodz @dmsnell @draganescu @ellatrix @fabiankaegy @flootr @fluiddot @fullofcaffeine @geriux @getdave @glendaviesnz @jameskoster @jasmussen @jeryj @jffng @jorgefilipecosta @juanmaguitar @kevin940726 @luisherranz @MaggieCabrera @Mamaduka @matiasbenedetto @megane9988 @NekoJonez @ntsekouras @oandregal @ramonjd @richtabor @ryanwelcher @SavPhill @Soean @t-hamano @talldan @tellthemachines @youknowriad @zaguiini
+
+
= 17.1.3 =
diff --git a/docs/getting-started/fundamentals/README.md b/docs/getting-started/fundamentals/README.md
new file mode 100644
index 00000000000000..26fc88981348b8
--- /dev/null
+++ b/docs/getting-started/fundamentals/README.md
@@ -0,0 +1,11 @@
+# Fundamentals of Block Development
+
+This section provides an introduction to the most relevant concepts in Block Development.
+
+In this section, you will learn:
+
+1. [**File structure of a block**](https://developer.wordpress.org/block-editor/getting-started/fundamentals/file-structure-of-a-block) - The purpose of each one of the types of files available for a block, the relationships between them, and their role in the output of the block.
+1. [**`block.json`**](https://developer.wordpress.org/block-editor/getting-started/fundamentals/block-json) - How a block is defined using its `block.json` metadata and some relevant properties of this file.
+1. [**Registration of a block**](https://developer.wordpress.org/block-editor/getting-started/fundamentals/registration-of-a-block) - How a block is registered in both the server and the client.
+1. [**Block wrapper**](https://developer.wordpress.org/block-editor/getting-started/fundamentals/block-wrapper) - How to set proper attributes to the block's markup wrapper.
+1. [**Javascript in the Block Editor**](https://developer.wordpress.org/block-editor/getting-started/fundamentals/javascript-in-the-block-editor) - How to work with Javascript for the Block Editor.
\ No newline at end of file
diff --git a/docs/getting-started/fundamentals/block-json.md b/docs/getting-started/fundamentals/block-json.md
new file mode 100644
index 00000000000000..3d65a8f016914e
--- /dev/null
+++ b/docs/getting-started/fundamentals/block-json.md
@@ -0,0 +1,115 @@
+# block.json
+
+The `block.json` file simplifies the processs of defining and registering a block by using the same block's definition in JSON format to register the block in both the server and the client.
+
+[![Open block.json diagram in excalidraw](https://developer.wordpress.org/files/2023/11/block-json.png)](https://excalidraw.com/#json=v1GrIkGsYGKv8P14irBy6,Yy0vl8q7DTTL2VsH5Ww27A "Open block.json diagram in excalidraw")
+
+
+
+Besides simplifying a block's registration, using a `block.json` has [several benefits](https://developer.wordpress.org/block-editor/reference-guides/block-api/block-metadata/#benefits-using-the-metadata-file), including improved performance and development.
+
+At [**Metadata in block.json**](https://developer.wordpress.org/block-editor/reference-guides/block-api/block-metadata/) you can find a detailed explanation of all the properties you can set in a `block.json` for a block. With these properties you can define things such as:
+
+- Basic metadata of the block
+- Files for the block's behavior, style, or output
+- Data Storage in the Block
+- Setting UI panels for the block
+
+## Basic metadata of the block
+
+Through properties of the `block.json`, we can define how the block will be uniquely identified, how it can be found, and the info displayed for the block in the Block Editor. Some of these properties are:
+
+- `apiVersion`: the version of [the API](https://developer.wordpress.org/block-editor/reference-guides/block-api/block-api-versions/) used by the block (current version is 2).
+- `name`: a unique identifier for a block, including a namespace.
+- `title`: a display title for a block.
+- `category`: a block category for the block in the Inserter panel.
+- `icon`: a [Dashicon](https://developer.wordpress.org/resource/dashicons) slug or a custom SVG icon.
+- `description`: a short description visible in the block inspector.
+- `keywords`: to locate the block in the inserter.
+- `textdomain`: the plugin text-domain (important for things such as translations).
+
+## Files for the block's behavior, output, or style
+
+The `editorScript` and `editorStyle` properties allow defining Javascript and CSS files to be enqueued and loaded **only in the editor**.
+
+The `script` and `style` properties allow the definition of Javascript and CSS files to be enqueued and loaded **in both the editor and the front end**.
+
+The `viewScript` property allow us to define the Javascript file or files to be enqueued and loaded **only in the front end**.
+
+All these properties (`editorScript`, `editorStyle`, `script` `style`,`viewScript`) accept as a value a path for the file, a handle registered with `wp_register_script` or `wp_register_style`, or an array with a mix of both. Paths values in `block.json` are prefixed with `file:`.
+
+The `render` property ([introduced on WordPress 6.1](https://make.wordpress.org/core/2022/10/12/block-api-changes-in-wordpress-6-1/)) sets the path of a `.php` template file that will render the markup returned to the front end. This only method will be used to return the markup for the block on request only if `$render_callback` function has not been passed to the `register_block_type` function.
+
+## Data Storage in the Block with `attributes`
+
+The [`attributes` property](https://developer.wordpress.org/block-editor/reference-guides/block-api/block-attributes/) allows a block to declare "variables" that store data or content for the block.
+
+_Example: Attributes as defined in block.json_
+```json
+"attributes": {
+ "fallbackCurrentYear": {
+ "type": "string"
+ },
+ "showStartingYear": {
+ "type": "boolean"
+ },
+ "startingYear": {
+ "type": "string"
+ }
+},
+```
+By default `attributes` are serialized and stored in the block's delimiter but this [can be configured](https://developer.wordpress.org/news/2023/09/understanding-block-attributes/).
+
+_Example: Atributes stored in the Markup representation of the block_
+```html
+
+
+x
+```
+
+These attributes are passed to the React component `Edit`(to display in the Block Editor) and the `save` function (to return the markup saved to the DB) of the block, and to any server-side render definition for the block (see `render` prop above).
+
+The `Edit` component receives exclusively the capability of updating the attributes via the `setAttributes` function.
+
+_See how the attributes are passed to the [`Edit` component](https://github.com/WordPress/block-development-examples/blob/trunk/plugins/copyright-date-block-09aac3/src/edit.js), [the `save` function](https://github.com/WordPress/block-development-examples/blob/trunk/plugins/copyright-date-block-09aac3/src/save.js) and [the `render.php`](https://github.com/WordPress/block-development-examples/blob/trunk/plugins/copyright-date-block-09aac3/src/render.php) in this [full block example](https://github.com/WordPress/block-development-examples/tree/trunk/plugins/copyright-date-block-09aac3) of the code above_
+
+
+Check the attributes reference page for full info about the Attributes API.
+
+
+[![Open Attributes diagram in excalidraw](https://developer.wordpress.org/files/2023/11/attributes.png)](https://excalidraw.com/#json=pSgCZy8q9GbH7r0oz2fL1,MFCLd6ddQHqi_UqNp5ZSgg "Open Attributes diagram in excalidraw")
+
+
+## Enable UI settings panels for the block with `supports`
+
+The `supports` property allows a block to declare support for certain features, enabling users to customize specific settings (like colors or margins) from the Settings Sidebar.
+
+_Example: Supports as defined in block.json_
+
+```json
+"supports": {
+ "color": {
+ "text": true,
+ "link": true,
+ "background": true
+ }
+}
+```
+
+The use of `supports` generates a set of properties that need to be manually added to the wrapping element of the block so they're properly stored as part of the block data.
+
+_Example: Supports custom settings stored in the Markup representation of the block_
+
+```html
+
+
Hello World
+
+```
+
+_See the [full block example](https://github.com/WordPress/block-development-examples/tree/trunk/plugins/block-supports-6aa4dd) of the [code above](https://github.com/WordPress/block-development-examples/blob/trunk/plugins/block-supports-6aa4dd/src/block.json)_
+
+
+Check the supports reference page for full info about the Supports API.
+
diff --git a/docs/getting-started/fundamentals/block-wrapper.md b/docs/getting-started/fundamentals/block-wrapper.md
new file mode 100644
index 00000000000000..7dce10fc80f89f
--- /dev/null
+++ b/docs/getting-started/fundamentals/block-wrapper.md
@@ -0,0 +1,114 @@
+# The block wrapper
+
+Each block's markup is wrapped by a container HTML tag that needs to have the proper attributes to fully work in the Block Editor and to reflect the proper block's style settings when rendered in the Block Editor and the front end. As developers, we have full control over the block's markup, and WordPress provides the tools to add the attributes that need to exist on the wrapper to our block's markup.
+
+Ensuring proper attributes to the block wrapper is especially important when using custom styling or features like `supports`.
+
+
+The use of supports generates a set of properties that need to be manually added to the wrapping element of the block so they're properly stored as part of the block data
+
+
+A block can have three sets of markup defined, each one of them with a specific target and purpose:
+
+- The one for the **Block Editor**, defined through a `edit` React component passed to `registerBlockType` when registering the block in the client.
+- The one used to **save the block in the DB**, defined through a `save` function passed to `registerBlockType` when registering the block in the client.
+ - This markup will be returned to the front end on request if no dynamic render has been defined for the block.
+- The one used to **dynamically render the markup of the block** returned to the front end on request, defined through the `render_callback` on `register_block_type` or the `render` PHP file in `block.json`
+ - If defined, this server-side generated markup will be returned to the front end, ignoring the markup stored in DB.
+
+For the React component `edit` and the `save` function, the block wrapper element should be a native DOM element (like `
`) or a React component that forwards any additional props to native DOM elements. Using a or component, for instance, would be invalid.
+
+
+## The Edit component's markup
+
+The `useBlockProps()` hook available on the `@wordpress/block-editor` allows passing the required attributes for the Block Editor to the `edit` block's outer wrapper.
+
+Among other things, the `useBlockProps()` hook takes care of including in this wrapper:
+- An `id` for the block's markup
+- Some accesibility and `data-` attributes
+- Classes and inline styles reflecting custom settings, which include by default:
+ - The `wp-block` class
+ - A class that contains the name of the block with its namespace
+
+For example, for the following piece of code of a block's registration in the client...
+
+```js
+const Edit = () =>
Hello World - Block Editor
;
+
+registerBlockType( ..., {
+ edit: Edit
+} );
+```
+_(see the [code above](https://github.com/WordPress/block-development-examples/blob/trunk/plugins/minimal-block-ca6eda/src/index.js) in [an example](https://github.com/WordPress/block-development-examples/tree/trunk/plugins/minimal-block-ca6eda))_
+
+...the markup of the block in the Block Editor could look like this:
+```html
+
Hello World - Block Editor
+```
+
+Any additional classes and attributes for the `Edit` component of the block should be passed as an argument of `useBlockProps` (see [example](https://github.com/WordPress/block-development-examples/blob/trunk/plugins/stylesheets-79a4c3/src/edit.js)). When you add `support` for any feature, they get added to the object returned by the `useBlockProps` hook.
+
+
+## The Save component's markup
+
+When saving the markup in the DB, it’s important to add the block props returned by `useBlockProps.save()` to the wrapper element of your block. `useBlockProps.save()` ensures that the block class name is rendered properly in addition to any HTML attribute injected by the block supports API.
+
+For example, for the following piece of code of a block's registration in the client that defines the markup desired for the DB (and returned to the front end by default)...
+
+```js
+const Edit = () =>
Hello World - Block Editor
;
+const save = () =>
Hello World - Frontend
;
+
+registerBlockType( ..., {
+ edit: Edit,
+ save,
+} );
+```
+
+_(see the [code above](https://github.com/WordPress/block-development-examples/blob/trunk/plugins/minimal-block-ca6eda/src/index.js) in [an example](https://github.com/WordPress/block-development-examples/tree/trunk/plugins/minimal-block-ca6eda))_
+
+
+...the markup of the block in the front end could look like this:
+```html
+
Hello World – Frontend
+```
+
+Any additional classes and attributes for the `save` function of the block should be passed as an argument of `useBlockProps.save()` (see [example](https://github.com/WordPress/block-development-examples/blob/trunk/plugins/stylesheets-79a4c3/src/save.js)).
+
+When you add `support` for any feature, the proper classes get added to the object returned by the `useBlockProps.save()` hook.
+
+```html
+
Hello World
+```
+
+_(check the [example](https://github.com/WordPress/block-development-examples/tree/trunk/plugins/block-supports-6aa4dd) that generated the HTML above in the front end)_
+
+## The server-side render markup
+
+Any markup in the server-side render definition for the block can use the [`get_block_wrapper_attributes()`](https://developer.wordpress.org/reference/functions/get_block_wrapper_attributes/) function to generate the string of attributes required to reflect the block settings (see [example](https://github.com/WordPress/block-development-examples/blob/f68640f42d993f0866d1879f67c73910285ca114/plugins/block-dynamic-rendering-64756b/src/render.php#L11)).
+
+```php
+
>
+
+
+```
\ No newline at end of file
diff --git a/docs/getting-started/fundamentals-block-development/file-structure-of-a-block.md b/docs/getting-started/fundamentals/file-structure-of-a-block.md
similarity index 92%
rename from docs/getting-started/fundamentals-block-development/file-structure-of-a-block.md
rename to docs/getting-started/fundamentals/file-structure-of-a-block.md
index dac8dd6c338091..130483ae5af70f 100644
--- a/docs/getting-started/fundamentals-block-development/file-structure-of-a-block.md
+++ b/docs/getting-started/fundamentals/file-structure-of-a-block.md
@@ -1,8 +1,8 @@
# File structure of a block
-It is recommended to **register blocks within plugins** to ensure they stay available when a theme gets switched. With the `create-block` tool you can quickly scaffold the structure of the files required to create a plugin that registers a block.
+It is recommended to **register blocks within plugins** to ensure they stay available when a theme gets switched. With the [`create-block` tool](https://developer.wordpress.org/block-editor/getting-started/devenv/get-started-with-create-block/) you can quickly scaffold the structure of the files required to create a plugin that registers a block.
-The files generated by this tool are a good reference of the files that can be involved in the definition and registration of a block.
+The files generated by `create-block` are a good reference of the files that can be involved in the definition and registration of a block.
[![Open File Structure of a Block Diagram in excalidraw](https://developer.wordpress.org/files/2023/11/file-structure-block.png)](https://excalidraw.com/#json=YYpeR-kY1ZMhFKVZxGhMi,mVZewfwNAh_oL-7bj4gmdw "Open File Structure of a Block Diagram in excalidraw")
@@ -47,7 +47,7 @@ The `edit.js` commonly gets used to contain the React component that gets used i
### `save.js`
-The `save.js` is similar to the `edit.js` file in that it exports a single React component. This component generates the static HTML markup that gets saved to the Database.
+The `save.js` exports the function that returns the static HTML markup that gets saved to the Database.
### `style.(css|scss|sass)`
diff --git a/docs/getting-started/fundamentals-block-development/javascript-in-the-block-editor.md b/docs/getting-started/fundamentals/javascript-in-the-block-editor.md
similarity index 90%
rename from docs/getting-started/fundamentals-block-development/javascript-in-the-block-editor.md
rename to docs/getting-started/fundamentals/javascript-in-the-block-editor.md
index 0ca88e1447437e..73c6a6c56e6328 100644
--- a/docs/getting-started/fundamentals-block-development/javascript-in-the-block-editor.md
+++ b/docs/getting-started/fundamentals/javascript-in-the-block-editor.md
@@ -30,7 +30,7 @@ With the [proper `package.json` scripts](https://developer.wordpress.org/block-e
Using Javascript without a build process may be another good option for code developments with few requirements (especially those not requiring JSX).
-Without a build process, you access the methods directly from the `wp` global object and must enqueue the script manually. [WordPress Javascript](https://developer.wordpress.org/block-editor/reference-guides/packages/) packages](https://developer.wordpress.org/block-editor/reference-guides/packages/) can be accessed through the `wp` [global variable](https://developer.mozilla.org/en-US/docs/Glossary/Global_variable) but every script that wants to use them through this `wp` object is responsible for adding [the handle of that package](https://developer.wordpress.org/block-editor/contributors/code/scripts/) to the dependency array when registered.
+Without a build process, you access the methods directly from the `wp` global object and must enqueue the script manually. [WordPress Javascript packages](https://developer.wordpress.org/block-editor/reference-guides/packages/) can be accessed through the `wp` [global variable](https://developer.mozilla.org/en-US/docs/Glossary/Global_variable) but every script that wants to use them through this `wp` object is responsible for adding [the handle of that package](https://developer.wordpress.org/block-editor/contributors/code/scripts/) to the dependency array when registered.
So, for example if a script wants to register a block variation using the `registerBlockVariation` method out of the ["blocks" package](https://developer.wordpress.org/block-editor/reference-guides/packages/packages-blocks/), the `wp-blocks` handle would need to get added to the dependency array to ensure that `wp.blocks.registerBlockVariation` is defined when the script tries to access it (see [example](https://github.com/wptrainingteam/block-theme-examples/blob/master/example-block-variation/functions.php)).
@@ -42,10 +42,10 @@ Use [`enqueue_block_editor_assets`](https://developer.wordpress.org/reference/ho
## Additional resources
+- [Get started with wp-scripts](https://developer.wordpress.org/block-editor/getting-started/devenv/get-started-with-wp-scripts/)
+- [Enqueueing assets in the Editor](https://developer.wordpress.org/block-editor/how-to-guides/enqueueing-assets-in-the-editor/)
+- [Wordpress Packages handles](https://developer.wordpress.org/block-editor/contributors/code/scripts/)
- [Javascript Reference](https://developer.mozilla.org/en-US/docs/Web/JavaScript) | MDN Web Docs
- [block-development-examples](https://github.com/WordPress/block-development-examples) | GitHub repository
- [block-theme-examples](https://github.com/wptrainingteam/block-theme-examples) | GitHub repository
-- [Get started with wp-scripts](https://developer.wordpress.org/block-editor/getting-started/devenv/get-started-with-wp-scripts/) | Block Editor Handbook
-- [Enqueueing assets in the Editor](https://developer.wordpress.org/block-editor/how-to-guides/enqueueing-assets-in-the-editor/) | Block Editor Handbook
-- [Wordpress Packages handles](https://developer.wordpress.org/block-editor/contributors/code/scripts/) | Block Editor Handbook
- [How webpack and WordPress packages interact](https://developer.wordpress.org/news/2023/04/how-webpack-and-wordpress-packages-interact/) | Developer Blog
diff --git a/docs/getting-started/fundamentals-block-development/registration-of-a-block.md b/docs/getting-started/fundamentals/registration-of-a-block.md
similarity index 94%
rename from docs/getting-started/fundamentals-block-development/registration-of-a-block.md
rename to docs/getting-started/fundamentals/registration-of-a-block.md
index 3e34f1368e8c41..7cc8e6bcbe8b06 100644
--- a/docs/getting-started/fundamentals-block-development/registration-of-a-block.md
+++ b/docs/getting-started/fundamentals/registration-of-a-block.md
@@ -70,7 +70,7 @@ The content of block.json (or any other .json file) ca
The client-side block settings object passed as a second parameter include two properties that are especially relevant:
- `edit`: The React component that gets used in the editor for our block.
-- `save`: The React component that generates the static HTML markup that gets saved to the Database.
+- `save`: The function that returns the static HTML markup that gets saved to the Database.
`registerBlockType` returns the registered block type (`WPBlock`) on success or `undefined` on failure.
@@ -78,15 +78,15 @@ The client-side block settings object passed as a second parameter include two p
```js
import { registerBlockType } from '@wordpress/blocks';
+import { useBlockProps } from '@wordpress/block-editor';
import metadata from './block.json';
+const Edit = () =>
;
- },
+ edit: Edit,
+ save,
} );
```
_See the [code above](https://github.com/WordPress/block-development-examples/blob/trunk/plugins/minimal-block-ca6eda/src/index.js) in [an example](https://github.com/WordPress/block-development-examples/tree/trunk/plugins/minimal-block-ca6eda)_
diff --git a/docs/manifest.json b/docs/manifest.json
index 5906743512062c..3ab4cefb2b533c 100644
--- a/docs/manifest.json
+++ b/docs/manifest.json
@@ -95,6 +95,42 @@
"markdown_source": "../docs/getting-started/create-block/submitting-to-block-directory.md",
"parent": "create-block"
},
+ {
+ "title": "Fundamentals of Block Development",
+ "slug": "fundamentals",
+ "markdown_source": "../docs/getting-started/fundamentals/README.md",
+ "parent": "getting-started"
+ },
+ {
+ "title": "File structure of a block",
+ "slug": "file-structure-of-a-block",
+ "markdown_source": "../docs/getting-started/fundamentals/file-structure-of-a-block.md",
+ "parent": "fundamentals"
+ },
+ {
+ "title": "block.json",
+ "slug": "block-json",
+ "markdown_source": "../docs/getting-started/fundamentals/block-json.md",
+ "parent": "fundamentals"
+ },
+ {
+ "title": "Registration of a block",
+ "slug": "registration-of-a-block",
+ "markdown_source": "../docs/getting-started/fundamentals/registration-of-a-block.md",
+ "parent": "fundamentals"
+ },
+ {
+ "title": "The block wrapper",
+ "slug": "block-wrapper",
+ "markdown_source": "../docs/getting-started/fundamentals/block-wrapper.md",
+ "parent": "fundamentals"
+ },
+ {
+ "title": "Working with Javascript for the Block Editor",
+ "slug": "javascript-in-the-block-editor",
+ "markdown_source": "../docs/getting-started/fundamentals/javascript-in-the-block-editor.md",
+ "parent": "fundamentals"
+ },
{
"title": "Glossary",
"slug": "glossary",
diff --git a/docs/reference-guides/block-api/block-metadata.md b/docs/reference-guides/block-api/block-metadata.md
index a91dfd747fa24b..edc61d138128e6 100644
--- a/docs/reference-guides/block-api/block-metadata.md
+++ b/docs/reference-guides/block-api/block-metadata.md
@@ -78,7 +78,7 @@ Development is improved by using a defined schema definition file. Supported edi
```
-Check Registration of a block to learn more about how to register a block using its metadata.
+Check Registration of a block to learn more about how to register a block using its metadata.
## Block API
diff --git a/docs/reference-guides/core-blocks.md b/docs/reference-guides/core-blocks.md
index 4f42550ba4cfbc..dd7ef824aa6b0c 100644
--- a/docs/reference-guides/core-blocks.md
+++ b/docs/reference-guides/core-blocks.md
@@ -378,7 +378,7 @@ Insert an image to make a visual statement. ([Source](https://github.com/WordPre
- **Name:** core/image
- **Category:** media
-- **Supports:** align (center, full, left, right, wide), anchor, color (~~background~~, ~~text~~), filter (duotone)
+- **Supports:** align (center, full, left, right, wide), anchor, color (~~background~~, ~~text~~), filter (duotone), interactivity
- **Attributes:** alt, aspectRatio, caption, height, href, id, lightbox, linkClass, linkDestination, linkTarget, rel, scale, sizeSlug, title, url, width
## Latest Comments
diff --git a/docs/reference-guides/data/data-core.md b/docs/reference-guides/data/data-core.md
index b2a75638ace9fe..b80703dcc67b18 100644
--- a/docs/reference-guides/data/data-core.md
+++ b/docs/reference-guides/data/data-core.md
@@ -741,7 +741,7 @@ _Returns_
### receiveRevisions
-Returns an action object used in signalling that revisions have been received.
+Action triggered to receive revision items.
_Parameters_
@@ -753,10 +753,6 @@ _Parameters_
- _invalidateCache_ `?boolean`: Should invalidate query caches.
- _meta_ `?Object`: Meta information about pagination.
-_Returns_
-
-- `Object`: Action object.
-
### receiveThemeSupports
> **Deprecated** since WP 5.9, this is not useful anymore, use the selector direclty.
diff --git a/docs/toc.json b/docs/toc.json
index 8a29d2d4f10aff..91017ce69643c3 100644
--- a/docs/toc.json
+++ b/docs/toc.json
@@ -46,6 +46,25 @@
}
]
},
+ {
+ "docs/getting-started/fundamentals/README.md": [
+ {
+ "docs/getting-started/fundamentals/file-structure-of-a-block.md": []
+ },
+ {
+ "docs/getting-started/fundamentals/block-json.md": []
+ },
+ {
+ "docs/getting-started/fundamentals/registration-of-a-block.md": []
+ },
+ {
+ "docs/getting-started/fundamentals/block-wrapper.md": []
+ },
+ {
+ "docs/getting-started/fundamentals/javascript-in-the-block-editor.md": []
+ }
+ ]
+ },
{ "docs/getting-started/glossary.md": [] },
{ "docs/getting-started/faq.md": [] }
]
diff --git a/lib/class-wp-theme-json-gutenberg.php b/lib/class-wp-theme-json-gutenberg.php
index 646c7abc59eafe..9311001f2edd14 100644
--- a/lib/class-wp-theme-json-gutenberg.php
+++ b/lib/class-wp-theme-json-gutenberg.php
@@ -426,6 +426,31 @@ class WP_Theme_JSON_Gutenberg {
),
);
+ const FONT_FAMILY_SCHEMA = array(
+ array(
+ 'fontFamily' => null,
+ 'name' => null,
+ 'slug' => null,
+ 'fontFace' => array(
+ array(
+ 'ascentOverride' => null,
+ 'descentOverride' => null,
+ 'fontDisplay' => null,
+ 'fontFamily' => null,
+ 'fontFeatureSettings' => null,
+ 'fontStyle' => null,
+ 'fontStretch' => null,
+ 'fontVariationSettings' => null,
+ 'fontWeight' => null,
+ 'lineGapOverride' => null,
+ 'sizeAdjust' => null,
+ 'src' => null,
+ 'unicodeRange' => null,
+ ),
+ ),
+ ),
+ );
+
/**
* The valid properties under the styles key.
*
@@ -550,6 +575,52 @@ class WP_Theme_JSON_Gutenberg {
'typography' => 'typography',
);
+ /**
+ * Return the input schema at the root and per origin.
+ *
+ * @since 6.5.0
+ *
+ * @param array $schema The base schema.
+ * @return array The schema at the root and per origin.
+ *
+ * Example:
+ * schema_in_root_and_per_origin(
+ * array(
+ * 'fontFamily' => null,
+ * 'slug' => null,
+ * )
+ * )
+ *
+ * Returns:
+ * array(
+ * 'fontFamily' => null,
+ * 'slug' => null,
+ * 'default' => array(
+ * 'fontFamily' => null,
+ * 'slug' => null,
+ * ),
+ * 'blocks' => array(
+ * 'fontFamily' => null,
+ * 'slug' => null,
+ * ),
+ * 'theme' => array(
+ * 'fontFamily' => null,
+ * 'slug' => null,
+ * ),
+ * 'custom' => array(
+ * 'fontFamily' => null,
+ * 'slug' => null,
+ * ),
+ * )
+ */
+ protected static function schema_in_root_and_per_origin( $schema ) {
+ $schema_in_root_and_per_origin = $schema;
+ foreach ( static::VALID_ORIGINS as $origin ) {
+ $schema_in_root_and_per_origin[ $origin ] = $schema;
+ }
+ return $schema_in_root_and_per_origin;
+ }
+
/**
* Returns a class name by an element name.
*
@@ -791,11 +862,12 @@ protected static function sanitize( $input, $valid_block_names, $valid_element_n
$schema_styles_blocks[ $block ]['variations'] = $schema_styles_variations;
}
- $schema['styles'] = static::VALID_STYLES;
- $schema['styles']['blocks'] = $schema_styles_blocks;
- $schema['styles']['elements'] = $schema_styles_elements;
- $schema['settings'] = static::VALID_SETTINGS;
- $schema['settings']['blocks'] = $schema_settings_blocks;
+ $schema['styles'] = static::VALID_STYLES;
+ $schema['styles']['blocks'] = $schema_styles_blocks;
+ $schema['styles']['elements'] = $schema_styles_elements;
+ $schema['settings'] = static::VALID_SETTINGS;
+ $schema['settings']['blocks'] = $schema_settings_blocks;
+ $schema['settings']['typography']['fontFamilies'] = static::schema_in_root_and_per_origin( static::FONT_FAMILY_SCHEMA );
// Remove anything that's not present in the schema.
foreach ( array( 'styles', 'settings' ) as $subtree ) {
@@ -967,18 +1039,39 @@ protected static function get_blocks_metadata() {
* @return array The modified $tree.
*/
protected static function remove_keys_not_in_schema( $tree, $schema ) {
- $tree = array_intersect_key( $tree, $schema );
+ if ( ! is_array( $tree ) ) {
+ return $tree;
+ }
- foreach ( $schema as $key => $data ) {
- if ( ! isset( $tree[ $key ] ) ) {
+ foreach ( $tree as $key => $value ) {
+ // Remove keys not in the schema or with null/empty values.
+ if ( ! array_key_exists( $key, $schema ) ) {
+ unset( $tree[ $key ] );
continue;
}
- if ( is_array( $schema[ $key ] ) && is_array( $tree[ $key ] ) ) {
- $tree[ $key ] = static::remove_keys_not_in_schema( $tree[ $key ], $schema[ $key ] );
+ // Check if the value is an array and requires further processing.
+ if ( is_array( $value ) && is_array( $schema[ $key ] ) ) {
+ // Determine if it is an associative or indexed array.
+ $schema_is_assoc = self::is_assoc( $value );
+
+ if ( $schema_is_assoc ) {
+ // If associative, process as a single object.
+ $tree[ $key ] = self::remove_keys_not_in_schema( $value, $schema[ $key ] );
- if ( empty( $tree[ $key ] ) ) {
- unset( $tree[ $key ] );
+ if ( empty( $tree[ $key ] ) ) {
+ unset( $tree[ $key ] );
+ }
+ } else {
+ // If indexed, process each item in the array.
+ foreach ( $value as $item_key => $item_value ) {
+ if ( isset( $schema[ $key ][0] ) && is_array( $schema[ $key ][0] ) ) {
+ $tree[ $key ][ $item_key ] = self::remove_keys_not_in_schema( $item_value, $schema[ $key ][0] );
+ } else {
+ // If the schema does not define a further structure, keep the value as is.
+ $tree[ $key ][ $item_key ] = $item_value;
+ }
+ }
}
} elseif ( is_array( $schema[ $key ] ) && ! is_array( $tree[ $key ] ) ) {
unset( $tree[ $key ] );
@@ -988,6 +1081,20 @@ protected static function remove_keys_not_in_schema( $tree, $schema ) {
return $tree;
}
+ /**
+ * Checks if the given array is associative.
+ *
+ * @since 6.5.0
+ * @param array $data The array to check.
+ * @return bool True if the array is associative, false otherwise.
+ */
+ protected static function is_assoc( $data ) {
+ if ( array() === $data ) {
+ return false;
+ }
+ return array_keys( $data ) !== range( 0, count( $data ) - 1 );
+ }
+
/**
* Returns the existing settings for each block.
*
diff --git a/lib/compat/wordpress-6.4/html-api/class-gutenberg-html-tag-processor-6-4.php b/lib/compat/wordpress-6.4/html-api/class-gutenberg-html-tag-processor-6-4.php
index 509d2c1a2c9abd..e22b4fb17b902e 100644
--- a/lib/compat/wordpress-6.4/html-api/class-gutenberg-html-tag-processor-6-4.php
+++ b/lib/compat/wordpress-6.4/html-api/class-gutenberg-html-tag-processor-6-4.php
@@ -116,7 +116,7 @@
*
* Example:
*
- * if ( $tags->next_tag( array( 'class' => 'wp-group-block' ) ) ) {
+ * if ( $tags->next_tag( array( 'class_name' => 'wp-group-block' ) ) ) {
* $tags->set_attribute( 'title', 'This groups the contained content.' );
* $tags->remove_attribute( 'data-test-id' );
* }
@@ -2031,8 +2031,8 @@ public function set_attribute( $name, $value ) {
*
* @see https://html.spec.whatwg.org/#attributes-2
*
- * @TODO as the only regex pattern maybe we should take it out? are
- * Unicode patterns available broadly in Core?
+ * @todo As the only regex pattern maybe we should take it out?
+ * Are Unicode patterns available broadly in Core?
*/
if ( preg_match(
'~[' .
diff --git a/lib/compat/wordpress-6.4/html-api/class-wp-html-processor.php b/lib/compat/wordpress-6.4/html-api/class-wp-html-processor.php
index e53e64c80e2e02..d1c8b9e82c708a 100644
--- a/lib/compat/wordpress-6.4/html-api/class-wp-html-processor.php
+++ b/lib/compat/wordpress-6.4/html-api/class-wp-html-processor.php
@@ -103,12 +103,16 @@
*
* The following list specifies the HTML tags that _are_ supported:
*
+ * - Containers: ADDRESS, BLOCKQUOTE, DETAILS, DIALOG, DIV, FOOTER, HEADER, MAIN, MENU, SPAN, SUMMARY.
+ * - Form elements: BUTTON, FIELDSET, SEARCH.
+ * - Formatting elements: B, BIG, CODE, EM, FONT, I, SMALL, STRIKE, STRONG, TT, U.
+ * - Heading elements: HGROUP.
* - Links: A.
- * - The formatting elements: B, BIG, CODE, EM, FONT, I, SMALL, STRIKE, STRONG, TT, U.
- * - Containers: DIV, FIGCAPTION, FIGURE, SPAN.
- * - Form elements: BUTTON.
+ * - Lists: DL.
+ * - Media elements: FIGCAPTION, FIGURE, IMG.
* - Paragraph: P.
- * - Void elements: IMG.
+ * - Sectioning elements: ARTICLE, ASIDE, NAV, SECTION
+ * - Deprecated elements: CENTER, DIR
*
* ### Supported markup
*
@@ -346,7 +350,7 @@ public function get_last_error() {
/**
* Finds the next tag matching the $query.
*
- * @TODO: Support matching the class name and tag name.
+ * @todo Support matching the class name and tag name.
*
* @since 6.4.0
*
@@ -555,9 +559,9 @@ public function step( $node_to_process = self::PROCESS_NEXT_NODE ) {
* Breadcrumbs start at the outermost parent and descend toward the matched element.
* They always include the entire path from the root HTML node to the matched element.
*
- * @TODO: It could be more efficient to expose a generator-based version of this function
- * to avoid creating the array copy on tag iteration. If this is done, it would likely
- * be more useful to walk up the stack when yielding instead of starting at the top.
+ * @todo It could be more efficient to expose a generator-based version of this function
+ * to avoid creating the array copy on tag iteration. If this is done, it would likely
+ * be more useful to walk up the stack when yielding instead of starting at the top.
*
* Example
*
@@ -625,11 +629,29 @@ private function step_in_body() {
* > "fieldset", "figcaption", "figure", "footer", "header", "hgroup",
* > "main", "menu", "nav", "ol", "p", "search", "section", "summary", "ul"
*/
+ case '+ADDRESS':
+ case '+ARTICLE':
+ case '+ASIDE':
case '+BLOCKQUOTE':
+ case '+CENTER':
+ case '+DETAILS':
+ case '+DIALOG':
+ case '+DIR':
case '+DIV':
+ case '+DL':
+ case '+FIELDSET':
case '+FIGCAPTION':
case '+FIGURE':
+ case '+FOOTER':
+ case '+HEADER':
+ case '+HGROUP':
+ case '+MAIN':
+ case '+MENU':
+ case '+NAV':
case '+P':
+ case '+SEARCH':
+ case '+SECTION':
+ case '+SUMMARY':
if ( $this->state->stack_of_open_elements->has_p_in_button_scope() ) {
$this->close_a_p_element();
}
@@ -643,11 +665,29 @@ private function step_in_body() {
* > "figcaption", "figure", "footer", "header", "hgroup", "listing", "main",
* > "menu", "nav", "ol", "pre", "search", "section", "summary", "ul"
*/
+ case '-ADDRESS':
+ case '-ARTICLE':
+ case '-ASIDE':
case '-BLOCKQUOTE':
case '-BUTTON':
+ case '-CENTER':
+ case '-DETAILS':
+ case '-DIALOG':
+ case '-DIR':
case '-DIV':
+ case '-DL':
+ case '-FIELDSET':
case '-FIGCAPTION':
case '-FIGURE':
+ case '-FOOTER':
+ case '-HEADER':
+ case '-HGROUP':
+ case '-MAIN':
+ case '-MENU':
+ case '-NAV':
+ case '-SEARCH':
+ case '-SECTION':
+ case '-SUMMARY':
if ( ! $this->state->stack_of_open_elements->has_element_in_scope( $tag_name ) ) {
// @TODO: Report parse error.
// Ignore the token.
diff --git a/lib/compat/wordpress-6.5/class-wp-navigation-block-renderer.php b/lib/compat/wordpress-6.5/class-wp-navigation-block-renderer.php
index e2eb4e10414fe8..9c2314ebe6890c 100644
--- a/lib/compat/wordpress-6.5/class-wp-navigation-block-renderer.php
+++ b/lib/compat/wordpress-6.5/class-wp-navigation-block-renderer.php
@@ -429,25 +429,25 @@ private static function get_responsive_container_markup( $attributes, $inner_blo
$close_button_directives = '';
if ( $should_load_view_script ) {
$open_button_directives = '
- data-wp-on--click="actions.core.navigation.openMenuOnClick"
- data-wp-on--keydown="actions.core.navigation.handleMenuKeydown"
+ data-wp-on--click="actions.openMenuOnClick"
+ data-wp-on--keydown="actions.handleMenuKeydown"
';
$responsive_container_directives = '
- data-wp-class--has-modal-open="selectors.core.navigation.isMenuOpen"
- data-wp-class--is-menu-open="selectors.core.navigation.isMenuOpen"
- data-wp-effect="effects.core.navigation.initMenu"
- data-wp-on--keydown="actions.core.navigation.handleMenuKeydown"
- data-wp-on--focusout="actions.core.navigation.handleMenuFocusout"
+ data-wp-class--has-modal-open="state.isMenuOpen"
+ data-wp-class--is-menu-open="state.isMenuOpen"
+ data-wp-watch="callbacks.initMenu"
+ data-wp-on--keydown="actions.handleMenuKeydown"
+ data-wp-on--focusout="actions.handleMenuFocusout"
tabindex="-1"
';
$responsive_dialog_directives = '
- data-wp-bind--aria-modal="selectors.core.navigation.ariaModal"
- data-wp-bind--aria-label="selectors.core.navigation.ariaLabel"
- data-wp-bind--role="selectors.core.navigation.roleAttribute"
- data-wp-effect="effects.core.navigation.focusFirstElement"
+ data-wp-bind--aria-modal="state.ariaModal"
+ data-wp-bind--aria-label="state.ariaLabel"
+ data-wp-bind--role="state.roleAttribute"
+ data-wp-watch="callbacks.focusFirstElement"
';
$close_button_directives = '
- data-wp-on--click="actions.core.navigation.closeMenuOnClick"
+ data-wp-on--click="actions.closeMenuOnClick"
';
}
@@ -521,19 +521,15 @@ private static function get_nav_element_directives( $should_load_view_script ) {
// When adding to this array be mindful of security concerns.
$nav_element_context = wp_json_encode(
array(
- 'core' => array(
- 'navigation' => array(
- 'overlayOpenedBy' => array(),
- 'type' => 'overlay',
- 'roleAttribute' => '',
- 'ariaLabel' => __( 'Menu' ),
- ),
- ),
+ 'overlayOpenedBy' => array(),
+ 'type' => 'overlay',
+ 'roleAttribute' => '',
+ 'ariaLabel' => __( 'Menu' ),
),
JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP
);
return '
- data-wp-interactive
+ data-wp-interactive=\'{"namespace":"core/navigation"}\'
data-wp-context=\'' . $nav_element_context . '\'
';
}
@@ -547,20 +543,28 @@ private static function get_nav_element_directives( $should_load_view_script ) {
*/
private static function handle_view_script_loading( $attributes, $block, $inner_blocks ) {
$should_load_view_script = static::should_load_view_script( $attributes, $inner_blocks );
+ $is_gutenberg_plugin = defined( 'IS_GUTENBERG_PLUGIN' ) && IS_GUTENBERG_PLUGIN;
+ $view_js_file = 'wp-block-navigation-view';
+ $script_handles = $block->block_type->view_script_handles;
- $view_js_file = 'wp-block-navigation-view';
-
- // If the script already exists, there is no point in removing it from viewScript.
- if ( ! wp_script_is( $view_js_file ) ) {
- $script_handles = $block->block_type->view_script_handles;
-
- // If the script is not needed, and it is still in the `view_script_handles`, remove it.
- if ( ! $should_load_view_script && in_array( $view_js_file, $script_handles, true ) ) {
- $block->block_type->view_script_handles = array_diff( $script_handles, array( $view_js_file ) );
+ if ( $is_gutenberg_plugin ) {
+ if ( $should_load_view_script ) {
+ gutenberg_enqueue_module( '@wordpress/block-library/navigation-block' );
}
- // If the script is needed, but it was previously removed, add it again.
- if ( $should_load_view_script && ! in_array( $view_js_file, $script_handles, true ) ) {
- $block->block_type->view_script_handles = array_merge( $script_handles, array( $view_js_file ) );
+ // Remove the view script because we are using the module.
+ $block->block_type->view_script_handles = array_diff( $script_handles, array( $view_js_file ) );
+ } else {
+ // If the script already exists, there is no point in removing it from viewScript.
+ if ( ! wp_script_is( $view_js_file ) ) {
+
+ // If the script is not needed, and it is still in the `view_script_handles`, remove it.
+ if ( ! $should_load_view_script && in_array( $view_js_file, $script_handles, true ) ) {
+ $block->block_type->view_script_handles = array_diff( $script_handles, array( $view_js_file ) );
+ }
+ // If the script is needed, but it was previously removed, add it again.
+ if ( $should_load_view_script && ! in_array( $view_js_file, $script_handles, true ) ) {
+ $block->block_type->view_script_handles = array_merge( $script_handles, array( $view_js_file ) );
+ }
}
}
}
diff --git a/lib/experimental/interactivity-api/class-wp-interactivity-store.php b/lib/experimental/interactivity-api/class-wp-interactivity-store.php
index 89cb58700554a9..c53701b14e8aff 100644
--- a/lib/experimental/interactivity-api/class-wp-interactivity-store.php
+++ b/lib/experimental/interactivity-api/class-wp-interactivity-store.php
@@ -62,7 +62,7 @@ public static function render() {
return;
}
echo sprintf(
- '',
+ '',
wp_json_encode( self::$store, JSON_HEX_TAG | JSON_HEX_AMP )
);
}
diff --git a/lib/experimental/interactivity-api/modules.php b/lib/experimental/interactivity-api/modules.php
new file mode 100644
index 00000000000000..02785a152ca1fa
--- /dev/null
+++ b/lib/experimental/interactivity-api/modules.php
@@ -0,0 +1,33 @@
+ 'defer',
+ )
+ );
+}
+
+add_action( 'wp_enqueue_scripts', 'gutenberg_register_interactivity_module' );
diff --git a/lib/experimental/interactivity-api/scripts.php b/lib/experimental/interactivity-api/scripts.php
deleted file mode 100644
index ed1fca85500701..00000000000000
--- a/lib/experimental/interactivity-api/scripts.php
+++ /dev/null
@@ -1,40 +0,0 @@
-=' );
- if ( $supports_defer ) {
- // Defer execution of @wordpress/interactivity package but continue loading in head.
- wp_script_add_data( 'wp-interactivity', 'strategy', 'defer' );
- wp_script_add_data( 'wp-interactivity', 'group', 0 );
- } else {
- // Move the @wordpress/interactivity package to the footer.
- wp_script_add_data( 'wp-interactivity', 'group', 1 );
- }
-
- // Move all the view scripts of the interactive blocks to the footer.
- $registered_blocks = \WP_Block_Type_Registry::get_instance()->get_all_registered();
- foreach ( array_values( $registered_blocks ) as $block ) {
- if ( isset( $block->supports['interactivity'] ) && $block->supports['interactivity'] ) {
- foreach ( $block->view_script_handles as $handle ) {
- // Note that all block view scripts are already made defer by default.
- wp_script_add_data( $handle, 'group', $supports_defer ? 0 : 1 );
- }
- }
- }
-}
-add_action( 'wp_enqueue_scripts', 'gutenberg_interactivity_move_interactive_scripts_to_the_footer', 11 );
diff --git a/lib/experimental/modules/class-gutenberg-modules.php b/lib/experimental/modules/class-gutenberg-modules.php
new file mode 100644
index 00000000000000..ca74d863043ee6
--- /dev/null
+++ b/lib/experimental/modules/class-gutenberg-modules.php
@@ -0,0 +1,195 @@
+ isset( $dependencies['static'] ) || isset( $dependencies['dynamic'] ) ? $dependencies['static'] ?? array() : $dependencies,
+ 'dynamic' => isset( $dependencies['dynamic'] ) ? $dependencies['dynamic'] : array(),
+ );
+
+ self::$registered[ $module_identifier ] = array(
+ 'src' => $src,
+ 'version' => $version,
+ 'dependencies' => $deps,
+ );
+ }
+ }
+
+ /**
+ * Enqueues a module in the page.
+ *
+ * @param string $module_identifier The identifier of the module.
+ */
+ public static function enqueue( $module_identifier ) {
+ // Add the module to the queue if it's not already there.
+ if ( ! in_array( $module_identifier, self::$enqueued, true ) ) {
+ self::$enqueued[] = $module_identifier;
+ }
+ }
+
+ /**
+ * Returns the import map array.
+ *
+ * @return array Associative array with 'imports' key mapping to an array of module identifiers and their respective source strings.
+ */
+ public static function get_import_map() {
+ $imports = array();
+ foreach ( self::get_dependencies( self::$enqueued, array( 'static', 'dynamic' ) ) as $module_identifier => $module ) {
+ $imports[ $module_identifier ] = $module['src'] . self::get_version_query_string( $module['version'] );
+ }
+ return array( 'imports' => $imports );
+ }
+
+ /**
+ * Prints the import map.
+ */
+ public static function print_import_map() {
+ $import_map = self::get_import_map();
+ if ( ! empty( $import_map['imports'] ) ) {
+ echo '';
+ }
+ }
+
+ /**
+ * Prints all the enqueued modules using
HTML;
diff --git a/packages/e2e-tests/plugins/interactive-blocks/store-tag/view.js b/packages/e2e-tests/plugins/interactive-blocks/store-tag/view.js
index 140cab6463137f..0faa9625cedd78 100644
--- a/packages/e2e-tests/plugins/interactive-blocks/store-tag/view.js
+++ b/packages/e2e-tests/plugins/interactive-blocks/store-tag/view.js
@@ -1,24 +1,24 @@
-( ( { wp } ) => {
- /**
- * WordPress dependencies
- */
- const { store } = wp.interactivity;
+/**
+ * WordPress dependencies
+ */
+import { store } from '@wordpress/interactivity';
- store( {
- state: {
- counter: {
- // `value` is defined in the server.
- double: ( { state } ) => state.counter.value * 2,
- clicks: 0,
+const { state } = store( 'store-tag', {
+ state: {
+ counter: {
+ // `value` is defined in the server.
+ get double() {
+ return state.counter.value * 2;
},
+ clicks: 0,
},
- actions: {
- counter: {
- increment: ( { state } ) => {
- state.counter.value += 1;
- state.counter.clicks += 1;
- },
+ },
+ actions: {
+ counter: {
+ increment() {
+ state.counter.value += 1;
+ state.counter.clicks += 1;
},
},
- } );
-} )( window );
+ },
+} );
diff --git a/packages/e2e-tests/plugins/interactive-blocks/tovdom-islands/render.php b/packages/e2e-tests/plugins/interactive-blocks/tovdom-islands/render.php
index a3ebb7a87424e4..7b1bc6513977b8 100644
--- a/packages/e2e-tests/plugins/interactive-blocks/tovdom-islands/render.php
+++ b/packages/e2e-tests/plugins/interactive-blocks/tovdom-islands/render.php
@@ -5,7 +5,9 @@
* @package gutenberg-test-interactive-blocks
*/
+gutenberg_enqueue_module( 'tovdom-islands-view' );
?>
+
@@ -13,7 +15,7 @@
-
+
This should not be shown because it is inside an island.
@@ -21,7 +23,7 @@
-
+
-
-
+
+
-
+
-
+
{
- const { store, directive, createElement } = wp.interactivity;
+/**
+ * WordPress dependencies
+ */
+import { store, directive, createElement as h } from '@wordpress/interactivity';
- // Fake `data-wp-show-mock` directive to test when things are removed from the
- // DOM. Replace with `data-wp-show` when it's ready.
- directive(
- 'show-mock',
- ( {
- directives: {
- "show-mock": { default: showMock },
- },
- element,
- evaluate,
- } ) => {
- if ( ! evaluate( showMock ) )
- element.props.children =
- createElement( "template", null, element.props.children );
+// Fake `data-wp-show-mock` directive to test when things are removed from the
+// DOM. Replace with `data-wp-show` when it's ready.
+directive(
+ 'show-mock',
+ ( { directives: { 'show-mock': showMock }, element, evaluate } ) => {
+ const entry = showMock.find( ( { suffix } ) => suffix === 'default' );
+
+ if ( ! evaluate( entry ) ) {
+ element.props.children = h(
+ 'template',
+ null,
+ element.props.children
+ );
}
- );
+ }
+);
- store( {
- state: {
- falseValue: false,
- },
- } );
-} )( window );
+store( 'tovdom-islands', {
+ state: {
+ falseValue: false,
+ },
+} );
diff --git a/packages/e2e-tests/plugins/interactive-blocks/tovdom/render.php b/packages/e2e-tests/plugins/interactive-blocks/tovdom/render.php
index 952a4f6c0a455d..309b42a5829359 100644
--- a/packages/e2e-tests/plugins/interactive-blocks/tovdom/render.php
+++ b/packages/e2e-tests/plugins/interactive-blocks/tovdom/render.php
@@ -8,9 +8,11 @@
$plugin_url = plugin_dir_url( __DIR__ );
$src_proc_ins = $plugin_url . 'tovdom/processing-instructions.js';
$src_cdata = $plugin_url . 'tovdom/cdata.js';
+
+gutenberg_enqueue_module( 'tovdom-view' );
?>
-