8

I'm writing a function to allow only some custom blocks - essentially I want to register all the blocks, then based on a database table of 'selected' blocks disallow any other custom block.

I can use allowed_block_types to make an array of allowed blocks, but it wipes all the core ones, is there a way to either get a reliable list of core blocks, or only add a filter for plugin/theme registered blocks? Or possibly, allow all block categories then my own block category is filtered?

7 Answers 7

12

AFAIK there is only one way to remove blocks from Gutenberg - you have to use allowed_block_types filter.

Unfortunately Gutenberg developers are not very familiar with WordPress hooks and filters, so they created a little monster with this one. So instead of passing a list of core blocks in there, they pass true to enable all blocks. That way you're unable to obtain the list of all blocks registered.

So if you want to disable just one block, then you have to get all blocks bu yourself...

Here's the list of core blocks:

  • core/shortcode
  • core/image
  • core/gallery
  • core/heading
  • core/quote
  • core/embed
  • core/list
  • core/separator
  • core/more
  • core/button
  • core/pullquote
  • core/table
  • core/preformatted
  • core/code
  • core/html
  • core/freeform
  • core/latest-posts
  • core/categories
  • core/cover (previously core/cover-image)
  • core/text-columns
  • core/verse
  • core/video
  • core/audio
  • core/block
  • core/paragraph

  • core-embed/twitter

  • core-embed/youtube
  • core-embed/facebook
  • core-embed/instagram
  • core-embed/wordpress
  • core-embed/soundcloud
  • core-embed/spotify
  • core-embed/flickr
  • core-embed/vimeo
  • core-embed/animoto
  • core-embed/cloudup
  • core-embed/collegehumor
  • core-embed/dailymotion
  • core-embed/funnyordie
  • core-embed/hulu
  • core-embed/imgur
  • core-embed/issuu
  • core-embed/kickstarter
  • core-embed/meetup-com
  • core-embed/mixcloud
  • core-embed/photobucket
  • core-embed/polldaddy
  • core-embed/reddit
  • core-embed/reverbnation
  • core-embed/screencast
  • core-embed/scribd
  • core-embed/slideshare
  • core-embed/smugmug
  • core-embed/speaker
  • core-embed/ted
  • core-embed/tumblr
  • core-embed/videopress
  • core-embed/wordpress-tv

On the other hand...

It's a lot easier to unregister given block in JS... In there you can use:

wp.blocks.unregisterBlockType( 'core/verse' );
5
  • Quite the list! I appreciate the effort getting it. It is frustrating there is not a better hook from the Gutenberg developers - thank you for the answer.
    – Aravona
    Jan 29, 2019 at 9:31
  • Totally agree on that. It should be possible to get list of all registered blocks with PHP... Jan 29, 2019 at 9:41
  • 2
    core/cover-image has been changed to core/cover.
    – Christine Cooper
    May 6, 2019 at 10:38
  • 1
    Apparently this decision wasn't just oversight from the developers, but rather that it's not currently possible for the server to know which blocks are registered on the front-end (due to lack of server-side registration). See this GitHub issue response for more details. Since this issue is being addressed, hopefully we'll have a way to blacklist blocks soon.
    – Sean
    Oct 4, 2019 at 7:29
  • 1
    @KrzysiekDróżdż The core-embed/* blocks no longer exist and are now block variations of core/embed. See my answer here: wordpress.stackexchange.com/a/379613/32946
    – Sven
    Dec 10, 2020 at 18:15
12

There's a whitelist blocks removal example from the Gutenberg Handbook:

var allowedBlocks = [
    'core/paragraph',
    'core/image',
    'core/html',
    'core/freeform'
];

wp.blocks.getBlockTypes().forEach( function( blockType ) {
    if ( allowedBlocks.indexOf( blockType.name ) === -1 ) {
        wp.blocks.unregisterBlockType( blockType.name );
    }
} );

One might try to modify it to remove blocks that do not start with core and are not part of allowedExtraBlocks (untested):

var allowedExtraBlocks = [
    'my-plugin/block-example-1',
    'my-plugin/block-example-2'
];

wp.blocks.getBlockTypes().forEach( function( blockType ) {
    if ( ! blockType.name.startsWith( 'core' )
         && allowedExtraBlocks.indexOf( blockType.name ) === -1
    ) {
        wp.blocks.unregisterBlockType( blockType.name );
    }
} );

One could adjust this further to match block names that start with core/ or core-embed/ instead of core to be more precise.

The blacklist example wraps it with:

wp.domReady( function() {
    // ...
} );

so this might be needed for the whitelist example too.


Here's a quick way to see available blocks on the editing page, in the browser's console:

In the 5.1 version there are 70 core blocks available, according to

wp.blocks.getBlockTypes().length;

number of core blocks

The list of available block names:

wp.blocks.getBlockTypes().forEach( function( blockType ){ console.log( blockType.name ); }); 

block names

Here's a table of available blocks:

console.table( wp.blocks.getBlockTypes() );

Table of available blocks

4
  • 1
    The part I really don’t like in this code is that it’s on JS side. It would be nice to be able to restrict this on PHP side... :( Jan 28, 2019 at 20:42
  • It would be nice to have a PHP version, maybe one could look further at WP_Block_Type_Registry::get_instance()->get_all_registered() within the allowed_block_types filter callback, but it will probably not show all blocks there. @KrzysiekDróżdż
    – birgire
    Jan 28, 2019 at 20:46
  • 2
    No, it does not. I’ve already created a ticket with such enhancement in trac Jan 28, 2019 at 20:48
  • 2
    Thanks for this answer! I agree with @KrzysiekDróżdż that it's frustrating there is no PHP solution to this as it stands. I appreciate the answer though and a JS solution is still viable within my plugin.
    – Aravona
    Jan 29, 2019 at 9:29
2

@birgire 's answer is very good. https://wordpress.stackexchange.com/a/326969/198298

Some information might be missing though.

As @birgire guesses, it really is necessary to wrap the code inside a

wp.domReady( function() {
    // ...
} );

even if the script is loaded with the dependencies array( 'wp-blocks', 'wp-dom-ready', 'wp-edit-post' ) like it is recommended in the block filters guide.

Speaking of loading: If you're no plugin developer (like me) but only want to remove some block types for the users of your (company's) blog, you should load the js file for this in your child-theme's functions.php like that:

/** Allow js-side adjustments to block editor (aka Gutenberg), i.e. remove certain block types. */
function my_childtheme_enqueue_block_editor_adj() {
    wp_enqueue_script(
        'block-editor-adjustments',
        get_stylesheet_directory_uri() . '/js/block-editor-adjustments.js',
        array( 'wp-blocks', 'wp-dom-ready', 'wp-edit-post' ),
    );
}
add_action( 'enqueue_block_editor_assets', 'my_childtheme_enqueue_block_editor_adj' );

