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

Allow block to be constrained to only be used in root (when it has no parent) #7845

Closed
westonruter opened this issue Jul 9, 2018 · 37 comments
Labels
[Feature] Block API API that allows to express the block paradigm. [Feature] Nested / Inner Blocks Anything related to the experience of nested/inner blocks inside a larger container, like Group or P Needs Dev Ready for, and needs developer efforts Needs Technical Feedback Needs testing from a developer perspective.

Comments

@westonruter
Copy link
Member

I've been looking for a way to force a block to only be used at the root level. I'm trying to create a block taxonomy where only one block type (A) is allowed in the root, and it only allows another block type (B) as its child, and then B allows a restricted set of blocks, but not A or B, for example:

A > B > !(A|B)

The context here is implementing AMP Stories in Gutenberg. The structure of an AMP Story is as follows:

image

So I have an amp-story post type which should only take 1 or more amp-story-page blocks, and the amp-story-page blocks should only allow one or more amp-story-grid-layer blocks, and then lastly amp-story-grid-layer allows a subset of the core blocks (e.g. paragraph, video, image) but not any amp-story-* blocks.

At the moment, the amp-story-page block is offered in the inserter to be added to the root and to any of the other nesting blocks because there is nothing constraining it otherwise.

I tried a top-down and bottom-up approach where I explicitly set the allowedBlocks and the parent block property but thus resulted in some infinite recursion error.

I also tried to register a block with parent: [] but this just results in the inserter being hidden entirely, since all of the blocks other than amp-story-page have a parent set to be amp-story-page or amp-story-grid-layer.

Discussed in Slack at https://wordpress.slack.com/archives/C02QB2JS7/p1531158200000319

/cc @noisysocks

@westonruter westonruter added [Feature] Block API API that allows to express the block paradigm. [Feature] Nested / Inner Blocks Anything related to the experience of nested/inner blocks inside a larger container, like Group or P labels Jul 9, 2018
@noisysocks
Copy link
Member

This definitely sounds like a use case we should support. I have a few ideas on how to enable it.

1) Using parent

My first thought is that we should support this via parent which is similar to what @mtias first suggested in #5540.

registerBlockType( 'amp-story', {
    parent: [ 'post', 'page' ],
} );
registerBlockType( 'amp-story-page', {
    parent: [ 'amp-story' ],
} );
registerBlockType( 'amp-story-grid', {
    parent: [ 'amp-story-page' ],
} );

We've gone back-and-forth on whether or not to include post types in parent—see discussion in #6753. I think it's a clean API, though, and makes sense to allow a block to only be inserted into certain post types, just as we allow a block to only be inserted into certain block types.

2) Using InnerBlocks

This came up in #5540 and #6753 as well. The basic idea is to allow you to specify a blacklist of blocks that cannot go inside a <InnerBlocks>, rather than just the whitelist which is what allowedBlocks currently acts as.

registerBlockType( 'amp-story', {
    edit() {
        return <InnerBlocks disallowedBlocks={ [ 'amp-story' ] } />;
    },
} );
registerBlockType( 'amp-story-page', {
    parent: [ 'amp-story' ],
    edit() {
        return <InnerBlocks disallowedBlocks={ [ 'amp-story' ] } />;
    },
} );
registerBlockType( 'amp-story-grid', {
    parent: [ 'amp-story-page' ],
    edit() {
        return <InnerBlocks disallowedBlocks={ [ 'amp-story' ] } />;
    },
} );

It's not clear what would happen if one specified both allowedBlocks and disallowedBlocks. We'd likely have to raise an error.

We can, alternatively, combine allowedBlocks and disallowedBlocks, which I experimented with in #6753, e.g. allowedBlocks={ { 'amp-story': false, '*': true } } would allow all blocks except for amp-story. I sensed that this is too complex of an API, though.


Thoughts? cc. @WordPress/gutenberg-core

@westonruter
Copy link
Member Author

The use of parent in option 1 certainly seems simpler. For option 2 using disallowedBlocks it seems not-ideal to have to copy the root block for every nested block type.

@ellatrix
Copy link
Member

ellatrix commented Mar 1, 2019

I'm looking for something similar. I want to restrict the insertion of all block but one at the root level. So you can only insert one type of block at the root level. The rest can be inserted inside this block.

@edirpedro
Copy link

edirpedro commented May 16, 2019

+1

The disallowedBlocks option for <InnerBlocks> is enough to doesn't let users repeat the same block inside itself, causing some visual error, sometimes difficult to see and revert. I'm thinking about a section block to wrap contents as an example.

@idea--list
Copy link

+1

I experince most clients insisting to the classical editor and those few changing to GB tend to screw up their own websites because they are overwhelmed and even the UX is not intuitive enough.
I like the idea of disallowedBlocks for a beginning, however we build websites based on graphical layouts.

Those layouts have blocks but those blocks do not have content types (as they are all just graphical) but the designers give them aliases (like team member that contains a thumbnail and text for example).
What if later we could give our blocks such aliases and setup restriction rules based on those aliases rather than rules based on block types?

I mean most probably i do not want to make such a restriction that the client may not place an image block inside a text block... but for sure i do not want to allow them to place any text block in a block that has the alias "portrait gallery".

This way we would have an abstraction layer allowing us to group the very same block types together -but as they may have different aliases- we could set up different rules what content they are intended to contain based on the layout we got from the designer.

@MohammadAlBanna
Copy link

MohammadAlBanna commented May 18, 2019

I couldn't make disallowedBlocks works with me. Is it still active and implemented? Or removed from the current version of Gutenberg?

Also, this one couldn't work with me:

registerBlockType( 'amp-story', {
    parent: [ 'post', 'page' ],
} );

I would like section block I made just visible on root of the blocks...any ideas?

@ellatrix
Copy link
Member

ellatrix commented May 20, 2019

If it helps, here is another use case: custom "slides" post type with "slide" blocks. No other block should be inserted at the root.

@ellatrix
Copy link
Member

@swissspidy Is this the issue we discussed at WCEU? :)

@swissspidy
Copy link
Member

@ellatrix Yes I believe so!

@rdswd
Copy link

rdswd commented Jul 12, 2019

Having a similar need to what a few have described: Limit root-level blocks to one type. Allow multiple blocks within that block.

The post type template_locks or allowed_block_types filter (root level) override the individual block templateLock and allowedBlocks.

Is it a possibility that block level templateLock and allowedBlocks can override these root-level settings (for their level), or does it need to stay that way by design? Considering the example, child block settings would override parent blocks for their level, and the next child would for theirs, and so on. It seems like there is already a WP precedence for children to override parents.

There's many use cases where users should have the flexibility of multiple blocks, but certain layout parts/levels are locked/limited (event/product/realty listings).

@krywa5
Copy link

krywa5 commented Jan 24, 2020

I face the same problem. For now I just hide unnecesary blocks depending where inserter is in DOM structure, but it's neither clean nor working 100%. If only we could set 'root' blocks. Have anyone managed to solve the problem?

@myleshyson
Copy link
Contributor

myleshyson commented Feb 5, 2020

+1

We need this as well, but with the added constraint of only allowing 2 blocks for a specific page template in the root.

For example, we have a landing-page template and a home-page template, and on those two templates, we need the only option for editors to be inserting a section block in the root. That section block in turn would allow for about 10 or so blocks in itself.

Would be super helpful for us since Gutenberg is inherently a little confusing to a lot of our editors (most of them aren't WordPress editors by trade, its just part of their job to update their sites) and even more confusing is that there are different rules for different page templates (sections can go in these two templates but not these. Your page looks bad here because you picked the landing-page template but didn't use a section...etc.) Really would save our support team a lot of hours of explaining that over and over again if we could just automate which blocks are available given certain conditions.

@ckasimons
Copy link

+1

The need for block restriction is very real.

Is it possible to de-couple the definition modules made in allowedBlocks prop (js) and the 'allowed_block_types' filter (php) so that the InnerBlocks module can grant provision of the allowedBlocks independently? This would provide a way of explicity defining sets of allowed blocks in both the Root and the InnerBlock.

