3 May 22

How to Build a Business Listing Using ACF Blocks and the Query Loop Block in a Block Theme

By Liam Gladdy

Full Site Editing in WordPress is here, and it’s going to change the way you build themes. In this tutorial, I’ll show you how block themes work, how to use ACF Blocks in a block theme, and provide some real world examples. By the time we get to the end, you’ll know how to give your clients a more complete site editing experience, and how to use ACF Blocks to give yourself a head start in switching to block theme development.

Full Site Editing (FSE) involves changes to WordPress core that extend the Block Editor to the whole page, from the header to the footer, making it editable with blocks. If you’re already familiar with the Block Editor, this allows you to modify things like header logos or footer social media icons in a similar interface. Even widgets have been replaced by blocks.

However, it’s not just a case of flicking a switch. Enabling FSE on your WordPress site requires a block-based theme. This new style of theme requires significant changes to how you build your WordPress themes.

How Block Themes Work

Block themes came to WordPress with the release of the block-based version of Twenty Twenty-One, the TT1 Blocks theme. This is an experimental theme built to show WordPress users the new features of FSE. There are now a number of new themes that take advantage of the new WordPress FSE features, such as Blockbase and Frost.

There have been a lot of changes “under the hood” to bring Full Site Editing features into WordPress, but from the user experience point of view, the key point is that it turns everything on your WordPress website into an editable block as long as you’re using a block theme. This extends to the entire site, not just obvious items like post content and post titles. A block theme gives you the power to edit just about everything, from the site title right down to the footer.

WordPress 5.9 ships with a block theme called Twenty Twenty-Two, the first default block theme. We’ll use this for the examples in this article.

In a block theme, your templates become HTML files that contain block markup. Using Twenty Twenty-Two’s home page template as an example, you can see the block markup that builds the frontend output, including reusable template-part blocks. These contain reusable aspects of the site, like the header and footer. You can learn more about template parts and template editing in the WordPress developer documentation.

Template view with template parts.

A block theme also contains a theme.json file which contains a list of all the custom templates your theme is using, as well as all the default configuration for typography, fonts, and global styles that will apply across all your templates. The full documentation for theme.json has more information on this.

{
    "version": 2,
    "customTemplates": [
        {
            "name": "blank",
            "title": "Blank",
            "postTypes": [
                "page",
                "post"
            ]
        },
        ...
    ],
    "settings": {+
        "appearanceTools": true,
        "color": {
            "palette": [
                {
                    "slug": "foreground",
                    "color": "#000000",
                    "name": "Foreground"
                },
                ...
            ]
        },
        ...
        "layout": {
            "contentSize": "650px",
            "wideSize": "1000px"
        }
    },
    "styles": {
        "color": {
            "background": "var(--wp--preset--color--background)",
            "text": "var(--wp--preset--color--foreground)"
        },
        ...
    },
    "templateParts": [
        {
            "name": "header",
            "title": "Header",
            "area": "header"
        },
        ...
    ]
}

Another core aspect of a block theme is the Query Loop block, which displays posts based on specified parameters. It’s like a WordPress Loop without the code. This block handles configuration of the WordPress Loop, and lets you use your other blocks in the context of a loop.

We’ve worked hard across our recent releases of Advanced Custom Fields PRO to let you use ACF Blocks to bridge the gap between the old style of theme building and the new block theme style of development.

How ACF Blocks Work

ACF Blocks were introduced in ACF PRO’s 5.8 release. Unlike a native WordPress block, an ACF Block lets you write your blocks purely in PHP, without the need to write any JavaScript or React code, and use ACF to define which fields the block uses.

Because ACF Blocks load a PHP template for their output, you can continue writing code and templates the same way you always have, using ACF as a bridge between the old way and the new way. Let’s say you created a testimonial block; you’d create an ACF Field Group containing the fields required for that block to function, such as the text, author, and date, then assign that to the block. These fields would then be shown on the page when a testimonial has been added to the page.

The introduction of the Query Loop block gives us another use case for ACF Blocks: using an ACF Block and its templating system to display fields assigned to a post type rather than assigned to the block itself.