My js file looks like this:

wp.domReady(function () {
    /**
     * Remove some blocks from the block editor.
     * This is not possible in php unfortunately.
     */
    wp.blocks.unregisterBlockType('core/embed');

    var allowedEmbedBlocks = [
        'core-embed/twitter',
        'core-embed/youtube',
        'core-embed/facebook',
        'core-embed/instagram',
        'core-embed/wordpress',
        'core-embed/flickr',
        'core-embed/vimeo',
    ];

    wp.blocks.getBlockTypes().forEach(function (blockType) {
        if (blockType.name.startsWith('core-embed')
            && allowedEmbedBlocks.indexOf(blockType.name) === -1
        ) {
            wp.blocks.unregisterBlockType(blockType.name);
        }
    });
});

This way I can now focus on the embed options in allowedEmbedBlocks regarding the Usercentrics data privacy settings.

2

core-embed does no longer exist in the latest version of the Gutenberg editor. All embeds now seem to be block variations of core/embed. So you cannot unregister the default core/embed block, because if you do, you will automatically unregister all its variations. However, you can unregister any variations with wp.blocks.unregisterBlockVariation(blockName, variationName).

Example: only allow the YouTube embed block:

wp.domReady( function() {
    const allowedEmbedBlocks = [
        'youtube',
    ];

    wp.blocks.getBlockType( 'core/embed' ).variations.forEach( function( blockVariation ) {
        if (
            allowedEmbedBlocks.indexOf( blockVariation.name ) === -1
        ) {
            wp.blocks.unregisterBlockVariation( 'core/embed', blockVariation.name );
        }
    } );
} );

(Sadly you will still be able to use the regular embed block as well. I'm not sure yet how this can be removed.)

0

This is a one liner solution to remove all blocks that aren't of the core group:

wp.blocks.getBlockTypes()
.filter( b => ! b.name.startsWith('core') )
.forEach( b => wp.blocks.unregisterBlockType(b.name) )

I hope it will be useful to someone in the future!

0

You can follow this approach that I am using to disable custom blocks in the block editor. Just replace the array values with the blocks that you want to disable.

<?php
function disable_specific_blocks( $allowed_block_types, $post ) {
    // An array of block names to disable
    $disabled_blocks = array(
        'core/table',
        'core/image',
        'core/gallery',
    );
  
    // Use this condition to disable blocks on certain post types, otherwise you can remove this IF condition
    if ( $post->post_type === 'post' ) {
        $allowed_block_types = array_diff( $allowed_block_types, $disabled_blocks );
    }

    return $allowed_block_types;
}
add_filter( 'allowed_block_types_all', 'disable_specific_blocks', 10, 2 );
?>

You can also follow this full guide on how to disable specific Gutenberg blocks on WordPress.

0

Unregistering blocks can cause issues, especially if you operate using a whitelist instead of a blacklist. When an update switched the core/list block to use core/list-item inner blocks the editor just hard crashed.

I've found that removing blocks from the inserter is a safer tactic:

const visible_blocks = ["core/paragraph", "core/heading", "etc/etc"];

wp.hooks.addFilter("blocks.registerBlockType", "hideBlocks", (blockSettings, blockName) => {
    // Return early in case something has gone wrong with this variable (otherwise the editor whitescreens)
    if (visible_blocks === undefined || typeof visible_blocks !== "object") {
        return blockSettings;
    }

    // Check and see if the block is one we want to hide
    if (!visible_blocks.includes(blockName)) {
        return Object.assign({}, blockSettings, {
            // Otherwise hide the block from the inserter
            supports: Object.assign({}, blockSettings.supports, { inserter: false }),
        });
    }

    return blockSettings;
});

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.