diff --git a/.eslintrc.js b/.eslintrc.js index 83b22cbabfb2d8..7b696b6bd9202f 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -49,6 +49,7 @@ module.exports = { jsdoc: { mode: 'typescript', }, + 'import/internal-regex': null, 'import/resolver': require.resolve( './tools/eslint/import-resolver' ), }, rules: { diff --git a/changelog.txt b/changelog.txt index ab438d77147cb1..8b792e17d33819 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,212 @@ == Changelog == += 12.3.0-rc.1 = + +### Features + +#### Block Library + +- Group/row blocks: + - Add Gap support. ([37459](https://github.com/WordPress/gutenberg/pull/37459)) + - Add Typography support. ([37456](https://github.com/WordPress/gutenberg/pull/37456)) +- New Author Name block. ([36001](https://github.com/WordPress/gutenberg/pull/36001)) +- Comments Pagination: + - New Comments Pagination Next block. ([36562](https://github.com/WordPress/gutenberg/pull/36562)) + - New Comments Pagination Previous block. ([36912](https://github.com/WordPress/gutenberg/pull/36912)) + +### Enhancements + +#### Block Library + +- Navigation: + - Enable even more compact setup state. ([37089](https://github.com/WordPress/gutenberg/pull/37089)) + - Use rems for padding. ([37478](https://github.com/WordPress/gutenberg/pull/37478)) +- Site Logo: Add option to set site icon from Site Logo block. ([35892](https://github.com/WordPress/gutenberg/pull/35892)) +- Paragraph: Add font family support. ([37586](https://github.com/WordPress/gutenberg/pull/37586)) +- Comments Template: Add comments pagination. ([37610](https://github.com/WordPress/gutenberg/pull/37610)) +- Embeds: Simplify the embed loading state. ([37548](https://github.com/WordPress/gutenberg/pull/37548)) +- Spacer: Add custom units for height and width. ([36186](https://github.com/WordPress/gutenberg/pull/36186)) + +#### Global Styles + +- Make the global styles subtitles font smaller. ([37600](https://github.com/WordPress/gutenberg/pull/37600)) +- Add support for nameless font sizes. ([37410](https://github.com/WordPress/gutenberg/pull/37410)) + +#### Colors + +- Allow color gradient popover to be above the color toggle. ([37430](https://github.com/WordPress/gutenberg/pull/37430)) +- Make color styles labels simpler. ([37493](https://github.com/WordPress/gutenberg/pull/37493)) +- Use subtitle styles for the palette names. ([37460](https://github.com/WordPress/gutenberg/pull/37460)) + +#### Design Tools + +- Border panel: Collapse color controls. ([37425](https://github.com/WordPress/gutenberg/pull/37425)) + +#### Document Settings + +- Add class name to post author on edit post sidebar. ([36269](https://github.com/WordPress/gutenberg/pull/36269)) + +#### Site Editor + +- Update save panel's cancel button from icon to visible text. ([37310](https://github.com/WordPress/gutenberg/pull/37310)) + +#### Accessibility + +- Latest Posts: Add aria-label to featured links. ([36251](https://github.com/WordPress/gutenberg/pull/36251)) + +### Bug Fixes + +#### Block Library + +- Navigation: + - Restrict Navigation permissions and show UI warning if cannot create. ([37454](https://github.com/WordPress/gutenberg/pull/37454)) + - Ensure the overlay menu works when inserting navigation block patterns and that inner blocks are retained. ([37358](https://github.com/WordPress/gutenberg/pull/37358)) + - Fix navigation appender. ([37447](https://github.com/WordPress/gutenberg/pull/37447)) + - Revert all margins on navigation-item in editor. ([37587](https://github.com/WordPress/gutenberg/pull/37587)) + - Fix page list issues in overlay. ([37444](https://github.com/WordPress/gutenberg/pull/37444)) + - Show a UI warning when user does not have permission to update/edit an existing Navigation block. ([37286](https://github.com/WordPress/gutenberg/pull/37286)) + - Try cascading nav styles through classnames. ([37473](https://github.com/WordPress/gutenberg/pull/37473)) +- Query Loop: + - Fix editable post blocks in Query Loop with `zero` `queryId`. ([37629](https://github.com/WordPress/gutenberg/pull/37629)) + - Changed the letter case for Post Type to Post type. ([37499](https://github.com/WordPress/gutenberg/pull/37499)) + - Query Pagination Next: Hide block if custom query has no results. ([37553](https://github.com/WordPress/gutenberg/pull/37553)) + - Revert Query Pagination Next/Previous placeholder(36681). ([37520](https://github.com/WordPress/gutenberg/pull/37520)) +- Site Logo: Fix block alignment issues. ([36627](https://github.com/WordPress/gutenberg/pull/36627)) +- Gallery: Fix block registration hook priority. ([37409](https://github.com/WordPress/gutenberg/pull/37409)) +- Post Content/Title: Reflect changes when previewing post. ([37622](https://github.com/WordPress/gutenberg/pull/37622)) +- Post Excerpt: Specify paragraph as post excerpt tag name. ([37412](https://github.com/WordPress/gutenberg/pull/37412)) +- Reusable Block: Fix embed handling. ([37554](https://github.com/WordPress/gutenberg/pull/37554)) +- Site icon: Fix site icon styling to display non-square site icons within a square button. ([37570](https://github.com/WordPress/gutenberg/pull/37570)) +- Template Part: Only display a missing notice in debug mode. ([37404](https://github.com/WordPress/gutenberg/pull/37404)) +- ServerSideRender: Fix loading state. ([37623](https://github.com/WordPress/gutenberg/pull/37623)) +- Comments Avatar Block: Show avatar drag handles only when selected. ([37567](https://github.com/WordPress/gutenberg/pull/37567)) + +#### Global Styles + +- Color editor discards colors with default name. ([37496](https://github.com/WordPress/gutenberg/pull/37496)) +- Gradients are not being applied by class. ([37597](https://github.com/WordPress/gutenberg/pull/37597)) +- Impossible to edit theme and default colors. ([37497](https://github.com/WordPress/gutenberg/pull/37497)) +- Blank site editor when theme name contains a period. ([37167](https://github.com/WordPress/gutenberg/pull/37167)) +- Lower the specificity of font size CSS Custom Properties in the editor. ([37526](https://github.com/WordPress/gutenberg/pull/37526)) +- Use inset shadow on color indicators and adjust spacing. ([37500](https://github.com/WordPress/gutenberg/pull/37500)) + +#### Block Editor + +- Fix Enter handling for nested blocks. ([37453](https://github.com/WordPress/gutenberg/pull/37453)) +- Restrict delete multi selected blocks shortcut. ([37595](https://github.com/WordPress/gutenberg/pull/37595)) +- Avoid using CSS variables for block gap styles. ([37360](https://github.com/WordPress/gutenberg/pull/37360)) + +#### Themes + +- Add comment-form and comment-list to default html5 theme support. ([37536](https://github.com/WordPress/gutenberg/pull/37536)) +- Avoid Duplicated "Theme File Editor" menu. ([37592](https://github.com/WordPress/gutenberg/pull/37592)) +- Fix conditional check "Theme File Editor" menu. ([37616](https://github.com/WordPress/gutenberg/pull/37616)) +- Fix duotone theme cache. ([36236](https://github.com/WordPress/gutenberg/pull/36236)) + +#### Template Editor + +- Avoid undo issues when reset parent blocks for controlled blocks. ([37484](https://github.com/WordPress/gutenberg/pull/37484)) +- Change color of welcome dialog close icon so it is visible against black background. ([37435](https://github.com/WordPress/gutenberg/pull/37435)) +- Template Editing Mode: Fix options dropdown. ([37442](https://github.com/WordPress/gutenberg/pull/37442)) +- Try to fix auto resizing in template part focus mode. ([37394](https://github.com/WordPress/gutenberg/pull/37394)) +- Update the template list action labels. ([37576](https://github.com/WordPress/gutenberg/pull/37576)) + +#### Site Editor + +- Add customized indicator to plugin templates that have been customized. ([37329](https://github.com/WordPress/gutenberg/pull/37329)) +- Register block editor shortcuts. ([37577](https://github.com/WordPress/gutenberg/pull/37577)) +- Update regex to handle 404 template slug. ([37579](https://github.com/WordPress/gutenberg/pull/37579)) +- Parse shortcode blocks outside the content. ([37545](https://github.com/WordPress/gutenberg/pull/37545)) + +#### Accessibility + +- Editor: Focus when navigation toggle receives state false. ([37265](https://github.com/WordPress/gutenberg/pull/37265)) +- Navigation: Only add dialog role when modal is open. ([37434](https://github.com/WordPress/gutenberg/pull/37434)) + +#### npm Packages + +- Fix missing peer dependencies where React is used indirectly. ([37578](https://github.com/WordPress/gutenberg/pull/37578)) + +#### Testing + +- Fix flaky Navigation block end-to-end test by mocking out URL details endpoint to avoid 404. ([37501](https://github.com/WordPress/gutenberg/pull/37501)) + +#### Post Editor + +- Multi-entity saving: Allow publishing a post while not saving changes to non-post entities. ([37383](https://github.com/WordPress/gutenberg/pull/37383)) + +#### Components + +- ToolsPanel: Allow items to register when panelId is null. ([37273](https://github.com/WordPress/gutenberg/pull/37273)) + +#### Design Tools + +- Make block support tools panels compatible with multi-selection. ([37216](https://github.com/WordPress/gutenberg/pull/37216)) + +### Documentation + +#### Packages + +- Add automated core blocks documentation. ([36183](https://github.com/WordPress/gutenberg/pull/36183)) +- Added README for GradientPicker. ([37614](https://github.com/WordPress/gutenberg/pull/37614)) +- Add link to meta-block example in gutenberg-examples repo. ([37633](https://github.com/WordPress/gutenberg/pull/37633)) +- Fix parameter type in render function of file block. ([36262](https://github.com/WordPress/gutenberg/pull/36262)) +- Add changelog entry for \_\_experimentalIsRenderedInSidebar gradient components flag. ([37457](https://github.com/WordPress/gutenberg/pull/37457)) + +#### Handbook + +- Switch code distinction to JSX & Plain. ([37348](https://github.com/WordPress/gutenberg/pull/37348)) +- Fix a grammatical error in the Create Block tutorial. ([37636](https://github.com/WordPress/gutenberg/pull/37636)) +- Fix plugin sidebar tutorial not publishing. ([37505](https://github.com/WordPress/gutenberg/pull/37505)) +- Update plugin sidebar to new how to guide template. ([37490](https://github.com/WordPress/gutenberg/pull/37490)) +- Update "Local by Flywheel" name and URL. ([37512](https://github.com/WordPress/gutenberg/pull/37512)) +- Update Meta Boxes to a single page how to guide. ([37621](https://github.com/WordPress/gutenberg/pull/37621)) + +### Code Quality + +#### Compatibility with Core + +- Adds missing block template class properties. ([37556](https://github.com/WordPress/gutenberg/pull/37556)) + +#### Formatting + +- Fix lint issues. ([37618](https://github.com/WordPress/gutenberg/pull/37618)) +- Move block patterns compatibility code to lib/compat folder. ([37451](https://github.com/WordPress/gutenberg/pull/37451)) + +#### Packages + +- Data: + - Block top level useSetting paths. ([37428](https://github.com/WordPress/gutenberg/pull/37428)) + - Deprecate receiveUploadPermissions. ([37508](https://github.com/WordPress/gutenberg/pull/37508)) + +#### Site Editor + +- Remove dead code. ([37581](https://github.com/WordPress/gutenberg/pull/37581)) + +#### Components + +- Storybook: Tweak configuration for v6.4 update. ([37544](https://github.com/WordPress/gutenberg/pull/37544)) + +#### Security + +- Update `yargs` dependency for `@wordpress/env` to fix CVE-2021-3807. ([37601](https://github.com/WordPress/gutenberg/pull/37601)) + +### Tools + +#### Testing + +- End to end: + - Switch to using a $eval to fill user creation fields. ([37469](https://github.com/WordPress/gutenberg/pull/37469)) + - Fix and enable remaining navigation block end-to-end tests. ([37437](https://github.com/WordPress/gutenberg/pull/37437)) + - Add block editor shortcuts end-to-end tests. ([37624](https://github.com/WordPress/gutenberg/pull/37624)) + +#### Build Tooling + +- Add npm-run-all package to simplify running scripts. ([37558](https://github.com/WordPress/gutenberg/pull/37558)) +- Update caniuse to latest. ([37588](https://github.com/WordPress/gutenberg/pull/37588)) +- Fix pre commit hook to build block documentation. ([37613](https://github.com/WordPress/gutenberg/pull/37613)) + + = 12.2.0 = ### Enhancements diff --git a/docs/how-to-guides/metabox/meta-block.png b/docs/assets/meta-block.png similarity index 100% rename from docs/how-to-guides/metabox/meta-block.png rename to docs/assets/meta-block.png diff --git a/docs/getting-started/create-block/wp-plugin.md b/docs/getting-started/create-block/wp-plugin.md index 00feccb375d299..35456a90dc01c7 100644 --- a/docs/getting-started/create-block/wp-plugin.md +++ b/docs/getting-started/create-block/wp-plugin.md @@ -88,7 +88,7 @@ By default, the build scripts looks for `src/index.js` for the JavaScript file t ## Plugin to Load Script -To load the built script, so it is run within the editor, you need to tell WordPress about the script. This done in the init action in the `gutenpride.php` file. +To load the built script, so it is run within the editor, you need to tell WordPress about the script. This is done in the init action in the `gutenpride.php` file. ```php function create_block_gutenpride_block_init() { diff --git a/docs/how-to-guides/README.md b/docs/how-to-guides/README.md index 198108e5783167..1aeee6c5c3b877 100644 --- a/docs/how-to-guides/README.md +++ b/docs/how-to-guides/README.md @@ -24,9 +24,7 @@ You can also filter certain aspects of the editor; this is documented on the [Ed ## Meta Boxes -Porting PHP meta boxes to blocks or sidebar plugins is highly encouraged, learn how through these [meta data tutorials](/docs/how-to-guides/metabox/README.md). - -See how the new editor [supports existing Meta Boxes](/docs/reference-guides/backward-compatibility/meta-box.md). +Porting PHP meta boxes to blocks or sidebar plugins is highly encouraged, learn how in the [meta box](/docs/how-to-guides/metabox.md) and [sidebar plugin](/docs/how-to-guides/plugin-sidebar-0.md) guides. ## Theme Support diff --git a/docs/how-to-guides/backward-compatibility/meta-box.md b/docs/how-to-guides/backward-compatibility/meta-box.md deleted file mode 100644 index 28839e4256a683..00000000000000 --- a/docs/how-to-guides/backward-compatibility/meta-box.md +++ /dev/null @@ -1,80 +0,0 @@ -# Meta Boxes - -This is a brief document detailing how meta box support works in the block editor. With the superior developer and user experience of blocks, especially once block templates are available, **porting PHP meta boxes to blocks is highly encouraged!** See the [Meta Block tutorial](/docs/how-to-guides/metabox/meta-block-1-intro.md) for how to store post meta data using blocks. - -### Testing, Converting, and Maintaining Existing Meta Boxes - -Before converting meta boxes to blocks, it may be easier to test if a meta box works with the block editor, and explicitly mark it as such. - -If a meta box _doesn't_ work with the block editor, and updating it to work correctly is not an option, the next step is to add the `__block_editor_compatible_meta_box` argument to the meta box declaration: - -```php -add_meta_box( 'my-meta-box', 'My Meta Box', 'my_meta_box_callback', - null, 'normal', 'high', - array( - '__block_editor_compatible_meta_box' => false, - ) -); -``` - -WordPress won't show the meta box but a message saying that it isn't compatible with the block editor, including a link to the Classic Editor plugin. By default, `__block_editor_compatible_meta_box` is `true`. - -After a meta box is converted to a block, it can be declared as existing for backward compatibility: - -```php -add_meta_box( 'my-meta-box', 'My Meta Box', 'my_meta_box_callback', - null, 'normal', 'high', - array( - '__back_compat_meta_box' => true, - ) -); -``` - -When the block editor is used, this meta box will no longer be displayed in the meta box area, as it now only exists for backward compatibility purposes. It will continue to display correctly in the classic editor. - -### Meta Box Data Collection - -On each block editor page load, we register an action that collects the meta box data to determine if an area is empty. The original global state is reset upon collection of meta box data. - -See [`register_and_do_post_meta_boxes`](https://developer.wordpress.org/reference/functions/register_and_do_post_meta_boxes/). - -It will run through the functions and hooks that `post.php` runs to register meta boxes; namely `add_meta_boxes`, `add_meta_boxes_{$post->post_type}`, and `do_meta_boxes`. - -Meta boxes are filtered to strip out any core meta boxes, standard custom taxonomy meta boxes, and any meta boxes that have declared themselves as only existing for backward compatibility purposes. - -Then each location for this particular type of meta box is checked for whether it is active. If it is not empty a value of true is stored, if it is empty a value of false is stored. This meta box location data is then dispatched by the editor Redux store in `INITIALIZE_META_BOX_STATE`. - -Ideally, this could be done at instantiation of the editor and help simplify this flow. However, it is not possible to know the meta box state before `admin_enqueue_scripts`, where we are calling `initializeEditor()`. This will have to do, unless we want to move `initializeEditor()` to fire in the footer or at some point after `admin_head`. With recent changes to editor bootstrapping this might now be possible. Test with ACF to make sure. - -### Redux and React Meta Box Management - -When rendering the block editor, the meta boxes are rendered to a hidden div `#metaboxes`. - -_The Redux store will hold all meta boxes as inactive by default_. When -`INITIALIZE_META_BOX_STATE` comes in, the store will update any active meta box areas by setting the `isActive` flag to `true`. Once this happens React will check for the new props sent in by Redux on the `MetaBox` component. If that `MetaBox` is now active, instead of rendering null, a `MetaBoxArea` component will be rendered. The `MetaBox` component is the container component that mediates between the `MetaBoxArea` and the Redux Store. _If no meta boxes are active, nothing happens. This will be the default behavior, as all core meta boxes have been stripped._ - -#### MetaBoxArea Component - -When the component renders it will store a reference to the meta boxes container and retrieve the meta boxes HTML from the prefetch location. - -When the post is updated, only meta box areas that are active will be submitted. This prevents unnecessary requests. No extra revisions are created by the meta box submissions. A Redux action will trigger on `REQUEST_POST_UPDATE` for any active meta box. See `editor/effects.js`. The `REQUEST_META_BOX_UPDATES` action will set that meta box's state to `isUpdating`. The `isUpdating` prop will be sent into the `MetaBoxArea` and cause a form submission. - -When the meta box area is saving, we display an updating overlay, to prevent users from changing the form values while a save is in progress. - -An example save url would look like: - -`mysite.com/wp-admin/post.php?post=1&action=edit&meta-box-loader=1` - -This url is automatically passed into React via a `_wpMetaBoxUrl` global variable. - -This page mimics the `post.php` post form, so when it is submitted it will fire all of the normal hooks and actions, and have the proper global state to correctly fire any PHP meta box mumbo jumbo without needing to modify any existing code. On successful submission, React will signal a `handleMetaBoxReload` to remove the updating overlay. - -### Common Compatibility Issues - -Most PHP meta boxes should continue to work in the block editor, but some meta boxes that include advanced functionality could break. Here are some common reasons why meta boxes might not work as expected in the block editor: - -- Plugins relying on selectors that target the post title, post content fields, and other metaboxes (of the old editor). -- Plugins relying on TinyMCE's API because there's no longer a single TinyMCE instance to talk to in the block editor. -- Plugins making updates to their DOM on "submit" or on "save". - -Please also note that if your plugin triggers a PHP warning or notice to be output on the page, this will cause the HTML document type (``) to be output incorrectly. This will cause the browser to render using "Quirks Mode", which is a compatibility layer that gets enabled when the browser doesn't know what type of document it is parsing. The block editor is not meant to work in this mode, but it can _appear_ to be working just fine. If you encounter issues such as _meta boxes overlaying the editor_ or other layout issues, please check the raw page source of your document to see that the document type definition is the first thing output on the page. There will also be a warning in the JavaScript console, noting the issue. diff --git a/docs/how-to-guides/metabox.md b/docs/how-to-guides/metabox.md new file mode 100644 index 00000000000000..aaa858558a0462 --- /dev/null +++ b/docs/how-to-guides/metabox.md @@ -0,0 +1,261 @@ +# Meta Boxes + +## Overview + +Prior to the block editor, custom meta boxes were used to extend the editor. Now there are new ways to extend, giving more power to the developer and a better experience for the authors. It is recommended to port older custom meta boxes to one of these new methods to create a more unified and consistent experience for those using the editor. + +The block editor does support most existing meta boxes, see [the backward compatibility section below](#backward-compatibility) for details . + +If you are interested in working with the post meta outside the editor, check out the [Sidebar Tutorial](/docs/how-to-guides/sidebar-tutorial/plugin-sidebar-0.md). + +### Use Blocks to Store Meta + +Typically, blocks store attribute values in the serialized block HTML. However, you can also create a block that saves its attribute values as post meta, that can be accessed programmatically anywhere in your template. + +This guide shows how to create a block that prompts a user for a single value, and saves it to post meta. + +## Before you start + +This guide assumes you are already familiar with WordPress plugins, post meta, and basic JavaScript. Review the [Getting started with JavaScript tutorial](/docs/how-to-guides/javascript/README.md) for an introduction. + +The guide will walk through creating a basic block, but recommended to go through the [Create Block tutorial](/docs/getting-started/create-block/README.md) for a deeper understanding of creating custom blocks. + +You will need: + +- WordPress development environment, +- A minimal plugin activated and ready to edit +- JavaScript setup for building and enqueuing + +A [complete meta-block example](https://github.com/WordPress/gutenberg-examples/tree/trunk/meta-block) is available that you can use as a reference for your setup. + +## Step-by-step guide + +1. [Register Meta Field](#step-1-register-meta-field) +2. [Add Meta Block](#step-2-add-meta-block) +3. [Use Post Meta Data](#step-3-use-post-meta-data) +4. [Finishing Touches](#step-4-use-block-templates-optional) + +### Step 1: Register Meta Field + +A post meta field is a WordPress object used to store extra data about a post. You need to first register a new meta field prior to use. See Managing [Post Metadata](https://developer.wordpress.org/plugins/metadata/managing-post-metadata/) to learn more about post meta. + +When registering the field, note the `show_in_rest` parameter. This ensures the data will be included in the REST API, which the block editor uses to load and save meta data. See the [`register_post_meta`](https://developer.wordpress.org/reference/functions/register_post_meta/) function definition for extra information. + +Additionally, your post type needs to support `custom-fields` for `register_post_meta` function to work + +To register the field, add the following to your PHP plugin: + +```php + true, + 'single' => true, + 'type' => 'string', + ) ); +} +add_action( 'init', 'myguten_register_post_meta' ); +``` + +### Step 2: Add Meta Block + +With the meta field registered in the previous step, next create a new block to display the field value to the user. + +The hook `useEntityProp` can be used by the blocks to get or change meta values. + +Add this code to the JavaScript `src/index.js`: + +```js +import { registerBlockType } from '@wordpress/blocks'; +import { TextControl } from '@wordpress/components'; +import { useSelect } from '@wordpress/data'; +import { useEntityProp } from '@wordpress/core-data'; +import { useBlockProps } from '@wordpress/block-editor'; + +registerBlockType( 'myguten/meta-block', { + edit: ( { setAttributes, attributes } ) => { + const blockProps = useBlockProps(); + const postType = useSelect( + ( select ) => select( 'core/editor' ).getCurrentPostType(), + [] + ); + + const [ meta, setMeta ] = useEntityProp( 'postType', postType, 'meta' ); + + const metaFieldValue = meta[ 'myguten_meta_block_field' ]; + const updateMetaValue = ( newValue ) => { + setMeta( { ...meta, myguten_meta_block_field: newValue } ); + }; + + return ( +
+ +
+ ); + }, + + // No information saved to the block. + // Data is saved to post meta via the hook. + save: () => { + return null; + }, +} ); +``` + +Confirm this works by creating a post and add the Meta Block. You will see your field that you can type a value in. When you save the post, either as a draft or published, the post meta value will be saved too. You can verify by +saving and reloading your draft, the form will still be filled in on reload. + +You could also confirm the data is saved by checking the database table `wp_postmeta` and confirm the new post id contains the new field data. + +**Troubleshooting**: Be sure to build your code between changes, you updated the PHP code from Step 1, and JavaScript files are enqueued. Check the build output and developer console for errors. + +### Step 3: Use Post Meta Data + +You can use the post meta data stored in the last step in multiple ways. + +#### Use Post Meta in PHP + +The first example uses the value from the post meta field and appends it to the end of the post content wrapped in a `H4` tag. + +```php +function myguten_content_filter( $content ) { + $value = get_post_meta( get_the_ID(), 'myguten_meta_block_field', true ); + if ( $value ) { + return sprintf( "%s

