Bill Erickson describes the process of building a block with Advanced Custom Fields in his post Building a block with Advanced Custom Fields.

I wanted to take his excellent post a bit further and describe how to do this for a custom post type.

Here are the steps I will discuss:

  1. What to include in your code to make sure your post and any custom taxonomies actually appear in the Gutenberg editor.
  2. How to restrict you block to your custom post type.
  3. Block templates.
  4. Code examples.

Making Sure your Custom Post and Taxonomies appear in the Gutenberg editor

This part is quite easy. You just need to make sure “show_in_rest” is set to true for both your post and taxonomy registration. The reason for this is that the Gutenberg editor relies on the Rest API.

Restrict your Block to your Custom Post Type

In your register block code, include the “post_types” argument so your block is only available for that post type. Note that this is an array so you can include multiple types.

Block Templates

When displaying custom posts on the front end of a website, there is often a need for more than one user interface. For example, a site might include both a grid of all team members on one page and an interface that shows an individual team member on another page.

When the layout and UI are different, it can be easier to have separate templates. This can be achieved when you register your Gutenberg Block.

Instead of just pointing directly to your template, the code can point to a call back function which then determines which template to call. This is accomplished by using “render_callback” instead of “render_template”.

Code Examples

Using “show_in_rest”

Here the example is for registering a taxonomy but the same setting is used for registering a custom post

register_taxonomy( 'gbk_properties_cat', 
	array('hierarchical' => true,     
	'labels' => array(
	   'name' => __( 'Categories', 'gbk' ),
	   'singular_name' => __( 'Category', 'gbk' ), 
	   'search_items' =>  __( 'Search Categories', 'gbk' ), 
	   'all_items' => __( 'All Categories', 'gbk' ), 
	   'parent_item' => __( 'Parent Categories', 'gbk' ), 
	   'parent_item_colon' => __( 'Parent Categories Category:', 'gbk' ), 
	   'edit_item' => __( 'Edit Category', 'gbk' ), 
	   'update_item' => __( 'Update Categories', 'gbk' ), 
	   'add_new_item' => __( 'Add New Category', 'gbk' ), 
	   'publicly_queryable' => false,
	   'show_admin_column' => true,
	    'new_item_name' => __( 'New Category', 'gbk' )
	'show_admin_column' => true, 
	'show_ui' => true,
	'show_in_rest' => true,
	'query_var' => true,
	'rewrite' => false,

Restricting Post Types and Rendering

Note in the code below, the “render_callback” and “post_types” settings.

if( function_exists('acf_register_block') ) {
// register a properties block
	'name'		=> 'properties',
	'title'		=> __('Properties'),
	'description'	=> __('GBK Properties Block.'),
	'render_callback' => array($this, 'gbk_acf_block_render_callback'),
	'category'	=> 'layout',
	'icon'		=> 'admin-home',
	'align' => false,
	'post_types' => array( 'gbk_properties' ),
	'mode' => 'edit',
	'keywords'	=> array( 'properties', 'broker' ),

The Render Callback Function

Note how we can show a different UI using a different template based on whether is is the single post view.

function gbk_acf_block_render_callback( $block, $content = '', $is_preview = false ) {
	 // convert name  into path friendly slug 
	$slug = str_replace('acf/', '', $block['name']);
	// include a template part from within the "template-parts/block" folder
	if ( is_single() ) :
		if( file_exists(plugin_dir_path( __FILE__ ) . "/template-parts/blocks/content-{$slug}.php") ) :
			include( plugin_dir_path( __FILE__ ) . "/template-parts/blocks/content-{$slug}.php" );
	else :
		if( file_exists(plugin_dir_path( __FILE__ ) . "/template-parts/blocks/content-all-properties.php") ) :
			include( plugin_dir_path( __FILE__ ) . "/template-parts/blocks/content-all-properties.php" );


Next, we will discuss how to include reusable blocks when building a block template.