How To Build A Block With ACF

Advanced Custom Fields is a plugin that has been in the WordPress community for quite some time now. Originally it was built to allow developers to have a quick way to set up custom meta fields for sites they were developing. Since the release of the block editor the ability build custom blocks was added to the plugin.

Quick Pros and Cons

ACF offers two version, a free version that can be downloaded from the WordPress plugin repo and a pro version that can be downloaded from their site. The feature to build the blocks only comes in their pro version which starts at $49/year. Other options we are going to look at for building blocks are free, so that $49/year can be a con to some but the pros that the acf workflow provide I believe make the price well worth it for certain applications.

Let’s talk about a major pro to using ACF for creating your blocks. Other than having a quick interface for setting up your block settings which is a huge time saver, building blocks with ACF is php based. The block editor is built in react, and while technically the block editor is agnostic when it comes to the javascript library you use, you still will generally be developing custom blocks with a javascript library, usually react. At it’s core WordPress has been php based for years and as a result that is where many of the developers comfort zone is. ACF provides a way to create the block and create templates for the block using php. A game changer for many trying to get into the block development game.

The Block

So let’s talk about the block we’re going to build. In order to demo the different methods for each build method we are going to look at I’m going to be building the same block each time. It’s going to be a simple “Hello World” testimonial type of block with an editable title and content area that will display a simple review. So let’s dive in.

The Build

Step 1, is obviously to install and activate ACF Pro.

Once that is done you should see a new “Custom Fields” option in the admin sidebar.

So far so good!

Register Your Block

The next thing you need to do in your custom theme or plugin at this point is to register your block. For this demo I’ll be working in a child theme and registering my block in the functions.php file, but that may be different depending on your setup.

The function to register a block using ACF is

acf_register_block_type( $settings );

The function take in a required array for it’s settings. To learn more about the arguments that would go into the array you can read about them here https://www.advancedcustomfields.com/resources/acf_register_block_type/

For our demo our settings array will begin like this:

$acf_settings = array(
    'name'              => 'jnreview',
    'title'             => __('Review'),
    'description'       => __('A custom reviews block.'),
    'render_template'   => 'template-parts/blocks/review/review.php',
    'category'          => 'text',
);

I’ve provided a unique name to identify the block, a display title and description, a location for the file that will render our front-end template and a category that the block should display in within the block inserter.

With our settings determined the next step is to register our block. I’m going to do this in a function and with an ACF hook. All together we have

add_action('acf/init', 'jn_acf_blocks_init');
function jn_acf_blocks_init() {

    // Check function exists.
    if( function_exists('acf_register_block_type') ) {

        $acf_settings = array(
            'name'              => 'jnreview',
            'title'             => __('Review'),
            'description'       => __('A custom reviews block.'),
            'render_template'   => 'template-parts/blocks/testimonial/testimonial.php',
            'category'          => 'text',
        );

        // Register a testimonial block.
        acf_register_block_type( $acf_settings );
    }
}

With our block registered, we can now go back into the WordPress admin area and in ACF to set up our fields for our block. To do this go to “Custom Fields” in the admin sidebar (as pictured above) and “Add New”. We are going to name our field group “Reviews Block” and set it’s location to Show if the group is a block and if the block is equal to “Review”. So far your settings should look similar to this.

Now we can begin to add our fields. I’m going to add three fields, a text field for the name, a text area field for the review description, and a radio button group for the stars selection.

With our block registered, and fields added we should now be able to see the block showing up within the block inserter.

Now, because we have not created our template yet, if we try to insert the block it won’t show any content but you will be able to see your fields. With the current setting if the block is not in preview mode the fields will show in the block, if you are trying to preview the block the fields will show in the sidebar.

ACF Block Form
ACF Block Preview Sidebar

The Template

Now we can turn our attention to building the template for our block. This will take the content added, and render the html needed to display it. If we go back and take a look at our settings array that was passed when the block was registered we can see that the template location was set to:

