Skip to content
This repository has been archived by the owner on Jul 28, 2023. It is now read-only.

<wp-inner-blocks> causes DOM differences between edit and frontend #50

Closed
yscik opened this issue Aug 8, 2022 · 6 comments
Closed

<wp-inner-blocks> causes DOM differences between edit and frontend #50

yscik opened this issue Aug 8, 2022 · 6 comments

Comments

@yscik
Copy link
Collaborator

yscik commented Aug 8, 2022

The <wp-inner-blocks> wrapper being added implicitly on the frontend is something block authors might not expect. It's not added in the editor right now, so anything relying on the DOM tree needs to handle two versions. Most notably this is styles with relationship selectors.

For example, Sensei's Flashcard block uses a structure where the first and second child blocks are considered the front and back of the card, respectively:

&--flipped-front > *:nth-child(1),
&--flipped-back > *:nth-child(2) { ... }

This is likely an edge case and can be worked around, but making it consistent across editor and frontend could improve the developer experience.

@luisherranz
Copy link
Member

Interesting.

I thought display: contents would solve all the CSS issues, but it doesn't work with nth-child: https://codepen.io/luisherranz/pen/WNzyMJW

@luisherranz
Copy link
Member

making it consistent across editor and frontend could improve the developer experience.

@yscik: will adding <wp-inner-blocks> to the Edit component would be enough, or can it cause other issues?

@yscik
Copy link
Collaborator Author

yscik commented Aug 29, 2022

On second thought, there are a few cases where having a wrapper is not desired, like HTML list and tables, and sometimes folks want to insert elements at the same level as the inner blocks. I think those were the reasons on introducing the useInnerBlocksProps API:

@luisherranz
Copy link
Member

luisherranz commented Aug 30, 2022

Ok. Thanks, Peter.

It seems like flex children could use display: contents, but for the rest of the cases, targeting the correct nodes still requires knowing that the wp-inner-block/slot exists in the hierarchy:

:is(wp-inner-blocks, div) > span:nth-child(2) {
  color: red;
}

codepen

Let's keep talking about the alternatives in:

@luisherranz
Copy link
Member

luisherranz commented Sep 2, 2022

Coming back from #62, I think the solution for blocks (islands) can be different than for client components.

Blocks can't be nested, and they usually have a single wrapper node (although it doesn't seem to be mandatory). So I think the attribute approach could work:

<div class="wp-block-parent">
  <div>Some content</div>
  <div class="wp-block-child-1" wp-inner-block>Some child content</div>
  <div class="wp-block-child-2" wp-inner-block>More child content</div>
</div>

And instead of using:

document.querySelector("wp-inner-blocks");

We could use:

document.querySelectorAll("[wp-inner-block]");

The template selector (currently "template.wp-inner-blocks") that we use when the inner blocks are hidden doesn't change.

To avoid serializing or adding the attribute unnecessarily to the inner blocks of non-interactive blocks, we could do it dynamically with the upcoming WP_HTML_Walker:

if ( $is_this_block_interactive ) {
  $inner_blocks_html = '';
  foreach ( $block->inner_blocks as $inner_block ) {
    $html = new WP_HTML_Walker( $inner_block->render() );
    $html->next_tag(); // Find the first tag, which should be the wrapper.
    $html->set_attribute( "wp-inner-block" ); // Add the `wp-inner-block` attr.
    $inner_blocks_html .= string $html;
  }
}

And if we want to support multiple wrapper nodes (as long as they have the correct class):

EDIT: Not sure if this is feasible because:

  • It'd have to rely on class names that start with wp-block but don't contain underscores (like wp-button__link) which seems fragile.
  • It only works if we can apply it to the direct children's HTML. If not, the children's children's HTML will be incorrectly marked as well.
if ( $is_this_block_interactive ) {
  $inner_blocks_html = '';
  foreach ( $block->inner_blocks as $inner_block ) {
    $html = new WP_HTML_Walker( $inner_block->render() );
    while ( $html->next_tag() ) {
      $is_wrapper = $html->get_class( $block_classname ); // `get_class()` it is not implemented yet
      if ( $is_wrapper ) {
        $html->set_attribute( "wp-inner-block" ); // Add the `wp-inner-block` attr.
      }
    }
    $inner_blocks_html .= string $html;
  }
}

@luisherranz
Copy link
Member

Closed as we're not actively working on this experiment anymore and this works fine in the Directives Hydration.

@luisherranz luisherranz closed this as not planned Won't fix, can't repro, duplicate, stale Jan 16, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants