Building a block with Advanced Custom Fields

The new block-based editor in WordPress provides a great new content editing experience, and it’s even more powerful with custom blocks.

The core blocks are built using React and JavaScript. You can build your own Gutenberg blocks with JavaScript as well. If you plan to distribute your block publicly as a plugin, I recommend building it with JavaScript to keep it lean and decrease dependencies on other libraries.

When building a single website with many unique blocks, it’s more effective to use a block-building plugin like Advanced Custom Fields. You can build blocks much faster by leveraging a tool you likely already use. This is especially useful if you’re a PHP developer with little JavaScript experience. ACF lets you build everything using PHP.

For more real-world examples of custom ACF blocks, see my article on Building a WordPress theme with Gutenberg.

What is Advanced Custom Fields

Advanced Custom Fields is a plugin for building additional content editing fields throughout the WordPress interface. You can build custom metaboxes, site options, user profile fields, and term metadata.

For a more detailed walkthrough of ACF and how it compares to similar plugins, see my Introduction to Custom Metaboxes. I plan to write more about ACF in the near future, so keep an eye on my Advanced Custom Fields category page.

ACF is the first popular metabox plugin to add support for building blocks. Other plugins are working on it as well – see CMB2 and Carbon Fields articles on Gutenberg compatibility – but ACF is leading the way.

Creating a block

There are three key parts to building a Gutenberg block with ACF:

  1. Register the block with PHP
  2. Build the block editor with the ACF user interface
  3. Describe how the block is rendered using PHP

I’ll walk you through each step required to build a simple “Team Member” block.

I’m storing the block’s markup and styles inside the theme to keep things simple, but you could also place the code in a core functionality plugin.

Register the block

We’ll use the acf_register_block_type() to register our custom block. I’ve provided a summary of the parameters below, and for more information see the ACF documentation.

You must have ACF 5.8 or later installed for this to work.

/**
 * Register Blocks
 * @link https://www.billerickson.net/building-gutenberg-block-acf/#register-block
 *
 */
function be_register_blocks() {
	
	if( ! function_exists( 'acf_register_block_type' ) )
		return;

	acf_register_block_type( array(
		'name'			=> 'team-member',
		'title'			=> __( 'Team Member', 'clientname' ),
		'render_template'	=> 'partials/block-team-member.php',
		'category'		=> 'formatting',
		'icon'			=> 'admin-users',
		'mode'			=> 'auto',
		'keywords'		=> array( 'profile', 'user', 'author' )
	));

}
add_action('acf/init', 'be_register_blocks' );
Name

This is your unique name for the block. ACF automatically namespaces it for you, so my team-member name becomes acf/team-member in the database.

Title

This is the title shown in the Gutenberg block editor.

Render Template

The template file used to render the block. The same template file will be used on the frontend and as the “Preview” view in the backend editor. This can either be a relative URL from the current theme, as shown above, or a full path to any file.

Alternatively, you can use the render_callback parameter to specify a function name that output’s the block’s HTML.

Category

This determines in which section of the “Add Block” window it appears. The options provided by WP core are: common, formatting, layout, widgets, and embed.

Icon

Specify a dashicons icon to use, or a custom SVG icon.

Mode

This lets you control how the block is presented the Gutenberg block editor. The default is “auto” which renders the block to match the frontend until you select it, then it becomes an editor.

If set to “preview” it will always look like the frontend and you can edit content in the sidebar.

If set to “Edit” it appears like a metabox in the content area. The user can switch the mode by clicking the button in the top right corner, unless you specifically disable it with 'supports' => array( 'mode' => false ).

Keywords

Up to three additional terms to use when a user is searching for the block. The name is always indexed so you don’t need to repeat it as a keyword here.

Build the block editor

Once the block has been registered, you can now go to Custom Fields in the admin and create your block editor. It works just like a standard metabox built in ACF.

Under the location rules, select “Block” is equal to “Team Member”.

Build the block markup

The final step is to write the markup for the block. I created a template partial in /partials/block-team-member.php , matching the render_template parameter I specified when registering the block. My template partial looks like:

<?php
/**
 * Team Member block
 *
 * @package      ClientName
 * @author       Bill Erickson
 * @since        1.0.0
 * @license      GPL-2.0+
**/

$name = get_field( 'name' );
$title = get_field( 'title' );
$photo = get_field( 'photo' );
$description = get_field( 'description' );


echo '<div class="team-member">';
	echo '<div class="team-member--header">';
		if( !empty( $photo ) )
			echo wp_get_attachment_image( $photo['ID'], 'thumbnail', null, array( 'class' => 'team-member--avatar' ) );
		if( !empty( $name ) )
			echo '<h4>' . esc_html( $name ) . '</h4>';
		if( !empty( $title ) )
			echo '<h6 class="alt">' . esc_html( $title ) . '</h6>';
	echo '</div>';
	echo '<div class="team-member--content">' . apply_filters( 'ea_the_content', $description ) . '</div>';
echo '</div>';

Use the get_field() function to access the fields set in the block settings. You can then build the markup for your block based on your specific design requirements.

Building a Table of Contents block

In my article on Developing a Gutenberg Website I mentioned the Table of Contents block I built for a few clients. It dynamically lists all h2’s within the current article and links to each one.

I started by forking the WP Anchor Header plugin. My changes include:

  • Limiting it to only h2’s
  • Only running on posts that have the table-of-contents block.
  • Before automatically adding an ID to each heading, check if one exists already. Clients can manually specify the heading’s anchor link in the Gutenberg editor so we should respect that.
  • My ea_table_of_contents() function accepts a $count parameter. We use this to list the first few headings in the article on the homepage

The block doesn’t have any editable fields so I added a Message field describing how it works:

Here is the full code for the table of contents block.

Bill Erickson

Bill Erickson is a freelance WordPress developer and a contributing developer to the Genesis framework. For the past 14 years he has worked with attorneys, publishers, corporations, and non-profits, building custom websites tailored to their needs and goals.

Ready to upgrade your website?

I build custom WordPress websites that look great and are easy to manage.

Let's Talk

Reader Interactions

Comments

  1. David says

    Great article Bill! If I wanted to register multiple ACF blocks, would I just repeat ‘acf_register_block_type’ within the ‘be_register_blocks’ fucntion or is there perhaps a more efficient way of coding it?

    • Bill Erickson says

      Correct, you use the acf_register_block_type() function for each block type. You could create an array of ACF block settings arrays, then foreach( $blocks as $block ) { acf_register_block_type( $block ); }, but I think that’s less readable and no more efficient.

  2. Marius Sonnentag says

    As always Bill nails it with his smart shortness. I really like your stuff!

    Coming from Genesis and i’ve been following your tutorials for years.

    Greetz from Germany
    Marius

Leave A Reply