Opened 13 months ago
Closed 13 months ago
#58997 closed defect (bug) (reported-upstream)
Compound block and layout type classname incorrect for custom blocks
Reported by: | wongjn | Owned by: | |
---|---|---|---|
Milestone: | Priority: | normal | |
Severity: | normal | Version: | 6.3 |
Component: | Themes | Keywords: | |
Focuses: | css | Cc: |
Description
Opened in `WordPress/Gutenberg` as #53295 but considered a feature, whereas I would suggest it be considered a bug.
Description
As per Layout updates in the editor for WordPress 6.3:
In 6.3, a new classname is added to the inner wrapper of all blocks with layout, comprised of block classname + layout classname, e.g.:
.wp-block-cover-is-layout-constrained
.
However, this does not work for third-party blocks since the vendor prefix of the block gets cut off in the class name generated in markup, but the CSS generated from the style engine has the prefix.
Given the block detailed in the code snippet further down, you'll get markup like this in the block editor:
<div … class="block-editor-block-list__block wp-block wp-block-foo-bar"> <div class="block-editor-block-list__layout is-layout-flow wp-block-bar-is-layout-flow" …>
With the associative CSS (where settings.styles.blocks.foo/bar.spacing.blockGap
has been set to var(--wp--preset--spacing--12)
in theme.json
):
… .editor-styles-wrapper .wp-block-foo-bar-is-layout-flow > :first-child:first-child { margin-block-start: 0; } .editor-styles-wrapper .wp-block-foo-bar-is-layout-flow > :last-child:last-child { margin-block-end: 0; } .editor-styles-wrapper .wp-block-foo-bar-is-layout-flow > * { margin-block-start: var(--wp--preset--spacing--12); margin-block-end: 0; } …
Notice how the combined CSS classes like wp-block-foo-bar-is-layout-flow
have wp-block-foo-bar-
but the class name on the HTML block itself is wp-block-bar-
.
This difference seems to be due to the `packages/block-editor/src/hooks/layout.js` only looking at the second part of the block name after the slash (`/`):
if ( LAYOUT_DEFINITIONS[ usedLayout?.type || 'default' ]?.className ) { const baseClassName = LAYOUT_DEFINITIONS[ usedLayout?.type || 'default' ]?.className; const compoundClassName = `wp-block-${ blockName .split( '/' ) .pop() }-${ baseClassName }`; layoutClassnames.push( baseClassName, compoundClassName ); }
when building the class name for HTML.
This behavior is mirrored for server side layout supports PHP code:
<?php // Add combined layout and block classname for global styles to hook onto. $block_name = explode( '/', $block['blockName'] ); $class_names[] = 'wp-block-' . end( $block_name ) . '-' . $layout_classname;
Again, only looking at the second part of the block name after the slash (/
).
The CSS I believe comes from `WP_Theme_JSON::get_layout_styles()` and we can see the difference with how the CSS is constructed:
<?php $selector = isset( $block_metadata['selector'] ) ? $block_metadata['selector'] : ''; // $selector = '.wp-block-foo-bar' // … $format = static::ROOT_BLOCK_SELECTOR === $selector ? ':where(%s .%s) %s' : '%s-%s%s'; $layout_selector = sprintf( $format, // = '%s-%s%s' $selector, // = '.wp-block-foo-bar' $class_name, // = 'is-layout-flow' $spacing_rule['selector'] // = ' > *', ); // $layout_selector = '.wp-block-foo-bar-is-layout-flow > *'
Step-by-step reproduction instructions
- Create a custom block like the example provided in the code snippets further down.
- Insert into a post.
- See that an incorrect compound block and layout type class name is applied to the inner
<div>
, both in the editor or in the live webpage.
Example block
block.json
:
{ "apiVersion": 3, "name": "foo/bar", "title": "Foo Bar", "supports": { "layout": true }, "editorScript": "file:./index.js" }
index.js
:
import { useBlockProps, useInnerBlocksProps } from '@wordpress/block-editor'; import { registerBlockType } from '@wordpress/blocks'; registerBlockType( 'foo/bar', { edit: function FooBarEdit() { const blockProps = useBlockProps(); const innerProps = useInnerBlocksProps(); return ( <div { ...blockProps }> <div { ...innerProps } /> </div> ); }, save: function FooBarSave() { const blockProps = useBlockProps.save(); const innerProps = useInnerBlocksProps.save(); return ( <div { ...blockProps }> <div { ...innerProps } /> </div> ); }, }
index.js
(no build step neccessary):
const { useBlockProps, useInnerBlocksProps } = wp.blockEditor; const { createElement } = wp.element; wp.blocks.registerBlockType( 'foo/bar', { edit: function FooBarEdit() { const blockProps = useBlockProps(); const innerProps = useInnerBlocksProps(); return createElement( 'div', blockProps, [ createElement( 'div', innerProps ), ] ); }, save: function FooBarSave() { const blockProps = useBlockProps.save(); const innerProps = useInnerBlocksProps.save(); return createElement( 'div', blockProps, [ createElement( 'div', innerProps ), ] ); }, }
Tested on WordPress 6.3-RC3-56344
Thanks for the report @wongjn! I'm closing this as it's already been reported in Gutenberg, which is the correct place for it :)