Skip to content

Auto-inserting Blocks #39439

@ockham

Description

@ockham

Tasks list

What problem does this address?

There are plugins in the WordPress ecosystem that, when activated, auto-append a Login/out link to any Navigation menu present on the site (via the wp_nav_menu_items filter):

image

These no longer work if an FSE theme is active, where all the presentational elements are provided by blocks rather than PHP code. And while there even is a Login/out link block in WordPress (see e.g. #29766), it has been argued that adding it manually isn’t on par with the user experience offered by simply activating a plugin. So in the following, we’ll assume that this is the baseline UX that we want to retain.

We cannot simply add the wp_nav_menu_items filter to the Navigation block, as it would allow arbitrary modifications of the block HTML – which could potentially cause it to be no longer parseable. It has thus been requested to add a counterpart filter to the Navigation block that allows for more “controlled” modifications.

However, another problem remains: Any (PHP) filter that modifies the rendered markup (of a dynamic block) on the frontend doesn’t allow for those modifications to be edited by the user inside the (FSE) block editor. Frontend/editor parity is an important tenet in Gutenberg, so we’ll add that to our constraints. Gutenberg contributors have thus been wary about adding such a filter, suggesting that in a block theme world, the ideal counterpart to a pre-FSE filter might not be another filter, but a different kind of extension mechanism altogether.

In a previous discussion, @mtias had clarified one more constraint: While a plugin should be able to add a block upon activation that would be both visible on the frontend and modifiable in the editor, that block should not be serialized. Instead, there would need to be a mechanism that would allow the user to either save the block to whatever template they’re editing, or dismiss it. I adopted the term “Ghost Block” to refer to this kind of blocks that are there but aren’t 👻

What is your proposed solution?

A mechanism that would vaguely consist of the following pieces:

  • Add a filter that allows changing the allowlist of inner blocks for a given parent block.
  • Add a filter that allows adding a ghost block to a relative position, specified e.g. by a parent block and a "first"/"last" argument, or a sibling block and a "before"/"after" argument.
    • In the frontend code, we’d need to modify Core’s block rendering logic to dynamically render a ghost block in the correct position. @youknowriad suggested using the render_block hook for this.
    • In the editor, we could add code that would insert the ghost block after loading the content, thus dirtying the editor state. This would have the desired effect of prompting the user to either save the ghost block, or dismiss it.
  • Provide an insert_ghost_block() PHP function to plugin authors that utilizes the above filters and that they can hook into plugin activation.

We'd obviously also need some UI in the editor in order to alert the user to the automatically added block that needs saving or dismissing, but this seems like the lesser problem for now.

Alternatives

  • It was suggested to add the ghost blocks at REST API layer (e.g. when requesting a wp_template CPT). This turned out problematic, since it wouldn’t cover the case where a user newly inserts a Navigation block.
  • Matías advised against introducing a collection of filters to create the desired behavior, but to rather use Global Settings instead, since this would also allow adding (and dismissing) ghost blocks at theme, site, or user level.

Open questions

  • It was brought up that while inserting the block into all parent blocks of a given type might be good enough for some blocks (such as the Login/out block inside of the Navigation block: in a lot of sites, there will be only one Navigation block anyway, likely present in one reusable template part), we might need to go more fine-grained in general, i.e. allow inserting only into parent blocks that are in a certain template or template part. For this, we’d need some sort of selector syntax.
  • Riad brought up the question whether a parent block should still show its "placeholder" state, even if it contains ghost blocks only. (He was leaning against, as the user could remove those manually to reset the parent block to its placeholder state.)

(Most of the discussions mentioned above happened at an IRL meeting with @mtias, @youknowriad, @priethor, @Poliuk, @luisherranz, @michalczaplinski, @mburridge, @c4rl0sbr4v0, @SantosGuillamot, and @DAreRodz.)

Metadata

Metadata

Assignees

Labels

[Feature] Block APIAPI that allows to express the block paradigm.[Feature] BlocksOverall functionality of blocks[Feature] ExtensibilityThe ability to extend blocks or the editing experience[Status] In ProgressTracking issues with work in progress[Type] DiscussionFor issues that are high-level and not yet ready to implement.

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions