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/deny block use based on post-type or template context #41062

Open
boonebgorges opened this issue May 13, 2022 · 9 comments · May be fixed by #41718
Open

Allow/deny block use based on post-type or template context #41062

boonebgorges opened this issue May 13, 2022 · 9 comments · May be fixed by #41718
Labels
Developer Experience Ideas about improving block and theme developer experience [Feature] Block API API that allows to express the block paradigm. [Feature] Site Editor Related to the overarching Site Editor (formerly "full site editing") [Focus] Blocks Adoption For issues that directly impact the ability to adopt features of Gutenberg. [Status] In Progress Tracking issues with work in progress [Type] Enhancement A suggestion for improvement.

Comments

@boonebgorges
Copy link
Member

What problem does this address?

It's sometimes desirable to limit blocks to certain post-type contexts (or, in a parallel fashion, to prevent a specific block from being used in a given context). As far as I can see, the current recommendation is to use unregisterBlockType() to unregister a given block based on getCurrentPostType(), etc. See eg #27607.

While the semantics of this technique are not entirely straightforward ("unregister" rather than "hide", or better still, "prevent from showing in this context"), it pretty much works in the post editor. However, it's not workable in the Site Editor. It's possible to fetch the currently edited template using wp.data.select( 'core/edit-site' ).getEditedPostId(), and to unregisterBlockType() based on this. But it's possible to switch the currently-edited template without a page reload, meaning that you'd have to re-registerBlockType(). Moreover, setting up a subscribe() callback for getEditedPostId() to determine the current context is pretty clumsy.

What is your proposed solution?

I propose that, as part of their registration metadata, a block can specify allow or deny contexts. Maybe something like:

allowForPostTypes: [ 'post', 'page', 'my_custom_post_type' ],
allowForTemplates: [ 'archive', 'single', 'page', 'archive-my_custom_post_type', 'single-my_custom_post_type' ],

postTypes would specify the contexts for the post editor, while templates would be for the site editor. Or it might be better to have a single declaration that covers both cases, depending on the overall strategy for merging the editing experience.

Similarly, it might be nice to have deny declarations that work similarly (though of course there are problems with allowing both).

Apologies in advance if this idea's already in circulation - I searched but couldn't find anything.

@Mamaduka Mamaduka added the Developer Experience Ideas about improving block and theme developer experience label May 17, 2022
@gigitux
Copy link
Contributor

gigitux commented Jun 8, 2022

For woocommerce/woocommerce-blocks#5193 we are trying the solution with a subscribe callback. Maybe, could we try to contribute upstream to support these APIs? I guess that could be useful for other plugins too.

@noisysocks
Copy link
Member

When designing the parent attribute in the block schema there was discussion about allowing you to specify post types as well as block types. I could see it working for templates too.

Regarding a deny list, there was a proposal about allowing you to pass an object to parent which lets you control which blocks are explicitly allowed, explicitly denied, and what the default is. Have a look at #5540 (comment).

Maybe can revisit some of this 😀

@annezazu annezazu added the [Focus] Blocks Adoption For issues that directly impact the ability to adopt features of Gutenberg. label Jun 13, 2022
gigitux added a commit to gigitux/gutenberg that referenced this issue Jun 14, 2022
allow block use by post and template type
@gziolo gziolo added the [Feature] Block API API that allows to express the block paradigm. label Feb 3, 2023
@gziolo gziolo mentioned this issue Feb 20, 2023
69 tasks
@gziolo
Copy link
Member

gziolo commented Feb 20, 2023

Regarding a deny list, there was a proposal about allowing you to pass an object to parent which lets you control which blocks are explicitly allowed, explicitly denied, and what the default is. Have a look at #5540 (comment).

Good point. I know about a similar discussion when ancestor field was in development: #37181 (comment). There are more thoughts on how parent and ancestor could intersect with more complex use cases. It could also get extended to deny list.

This issue is related to #46900, which proposes adding a way to register a block only in a specific editor. In some cases, providing a post type would be equivalent to limiting access to the post editor, and providing a template would be equivalent to limiting access to the site/template editor.

@gigitux
Copy link
Contributor

gigitux commented Feb 24, 2023

It would be very interesting to have this setting for the variations too. Regarding the variations, I created an issue about the support for the ancestor/parent #48424

@jordesign jordesign added the [Type] Enhancement A suggestion for improvement. label Sep 12, 2023
@ndiego ndiego removed the [Focus] Blocks Adoption For issues that directly impact the ability to adopt features of Gutenberg. label Nov 17, 2023
@bph bph moved this from In Progress to Needs discussion in Increase Gutenberg Extensibility Nov 21, 2023
@bph bph moved this from Needs discussion to Todo in Increase Gutenberg Extensibility Nov 22, 2023
@bph bph moved this from Todo to In Progress in Increase Gutenberg Extensibility Nov 23, 2023
@bph
Copy link
Contributor

bph commented Dec 13, 2023

@gigitux @boonebgorges What do you think about the approach to handling this on a post type level, as @mtias suggests in his comment.

We should probably discuss some default_blocks, allow_blocks, disallow_blocks properties in register_post_type instead. Consider post types already allow specifying a template property.

@mikejolley
Copy link
Contributor

mikejolley commented Apr 12, 2024

We have use cases where we need to limit the available blocks within a specific Block Template. allowed_block_types_all is not suitable because it only runs once in the site editor, and there is no context that changes based on the edited template.

Something like this could deregister blocks based on template, but then there is no good way to restore the block types once the user switches to another template or view.

wp_add_inline_script('wp-edit-site', "
    wp.domReady( () => {
      let currentTemplateId;

      wp.data.subscribe(function(){
        const previousTemplateId = currentTemplateId;
        currentTemplateId = wp.data.select( 'core/edit-site' )?.getEditedPostId();

        if ( previousTemplateId === currentTemplateId ) {
          return;
        }

        const allowedBlocks = [
          'core/heading',
          'core/image',
          'core/list',
          'core/paragraph',
        ];

        if ( currentTemplateId === 'mailpoet/mailpoet//email-general' ) {
          wp.blocks.getBlockTypes().forEach( function ( blockType ) {
            if ( allowedBlocks.indexOf( blockType.name ) === -1 ) {
              console.log(blockType.name);
              wp.blocks.unregisterBlockType( blockType.name );
            }
          } );
        }
      });
    } );
    ", 'before');

Ideally we'd like some additional context passed to allowed_block_types_all which gives us the name of the edited template. And this would hopefully get ran every time the user switches views.

@gziolo gziolo added the [Feature] Site Editor Related to the overarching Site Editor (formerly "full site editing") label Apr 14, 2024
@ndiego
Copy link
Member

ndiego commented Jul 15, 2024

Something like this could deregister blocks based on template, but then there is no good way to restore the block types once the user switches to another template or view.

Thanks for this additional context @mikejolley. Dynamically restricting blocks in the Site/Template Editor is definitely more complicated than the Post Editor and we currently lack the tools to do so.

Also, not sure why I removed the "Blocks Adoption" tag in the past 🤦‍♂️, but added it back.

@ndiego ndiego added the [Focus] Blocks Adoption For issues that directly impact the ability to adopt features of Gutenberg. label Jul 15, 2024
@github-actions github-actions bot added the [Status] In Progress Tracking issues with work in progress label Oct 15, 2024
@benazeer-ben
Copy link
Contributor

Hi everyone,

Greetings!

I have created a straightforward filter to deny specific blocks from posts and pages based on the post_type. We can also specify which blocks should be removed from the site editor templates.

Here is the filter code:

function gutenberg_denied_block_types( $allowed_blocks, $editor_context ) {

	// If $allowed_blocks is empty or not provided, fetch all registered blocks
	if ( ! $allowed_blocks || ! is_array( $allowed_blocks ) ) {
		$allowed_blocks = array_keys( WP_Block_Type_Registry::get_instance()->get_all_registered() );
	}
	// Check if the current context is post or site editor
	if ( isset( $editor_context->post ) ) {
		// Get the current post type
		$post_type = get_post_type( $editor_context->post );

		// Example: Deny specific blocks for 'post' post type
		if ( $post_type === 'post' ) {
			// Deny specific blocks by removing them from $allowed_blocks
			$denied_blocks = array(
				'core/gallery',
				'core/cover',
			);
			$allowed_blocks = array_diff( $allowed_blocks, $denied_blocks );
		} elseif ( $post_type === 'page' ) {
			// Deny specific blocks for pages
			$denied_blocks = array(
				'core/quote',
				'core/video',
			);
			$allowed_blocks = array_diff( $allowed_blocks, $denied_blocks );
		}
	}

	// Deny blocks in the Site Editor context
	if ( isset( $editor_context->name ) && 'core/edit-site' === $editor_context->name ) {
		if ( isset( $_GET['postId'] ) ) { //phpcs:ignore

			$template_post_id = sanitize_text_field( wp_unslash( $_GET['postId'] ) ); //phpcs:ignore

			$template_post = get_block_template( $template_post_id, 'wp_template' );

			if ( $template_post ) {
				// Now you can use this template slug to apply conditions and deny blocks
				if ( 'archive' === $template_post->slug ) {
					$denied_blocks = array(
						'core/columns',
						'core/quote',
					);
					$allowed_blocks = array_diff( $allowed_blocks, $denied_blocks );
				} elseif ( $template_post->slug === 'single' ) {
					// Deny specific blocks for other templates
					$denied_blocks = array(
						'core/gallery',
						'core/cover',
					);
					$allowed_blocks = array_diff( $allowed_blocks, $denied_blocks );
				}
			}
		}
	}

	return array_values( $allowed_blocks );
}

add_filter('allowed_block_types_all', 'gutenberg_denied_block_types', 10, 2);

Currently, when clicking on templates from the site editor template listing page, the page does not reload, so the filter does not apply until the template edit page is reloaded.

If this way of handling the block restriction using filter looks good, then we can further develop the current code with option to handle on-click scenario.

For further improvement, we can also provide a backend option for users to specify which blocks to avoid for which post types if it needed.

Please let me know whether this approach is suitable or not and also share your feedbacks/ thoughts on this.

Testing Instructions

Create a new post.
Search for Gallery/Cover block: it should not be visible.
Create a new page.
Search for Quote/Video block: it should not be visible.
Open the FSE.
Open the Archive template & reload
Search for Columns/Quote block: it should not be visible.
Open the single template & reload
Search for Gallery/Cover block: it should not be visible.

Screenshots before and after adding filter

post-edit-after

Image

post-edit-before

Image

template-edit-after

Image

template-edit-before

Image

Regards,
Benazeer

@ndiego
Copy link
Member

ndiego commented Oct 16, 2024

Thanks @benazeer-ben, this looks good, but as you noted, it does not work well in the Site Editor. For this, I recommend using JavaScript methods for disabling blocks based on post type.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Developer Experience Ideas about improving block and theme developer experience [Feature] Block API API that allows to express the block paradigm. [Feature] Site Editor Related to the overarching Site Editor (formerly "full site editing") [Focus] Blocks Adoption For issues that directly impact the ability to adopt features of Gutenberg. [Status] In Progress Tracking issues with work in progress [Type] Enhancement A suggestion for improvement.
Projects
Status: In Progress