'render_template' => 'template-parts/blocks/review/review.php'

Here’s what that looks like in my child theme.

With the template file set up, we can begin work on getting our field content and outputting some html.

$block

The first thing we need to do is store our field data into some variables. When setting up a template using acf you have access to a $block array. This array passes information about the block to the template, much of which is passed from when we registered the block. If you would like to see everything you have access to in this array, within your block template you can var_dump it and review what it includes. For now we are going to use the id value to create a unique id for our block.

// Create id attribute allowing for custom "anchor" value.
$id = 'review-' . $block['id'];
if( !empty($block['anchor']) ) {
    $id = $block['anchor'];
}

Next we are going to set up some class names and pull our alignment setting from the $block array.

// Create class attribute allowing for custom "className" and "align" values.
$className = 'review';
if( !empty($block['className']) ) {
    $className .= ' ' . $block['className'];
}
if( !empty($block['align']) ) {
    $className .= ' align' . $block['align'];
}

Get Field

ACF has a couple functions that allows you to retrieve your fields data, for our block we are going to use get_field(). get_field accepts 3 parameters:

get_field($selector, [$post_id], [$format_value]);

Only the $selector parameter is required and needed for our block.

We have three fields to retrieve and will store each of them in a variable, and also include a fallback value if the field is empty. The value for our $selector param are determined from the name value of the fields we set up earlier.

With those values saved into variables this is what we will write, just below our variables pulled from the $block array.

$name = get_field('name') ?: 'Reviewer Name....';
$description = get_field('review_description') ?: 'Review Description...';
$stars = get_field('stars') ?: 5;

Now we can begin to write our actual output. We will have a wrapper div that includes our id and class, within that a blockquote that outputs our text and stars.

<div id="<?php echo esc_attr($id); ?>" class="<?php echo esc_attr($className); ?>">
    <blockquote class="review-blockquote">
        <p class="review-description"><?php echo $description; ?></p>
        <p class="review-name"><?php echo $name; ?></p>
        <div class="review-stars">
            <?php for ($x = 1; $x <= $stars; $x++) { ?>
                ★
            <?php } ?>
        </div>
    </blockquote>
</div>

Now, there are better methods for outputting the stars, but for our review using a unicode character works.

So all together here is our code within our review.php template file

// Create id attribute allowing for custom "anchor" value.
$id = 'review-' . $block['id'];
if( !empty($block['anchor']) ) {
    $id = $block['anchor'];
}

// Create class attribute allowing for custom "className" and "align" values.
$className = 'review';
if( !empty($block['className']) ) {
    $className .= ' ' . $block['className'];
}
if( !empty($block['align']) ) {
    $className .= ' align' . $block['align'];
}

$name = get_field('name') ?: 'Reviewer Name....';
$description = get_field('review_description') ?: 'Review Description...';
$stars = get_field('stars') ?: 5;
?>

<div id="<?php echo esc_attr($id); ?>" class="<?php echo esc_attr($className); ?>">
    <blockquote class="review-blockquote">
        <p class="review-description"><?php echo $description; ?></p>
        <p class="review-name"><?php echo $name; ?></p>
        <div class="review-stars">
            <?php for ($x = 1; $x <= $stars; $x++) { ?>
                ★
            <?php } ?>
        </div>
    </blockquote>
</div>

So what does that look like now in the editor?

We see our description and name fall back, and since stars default is 1, we see 1 star. If we add some text to our fields, we get the following.

On the front end of the site we see

Wrapping Up

Setting up a block with ACF is quick and painless. There is a bit of an associated cost to it, but well worth it in my opinion. There are some additional things that can be done when registering a block like added paths to asset files. That will help add additional styles to our block and depending on your use case may or may not be needed.

As of ACF 6.0 you can register a block with the above method or with a json file. Hopefully in a future post we can address the new method.

In the next post on building custom blocks we are going to take a look at the plugin “Custom Blocks Constructor”.