ACF PRO 5.12 introduced compatibility with WordPress 5.9 and the Full Site Editor. As part of those changes, ACF now makes sure the post ID is set correctly where the block is being displayed. This means if you’re inside a Query Loop block and you call get_the_ID(), you’ll now correctly get the ID of the post the loop is showing, rather than the ID of the post or page hosting the Query Loop block. This allows you to access fields on that post directly.

Example: Using ACF Blocks Inside a Block Theme

Let’s say you’re producing a WordPress site listing your favorite local cafes. You’re likely to have a bunch of metadata for each shop, such as opening hours or a map showing its location. This metadata is stored as fields defined with ACF on a cafe custom post type, but displayed in a Block Theme template inside a Query Loop block.

For our examples below, we’ll create an “Opening Hours” block. We’ll use this to display a cafe’s opening hours across the site. The site itself is using a custom child theme based on the Twenty Twenty-Two block theme.

Fields

First, we need to create the custom fields on our cafe post type to store the opening hours for each location. We’ll do this using a repeater field type in ACF PRO so we can support different opening times for different days. The repeater contains a time_period, opening_time, and closing_time for each row, as shown in the screenshot.

A screenshot showing the field group settings for the cafe custom post type.

Creating the Block

Creating the block requires the use of ACF’s acf_register_block_type function. We do this in our theme’s functions.php with the following code:

<?php
add_action( 'acf/init', 'hfm_acf_init_blocks' );
function hfm_acf_init_blocks() {

    if ( function_exists( 'acf_register_block_type' ) ) {
        acf_register_block_type(
            array(
                'name'            => 'opening-hours',
                'title'           => 'Café Opening Hours',
                'description'     => 'Display opening hours for a café',
                'render_template' => 'block-templates/opening-hours.php',
                'category'        => 'text',
                'icon'            => 'admin-comments',
                'api_version'     => 2,
                'keywords'        => array( 'opening hours', 'hours' ),
                'mode'            => 'preview',
                'supports'        => array(
                    'jsx'        => true,
                    'color'      => array(
                        'text'       => true,
                        'background' => false,
                    ),
                    'align_text' => true,
                ),
            )
        );
    }
}

ACF PRO blocks can use the majority of supports options that WordPress provides in the Block Editor, so we can enable support for text-align and color for our block. The values selected for these in the Block Editor are passed into our template code via the $block variable.

You can also see in the example code that we provide a path to our render_template. This is the PHP file that is used to render the output for our block. Inside this file, you can use any WordPress functions you could normally use in a template file.

You may recall that we assigned our field group to the cafe post type, instead of to the block itself. This means we enter the field values when creating a new cafe page, instead of in the block directly. It also means that we’ll need to pass the post ID (via get_the_ID() or similar) to any calls to get_field() or the_field() in our block render template. For example, get_field('opening_times', get_the_ID()).

Here’s the content of our template code:

<?php
$align     = isset( $block['align_text'] ) ? $block['align_text'] : 'left';
$textcolor = isset( $block['textColor'] ) ? $block['textColor'] : 'inherit';

if ( substr( $textcolor, 0, 1 ) !== '#' && substr( $textcolor, 0, 4 ) !== 'rgb(' ) {
    $textcolor = 'var(--wp--preset--color--' . $textcolor . ')';
}
?>
<aside class="opening-times" style="color: <?php echo $textcolor; ?>; text-align: <?php echo $align; ?>">
    <h5 style="margin-top: 0; margin-bottom: 0.5rem;">Opening Hours</h5>
    <?php $opening_times = get_field( 'opening_times', get_the_ID() ); ?>
    <?php if ( ! empty( $opening_times ) ) { ?>
        <?php foreach ( $opening_times as $period ) { ?>
            <strong><?php echo $period['time_period']; ?></strong>:
            <?php echo $period['opening_time']; ?>
            <?php if ( ! empty( $period['closing_time'] ) ) { ?>
                - <?php echo $period['closing_time']; ?>
            <?php } ?>
            <br />
        <?php } ?>
    <?php } ?>