@noisysocks noisysocks added the Needs Dev Ready for, and needs developer efforts label Mar 23, 2020
@noisysocks
Copy link
Member

The next step here is for a developer who's interested in helping out to explore one of the approaches (probably (1)) described in #7845 (comment). I've added the Needs Dev label to signify this.

@ronakrrb
Copy link

ronakrrb commented Apr 27, 2020

Hello, I have registered a custom block as parent to all the default Gutenberg blocks. Also, inside the <InnerBlocks>, I have specified the allowedBlocks attribute to all the default Gutenberg blocks since the parent block was displaying in the inserter of InnerBlocks. Now the problem I am facing is, when click on the plus icon of the column block, it directly appends the custom block without opening the inserter.
To solve this, I added the column block also as the parent for all the default blocks so the inserter opens when clicked on the plus icon of the column block. This created another issue that is the custom block is now visible inside the inserter which opened on click of the plus icon of column block.

My question:

  1. Is the approach correct
  2. If yes, how can I make sure that the custom block is not visible inside the inserter of the column block?
  3. If no, what's the best approach?

My code
`
const parent = ['pykih/byo', 'core/column', 'core/group', 'core/media-text'];

addFilter('blocks.registerBlockType', 'assignParentBlock', (pSettings, pName) => {
    return Object.assign({}, pSettings, {
        parent: parent
    })
});

`

@frob
Copy link

frob commented May 8, 2020

It would seem to me that limiting by post type on parent could be limiting. Just specifying parent: 'root' aught to be enough to limit the block to only be posted in a top level.

I would also suggest this as a "Why not both" scenario. It makes sense to add dissallowedBlocks to the InnerBlock api, but I don't see how that would solve the need to limit blocks to the page/post root.

+1 to dissallowedBlocks

@LC43
Copy link

LC43 commented Aug 29, 2020

so... still no way to prevent editors to add blocks in root level, besides the ones we supply in the template?

@johnrom
Copy link

johnrom commented Sep 18, 2020

Can we make the definition of parent such that "no parent" is a valid test, and in the case above, if it is the only value then a block can only be used in the root? My use case is requiring a container for all WYSIWYG-like blocks since they are simple elements like <ul />, but not for layout blocks which are already wrapped in div containers which can be used for positioning.

I think that adding "root" here is strange because root is not a "parent block", nor is "post" or "page" a parent block. Instead, there is "no" parent block. I think an empty array for parent should also mean "no parents", as in it is only allowed in the root. But that could be a breaking change.

For the same reason, I disagree with adding "post type" to the parent definition. I think if we want to add post type restrictions to the block definition it should be as its own property postTypes. I think it would be weird to express "allow on page post type, with no parent or as a child of 'core/columns'" in a single array.

const Tabs = {
  // only allow this block in root, don't need tabbed columns
  parent: [], // or [ '' ]
}

const Accordion = {
  // this can be in a root, a column, a tab
  parent: ['', 'core/columns', 'myplugin/tabs'],
}

Another complementary idea which expresses the opposite of this would be to set the parent property to 'any' or ['any'] (or core/any to prevent collisions with custom blocks?) -- allowing a block to be inserted into any InnerBlocks, but NOT the root of Gutenberg. That way, the definition of parent doesn't have to include every possible, constantly evolving set of blocks that can be parents. The default for this property would now be equivalent to parent: [ '', 'any' ].

If we can agree this is a good way forward, I'll try and take a look and open a PR.

@mtias mtias added the Needs Technical Feedback Needs testing from a developer perspective. label Sep 25, 2020
@DemkivV
Copy link

DemkivV commented Oct 13, 2020

Here's a workaround that could work:

  • Define a custom block with InnerBlocks, which will be used as a parent (see docu)
    • This is also the place where you can restrict which types of blocks can be added by whitelisting (see docu)
    • Don't register this block to any category to avoid that it's added accidentally while editing, since there are no restrictions to this block (not sure if it'll pop up, but perhaps this is sufficient to hide it in the backend).
  • The blocks that are only allowed for the root level should define this root block as their parent, so they can only be added on this level (see docu)
  • Define a template for pages/posts and set it to this parent block (see docu)
    • Also lock the template, so the parent block is the only top level block (see docu)

Not the cleanest approach to nest the whole content in another div to mimic the root, but could work at least.

I didn't test this yet, but decided to write this idea down, since perhaps it could be useful for someone looking for a quick hack that makes this feature working now.

@kanlukasz
Copy link

For now I just hide unnecesary blocks depending where inserter is in DOM structure,

@krywa5 can you show an example of how you do it?
I am looking for a way to do it but I have no clever idea

@ronakrrb
Copy link

ronakrrb commented Dec 20, 2020

Hello, I have registered a custom block as parent to all the default Gutenberg blocks. Also, inside the <InnerBlocks>, I have specified the allowedBlocks attribute to all the default Gutenberg blocks since the parent block was displaying in the inserter of InnerBlocks. Now the problem I am facing is, when click on the plus icon of the column block, it directly appends the custom block without opening the inserter.
To solve this, I added the column block also as the parent for all the default blocks so the inserter opens when clicked on the plus icon of the column block. This created another issue that is the custom block is now visible inside the inserter which opened on click of the plus icon of column block.

My question:

  1. Is the approach correct
  2. If yes, how can I make sure that the custom block is not visible inside the inserter of the column block?
  3. If no, what's the best approach?

My code
`
const parent = ['pykih/byo', 'core/column', 'core/group', 'core/media-text'];

addFilter('blocks.registerBlockType', 'assignParentBlock', (pSettings, pName) => {
    return Object.assign({}, pSettings, {
        parent: parent
    })
});

`

Hello, Is there any update on this? Can I edit the default column block to updates its disallowed blocks? I don't want the custom blocks to be in the inserter of the column block.

@krywa5
Copy link

krywa5 commented Dec 21, 2020

For now I just hide unnecesary blocks depending where inserter is in DOM structure,

@krywa5 can you show an example of how you do it?
I am looking for a way to do it but I have no clever idea

It is not possible anymore. After gutenberg update a few months ago, the inserter isn't nested inside the block HTML. For now I just dropped the idea.

@myleshyson
Copy link
Contributor

myleshyson commented Dec 31, 2020

Hey so here's how we're currently constraining blocks to certain page templates. The same can probably be used to constrain blocks to just the root document.

I have a public repo with this code but I'm newer to open source and last time I tried to link to something on stack overflow I got points deducted...so here's the code and sorry for the length 😬

const { pick, intersection } = window.lodash
const { data, i18n } = window.wp
const { __ } = i18n
const { select, subscribe, dispatch } = data
const { isTyping, getBlocks } = select('core/block-editor')
const { getEditedPostAttribute } = select('core/editor')
const { isEditorPanelOpened, getActiveGeneralSidebarName } = select('core/edit-post')
const { getBlockType } = select('core/blocks')
const { addBlockTypes, removeBlockTypes } = dispatch('core/blocks')
const { updateEditorSettings } = dispatch('core/editor')

/**
 * Register a state subscriber ONLY WHEN the predicate is met, then unsubscribe it immediately.
 *
 * @param {function} predicate
 * @param {function} callback
 *
 * @return {function} The generated unsubscribe function, just in case you need it.
 */
const subscribeOnceWhen = (predicate, callback) => {
  const unsubscribe = subscribe(() => {
    if (predicate()) {
      unsubscribe()
      callback()
    }
  })

  return unsubscribe
}

/**
 * Map block names to the actual block object.
 *
 * @type {object}
 */
const unregisteredBlocks = {}

/**
 * Defines the map of block types and the templates they are restricted to.
 *
 * @type {object}
 */
const blockTemplateRestrictions = {
  'ufhealth-apollo/hero': [
    'template-homepage.php',
  ],
  'ufhealth-apollo/landing-hero': [
    'template-landing.php',
  ],
  'ufhealth-apollo/section': [
    'template-homepage.php',
    'template-landing.php',
  ],
  'ufhealth-apollo/section-heading': [
    'template-homepage.php',
    'template-landing.php',
  ],
}

/**
 * Currently selected template.
 * @type {string}
 */
let currentTemplate = ''

/**
 * Current restricted block count.
 *
 * @type {number}
 */
let currentRestrictedBlocks = 0

/**
 * Page Templates loaded with the page.
 *
 * @type {object}
 */
let defaultPageTemplates = {}

/**
 * Are we currently restricting page templates? Determines
 * if we show the notice under the select box or not.
 *
 * @type {boolean}
 */
let isRestricted = false

const blocksLoaded = () => {
  const blockList = getBlocks()
  return blockList.length > 0
}

/**
 * Our whitelist notice that we inject under the Page Templates select box.
 */
const templateWhitelistNotice = document.createElement('p')
const templateWhitelistBlockList = document.createElement('ul')

templateWhitelistNotice.classList.add('components-base-control__note')
templateWhitelistBlockList.classList.add('components-base-control__note')
templateWhitelistNotice.innerText = __('Some page templates are currently unavailable because they are incompatible with the following blocks on this page. You will need to remove them in order to make those templates available again.', 'ufhealth-apollo')

/**
 * Add a note below the page template dropdown to inform the user of active template restrictions.
 */
const addTemplateWhitelistNotice = restrictedBlocks => setTimeout(() => {
  const wrapper = document.querySelector('.editor-page-attributes__template')

  templateWhitelistBlockList.innerHTML = ''

  if (restrictedBlocks.length) {
    restrictedBlocks.forEach(blockName => {
      const block = getBlockType(blockName)
      const item = document.createElement('li')
      item.innerText = `${block.title} Block`
      templateWhitelistBlockList.appendChild(item)
    })
  }

  if (wrapper && wrapper.lastElementChild !== templateWhitelistNotice) {
    wrapper.appendChild(templateWhitelistNotice)
    wrapper.appendChild(templateWhitelistBlockList)
  }
}, 50)

/**
 * Removes the notice from under the Page Templates select box.
 */
const removeTemplateWhitelistNotice = () => setTimeout(() => {
  const wrapper = document.querySelector('.editor-page-attributes__template')
  if (wrapper && wrapper.contains(templateWhitelistNotice)) {
    templateWhitelistNotice.remove()
  }
}, 50)

/**
 * Run our listeners once the editor is finished loading.
 */
const run = () => {
  return new Promise(resolve => {
    subscribeOnceWhen(blocksLoaded, () => {
      defaultPageTemplates = select('core/editor').getEditorSettings().availableTemplates
      restrictBlocks()
      whitelistPageTemplates()
      resolve()
    })
  })
}

/**
 * Responsible for unregistering blocks based on the template selected. It will re-register those
 * blocks if a non-restricted template is selected.
 */
const restrictBlocks = () => {
  currentTemplate = getEditedPostAttribute('template') || 'default'
  restrictBlocksForTemplate(currentTemplate)

  subscribe(() => {
    if (isTyping()) {
      return false
    }

    const newTemplate = getEditedPostAttribute('template') || 'default'

    if (currentTemplate !== newTemplate) {
      currentTemplate = newTemplate
      restrictBlocksForTemplate(currentTemplate)
    }
  })
}

/**
 * Responsible for hiding templates based off if there exists restricted blocks
 * in the editor.
 */
const whitelistPageTemplates = () => {
  const blocks = getBlocks()
  const { templates, restrictedBlocks } = checkForRestrictedBlocks(blocks)
  currentRestrictedBlocks = restrictedBlocks.length

  updateWhitelistedTemplates(templates)
  addOrRemoveWhitelistNotice(restrictedBlocks)

  subscribe(() => {
    if (isTyping() === true) {
      return false
    }

    const blocks = getBlocks()
    const { templates, restrictedBlocks } = checkForRestrictedBlocks(blocks)

    addOrRemoveWhitelistNotice(restrictedBlocks)

    if (restrictedBlocks.length !== currentRestrictedBlocks.length) {
      currentRestrictedBlocks = restrictedBlocks
      updateWhitelistedTemplates(templates, restrictedBlocks)
    }
  })
}

/**
 * Adds the whitelist notice under the Page Templates select box to let
 * users know why they only see certain templates.
 */
const addOrRemoveWhitelistNotice = (restrictedBlocks) => {
  if (isEditorPanelOpened('page-attributes') && getActiveGeneralSidebarName() === 'edit-post/document') {
    if (isRestricted) {
      addTemplateWhitelistNotice(restrictedBlocks)
    } else {
      removeTemplateWhitelistNotice()
    }
  }
}

/**
 * Either registers or unregisters blocks based on the selected template.
 *
 * @param {string} template
 */
const restrictBlocksForTemplate = (template) => {
  const { blocksToRegister, blocksToUnregister } = templateBlockRegistry(template)
  if (blocksToUnregister.length) {
    blocksToUnregister.forEach((blockName) => {
      const blockExists = typeof getBlockType(blockName) !== 'undefined'
      const isRegistered = typeof unregisteredBlocks[blockName] === 'undefined'

      if (blockExists && isRegistered) {
        unregisteredBlocks[blockName] = getBlockType(blockName)
      }
    })
    removeBlockTypes(Object.keys(unregisteredBlocks))
  }

  if (blocksToRegister.length) {
    let registeredBlocks = []
    blocksToRegister.forEach(blockName => {
      const blockDoesNotExist = typeof getBlockType(blockName) === 'undefined'
      const isUnregistered = typeof unregisteredBlocks[blockName] !== 'undefined'

      if (blockDoesNotExist && isUnregistered) {
        registeredBlocks.push(unregisteredBlocks[blockName])
        delete unregisteredBlocks[blockName]
      }
    })
    addBlockTypes(registeredBlocks)
  }
}

/**
 * Decides what blocks we need to register and unregister
 *
 * @param {string} template
 * @returns {{blocksToRegister: [], blocksToUnregister: []}}
 */
const templateBlockRegistry = (template) => {
  let blocksToRegister = []
  let blocksToUnregister = []

  Object.keys(blockTemplateRestrictions).forEach((block) => {
    if (blockTemplateRestrictions[block].includes(template)) {
      blocksToRegister.push(block)
    } else {
      blocksToUnregister.push(block)
    }
  })

  return {
    blocksToRegister,
    blocksToUnregister
  }
}

/**
 * Update the editor settings in gutenberg to show only templates that are not restricted
 * for certain blocks.
 * @param templates
 */
const updateWhitelistedTemplates = (templates) => {
  if (templates.length > 0) {
    isRestricted = true
    updateEditorSettings({ availableTemplates: pick(defaultPageTemplates, templates) })
  } else {
    isRestricted = false
    updateEditorSettings({ availableTemplates: defaultPageTemplates })
  }
}

/**
 * Checks to see what templates we should restrict to based on the blocks found in the editor.
 * If empty, then no templates will be restricted.
 *
 * @param {array} blocks
 * @returns {array}
 */
const checkForRestrictedBlocks = (blocks) => {
  let foundTemplates = []
  let foundBlocks = []

  blocks.forEach(block => {
    if (typeof blockTemplateRestrictions[block.name] !== 'undefined') {
      foundTemplates.push(blockTemplateRestrictions[block.name])
      if (!foundBlocks.includes(block.name)) {
        foundBlocks.push(block.name)
      }
    }

    if (block.innerBlocks.length > 0) {
      const { templates, restrictedBlocks } = checkForRestrictedBlocks(block.innerBlocks)

      if (templates.length > 0) {
        foundTemplates.push(templates)
      }

      restrictedBlocks.forEach(blockName => {
        if (!foundBlocks.includes(blockName)) {
          foundBlocks.push(blockName)
        }
      })
    }
  })

  return {
    templates: intersection(...foundTemplates),
    restrictedBlocks: foundBlocks
  }
}

export const RestrictBlocks = { run }

Then in your entry file you would just use it like this

import { RestrictBlocks } from './path/to/above/snippet'

window.wp.domReady(() => {
  RestrictBlocks.run()
})

@prathamesh-gharat
Copy link

I was able to limit a block to the content (root) level by using parent: ['core/post-content'].

It works in my case but would this be sufficient? would this have any edge cases?

Note: Using blocks.registerBlockType JS filter allows you to update the parent property of existing blocks to your own block.

@johnrom
Copy link

johnrom commented May 3, 2021

Nice, I don't think post-content was a block when this issue was created. Seems like that would have come from the recent Gutenberg layout editor updates.

If that's now a block that can be specified as parent, I think this issue can be closed? (I haven't confirmed)

@landwire
Copy link

landwire commented May 3, 2021

I know it's not super related, but is the parent info also available in the render_block PHP hook? I want to add some block wrapper html to all/most blocks (also core), but only to the top-level blocks.

@Bysander
Copy link

I was able to limit a block to the content (root) level by using parent: ['core/post-content'].

Plus bloody 10 for this - didn't hear about that one sneak in.

Also +10 for disallowedBlocks please - I've needed it for nearly every nested block I've written

Anyway, one method I've tried is using select > getInserterItems( clientId ) then removing your "disallowedBlocks" works in the console - but you can't pass this to allowedBlocks without a clientId - and you don't have on on the block init.

Unless anyone knows of a method to edit the insertable items or allowedBlocks after the block has loaded?

@Rockstar907
Copy link

Rockstar907 commented Jan 14, 2022 via email

@Rockstar907
Copy link

Rockstar907 commented Jan 14, 2022 via email

@Rockstar907
Copy link

Rockstar907 commented Jan 14, 2022 via email

@Bysander
Copy link

This is a GitHub thread for Wordpress Gutenberg @Rockstar907 is your username and you're posting to a bug board via email. We can't see your details or info.

@thomasdebruin
Copy link

Thnx @prathamesh-gharat saved me some time!
In my case I also wanted to restrict blocks on the widget areas.
Took me some time to find out i had to use ''core/widget-area''.

For me it seems also related to this issue:
#28517

The Gutenberg editor is really nice, but it still misses some solid functionality. When you build a custom theme where you want to control the editing experience, offer only the blocks/options that are relevant.
What I would prefer is a straightforward api (or json config file, or both):

  • restrict available blocks + nesting options
  • per post type
  • per widget area
  • per user/role (this would be really luxury)

@cr0ybot
Copy link
Contributor

cr0ybot commented Oct 6, 2022

It's great, even if currently undocumented, that this works with core/post-content and core/widget-area. I got my hopes up that I would be able to find something to limit a block to the root of the site editor, but no luck so far.

@mtias
Copy link
Member

mtias commented Oct 6, 2022

Indeed, core/post-content allows restricting to the root of post content and paired with postType you can restrict to a given CPT. Regarding root of site editor, it's worth reading through #39281

@juanmaguitar
Copy link
Contributor

juanmaguitar commented Oct 6, 2022

@westonruter as this issue was created 4 years ago, could you please verify that according to @mtias comment here (and previous ones) you're currently able to restrict blocks to only be used from the root of your Custom Post Type?
If so, I think we can close this issue.
I have created #44729 to ensure this capability is properly documented in the Handbook.

@westonruter
Copy link
Member Author

@juanmaguitar It's been so long that the original reason I filed this issue is now obsolete. I'll trust what @mtias says 😄

@toelli
Copy link

toelli commented Dec 14, 2022

Indeed, core/post-content allows restricting to the root of post content and paired with postType you can restrict to a given CPT. Regarding root of site editor, it's worth reading through #39281

Think I found a bug with this solution: When you restrict a block with parent set as core/post-content you can only add it to the content at root level using the inserter (as expected) but you can still focus on the block after it has been added on root level and then click the "..." menu and from there make a group and suddenly the block that is supposed to be restricted to the root is now inside a group block and no longer in the root. Any ideas on how to fix this issue?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Feature] Block API API that allows to express the block paradigm. [Feature] Nested / Inner Blocks Anything related to the experience of nested/inner blocks inside a larger container, like Group or P Needs Dev Ready for, and needs developer efforts Needs Technical Feedback Needs testing from a developer perspective.
Projects
None yet
Development

No branches or pull requests