0

One of my blocks only works in posts. It does not make sense to use it on the homepage. Another thing my block does not support is multiple instances on the same post id. I could prevent that with:

"supports": {
        "multiple": false
    },

in block.json. How can I allow the block being used only on pages and posts but not in FSE?

2
  • It doesn't look like there is a setting or hook to prevent a block from being available in FSE, but you could check within the block so that if it is not within a Page or Post (or Editor for those contexts) it returns either a warning that it can only be used in Pages and Posts, or else nothing so it's invisible if it's in the wrong context.
    – WebElaine
    Jan 19, 2022 at 16:52
  • is your block rendered in javascript or in PHP server side? Note this will eliminate/allow options. Also keep in mind that posts can be edited from within full site editing, and templates can be inserted into posts and gain that posts context. Posts and pages can also have custom templates defined via full site editing, so the idea that a block either is or is not in the full site editor doesn't make sense unless you're very careful about how you use a block
    – Tom J Nowell
    Jan 19, 2022 at 19:03

2 Answers 2

4

No, you don't, and for very good reasons that might not seem obvious at first. In essence your block needs to be available everywhere and to be able to handle that, even if it does this by not displaying anything. Just because you're in the site editor doesn't mean the block won't appear inside a post.

But before that makes sense there is missing information you are unaware of. I'll need to explain why, and how Core itself tackles this for block such as post content etc.

in block.json. How can I allow the block being used only on pages and posts but not in FSE?

This is a contradiction and a paradox. This hypothetical scenario is simply impossible in a block theme.

This is because:

  • a homepage template will contain posts which themselves are composed of blocks
  • a post context itself may be provided by an FSE template or template part, or even another block, e.g. a query block
  • posts themselves can contain template parts
  • posts can have custom FSE templates
  • reusable blocks, widgets, block based nav, etc

So the distinction between FSE and post blocks does not exist, based on a common misunderstanding. The way you've thought of it is natural given how Gutenberg has been presented as a post editor though.

Use Block Context Instead

Instead, you need to do what all the post specific blocks in core do and rely on context:

https://developer.wordpress.org/block-editor/reference-guides/block-api/block-context/

Lets use the official post title block as an example. We can see that its block.json uses:

    "usesContext": [ "postId", "postType", "queryId" ],

That requested context is then pulled into the javascript Edit component as a prop, the same way attributes are:

export default function PostTitleEdit( {
    attributes: { level, textAlign, isLink, rel, linkTarget },
    setAttributes,
    context: { postType, postId, queryId },
} ) {

The title block then does some internal logic and pulls in some values via the useEntity hook to make some decisions, and the context values it was given provide the post type and ID.

Finally, when deciding if it should render components, it does this:

    let titleElement = (
        <TagName { ...blockProps }>{ __( 'Post Title' ) }</TagName>
    );

    if ( postType && postId ) {
        titleElement =

Here it's showing Post Title as a placeholder, then replacing that placeholder if there's a post ID/type available, and it does this again further down the file before doing {titleElement} at the end of its edit component. As a result, it shows the post information in both the post editor and in the site editor, while still providing the settings UI.

We also see in index.php when rendering server side it gets the context via the $block parameter:

function render_block_core_post_title( $attributes, $content, $block ) {
    if ( ! isset( $block->context['postId'] ) ) {
        return '';
    }

Here it short circuits and exits with '' if there is no post ID.


It's important to note here that you do not know where a site template part is going to be used, or where a block may appear. You don't have to restrict your block to only appearing in the post editor, and if you do you'll probably end up with a broken post when that post shows up in the site editor with missing or unloaded blocks that the editor complains about.

By requesting and using context, you can be sure your block is always rendering the current post. Some people try to build work arounds and fetch the post ID from the store and save it as an attribute, but that means their block can't be used in context dependent situations reliably, e.g. inside query blocks.

Generally, refer to what the official Gutenberg repo does for these things. Core blocks tend to be kept up to late, sometimes bleeding edge, and should be taken as best practice in most cases.

Here's the official post title block for a closer view:

https://github.com/WordPress/gutenberg/tree/trunk/packages/block-library/src/post-title

You'll find other core blocks including those for the site editor here:

https://github.com/WordPress/gutenberg/tree/trunk/packages/block-library/src/

2
  • I did look to see if this also influenced the block inserter options but it does not. Note that you can also define custom contexts, though I'm not personally familiar with how that works or examples of its use. Post title etc are classified under the theme category in the inserter and can be used everywhere. You could even use these to build article meta in widget areas
    – Tom J Nowell
    Jan 19, 2022 at 19:30
  • 1
    THank you very much for that answer! =)
    – Marc
    Jan 19, 2022 at 20:11
0

Using context here is indeed a good solution. So following this example to check if edit happens in a Site Editor you just use this logic const isTemplateEdit = ! ( !! postId && !! postType );

1

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.