</aside>

Because the template receives the raw values from the Block Editor for any supports options, we have to manually translate those values into valid CSS properties. In the case of color values, they could be passed to us as hex, RGB, or CSS variables. For the CSS variables, we need to apply the WordPress prefix of --wp--preset--color-- to the variable name. In a future version of ACF PRO, we intend to automatically handle the conversion of these variables to valid CSS for you.

Outputting the Block

Now our block is ready to be displayed on the page. We can output our block anywhere a cafe post type is displayed, so we’ll add this in two places: once in the template for a single post, and once on a page where we’ll highlight our favorite cafes from all the options available using the new Query Loop block.

Single Post Template

Let’s start with the single post template. We can do this by selecting the template from the sidebar, and clicking the Edit button. This will launch the template editor, showing the template currently being used for our cafe post type.

A screenshot showing the custom post type meta edit screen.

Once we’re in the template editor, we can modify the default template to add a column layout block. This allows us to move the content to one side, and add our “Café Opening Hours” block to the right-hand side.

A screenshot showing the template editor and the custom block.

Now we just need to save the template, and it will be used for any of our cafes.

Adding a Query Loop Block

Next, we want to create a page highlighting our favorite cafes. To do this, we create a page as normal, use the Block Editor to set the title, and add any content we want to show on the page.

To bring the cafe post types onto the page, we need to add a Query Loop block to the page. Once we’ve added this, we can configure it to show the cafe post type by selecting the post type from the sidebar. We can also set any parameters we want here, such as filtering by keyword or category. In an upcoming version of WordPress, we’ll also be able to use custom taxonomies to filter the Query Loop block too. You can use this feature now by installing the Gutenberg plugin, which offers an advanced preview of Gutenberg releases before they’re merged into WordPress core.

A screenshot showing the Query Loop block configuration.

Now we can configure the Query Loop block to display content how we like. I’ve decided to use a column layout, showing a split for the featured image block, the title and excerpt blocks, then our opening hours block, all nested inside our Query Loop block. This is easier to configure using the left-hand sidebar (“List view”), as it makes it easier to see what blocks are nested under each other, and lets you drag items around to change things. We’ll also customize the text color used for our “Café Opening Hours” block, and align the text to the right using the default WordPress editor toolbar, enabled by our block supports.

A screenshot showing the Query Loop block with our custom block inside.

Conclusion

Block themes are a significant change to the development workflow of building WordPress themes. However, you can grant your users a significantly more complete site editing experience, and reduce the amount of support you’ll need to provide them to update things like logos, headers, and footers. For more on how you can do this, see our case study with Sam Kent of Zoo Studios.

There are also many more usability features, like block patterns. You can use these to save a group of blocks as a reusable one-click addition to your content.

That said, giving that much control to your users might be detrimental. If you’ve got a beautifully designed theme, the user could break it by adding a huge banner in the middle of the homepage or changing the column percentages on a whim. WordPress is starting to cater for this situation with template and block level locking. You can use this to prevent users editing areas of the site which should be fixed, such as column widths, while still letting them edit the content inside using the Block Editor.

No matter which method of theme building you decide to use, block themes or traditional theme development, both will be supported for the foreseeable future, and both work well with ACF Blocks.

Using ACF Blocks also gives you a head start if the time comes for you to switch to block theme development. Your existing blocks will be portable across projects and themes and you will also keep a consistent development experience by giving you a templating system that you already know from developing traditional themes.

Are you using ACF Blocks already? Do you have any feature requests for us for how we can make your development experience even easier? Let us know in the comments below! We’d love to hear from you.

Supercharge Your Website With Premium Features Using ACF PRO

Speed up your workflow and unlock features to better develop websites using ACF Blocks and Options Pages, with the Flexible Content, Repeater, Clone, Gallery Fields & More.

Explore Features View Pricing

PRO Features
ACF Blocks
Options Pages
PRO Fields
Repeater
Flexible Content
Gallery
Clone

About the Author