%s

", $content, esc_html( $value ) ); + } else { + return $content; + } +} +add_filter( 'the_content', 'myguten_content_filter' ); +``` + +#### Use Post Meta in Block + +You can also use the post meta data in other blocks. For this example the data is loaded at the end of every Paragraph block when it is rendered, ie. shown to the user. You can replace this for any core or custom block types as needed. + +In PHP, use the [register_block_type](https://developer.wordpress.org/reference/functions/register_block_type/) function to set a callback when the block is rendered to include the meta value. + +```php +function myguten_render_paragraph( $block_attributes, $content ) { + $value = get_post_meta( get_the_ID(), 'myguten_meta_block_field', true ); + // check value is set before outputting + if ( $value ) { + return sprintf( "%s (%s)", $content, esc_html( $value ) ); + } else { + return $content; + } +} + +register_block_type( 'core/paragraph', array( + 'api_version' => 2, + 'render_callback' => 'myguten_render_paragraph', +) ); +``` + +### Step 4: Use Block Templates (optional) + +One problem using a meta block is the block is easy for an author to forget, since it requires being added to each post. You solve this by using [block templates](/docs/reference-guides/block-api/block-templates.md). A block template is a predefined list of block items per post type. Templates allow you to specify a default initial state for a post type. + +For this example, you use a template to automatically insert the meta block at the top of a post. + +Add the following code to the `myguten-meta-block.php` file: + +```php +function myguten_register_template() { + $post_type_object = get_post_type_object( 'post' ); + $post_type_object->template = array( + array( 'myguten/meta-block' ), + ); +} +add_action( 'init', 'myguten_register_template' ); +``` + +You can also add other block types in the array, including placeholders, or even lock down a post to a set of specific blocks. Templates are a powerful tool for controlling the editing experience, see the documentation linked above for more. + +## Conclusion + +This guide showed how using blocks you can read and write to post meta. See the section below for backward compatibility with existing meta boxes. + +## Backward Compatibility + +### Testing, Converting, and Maintaining Existing Meta Boxes + +Before converting meta boxes to blocks, it may be easier to test if a meta box works with the block editor, and explicitly mark it as such. + +If a meta box _doesn't_ work with the block editor, and updating it to work correctly is not an option, the next step is to add the `__block_editor_compatible_meta_box` argument to the meta box declaration: + +```php +add_meta_box( 'my-meta-box', 'My Meta Box', 'my_meta_box_callback', + null, 'normal', 'high', + array( + '__block_editor_compatible_meta_box' => false, + ) +); +``` + +WordPress won't show the meta box but a message saying that it isn't compatible with the block editor, including a link to the Classic Editor plugin. By default, `__block_editor_compatible_meta_box` is `true`. + +After a meta box is converted to a block, it can be declared as existing for backward compatibility: + +```php +add_meta_box( 'my-meta-box', 'My Meta Box', 'my_meta_box_callback', + null, 'normal', 'high', + array( + '__back_compat_meta_box' => true, + ) +); +``` + +When the block editor is used, this meta box will no longer be displayed in the meta box area, as it now only exists for backward compatibility purposes. It will display as before in the classic editor. + +### Meta Box Data Collection + +On each block editor page load, we register an action that collects the meta box data to determine if an area is empty. The original global state is reset upon collection of meta box data. + +See [`register_and_do_post_meta_boxes`](https://developer.wordpress.org/reference/functions/register_and_do_post_meta_boxes/). + +It will run through the functions and hooks that `post.php` runs to register meta boxes; namely `add_meta_boxes`, `add_meta_boxes_{$post->post_type}`, and `do_meta_boxes`. + +Meta boxes are filtered to strip out any core meta boxes, standard custom taxonomy meta boxes, and any meta boxes that have declared themselves as only existing for backward compatibility purposes. + +Then each location for this particular type of meta box is checked for whether it is active. If it is not empty a value of true is stored, if it is empty a value of false is stored. This meta box location data is then dispatched by the editor Redux store in `INITIALIZE_META_BOX_STATE`. + +Ideally, this could be done at instantiation of the editor and help simplify this flow. However, it is not possible to know the meta box state before `admin_enqueue_scripts`, where we are calling `initializeEditor()`. This will have to do, unless we want to move `initializeEditor()` to fire in the footer or at some point after `admin_head`. With recent changes to editor bootstrapping this might now be possible. Test with ACF to make sure. + +### Redux and React Meta Box Management + +When rendering the block editor, the meta boxes are rendered to a hidden div `#metaboxes`. + +_The Redux store will hold all meta boxes as inactive by default_. When +`INITIALIZE_META_BOX_STATE` comes in, the store will update any active meta box areas by setting the `isActive` flag to `true`. Once this happens React will check for the new props sent in by Redux on the `MetaBox` component. If that `MetaBox` is now active, instead of rendering null, a `MetaBoxArea` component will be rendered. The `MetaBox` component is the container component that mediates between the `MetaBoxArea` and the Redux Store. _If no meta boxes are active, nothing happens. This will be the default behavior, as all core meta boxes have been stripped._ + +#### MetaBoxArea Component + +When the component renders it will store a reference to the meta boxes container and retrieve the meta boxes HTML from the prefetch location. + +When the post is updated, only meta box areas that are active will be submitted. This prevents unnecessary requests. No extra revisions are created by the meta box submissions. A Redux action will trigger on `REQUEST_POST_UPDATE` for any active meta box. See `editor/effects.js`. The `REQUEST_META_BOX_UPDATES` action will set that meta box's state to `isUpdating`. The `isUpdating` prop will be sent into the `MetaBoxArea` and cause a form submission. + +When the meta box area is saving, we display an updating overlay, to prevent users from changing the form values while a save is in progress. + +An example save url would look like: + +`mysite.com/wp-admin/post.php?post=1&action=edit&meta-box-loader=1` + +This url is automatically passed into React via a `_wpMetaBoxUrl` global variable. + +This page mimics the `post.php` post form, so when it is submitted it will fire all of the normal hooks and actions, and have the proper global state to correctly fire any PHP meta box mumbo jumbo without needing to modify any existing code. On successful submission, React will signal a `handleMetaBoxReload` to remove the updating overlay. + +### Common Compatibility Issues + +Most PHP meta boxes should continue to work in the block editor, but some meta boxes that include advanced functionality could break. Here are some common reasons why meta boxes might not work as expected in the block editor: + +- Plugins relying on selectors that target the post title, post content fields, and other metaboxes (of the old editor). +- Plugins relying on TinyMCE's API because there's no longer a single TinyMCE instance to talk to in the block editor. +- Plugins making updates to their DOM on "submit" or on "save". + +Please also note that if your plugin triggers a PHP warning or notice to be output on the page, this will cause the HTML document type (``) to be output incorrectly. This will cause the browser to render using "Quirks Mode", which is a compatibility layer that gets enabled when the browser doesn't know what type of document it is parsing. The block editor is not meant to work in this mode, but it can _appear_ to be working just fine. If you encounter issues such as _meta boxes overlaying the editor_ or other layout issues, please check the raw page source of your document to see that the document type definition is the first thing output on the page. There will also be a warning in the JavaScript console, noting the issue. diff --git a/docs/how-to-guides/metabox/README.md b/docs/how-to-guides/metabox/README.md deleted file mode 100644 index a5e7917035f846..00000000000000 --- a/docs/how-to-guides/metabox/README.md +++ /dev/null @@ -1,17 +0,0 @@ -# Meta Boxes - -Prior to the block editor, custom meta boxes were used to extend the editor. With the new editor there are new ways to extend, giving more power to the developer and a better experience for the authors. Porting older custom meta boxes to one of these new methods is encouraged as to create a more unified and consistent experience for those using the editor. - -The new block editor does support most existing meta boxes, see [this backward compatibility article](/docs/reference-guides/backward-compatibility/meta-box.md) for more support details . - -Here are two mini-tutorials for creating similar functionality to meta boxes in the block editor. - -## Use Blocks to Store Meta - -The first method is to use Blocks to store extra data with a post. The data is stored in a post meta field, similar to how meta boxes store information. - -- [Store Post Meta with a Block](/docs/how-to-guides/metabox/meta-block-1-intro.md) - -## Sidebar Plugin - -If you are interested in working with the post meta outside the editor, check out the [Sidebar Tutorial](/docs/how-to-guides/sidebar-tutorial/plugin-sidebar-0.md). diff --git a/docs/how-to-guides/metabox/meta-block-1-intro.md b/docs/how-to-guides/metabox/meta-block-1-intro.md deleted file mode 100644 index 5111ca356972cd..00000000000000 --- a/docs/how-to-guides/metabox/meta-block-1-intro.md +++ /dev/null @@ -1,16 +0,0 @@ -# Store Post Meta with a Block - -Typically, blocks store their attribute values in the serialised block HTML. However, you can also create a block that saves its attribute values as post meta, which can be accessed programmatically anywhere in your template. - -In this short tutorial you will create one of these blocks, which will prompt a user for a single value, and save it as post meta. - -For background around the thinking of blocks as the interface, please see the [key concepts section](/docs/explanations/architecture/key-concepts.md) of the handbook. - -Before starting this tutorial, you will need a plugin to hold your code. Please take a look at the first two steps of [the JavaScript tutorial](/docs/how-to-guides/javascript/README.md) for information setting up a plugin. - -## Table of Contents - -1. [Register Meta Field](/docs/how-to-guides/metabox/meta-block-2-register-meta.md) -2. [Add Meta Block](/docs/how-to-guides/metabox/meta-block-3-add.md) -3. [Use Post Meta Data](/docs/how-to-guides/metabox/meta-block-4-use-data.md) -4. [Finishing Touches](/docs/how-to-guides/metabox/meta-block-5-finishing.md) diff --git a/docs/how-to-guides/metabox/meta-block-2-register-meta.md b/docs/how-to-guides/metabox/meta-block-2-register-meta.md deleted file mode 100644 index 5b22366dbdd41a..00000000000000 --- a/docs/how-to-guides/metabox/meta-block-2-register-meta.md +++ /dev/null @@ -1,39 +0,0 @@ -# Register Meta Field - -A post meta field is a WordPress object used to store extra data about a post. You need to first register a new meta field prior to use. See Managing [Post Metadata](https://developer.wordpress.org/plugins/metadata/managing-post-metadata/) to learn more about post meta. - -When registering the field, note the `show_in_rest` parameter. This ensures the data will be included in the REST API, which the block editor uses to load and save meta data. See the [`register_post_meta`](https://developer.wordpress.org/reference/functions/register_post_meta/) function definition for extra information. - -Additionally, your post type needs to support `custom-fields` for `register_post_meta` function to work - -To register the field, create a PHP plugin file called `myguten-meta-block.php` including: - -```php - true, - 'single' => true, - 'type' => 'string', - ) ); -} -add_action( 'init', 'myguten_register_post_meta' ); -``` - -**Note:** If the meta key name starts with an underscore WordPress considers it a protected field. Editing this field requires passing a permission check, which is set as the `auth_callback` in the `register_post_meta` function. Here is an example: - -```php -register_post_meta( 'post', '_myguten_protected_key', array( - 'show_in_rest' => true, - 'single' => true, - 'type' => 'string', - 'auth_callback' => function() { - return current_user_can( 'edit_posts' ); - } -) ); -``` diff --git a/docs/how-to-guides/metabox/meta-block-3-add.md b/docs/how-to-guides/metabox/meta-block-3-add.md deleted file mode 100644 index c3c4f576cd18b2..00000000000000 --- a/docs/how-to-guides/metabox/meta-block-3-add.md +++ /dev/null @@ -1,130 +0,0 @@ -# Create Meta Block - -With the meta field registered in the previous step, next you will create a new block used to display the field value to the user. See the [Block Tutorial](/docs/how-to-guides/block-tutorial/README.md) for a deeper understanding of creating custom blocks. - -For this block, you will use the TextControl component, which is similar to an HTML input text field. For additional components, check out the [Component Reference](/packages/components/README.md). - -The hook `useEntityProp` can be used by the blocks to get or change meta values. - -Add this code to your JavaScript file (this tutorial will call the file `myguten.js`): - -{% codetabs %} -{% JSX %} - -```js -import { registerBlockType } from '@wordpress/blocks'; -import { TextControl } from '@wordpress/components'; -import { useSelect } from '@wordpress/data'; -import { useEntityProp } from '@wordpress/core-data'; -import { useBlockProps } from '@wordpress/block-editor'; - -registerBlockType( 'myguten/meta-block', { - title: 'Meta Block', - icon: 'smiley', - category: 'text', - - edit( { setAttributes, attributes } ) { - const blockProps = useBlockProps(); - const postType = useSelect( - ( select ) => select( 'core/editor' ).getCurrentPostType(), - [] - ); - const [ meta, setMeta ] = useEntityProp( 'postType', postType, 'meta' ); - const metaFieldValue = meta[ 'myguten_meta_block_field' ]; - function updateMetaValue( newValue ) { - setMeta( { ...meta, myguten_meta_block_field: newValue } ); - } - - return ( -
- -
- ); - }, - - // No information saved to the block - // Data is saved to post meta via the hook - save() { - return null; - }, -} ); -``` - -{% Plain %} - -```js -( function ( wp ) { - var el = wp.element.createElement; - var registerBlockType = wp.blocks.registerBlockType; - var TextControl = wp.components.TextControl; - var useSelect = wp.data.useSelect; - var useEntityProp = wp.coreData.useEntityProp; - var useBlockProps = wp.blockEditor.useBlockProps; - - registerBlockType( 'myguten/meta-block', { - title: 'Meta Block', - icon: 'smiley', - category: 'text', - - edit: function ( props ) { - var blockProps = useBlockProps(); - var postType = useSelect( function ( select ) { - return select( 'core/editor' ).getCurrentPostType(); - }, [] ); - var entityProp = useEntityProp( 'postType', postType, 'meta' ); - var meta = entityProp[ 0 ]; - var setMeta = entityProp[ 1 ]; - - var metaFieldValue = meta[ 'myguten_meta_block_field' ]; - function updateMetaValue( newValue ) { - setMeta( - Object.assign( {}, meta, { - myguten_meta_block_field: newValue, - } ) - ); - } - - return el( - 'div', - blockProps, - el( TextControl, { - label: 'Meta Block Field', - value: metaFieldValue, - onChange: updateMetaValue, - } ) - ); - }, - - // No information saved to the block - // Data is saved to post meta via attributes - save: function () { - return null; - }, - } ); -} )( window.wp ); -``` - -{% end %} - -**Important:** Before you test, you need to enqueue your JavaScript file and its dependencies. Note the WordPress packages used above are `wp.element`, `wp.blocks`, `wp.components`, `wp.data`, and `wp.coreData`. Each of these need to be included in the array of dependencies. Update the `myguten-meta-block.php` file adding the enqueue function: - -```php -function myguten_enqueue() { - wp_enqueue_script( - 'myguten-script', - plugins_url( 'myguten.js', __FILE__ ), - array( 'wp-blocks', 'wp-element', 'wp-components', 'wp-data', 'wp-core-data', 'wp-block-editor' ) - ); -} -add_action( 'enqueue_block_editor_assets', 'myguten_enqueue' ); -``` - -You can now edit a draft post and add a Meta Block to the post. You will see your field that you can type a value in. When you save the post, either as a draft or published, the post meta value will be saved too. You can verify by saving and reloading your draft, the form will still be filled in on reload. - -![Meta Block](https://raw.githubusercontent.com/WordPress/gutenberg/HEAD/docs/how-to-guides/metabox/meta-block.png) - -You can now use the post meta data in a template, or another block. See next section for [using post meta data](/docs/how-to-guides/metabox/meta-block-4-use-data.md). You could also confirm the data is saved by checking the database table `wp_postmeta` and confirm the new post id contains the new field data. diff --git a/docs/how-to-guides/metabox/meta-block-4-use-data.md b/docs/how-to-guides/metabox/meta-block-4-use-data.md deleted file mode 100644 index b445e07c0a8a09..00000000000000 --- a/docs/how-to-guides/metabox/meta-block-4-use-data.md +++ /dev/null @@ -1,42 +0,0 @@ -# Use Post Meta Data - -You can use the post meta data stored in the last step in multiple ways. - -## Use Post Meta in PHP - -The first example uses the value from the post meta field and appends it to the end of the post content wrapped in a H4 tag. This method in PHP is unchanged in WordPress 5.0. - -```php -function myguten_content_filter( $content ) { - $value = get_post_meta( get_the_ID(), 'myguten_meta_block_field', true ); - if ( $value ) { - return sprintf( "%s

