Whitelisting & Blacklisting Blocks

The Gutenberg editor (slated for WordPress core release in v5.0) ships with more than 60 blocks, many of which are likely irrelevant for many projects.

The official Gutenberg documentation provides methods for whitelisting and blacklisting blocks, but at the time of writing this, those documented methods don’t work, and there are several open issues in the Gutenberg Github repo regarding this.

If you need to whitelist (or blacklist) blocks today, below is an outline of how I accomplished this.

Note, that at the time of writing this, I’m using Gutenberg v2.8, and based on how quickly Gutenberg is moving, I don’t have much confidence that this will work for future versions, so take my tips/tricks with a grain of Gutenberg salt.

tl;dr

The approach below documents how to whitelist blocks in Gutenberg. You can use this to blacklist if that’s your cup of tea as well. The gist of what needs to happen:

  • Defined a list of allowed blocks
  • Pass that list from the server to the client on page load
  • Use that list with some custom JS to remove blocks that are not whitelisted

Define the list of allowed blocks & pass to the client

Gutenberg core ships with an allowed_block_types filter, but there are several issues open related to this filter not being well respected by the Gutenberg client (#6363, #6070, #5893), so before you get burned trying to use this, we’re going to define our own list of blocks and send the list up to the client.

Here we define a filterable array, and localize that array to be passed up to the client with the custom Gutenblock JS you’re already enqueuing to interact with Gutenberg (assuming you already have custom JS being enqueued)

$localized_data = apply_filters( 'my_localized_gutenblock_data_filter', [] ) ;
wp_localize_script( 'my-custom-gutenblocks-js', 'gutenblockHelpers', $localized_data );

Next, we’re going to add a whitelist of blocks to this filtered data.

add_filter( 'my_localized_gutenblock_data_filter', function( $localized_data ) {

  $localized_data['whitelistedBlocks'] = [
    'core/image',
    'core/paragraph'
  ];

  return $localized_data;

}, 10, 1 );

This adds a new whitelistedBlocks key to our localized data, with an array of blocks that we want to whitelist, in this case, core/image and core/paragraph.

Now, if we did this properly, we should see our `gutenblockHelpers` object enqueued and accessible via window.gutenblockHelpers. You can see this in your browser console.

 

Use the whitelist on the client to filter Gutenberg

Now that we’re successfully passing up a list of whitelistedBlocks up to the client, we need some JS to use that list and tell Gutenberg to respect it.

We need to enqueue a new script like so:

wp_enqueue_script(
  'gutenberg-block-whitelist',
  "/path/to/your/gutenbergWhitelist.min.js",
  [ 'wp-i18n', 'wp-element', 'wp-blocks', 'wp-components', 'wp-api' ],
  1,
  true
);

Note the dependencies. I noticed that if this script is loaded without the proper dependencies, it will be enqueued too early and not work. I can’t explain all the reasons why these need to be the dependencies, but these are the dependencies I declared to get things working and without them, things went a bit wonky.

Next, we need to write the script that we’re enqueueing.

Note:, I’m using es6 which is being transpiled/minified by Webpack & Babel. I’m using the 10up theme scaffold which has Webpack configured and a build script that handles this. 

let whitelistedBlocks =gutenblockHelpers &&gutenblockHelpers.whitelistedBlocks ?gutenblockHelpers.whitelistedBlocks : null;
const {unregisterBlockType, getBlockTypes} = wp.blocks;


/**
 * We have to wait until all blocks have been registered before unregistering them.
 *
 * This is SUPER fragile and hacky and will likely cause things to break over time, so I suggest
 * keeping an eye on Gutenberg to see how blacklisting/whitelisting evolves in the core plugin.
 */
wp.api.init().then( ( () => {

	/**
	 * Loop through the blacklisted blocks and unregister them.
	 *
	 * The blacklist is added to the gutenblockHelpers global via wp_localize_script.
	 */
	if (
		whitelistedBlocks.length &&
		typeof unregisterBlockType !== 'undefined' &&
		getBlockTypes !== 'undefined'
	) {
		getBlockTypes().forEach( block => {
			if ( whitelistedBlocks.indexOf( block.name ) === -1 ) {
				unregisterBlockType( block.name );
			}
		} );
	}

} ) );

This script checks to see if there’s a list of whitelisted blocks passed up to the client from our localized data.

If there is, it waits for the wp.api to initialize, then if the core Gutenberg methods getBlockTypes and unregisterBlockType is available and the whitelist has items defined, it asks Gutenberg for a list of ALL registered blocks usinggetBlockTypes, then it loops through them and unregisters all that are NOT part of the list of whitelisted blocks.

At this point, if you try and interact with Gutenberg, the only blocks you should now have access to are the core/paragraph and core/image blocks.

Customizing the whitelist for Post Types or other conditions

It’s likely that you may want to customize the list of blocks that are allowed for certain post_types.

To do that, you just need to adjust your filtered list of blocks, like so:

add_filter( 'my_localized_gutenblock_data_filter', function( $localized_data ) {

  global $post;

  $localized_data['whitelistedBlocks'] = [
    'core/image',
    'core/paragraph'
  ];

  // whitelist a custom block for a custom post type
  if ( 'my-custom-type' === $post->post_type ) {
    array_push( $localized_data, 'your-prefix/custom-block' );
  }

  // Remove the core/image block for a specific post type
  if ( isset(  $localized_data['whitelistedBlocks'][''core/image'] ) && 'my-custom-type' === $post->post_type ) {
    unset( $localized_data['whitelistedBlocks'][''core/image'] );
  }

  return $localized_data;

}, 10, 1 );

 

Sweet new WYSIWYG editor

I came across a new WYSIWYG editor today. Looks pretty sweet. I plan to play around with integrating it with WordPress and/or Meteor in some way.

http://getcontenttools.com/

Keeping tabs on WordPress actions

If you’ve ever needed to see if an action has been fired and/or how many times it has been fired, there’s a handy function that will return the amount of times an action has been fired.

https://developer.wordpress.org/reference/functions/did_action/

This function can come in handy when building things that could be extended by other developers that may want to filter out something.

I noticed it use in the WP-Shortcake plugin (https://github.com/wp-shortcake/shortcake/blob/7c9f5483b9ca10d38fa9412b264a2e6d1e12d528/inc/class-shortcode-ui.php)

The plugin introduces a Shortcode Interface on post edit pages, but only if a specific shortcode ui has been registered.

To register a UI for a plugin, an array of settings must be passed to the “register_shortcode_ui” action, but if that’s not done, the Shortcake UI is never loaded, all because of the “did_action” check.

This is a handy way to make code extendable, but avoid unnecessary bloat.

WordPress Moving Forward

One of the biggest complaints about WordPress’ commitment to backward compatibility is that it’s hard to move forward when supporting old versions of PHP.

Recently (I became aware today) the requirements for WordPress have been updated to be php 5.6+ instead of 5.2.4+, which means some deprecated code can be dropped and new ways of doing things can be implemented much easier.

This is great news for anyone not running a version of PHP < 5.6, but ideally that should be most people running WordPress.