For plugin support, please contact our support team directly, as comments aren't actively monitored.

  • Ola says:

    Thanks for the tutorial. As a programmer i find it a little odd though to use the Query Loop Block. Which programmer will want to use that? But fore sure Gutenberg has opened new doors how to update content in a nicer and more user friendly way. What i really like to see is the possibility to set a default prepopulated block or block pattern for posts and pages. So when you add a new post (maybe a custom post type) for instance it will already be populated with a certain block och blocks that may or may not be possible to remove or add new ones. I know you can use block patterns and i have experienced a little bit with them but i find them still very limited and very hard structure and style. If ACF could do something here it would be fantastic.

    • Gary Hughes says:

      Hi Ola, you can use block templates to assign a list of blocks to a newly created post – https://developer.wordpress.org/block-editor/reference-guides/block-api/block-templates/. These can be locked down, either at a post or block level, while optionally allowing users to add new blocks. Liam mentions the locking feature in the article. Bill Erickson wrote an article some time ago about block templates that I found particularly helpful in grasping this – https://www.billerickson.net/gutenberg-block-templates/.

    • Liam says:

      Hey Ola, I think with full site editing in a block theme, the Query Loop block makes much more sense, as it’s controlling the WP_Query that is used on the page, it makes configuration for things like category selection no need any code, but I agree it’s unlikely you’d use one on a normal post! What you’re talking about though in regards to the new post type having a predefined template of blocks is already possible! It’s called a post type template, and you can define it as part of your register_post_type call: https://developer.wordpress.org/reference/functions/register_post_type/ You can even set template lock on a post type to stop users removing or adding new blocks. That way, you could recreate a classic editor type view, but in Gutenberg.

      • Ola says:

        Thanks Liam! You´re right. You can. But I think they still are very limited and you need to create alot of nested arrays for more complex structures. I have experimented a bit with them and found them still very buggy. Fields that suddenly went invisible and so on. Many block items also missed support for a class attribute which makes it harder integrate with your initial designs making the workflow less hassle free. And why should you need to do your work twice? If you already have made a custom block, an ACF block for example, you should be able to just mark that block as the default block for that template. Or set a default blockpattern, even better. That would be i much easier process. Thats o my wishlist anyway. 🙂

  • Jonás García Fernández says:

    Hello. Very good article, it taught me several interesting tricks that I will put into practice. This month I spent my time reviewing the new block-based WordPress theme and tried some blocks made with ACF and everything works as expected, they are doing a good job. But I have a little problem, my blocks contain a separate css style file (‘enqueue_style’), which for some reason is not interpreted by the template editor. I want to add that I use a translator and this topic may be discussed in the post and with the translation I did not understand. But in the code that registers the block, its own separate css file is not added either. Could it be that right now it is not supported to do this in templates? It is the only inconvenience that I found along the way this month using Twenti Twenti Two with ACF after developing 5 blocks for a restaurant website, otherwise I am very happy with the development and constant updates of the plugins. Thank you!!!

  • rob.a.berger says:

    Great article. Two questions. Are we able to select the custom field data associated with the CPT that we want to display in the Query Loop? I haven’t been able to figure out how to do that. Second, you say "Now we can configure the Query Loop block to display content how we like." Apart from some very limited options in the Query Loop block, I don’t see how we can actually do this. Can you point me in the right direction? Thanks.

    • Liam says:

      Hey Rob, For your first question, we added support for that in ACF 5.12 (see the release notes here: https://www.advancedcustomfields.com/blog/acf-5-12-released/#post-id-changes) – Specifically, you can now use get_the_ID() in a template to access the ID of the post currently in context, so inside a query loop, that ID is the post ID of the thing currently being displayed. As for your second question, which things are you looking to configure? That’s a bunch of options available now, and WordPress 6.0 will add a few more (like taxonomy filtering) – but if there’s something specific you’d like to do, let me know and we’ll see how to make it happen!

  • Rima Gerhard says:

    Is it possible to filter the Query Loop block by an ACF Field that was added to the Post, Page, or Custom Post Type?