%s

", $content, esc_html( $value ) ); - } else { - return $content; - } -} -add_filter( 'the_content', 'myguten_content_filter' ); -``` - -## Use Post Meta in Block - -You can also use the post meta data in other blocks. For this example the data is loaded at the end of every Paragraph block when it is rendered, ie. shown to the user. You can replace this for any core or custom block types as needed. - -In PHP, use the [register_block_type](https://developer.wordpress.org/reference/functions/register_block_type/) function to set a callback when the block is rendered to include the meta value. - -```php -function myguten_render_paragraph( $block_attributes, $content ) { - $value = get_post_meta( get_the_ID(), 'myguten_meta_block_field', true ); - // check value is set before outputting - if ( $value ) { - return sprintf( "%s (%s)", $content, esc_html( $value ) ); - } else { - return $content; - } -} - -register_block_type( 'core/paragraph', array( - 'api_version' => 2, - 'render_callback' => 'myguten_render_paragraph', -) ); -``` diff --git a/docs/how-to-guides/metabox/meta-block-5-finishing.md b/docs/how-to-guides/metabox/meta-block-5-finishing.md deleted file mode 100644 index d190369c43fae1..00000000000000 --- a/docs/how-to-guides/metabox/meta-block-5-finishing.md +++ /dev/null @@ -1,19 +0,0 @@ -# Finishing Touches - -One problem using a meta block is the block is easy for an author to forget, since it requires being added to each post. You solve this by using [block templates](/docs/reference-guides/block-api/block-templates.md). A block template is a predefined list of block items per post type. Templates allow you to specify a default initial state for a post type. - -For this example, you use a template to automatically insert the meta block at the top of a post. - -Add the following code to the `myguten-meta-block.php` file: - -```php -function myguten_register_template() { - $post_type_object = get_post_type_object( 'post' ); - $post_type_object->template = array( - array( 'myguten/meta-block' ), - ); -} -add_action( 'init', 'myguten_register_template' ); -``` - -You can also add other block types in the array, including placeholders, or even lock down a post to a set of specific blocks. Templates are a powerful tool for controlling the editing experience, see the documentation linked above for more. diff --git a/docs/manifest.json b/docs/manifest.json index 0581a58e0fdbd5..f02508a1b71173 100644 --- a/docs/manifest.json +++ b/docs/manifest.json @@ -107,12 +107,6 @@ "markdown_source": "../docs/how-to-guides/backward-compatibility/deprecations.md", "parent": "backward-compatibility" }, - { - "title": "Meta Boxes", - "slug": "meta-box", - "markdown_source": "../docs/how-to-guides/backward-compatibility/meta-box.md", - "parent": "backward-compatibility" - }, { "title": "Blocks", "slug": "block-tutorial", @@ -284,39 +278,9 @@ { "title": "Meta Boxes", "slug": "metabox", - "markdown_source": "../docs/how-to-guides/metabox/README.md", + "markdown_source": "../docs/how-to-guides/metabox.md", "parent": "how-to-guides" }, - { - "title": "Store Post Meta with a Block", - "slug": "meta-block-1-intro", - "markdown_source": "../docs/how-to-guides/metabox/meta-block-1-intro.md", - "parent": "metabox" - }, - { - "title": "Register Meta Field", - "slug": "meta-block-2-register-meta", - "markdown_source": "../docs/how-to-guides/metabox/meta-block-2-register-meta.md", - "parent": "metabox" - }, - { - "title": "Create Meta Block", - "slug": "meta-block-3-add", - "markdown_source": "../docs/how-to-guides/metabox/meta-block-3-add.md", - "parent": "metabox" - }, - { - "title": "Use Post Meta Data", - "slug": "meta-block-4-use-data", - "markdown_source": "../docs/how-to-guides/metabox/meta-block-4-use-data.md", - "parent": "metabox" - }, - { - "title": "Finishing Touches", - "slug": "meta-block-5-finishing", - "markdown_source": "../docs/how-to-guides/metabox/meta-block-5-finishing.md", - "parent": "metabox" - }, { "title": "Notices", "slug": "notices", @@ -869,6 +833,12 @@ "markdown_source": "../packages/components/src/form-token-field/README.md", "parent": "components" }, + { + "title": "GradientPicker", + "slug": "gradient-picker", + "markdown_source": "../packages/components/src/gradient-picker/README.md", + "parent": "components" + }, { "title": "Grid", "slug": "grid", diff --git a/docs/reference-guides/block-api/block-attributes.md b/docs/reference-guides/block-api/block-attributes.md index de9b6e9bc139e4..78329b5823e199 100644 --- a/docs/reference-guides/block-api/block-attributes.md +++ b/docs/reference-guides/block-api/block-attributes.md @@ -343,7 +343,7 @@ Attribute available in the block: ## Meta (deprecated)
-Although attributes may be obtained from a post's meta, meta attribute sources are considered deprecated; EntityProvider and related hook APIs should be used instead, as shown in the Create Meta Block how-to. +Although attributes may be obtained from a post's meta, meta attribute sources are considered deprecated; EntityProvider and related hook APIs should be used instead, as shown in the Create Meta Block how-to.
Attributes may be obtained from a post's meta rather than from the block's representation in saved post content. For this, an attribute is required to specify its corresponding meta key under the `meta` key: diff --git a/docs/reference-guides/block-api/block-templates.md b/docs/reference-guides/block-api/block-templates.md index 343a27d1c00e1b..a565eec59b5059 100644 --- a/docs/reference-guides/block-api/block-templates.md +++ b/docs/reference-guides/block-api/block-templates.md @@ -59,7 +59,7 @@ registerBlockType( 'myplugin/template', { } ); ``` -See the [Meta Block Tutorial](/docs/how-to-guides/metabox/meta-block-5-finishing.md) for a full example of a template in use. +See the [Meta Block Tutorial](/docs/how-to-guides/metabox.md#step-4-finishing-touches) for a full example of a template in use. ## Block Attributes diff --git a/docs/reference-guides/core-blocks.md b/docs/reference-guides/core-blocks.md index b4cfb0f110caa9..1b460219d5fda6 100644 --- a/docs/reference-guides/core-blocks.md +++ b/docs/reference-guides/core-blocks.md @@ -95,7 +95,7 @@ Display content in multiple columns, with blocks added to each column. - **Name:** core/columns - **Category:** design -- **Supports:** align (full, wide), anchor, color (background, gradients, link, text), spacing (blockGap, margin, padding), ~~html~~ +- **Supports:** align (full, wide), anchor, color (background, gradients, link, text), spacing (margin, padding), ~~html~~ - **Attributes:** isStackedOnMobile, verticalAlignment ## Comment Author Avatar @@ -365,7 +365,7 @@ A collection of blocks that allow visitors to get around your site. - **Name:** core/navigation - **Category:** theme -- **Supports:** align (full, wide), anchor, inserter, spacing (blockGap, units), typography (fontSize, lineHeight), ~~html~~ +- **Supports:** align (full, wide), anchor, inserter, spacing (units), typography (fontSize, lineHeight), ~~html~~ - **Attributes:** __unstableLocation, backgroundColor, customBackgroundColor, customOverlayBackgroundColor, customOverlayTextColor, customTextColor, openSubmenusOnClick, overlayBackgroundColor, overlayMenu, overlayTextColor, ref, rgbBackgroundColor, rgbTextColor, showSubmenuIcon, textColor ## Navigation Area diff --git a/docs/reference-guides/data/data-core.md b/docs/reference-guides/data/data-core.md index 8bf9b08c273548..428b2c1a100f72 100644 --- a/docs/reference-guides/data/data-core.md +++ b/docs/reference-guides/data/data-core.md @@ -636,6 +636,8 @@ _Returns_ ### receiveUploadPermissions +> **Deprecated** since WP 5.9, use receiveUserPermission instead. + Returns an action object used in signalling that Upload permissions have been received. _Parameters_ diff --git a/docs/toc.json b/docs/toc.json index 35186a8579a4c3..ab49003a7a7ca4 100644 --- a/docs/toc.json +++ b/docs/toc.json @@ -48,9 +48,6 @@ "docs/how-to-guides/backward-compatibility/README.md": [ { "docs/how-to-guides/backward-compatibility/deprecations.md": [] - }, - { - "docs/how-to-guides/backward-compatibility/meta-box.md": [] } ] }, @@ -122,19 +119,7 @@ }, { "docs/how-to-guides/internationalization.md": [] }, { - "docs/how-to-guides/metabox/README.md": [ - { "docs/how-to-guides/metabox/meta-block-1-intro.md": [] }, - { - "docs/how-to-guides/metabox/meta-block-2-register-meta.md": [] - }, - { "docs/how-to-guides/metabox/meta-block-3-add.md": [] }, - { - "docs/how-to-guides/metabox/meta-block-4-use-data.md": [] - }, - { - "docs/how-to-guides/metabox/meta-block-5-finishing.md": [] - } - ] + "docs/how-to-guides/metabox.md": [] }, { "docs/how-to-guides/notices/README.md": [] }, { "docs/how-to-guides/plugin-sidebar-0.md": [] }, diff --git a/lib/block-supports/layout.php b/lib/block-supports/layout.php index fd2a84c84ea5f7..5ed5f2f16ae754 100644 --- a/lib/block-supports/layout.php +++ b/lib/block-supports/layout.php @@ -31,10 +31,11 @@ function gutenberg_register_layout_support( $block_type ) { * @param string $selector CSS selector. * @param array $layout Layout object. The one that is passed has already checked the existance of default block layout. * @param boolean $has_block_gap_support Whether the theme has support for the block gap. + * @param string $gap_value The block gap value to apply. * * @return string CSS style. */ -function gutenberg_get_layout_style( $selector, $layout, $has_block_gap_support = false ) { +function gutenberg_get_layout_style( $selector, $layout, $has_block_gap_support = false, $gap_value = null ) { $layout_type = isset( $layout['type'] ) ? $layout['type'] : 'default'; $style = ''; @@ -65,8 +66,9 @@ function gutenberg_get_layout_style( $selector, $layout, $has_block_gap_support $style .= "$selector .alignleft { float: left; margin-right: 2em; }"; $style .= "$selector .alignright { float: right; margin-left: 2em; }"; if ( $has_block_gap_support ) { - $style .= "$selector > * { margin-top: 0; margin-bottom: 0; }"; - $style .= "$selector > * + * { margin-top: var( --wp--style--block-gap ); margin-bottom: 0; }"; + $gap_style = $gap_value ? $gap_value : 'var( --wp--style--block-gap )'; + $style .= "$selector > * { margin-top: 0; margin-bottom: 0; }"; + $style .= "$selector > * + * { margin-top: $gap_style; margin-bottom: 0; }"; } } elseif ( 'flex' === $layout_type ) { $layout_orientation = isset( $layout['orientation'] ) ? $layout['orientation'] : 'horizontal'; @@ -89,7 +91,8 @@ function gutenberg_get_layout_style( $selector, $layout, $has_block_gap_support $style = "$selector {"; $style .= 'display: flex;'; if ( $has_block_gap_support ) { - $style .= 'gap: var( --wp--style--block-gap, 0.5em );'; + $gap_style = $gap_value ? $gap_value : 'var( --wp--style--block-gap, 0.5em )'; + $style .= "gap: $gap_style;"; } else { $style .= 'gap: 0.5em;'; } @@ -145,8 +148,13 @@ function gutenberg_render_layout_support_flag( $block_content, $block ) { $used_layout = $default_layout; } - $id = uniqid(); - $style = gutenberg_get_layout_style( ".wp-container-$id", $used_layout, $has_block_gap_support ); + $id = uniqid(); + $gap_value = _wp_array_get( $block, array( 'attrs', 'style', 'spacing', 'blockGap' ) ); + // Skip if gap value contains unsupported characters. + // Regex for CSS value borrowed from `safecss_filter_attr`, and used here + // because we only want to match against the value, not the CSS attribute. + $gap_value = preg_match( '%[\\\(&=}]|/\*%', $gap_value ) ? null : $gap_value; + $style = gutenberg_get_layout_style( ".wp-container-$id", $used_layout, $has_block_gap_support, $gap_value ); // This assumes the hook only applies to blocks with a single wrapper. // I think this is a reasonable limitation for that particular hook. $content = preg_replace( diff --git a/lib/block-supports/spacing.php b/lib/block-supports/spacing.php index ca7b77f43864b9..78f5b59f90fb04 100644 --- a/lib/block-supports/spacing.php +++ b/lib/block-supports/spacing.php @@ -90,57 +90,6 @@ function gutenberg_skip_spacing_serialization( $block_type ) { $spacing_support['__experimentalSkipSerialization']; } - -/** - * Renders the spacing gap support to the block wrapper, to ensure - * that the CSS variable is rendered in all environments. - * - * @param string $block_content Rendered block content. - * @param array $block Block object. - * @return string Filtered block content. - */ -function gutenberg_render_spacing_gap_support( $block_content, $block ) { - $block_type = WP_Block_Type_Registry::get_instance()->get_registered( $block['blockName'] ); - $has_gap_support = gutenberg_block_has_support( $block_type, array( 'spacing', 'blockGap' ), false ); - if ( ! $has_gap_support || ! isset( $block['attrs']['style']['spacing']['blockGap'] ) ) { - return $block_content; - } - - $gap_value = $block['attrs']['style']['spacing']['blockGap']; - - // Skip if gap value contains unsupported characters. - // Regex for CSS value borrowed from `safecss_filter_attr`, and used here - // because we only want to match against the value, not the CSS attribute. - if ( preg_match( '%[\\\(&=}]|/\*%', $gap_value ) ) { - return $block_content; - } - - $style = sprintf( - '--wp--style--block-gap: %s', - esc_attr( $gap_value ) - ); - - // Attempt to update an existing style attribute on the wrapper element. - $injected_style = preg_replace( - '/^([^>.]+?)(' . preg_quote( 'style="', '/' ) . ')(?=.+?>)/', - '$1$2' . $style . '; ', - $block_content, - 1 - ); - - // If there is no existing style attribute, add one to the wrapper element. - if ( $injected_style === $block_content ) { - $injected_style = preg_replace( - '/<([a-zA-Z0-9]+)([ >])/', - '<$1 style="' . $style . '"$2', - $block_content, - 1 - ); - }; - - return $injected_style; -} - // Register the block support. WP_Block_Supports::get_instance()->register( 'spacing', @@ -149,5 +98,3 @@ function gutenberg_render_spacing_gap_support( $block_content, $block ) { 'apply' => 'gutenberg_apply_spacing_support', ) ); - -add_filter( 'render_block', 'gutenberg_render_spacing_gap_support', 10, 2 ); diff --git a/lib/compat/wordpress-5.9/class-wp-theme-json-gutenberg.php b/lib/compat/wordpress-5.9/class-wp-theme-json-gutenberg.php index c223b9ac96f414..83d9508fb59565 100644 --- a/lib/compat/wordpress-5.9/class-wp-theme-json-gutenberg.php +++ b/lib/compat/wordpress-5.9/class-wp-theme-json-gutenberg.php @@ -285,7 +285,7 @@ class WP_Theme_JSON_Gutenberg { 'spacing' => array( 'margin' => null, 'padding' => null, - 'blockGap' => null, + 'blockGap' => 'top', ), 'typography' => array( 'fontFamily' => null, @@ -428,17 +428,28 @@ private static function sanitize( $input, $valid_block_names, $valid_element_nam $output = array_intersect_key( $input, array_flip( self::VALID_TOP_LEVEL_KEYS ) ); + // Some styles are only meant to be available at the top-level (e.g.: blockGap), + // hence, the schema for blocks & elements should not have them. + $styles_non_top_level = self::VALID_STYLES; + foreach ( array_keys( $styles_non_top_level ) as $section ) { + foreach ( array_keys( $styles_non_top_level[ $section ] ) as $prop ) { + if ( 'top' === $styles_non_top_level[ $section ][ $prop ] ) { + unset( $styles_non_top_level[ $section ][ $prop ] ); + } + } + } + // Build the schema based on valid block & element names. $schema = array(); $schema_styles_elements = array(); foreach ( $valid_element_names as $element ) { - $schema_styles_elements[ $element ] = self::VALID_STYLES; + $schema_styles_elements[ $element ] = $styles_non_top_level; } $schema_styles_blocks = array(); $schema_settings_blocks = array(); foreach ( $valid_block_names as $block ) { $schema_settings_blocks[ $block ] = self::VALID_SETTINGS; - $schema_styles_blocks[ $block ] = self::VALID_STYLES; + $schema_styles_blocks[ $block ] = $styles_non_top_level; $schema_styles_blocks[ $block ]['elements'] = $schema_styles_elements; } $schema['styles'] = self::VALID_STYLES; diff --git a/package-lock.json b/package-lock.json index 7aa8a8c8073d2c..7a68a9f93f0638 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "gutenberg", - "version": "12.2.0", + "version": "12.3.0-rc.1", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index d46a2091f862b2..507f4ff6418330 100755 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "gutenberg", - "version": "12.2.0", + "version": "12.3.0-rc.1", "private": true, "description": "A new WordPress editor experience.", "author": "The WordPress Contributors", diff --git a/packages/block-editor/package.json b/packages/block-editor/package.json index cc610c321eede2..15623b198b41a1 100644 --- a/packages/block-editor/package.json +++ b/packages/block-editor/package.json @@ -72,6 +72,10 @@ "rememo": "^3.0.0", "traverse": "^0.6.6" }, + "peerDependencies": { + "react": "^17.0.0", + "react-dom": "^17.0.0" + }, "publishConfig": { "access": "public" } diff --git a/packages/block-editor/src/components/colors-gradients/dropdown.js b/packages/block-editor/src/components/colors-gradients/dropdown.js index 4cbaa8b21c3cc5..17bf066266d5be 100644 --- a/packages/block-editor/src/components/colors-gradients/dropdown.js +++ b/packages/block-editor/src/components/colors-gradients/dropdown.js @@ -14,7 +14,6 @@ import { ColorIndicator, Dropdown, } from '@wordpress/components'; -import { isRTL } from '@wordpress/i18n'; /** * Internal dependencies @@ -33,7 +32,7 @@ export default function ColorGradientSettingsDropdown( { } ) { let dropdownPosition; if ( __experimentalIsRenderedInSidebar ) { - dropdownPosition = isRTL() ? 'bottom right' : 'bottom left'; + dropdownPosition = 'bottom left'; } return ( diff --git a/packages/block-editor/src/components/gradients/use-gradient.js b/packages/block-editor/src/components/gradients/use-gradient.js index 07130f37add24a..4acf09fc03b522 100644 --- a/packages/block-editor/src/components/gradients/use-gradient.js +++ b/packages/block-editor/src/components/gradients/use-gradient.js @@ -59,22 +59,22 @@ export function getGradientSlugByValue( gradients, value ) { return gradient && gradient.slug; } -const EMPTY_OBJECT = {}; - export function __experimentalUseGradient( { gradientAttribute = 'gradient', customGradientAttribute = 'customGradient', } = {} ) { const { clientId } = useBlockEditContext(); - const gradientsPerOrigin = useSetting( 'color.gradients' ) || EMPTY_OBJECT; + const userGradientPalette = useSetting( 'color.gradients.custom' ); + const themeGradientPalette = useSetting( 'color.gradients.theme' ); + const defaultGradientPalette = useSetting( 'color.gradients.default' ); const allGradients = useMemo( () => [ - ...( gradientsPerOrigin?.custom || [] ), - ...( gradientsPerOrigin?.theme || [] ), - ...( gradientsPerOrigin?.default || [] ), + ...( userGradientPalette || [] ), + ...( themeGradientPalette || [] ), + ...( defaultGradientPalette || [] ), ], - [ gradientsPerOrigin ] + [ userGradientPalette, themeGradientPalette, defaultGradientPalette ] ); const { gradient, customGradient } = useSelect( ( select ) => { diff --git a/packages/block-editor/src/hooks/color.js b/packages/block-editor/src/hooks/color.js index 0e9e31ba3a8537..bb648bac9f212c 100644 --- a/packages/block-editor/src/hooks/color.js +++ b/packages/block-editor/src/hooks/color.js @@ -32,8 +32,6 @@ import useSetting from '../components/use-setting'; export const COLOR_SUPPORT_KEY = 'color'; -const EMPTY_OBJECT = {}; - const hasColorSupport = ( blockType ) => { const colorSupport = getBlockSupport( blockType, COLOR_SUPPORT_KEY ); return ( @@ -232,7 +230,17 @@ export function ColorEdit( props ) { ], [ userPalette, themePalette, defaultPalette ] ); - const gradientsPerOrigin = useSetting( 'color.gradients' ) || EMPTY_OBJECT; + const userGradientPalette = useSetting( 'color.gradients.custom' ); + const themeGradientPalette = useSetting( 'color.gradients.theme' ); + const defaultGradientPalette = useSetting( 'color.gradients.default' ); + const allGradients = useMemo( + () => [ + ...( userGradientPalette || [] ), + ...( themeGradientPalette || [] ), + ...( defaultGradientPalette || [] ), + ], + [ userGradientPalette, themeGradientPalette, defaultGradientPalette ] + ); const areCustomSolidsEnabled = useSetting( 'color.custom' ); const areCustomGradientsEnabled = useSetting( 'color.customGradient' ); const isBackgroundEnabled = useSetting( 'color.background' ); @@ -244,17 +252,8 @@ export function ColorEdit( props ) { const gradientsEnabled = areCustomGradientsEnabled || - ! gradientsPerOrigin?.theme || - gradientsPerOrigin?.theme?.length > 0; - - const allGradients = useMemo( - () => [ - ...( gradientsPerOrigin?.custom || [] ), - ...( gradientsPerOrigin?.theme || [] ), - ...( gradientsPerOrigin?.default || [] ), - ], - [ gradientsPerOrigin ] - ); + ! themeGradientPalette || + themeGradientPalette?.length > 0; // Shouldn't be needed but right now the ColorGradientsPanel // can trigger both onChangeColor and onChangeBackground diff --git a/packages/block-editor/src/hooks/layout.js b/packages/block-editor/src/hooks/layout.js index a1f17c525c0c6a..b2cfde0b5e06cc 100644 --- a/packages/block-editor/src/hooks/layout.js +++ b/packages/block-editor/src/hooks/layout.js @@ -215,6 +215,7 @@ export const withLayoutStyles = createHigherOrderComponent( , element ) } diff --git a/packages/block-editor/src/hooks/style.js b/packages/block-editor/src/hooks/style.js index 8b0fbd6820e27b..5882d5275937be 100644 --- a/packages/block-editor/src/hooks/style.js +++ b/packages/block-editor/src/hooks/style.js @@ -74,6 +74,7 @@ function compileStyleValue( uncompiledValue ) { * @return {Object} Flattened CSS variables declaration. */ export function getInlineStyles( styles = {} ) { + const ignoredStyles = [ 'spacing.blockGap' ]; const output = {}; Object.keys( STYLE_PROPERTY ).forEach( ( propKey ) => { const path = STYLE_PROPERTY[ propKey ].value; @@ -93,7 +94,7 @@ export function getInlineStyles( styles = {} ) { output[ name ] = compileStyleValue( value ); } } ); - } else { + } else if ( ! ignoredStyles.includes( path.join( '.' ) ) ) { output[ propKey ] = compileStyleValue( get( styles, path ) ); } } diff --git a/packages/block-editor/src/hooks/test/style.js b/packages/block-editor/src/hooks/test/style.js index e8c3264eeba6b1..ac2b0690dd498e 100644 --- a/packages/block-editor/src/hooks/test/style.js +++ b/packages/block-editor/src/hooks/test/style.js @@ -30,7 +30,6 @@ describe( 'getInlineStyles', () => { }, } ) ).toEqual( { - '--wp--style--block-gap': '1em', backgroundColor: 'black', borderColor: '#21759b', borderRadius: '10px', @@ -104,7 +103,6 @@ describe( 'getInlineStyles', () => { }, } ) ).toEqual( { - '--wp--style--block-gap': '1em', margin: '10px', padding: '20px', } ); diff --git a/packages/block-editor/src/layouts/flex.js b/packages/block-editor/src/layouts/flex.js index 84125108515ad3..092da1e036a10f 100644 --- a/packages/block-editor/src/layouts/flex.js +++ b/packages/block-editor/src/layouts/flex.js @@ -84,10 +84,12 @@ export default { ); }, - save: function FlexLayoutStyle( { selector, layout } ) { + save: function FlexLayoutStyle( { selector, layout, style } ) { const { orientation = 'horizontal' } = layout; const blockGapSupport = useSetting( 'spacing.blockGap' ); const hasBlockGapStylesSupport = blockGapSupport !== null; + const blockGapValue = + style?.spacing?.blockGap ?? 'var( --wp--style--block-gap, 0.5em )'; const justifyContent = justifyContentMap[ layout.justifyContent ] || justifyContentMap.left; @@ -110,11 +112,7 @@ export default { ; + return ; }, getOrientation() { return 'vertical'; diff --git a/packages/block-library/src/columns/block.json b/packages/block-library/src/columns/block.json index dfbfb24e2251b0..c556d90a0d2d25 100644 --- a/packages/block-library/src/columns/block.json +++ b/packages/block-library/src/columns/block.json @@ -24,11 +24,10 @@ "link": true }, "spacing": { - "blockGap": true, "margin": [ "top", "bottom" ], "padding": true, "__experimentalDefaultControls": { - "blockGap": true + "padding": true } } }, diff --git a/packages/block-library/src/navigation/block.json b/packages/block-library/src/navigation/block.json index 96a049e9f0bad0..6759cde277fa27 100644 --- a/packages/block-library/src/navigation/block.json +++ b/packages/block-library/src/navigation/block.json @@ -92,11 +92,7 @@ } }, "spacing": { - "blockGap": true, - "units": [ "px", "em", "rem", "vh", "vw" ], - "__experimentalDefaultControls": { - "blockGap": true - } + "units": [ "px", "em", "rem", "vh", "vw" ] }, "__experimentalLayout": { "allowSwitching": false, diff --git a/packages/block-library/src/navigation/editor.scss b/packages/block-library/src/navigation/editor.scss index 7e694b0594c9ba..c161a540ab1615 100644 --- a/packages/block-library/src/navigation/editor.scss +++ b/packages/block-library/src/navigation/editor.scss @@ -304,7 +304,6 @@ $color-control-label-height: 20px; // Selected state. .wp-block-navigation-placeholder__controls { - padding: $grid-unit-10; border-radius: $radius-block-ui; background-color: $white; box-shadow: inset 0 0 0 $border-width $gray-900; @@ -313,11 +312,7 @@ $color-control-label-height: 20px; display: none; position: relative; z-index: 1; - - // Adjust padding for when shown horizontally. - .is-large & { - padding: $grid-unit-05 $grid-unit-10; - } + padding: $grid-unit-05 $grid-unit-10; // If an ancestor has a text-decoration property applied, it is inherited regardless of // the specificity of a child element. Only pulling the child out of the flow fixes it. @@ -330,9 +325,19 @@ $color-control-label-height: 20px; display: flex; } - // Show stacked for the vertical navigation, or small placeholders. - .is-small &, + // Hide a few elements in medium size placeholders. + // @todo: part of the code here will be irrelevant if https://github.com/WordPress/gutenberg/pull/36775 lands. .is-medium & { + .wp-block-navigation-placeholder__actions__indicator, + .wp-block-navigation-placeholder__actions__indicator + hr, + .wp-block-navigation-placeholder__actions > :nth-last-child(3), // Add all pages. + .wp-block-navigation-placeholder__actions > :nth-last-child(2) { // hr separator after it. + display: none; + } + } + + // Show stacked for the vertical navigation, or small placeholders. + .is-small & { .wp-block-navigation-placeholder__actions { flex-direction: column; } @@ -366,6 +371,11 @@ $color-control-label-height: 20px; } } +// Keep as row for medium. +.wp-block-navigation .components-placeholder.is-medium .components-placeholder__fieldset { + flex-direction: row !important; +} + .wp-block-navigation-placeholder__actions { display: flex; font-size: $default-font-size; diff --git a/packages/block-library/src/post-author/edit.js b/packages/block-library/src/post-author/edit.js index ffb138694c376c..d23e0965dadda8 100644 --- a/packages/block-library/src/post-author/edit.js +++ b/packages/block-library/src/post-author/edit.js @@ -25,7 +25,7 @@ function PostAuthorEdit( { attributes, setAttributes, } ) { - const isDescendentOfQueryLoop = !! queryId; + const isDescendentOfQueryLoop = Number.isFinite( queryId ); const { authorId, authorDetails, authors } = useSelect( ( select ) => { const { getEditedEntityRecord, getUser, getUsers } = select( diff --git a/packages/block-library/src/post-content/edit.js b/packages/block-library/src/post-content/edit.js index 4a0c277a1f5cfe..b9a11f0d1bec82 100644 --- a/packages/block-library/src/post-content/edit.js +++ b/packages/block-library/src/post-content/edit.js @@ -66,7 +66,7 @@ function EditableContent( { layout, context = {} } ) { function Content( props ) { const { context: { queryId, postType, postId } = {} } = props; - const isDescendentOfQueryLoop = !! queryId; + const isDescendentOfQueryLoop = Number.isFinite( queryId ); const userCanEdit = useCanEditEntity( 'postType', postType, postId ); const isEditable = userCanEdit && ! isDescendentOfQueryLoop; diff --git a/packages/block-library/src/post-content/index.php b/packages/block-library/src/post-content/index.php index 400e3068dfa0a9..7edb2cd604a719 100644 --- a/packages/block-library/src/post-content/index.php +++ b/packages/block-library/src/post-content/index.php @@ -36,11 +36,16 @@ function render_block_core_post_content( $attributes, $content, $block ) { $seen_ids[ $post_id ] = true; + // Check is needed for backward compatibility with third-party plugins + // that might rely on the `in_the_loop` check; calling `the_post` sets it to true. if ( ! in_the_loop() && have_posts() ) { the_post(); } - $content = get_the_content( null, false, $post_id ); + // When inside the main loop, we want to use queried object + // so that `the_preview` for the current post can apply. + // We force this behavior by omitting the third argument (post ID) from the `get_the_content`. + $content = get_the_content( null, false ); /** This filter is documented in wp-includes/post-template.php */ $content = apply_filters( 'the_content', str_replace( ']]>', ']]>', $content ) ); unset( $seen_ids[ $post_id ] ); diff --git a/packages/block-library/src/post-date/edit.js b/packages/block-library/src/post-date/edit.js index 97315736b005d3..2fa4507f1870a1 100644 --- a/packages/block-library/src/post-date/edit.js +++ b/packages/block-library/src/post-date/edit.js @@ -33,7 +33,7 @@ export default function PostDateEdit( { context: { postId, postType, queryId }, setAttributes, } ) { - const isDescendentOfQueryLoop = !! queryId; + const isDescendentOfQueryLoop = Number.isFinite( queryId ); const [ siteFormat ] = useEntityProp( 'root', 'site', 'date_format' ); const [ date, setDate ] = useEntityProp( 'postType', diff --git a/packages/block-library/src/post-excerpt/edit.js b/packages/block-library/src/post-excerpt/edit.js index 04c22acd2e36cb..a71bcc61567492 100644 --- a/packages/block-library/src/post-excerpt/edit.js +++ b/packages/block-library/src/post-excerpt/edit.js @@ -30,7 +30,7 @@ export default function PostExcerptEditor( { isSelected, context: { postId, postType, queryId }, } ) { - const isDescendentOfQueryLoop = !! queryId; + const isDescendentOfQueryLoop = Number.isFinite( queryId ); const userCanEdit = useCanEditEntity( 'postType', postType, postId ); const isEditable = userCanEdit && ! isDescendentOfQueryLoop; const [ diff --git a/packages/block-library/src/post-excerpt/index.js b/packages/block-library/src/post-excerpt/index.js index f382774f3e63d8..1f035a7940a6dd 100644 --- a/packages/block-library/src/post-excerpt/index.js +++ b/packages/block-library/src/post-excerpt/index.js @@ -8,11 +8,13 @@ import { postExcerpt as icon } from '@wordpress/icons'; */ import metadata from './block.json'; import edit from './edit'; +import transforms from './transforms'; const { name } = metadata; export { metadata, name }; export const settings = { icon, + transforms, edit, }; diff --git a/packages/block-library/src/post-excerpt/index.php b/packages/block-library/src/post-excerpt/index.php index cc68b24df971a4..d650cc3cf073b5 100644 --- a/packages/block-library/src/post-excerpt/index.php +++ b/packages/block-library/src/post-excerpt/index.php @@ -18,7 +18,7 @@ function render_block_core_post_excerpt( $attributes, $content, $block ) { return ''; } - $excerpt = get_the_excerpt( $block->context['postId'] ); + $excerpt = get_the_excerpt(); if ( empty( $excerpt ) ) { return ''; diff --git a/packages/block-library/src/post-excerpt/transforms.js b/packages/block-library/src/post-excerpt/transforms.js new file mode 100644 index 00000000000000..5135b7fbcf9337 --- /dev/null +++ b/packages/block-library/src/post-excerpt/transforms.js @@ -0,0 +1,23 @@ +/** + * WordPress dependencies + */ +import { createBlock } from '@wordpress/blocks'; + +const transforms = { + from: [ + { + type: 'block', + blocks: [ 'core/post-content' ], + transform: () => createBlock( 'core/post-excerpt' ), + }, + ], + to: [ + { + type: 'block', + blocks: [ 'core/post-content' ], + transform: () => createBlock( 'core/post-content' ), + }, + ], +}; + +export default transforms; diff --git a/packages/block-library/src/post-featured-image/edit.js b/packages/block-library/src/post-featured-image/edit.js index ca52ffcb694057..6d38eb17f79b15 100644 --- a/packages/block-library/src/post-featured-image/edit.js +++ b/packages/block-library/src/post-featured-image/edit.js @@ -52,7 +52,7 @@ function PostFeaturedImageDisplay( { setAttributes, context: { postId, postType, queryId }, } ) { - const isDescendentOfQueryLoop = !! queryId; + const isDescendentOfQueryLoop = Number.isFinite( queryId ); const { isLink, height, width, scale } = attributes; const [ featuredImage, setFeaturedImage ] = useEntityProp( 'postType', diff --git a/packages/block-library/src/post-title/edit.js b/packages/block-library/src/post-title/edit.js index 28ab04ed556851..18904364774fea 100644 --- a/packages/block-library/src/post-title/edit.js +++ b/packages/block-library/src/post-title/edit.js @@ -30,7 +30,7 @@ export default function PostTitleEdit( { context: { postType, postId, queryId }, } ) { const TagName = 0 === level ? 'p' : 'h' + level; - const isDescendentOfQueryLoop = !! queryId; + const isDescendentOfQueryLoop = Number.isFinite( queryId ); const userCanEdit = useCanEditEntity( 'postType', postType, postId ); const [ rawTitle = '', setTitle, fullTitle ] = useEntityProp( 'postType', diff --git a/packages/block-library/src/post-title/index.php b/packages/block-library/src/post-title/index.php index 61618939cec9dd..56302864265165 100644 --- a/packages/block-library/src/post-title/index.php +++ b/packages/block-library/src/post-title/index.php @@ -20,7 +20,7 @@ function render_block_core_post_title( $attributes, $content, $block ) { } $post_ID = $block->context['postId']; - $title = get_the_title( $post_ID ); + $title = get_the_title(); if ( ! $title ) { return ''; diff --git a/packages/components/package.json b/packages/components/package.json index ca2157b574cbfb..fb3dc5d4a2ebba 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -69,6 +69,10 @@ "rememo": "^3.0.0", "uuid": "^8.3.0" }, + "peerDependencies": { + "react": "^17.0.0", + "react-dom": "^17.0.0" + }, "publishConfig": { "access": "public" } diff --git a/packages/components/src/color-palette/index.js b/packages/components/src/color-palette/index.js index d2df31e086e979..1e540232a35b7d 100644 --- a/packages/components/src/color-palette/index.js +++ b/packages/components/src/color-palette/index.js @@ -10,7 +10,7 @@ import classnames from 'classnames'; /** * WordPress dependencies */ -import { __, sprintf, isRTL } from '@wordpress/i18n'; +import { __, sprintf } from '@wordpress/i18n'; import { useCallback, useMemo } from '@wordpress/element'; /** @@ -150,7 +150,7 @@ export default function ColorPalette( { let dropdownPosition; if ( __experimentalIsRenderedInSidebar ) { - dropdownPosition = isRTL() ? 'bottom right' : 'bottom left'; + dropdownPosition = 'bottom left'; } const colordColor = colord( value ); diff --git a/packages/components/src/custom-gradient-bar/control-points.js b/packages/components/src/custom-gradient-bar/control-points.js index 4abad2c38930e9..65c15567f72330 100644 --- a/packages/components/src/custom-gradient-bar/control-points.js +++ b/packages/components/src/custom-gradient-bar/control-points.js @@ -9,7 +9,7 @@ import { colord } from 'colord'; */ import { useInstanceId } from '@wordpress/compose'; import { useEffect, useRef, useState, useMemo } from '@wordpress/element'; -import { __, sprintf, isRTL } from '@wordpress/i18n'; +import { __, sprintf } from '@wordpress/i18n'; import { plus } from '@wordpress/icons'; import { LEFT, RIGHT } from '@wordpress/keycodes'; @@ -86,7 +86,7 @@ function GradientColorPickerDropdown( { }; if ( isRenderedInSidebar ) { result.anchorRef = gradientPickerDomRef.current; - result.position = isRTL() ? 'bottom right' : 'bottom left'; + result.position = 'bottom left'; } return result; }, [ gradientPickerDomRef.current, isRenderedInSidebar ] ); diff --git a/packages/components/src/gradient-picker/README.md b/packages/components/src/gradient-picker/README.md new file mode 100644 index 00000000000000..390631428028b5 --- /dev/null +++ b/packages/components/src/gradient-picker/README.md @@ -0,0 +1,94 @@ +# GradientPicker + +GradientPicker is a React component that renders a color gradient picker to define a multi step gradient. There's either a _linear_ or a _radial_ type available. + +![gradient-picker](https://user-images.githubusercontent.com/881729/147505438-3818c4c7-65b5-4394-b97b-af903c62adce.png) + +## Usage + +Render a GradientPicker. + +```jsx +import { GradientPicker } from '@wordpress/components'; +import { useState } from '@wordpress/element'; + +const myGradientPicker = () => { + const [ gradient, setGradient ] = useState( null ); + + return ( + setGradient( currentGradient ) } + gradients={ [ + { + name: 'JShine', + gradient: + 'linear-gradient(135deg,#12c2e9 0%,#c471ed 50%,#f64f59 100%)', + slug: 'jshine', + }, + { + name: 'Moonlit Asteroid', + gradient: + 'linear-gradient(135deg,#0F2027 0%, #203A43 0%, #2c5364 100%)', + slug: 'moonlit-asteroid', + }, + { + name: 'Rastafarie', + gradient: + 'linear-gradient(135deg,#1E9600 0%, #FFF200 0%, #FF0000 100%)', + slug: 'rastafari', + }, + ] } + /> + ); +}; +``` + +## Props + +The component accepts the following props: + +### value + +The current value of the gradient. Pass a css gradient like `linear-gradient(90deg, rgb(6, 147, 227) 0%, rgb(155, 81, 224) 100%)`. Optionally pass in a `null` value to specify no gradient is currently selected. + +- Type: `string` +- Required: No +- Default: `linear-gradient(90deg, rgb(6, 147, 227) 0%, rgb(155, 81, 224) 100%)` + +### onChange + +The function called when a new gradient has been defined. It is passed the `currentGradient` as an argument. + +- Type: `Function` +- Required: Yes + +### gradients + +An array of objects of predefined gradients which show up as `CircularOptionPicker` above the gradient selector. + +- Type: `array` +- Required: No + +### clearable + +Whether the palette should have a clearing button or not. + +- Type: `Boolean` +- Required: No +- Default: true + +### clearGradient + +Called when a new gradient has been defined. It is passed the `currentGradient` as an argument. + +- Type: `Function` +- Required: No + +### disableCustomGradients + +If true, the gradient picker will not be displayed and only defined gradients from `gradients` are available. + +- Type: `Boolean` +- Required: No +- Default: false diff --git a/packages/components/src/palette-edit/styles.js b/packages/components/src/palette-edit/styles.js index 1a04a5a38b7296..a04991da03a686 100644 --- a/packages/components/src/palette-edit/styles.js +++ b/packages/components/src/palette-edit/styles.js @@ -57,7 +57,9 @@ export const NameContainer = styled.div` export const PaletteHeading = styled( Heading )` text-transform: uppercase; line-height: ${ space( 6 ) }; + font-weight: 500; &&& { + font-size: 11px; margin-bottom: 0; } `; diff --git a/packages/compose/package.json b/packages/compose/package.json index a374199d237742..4e715c56d899ca 100644 --- a/packages/compose/package.json +++ b/packages/compose/package.json @@ -44,6 +44,9 @@ "react-resize-aware": "^3.1.0", "use-memo-one": "^1.1.1" }, + "peerDependencies": { + "react": "^17.0.0" + }, "publishConfig": { "access": "public" } diff --git a/packages/core-data/README.md b/packages/core-data/README.md index 09afdb0ece16fd..4af8bc12debe2b 100644 --- a/packages/core-data/README.md +++ b/packages/core-data/README.md @@ -170,6 +170,8 @@ _Returns_ ### receiveUploadPermissions +> **Deprecated** since WP 5.9, use receiveUserPermission instead. + Returns an action object used in signalling that Upload permissions have been received. _Parameters_ diff --git a/packages/core-data/src/actions.js b/packages/core-data/src/actions.js index 9381744a08eb32..42f087a0b6223c 100644 --- a/packages/core-data/src/actions.js +++ b/packages/core-data/src/actions.js @@ -696,16 +696,19 @@ export const __experimentalSaveSpecifiedEntityEdits = ( /** * Returns an action object used in signalling that Upload permissions have been received. * + * @deprecated since WP 5.9, use receiveUserPermission instead. + * * @param {boolean} hasUploadPermissions Does the user have permission to upload files? * * @return {Object} Action object. */ export function receiveUploadPermissions( hasUploadPermissions ) { - return { - type: 'RECEIVE_USER_PERMISSION', - key: 'create/media', - isAllowed: hasUploadPermissions, - }; + deprecated( "wp.data.dispatch( 'core' ).receiveUploadPermissions", { + since: '5.9', + alternative: 'receiveUserPermission', + } ); + + return receiveUserPermission( 'create/media', hasUploadPermissions ); } /** diff --git a/packages/create-block-tutorial-template/CHANGELOG.md b/packages/create-block-tutorial-template/CHANGELOG.md index 39fa4e1144b5fc..41ee24887857f0 100644 --- a/packages/create-block-tutorial-template/CHANGELOG.md +++ b/packages/create-block-tutorial-template/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +### Enhancement + +- Speed up scaffolding process by omitting WordPress dependencies in the template ([#37639](https://github.com/WordPress/gutenberg/pull/37639)). + ## 1.3.0 (2021-07-21) ### Enhancement diff --git a/packages/create-block-tutorial-template/index.js b/packages/create-block-tutorial-template/index.js index c39d2eaae4f678..5d2e7c04d5eee2 100644 --- a/packages/create-block-tutorial-template/index.js +++ b/packages/create-block-tutorial-template/index.js @@ -22,12 +22,6 @@ module.exports = { supports: { html: false, }, - npmDependencies: [ - '@wordpress/block-editor', - '@wordpress/blocks', - '@wordpress/components', - '@wordpress/i18n', - ], }, templatesPath: join( __dirname, 'templates' ), assetsPath: join( __dirname, 'assets' ), diff --git a/packages/create-block/CHANGELOG.md b/packages/create-block/CHANGELOG.md index 7811f4af10be86..7b91ea47086da0 100644 --- a/packages/create-block/CHANGELOG.md +++ b/packages/create-block/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +### Enhancement + +- Speed up scaffolding process by omitting WordPress dependencies in the template ([#37639](https://github.com/WordPress/gutenberg/pull/37639)). + ### Internal - The bundled `npm-package-arg` dependency has been updated from requiring `^8.0.1` to requiring `^8.1.5` ([#37395](https://github.com/WordPress/gutenberg/pull/37395)). diff --git a/packages/create-block/lib/init-package-json.js b/packages/create-block/lib/init-package-json.js index 31c376e4aa5f2b..98e7d0d680d878 100644 --- a/packages/create-block/lib/init-package-json.js +++ b/packages/create-block/lib/init-package-json.js @@ -48,7 +48,7 @@ module.exports = async ( { ) ); - if ( size( npmDependencies ) ) { + if ( wpScripts && size( npmDependencies ) ) { info( '' ); info( 'Installing npm dependencies. It might take a couple of minutes...' diff --git a/packages/create-block/lib/templates.js b/packages/create-block/lib/templates.js index 2740ad0958b83e..054573402d3b30 100644 --- a/packages/create-block/lib/templates.js +++ b/packages/create-block/lib/templates.js @@ -44,11 +44,6 @@ const predefinedBlockTemplates = { supports: { html: false, }, - npmDependencies: [ - '@wordpress/block-editor', - '@wordpress/blocks', - '@wordpress/i18n', - ], }, templatesPath: join( __dirname, 'templates', 'esnext' ), }, diff --git a/packages/data/package.json b/packages/data/package.json index d26a76996bcf9d..6cb606c3287eb5 100644 --- a/packages/data/package.json +++ b/packages/data/package.json @@ -42,6 +42,9 @@ "turbo-combine-reducers": "^1.0.2", "use-memo-one": "^1.1.1" }, + "peerDependencies": { + "react": "^17.0.0" + }, "publishConfig": { "access": "public" } diff --git a/packages/edit-site/src/components/block-editor/resizable-editor.js b/packages/edit-site/src/components/block-editor/resizable-editor.js index 9d53bcba10f84a..91dee707ccd757 100644 --- a/packages/edit-site/src/components/block-editor/resizable-editor.js +++ b/packages/edit-site/src/components/block-editor/resizable-editor.js @@ -57,22 +57,49 @@ function ResizableEditor( { enableResizing, settings, ...props } ) { return; } - const resizeObserver = new iframe.contentWindow.ResizeObserver( - () => { - setHeight( - iframe.contentDocument.querySelector( - `.edit-site-block-editor__block-list` - ).offsetHeight + let animationFrame = null; + + function resizeHeight() { + if ( ! animationFrame ) { + // Throttle the updates on animation frame. + animationFrame = iframe.contentWindow.requestAnimationFrame( + () => { + setHeight( + iframe.contentDocument.documentElement + .scrollHeight + ); + animationFrame = null; + } ); } - ); + } + + let resizeObserver; + + function registerObserver() { + resizeObserver?.disconnect(); + + resizeObserver = new iframe.contentWindow.ResizeObserver( + resizeHeight + ); + // Observing the rather than the because the latter + // gets destroyed and remounted after initialization in