Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Since apiVersion 2, customization of core blocks is more difficult #34104

Open
2 tasks done
maccyd10 opened this issue Aug 17, 2021 · 2 comments
Open
2 tasks done

Since apiVersion 2, customization of core blocks is more difficult #34104

maccyd10 opened this issue Aug 17, 2021 · 2 comments
Labels
Backwards Compatibility Issues or PRs that impact backwards compatability [Feature] Extensibility The ability to extend blocks or the editing experience Needs Technical Feedback Needs testing from a developer perspective. [Package] Block editor /packages/block-editor [Type] Enhancement A suggestion for improvement.

Comments

@maccyd10
Copy link

maccyd10 commented Aug 17, 2021

Description

Since apiVersion 2, Blocks are no longer automatically wrapped in a BlockListBlock.

} else if ( lightBlockWrapper ) {
Each block conforming to apiVersion 2 must use useBlockProps in order to render the blockProps
export function useBlockProps( props = {}, { __unstableIsHtml } = {} ) {
While this achieves the goal of lightening the editor content’s DOM tree , it comes with some undesirable side effects:

Step-by-step reproduction instructions

Lets say I wanted to add a title element to a core gallery:

const { createHigherOrderComponent } = wp.compose;
const { PlainText } = wp.blockEditor;
const { addFilter } = wp.hooks;
const { __ } = wp.i18n;

const addAttributes = (settings) => {
const { name } = settings;
 if (name === 'core/gallery') {
    settings.attributes = {
      title: {
        type: 'string',
        default: '',
      },
      ...settings.attributes,
    };
  }
  return settings;
};



const withTitle = createHigherOrderComponent((BlockEdit) => (props) => {
const { name } = props;
 if (name !== 'core/gallery') {
    return (
      <BlockEdit {...props} />
    );
  }

  const { attributes, setAttributes } = props;
  const { title } = attributes;

  return (
    <div className="my-wrapper">
      <PlainText
        placeholder={__('Title', 'text_domain')}
              onChange={(title) => { setAttributes({ title }); }} 
        value={title}
        className="h2"
      />
      <BlockEdit {...props} />
    </div>
  );
}, 'withTitleControl');

addFilter('blocks.registerBlockType', 'module/with-title-attributes', addAttributes);
addFilter('editor.BlockEdit', 'module/with-title-control', withTitle);

Screenshots, screen recording, code snippet

in apiVersion 1, this would have resulted in the following markup, note the block props on the outermost element:

<div 
  id="block-bbe18ba9-baa3-476d-be1b-598ae485fc8e" 
  tabindex="0" 
  role="group" 
  aria-label="Block: Gallery" 
  data-block="bbe18ba9-baa3-476d-be1b-598ae485fc8e" 
  data-type="core/gallery" 
  data-title="Gallery" 
  class="block-editor-block-list__block wp-block is-selected wp-block-gallery">
  <div class="my-wrapper">
  <textarea class="block-editor-plain-text h2" placeholder="Title" rows="1" style="overflow: hidden; overflow-wrap: break-word; resize: none; height: 68px;"></textarea>
    <div class="block-editor-block-list__block wp-block is-selected wp-block-gallery">
       ... Media inserter iframe ...
    </div>
  </div>
</div>

Which also results in appropriate placement of the block controls above the title field:

Screen Shot 2021-08-17 at 12 32 41 AM

Also, note the in-between inserter popover working as expected:

Screen Shot 2021-08-17 at 12 36 27 AM

in apiVersion 2, the blockProps are moved inside the wrapper element:

<div class="my-wrapper">
<textarea class="block-editor-plain-text h2" placeholder="Title" rows="1" style="overflow: hidden; overflow-wrap: break-word; resize: none; height: 68px;"></textarea>
  <div 
id="block-8d24ce25-4c4d-4d7f-b22e-cc37e9907d63" 
tabindex="0" 
role="group" 
aria-label="Block: Gallery" 
data-block="8d24ce25-4c4d-4d7f-b22e-cc37e9907d63" 
data-type="core/gallery" 
data-title="Gallery" 
class="block-editor-block-list__block wp-block is-selected wp-block-gallery">
    <div class="components-placeholder block-editor-media-placeholder is-large">
         ... Media inserter iframe ...
    </div>
  </div>
</div>

Note the bad placement of the block controls before the gallery component rather than wrapper element

Screen Shot 2021-08-17 at 12 50 05 AM

Also, the in-between inserter fails to function due to the incorrectly positioneded blockProps props

I can essentially solve this issue in a very hacky way by utilizing useBlockProps and applying to the wrapper div, but this results in duplicated id's and classnames etc because the core/gallery also implements useBlockProps

Adding a filter allowing developers to modify useBlockProps would be useful, but there would need to be some way to determine if useBlockProps was being called in the block edit function context, or the BlockEdit filter context, so as not to filter the props in both situations.

It occurred to me that another possible solution might be to create a Slot similar to inspector controls allowing developers to inject additional fields into core blocks.

Also if there is another solution, that I have not thought of or mentioned here, I'd love to know what peoples thought son that are.

Environment info

  • WordPress 5.8
  • Stock Gutenberg version (no plugins)
  • Chrome Version 92.0.4515.131 (Official Build) (x86_64)

Related - #33953

Pre-checks

  • I have searched the existing issues.
  • I have tested with all plugins deactivated except Gutenberg.
@talldan talldan added [Feature] Extensibility The ability to extend blocks or the editing experience Backwards Compatibility Issues or PRs that impact backwards compatability Needs Technical Feedback Needs testing from a developer perspective. labels Aug 17, 2021
@talldan
Copy link
Contributor

talldan commented Aug 17, 2021

This is an interesting issue, I'll label as a backwards compatibility issue because the API version 2 change impacts the usefulness of the existing BlockEdit filter.

Potentially an option is for useBlockProps to be able to detect whether it's already been called in a wrapping HOC for the block and return fewer props in the block's edit, but that may be complicated. It would mean the hook isn't idempotent.

@mcsf
Copy link
Contributor

mcsf commented Aug 18, 2021

Yes, interesting one. I think it's fair to say that, prior to apiVersion: 2, the described use case was supported almost accidentally — in the sense that BlockEdit is meant to represent the outermost element of a block on the canvas, and the filter allowed any markup (as opposed to a specific primitive) to wrap around it.

This isn't meant as criticism of the use case: at the time (late 2017?) I think we expected developers to be able to do this, providing these filters as use-at-your-own-risk hatches.

Since then, though, we've come up with better ways to ascribe meaning and function to React trees — mostly thanks to Slot and Fills, as you mention. That's why the current examples found in the docs for editor.BlockEdit showcase adding a fragment with an InspectorControls element alongside BlockEdit.

From that angle, a Slot-based solution might be in order. That said, I'd like to know more about the specific applications. Is the example of a gallery preceded by a title something in production, or a hypothetical? What is the intent, and what leads to this filtering approach being favoured others (e.g. a custom block, a pattern, a group)? What other examples do you have?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Backwards Compatibility Issues or PRs that impact backwards compatability [Feature] Extensibility The ability to extend blocks or the editing experience Needs Technical Feedback Needs testing from a developer perspective. [Package] Block editor /packages/block-editor [Type] Enhancement A suggestion for improvement.
Projects
None yet
Development

No branches or pull requests

5 participants