DEV Community

Cover image for Custom Post Loop as a Gutenberg Block
Joseph Farruggio
Joseph Farruggio

Posted on • Originally published at

Custom Post Loop as a Gutenberg Block

This post was featured in Matt Mullenweg's SOTW presentation at WCUS 2018. How cool is that?

This post was originally published on my blog.

First, let's take a quick look at what we'll be building together. The image below shows the output on the front end of my customizable CPT block. In this tutorial, I'm using basic markup to output a simple and subtly styled list of testimonials, but you feel free to style it up any way you'd like.

A custom post type testimonials block

So, in effort to spend more time and familiarize myself with Gutenberg, I wanted to convert my static front page into a Gutenberg page. One of the elements that would be handy as a block was my testimonials custom post type loop.

It turns out it was pretty easy to do. There were also some controls that I added into the block editor for a small level of configuration.

In my previous post I covered how to create a custom Gutenberg block with Advanced Custom Field’s acf_register_block().

At the time of this tutorial, Gutenberg has not yet been added into core, so we’ll need the Gutenberg plugin. We’ll also need the beta version of ACF Pro, which is currently 5.8.0 Beta. To quickly prototype my testimonial template, I'm using Tailwind.css. You'll notice the use of utility classes in my markup.

Setting up the CPT

I use the free CPT UI plugin for quickly setting up custom post types.

Setting up a custom post type

For this CPT, I want to mainly use custom fields. So that means no classic editor or Gutenberg. In order to disable Gutenberg on CPT you need to set the “Show in REST API” to false. Set it to true if you do want to use the Gutenberg editor.

Enabling the REST API

Creating the Custom Fields

Within Advanced Custom Fields I created just two fields for the testimonial; the author’s title and the quote. I’ll use the post title for the author’s name and the feature image for the author’s profile image.

Creating the post loop custom fields with ACF

Register the Testimonial Block

Within our functions.php file we’ll register our testimonial block.


// Register Custom Blocks
add_action('acf/init', 'my_acf_init');
function my_acf_init() {

    // check function exists
    if( function_exists('acf_register_block') ) {

        // register a testimonials block
            'name'              => 'testimonials',
            'title'             => __( 'Testimonials', 'wprig' ),
            'description'       => __( 'A custom testimonial block.', 'wprig' ),
            'render_callback'   => 'my_acf_block_render_callback',
            'category'          => 'formatting',
            'icon'              => 'admin-comments',
            'keywords'          => array( 'testimonial' ),

        // register other blocks

Create the Testimonial Block Fields

I want some level of configuration over my testimonial block. Depending on where I use it, I’ll want to either loop testimonials with a ‘posts_per_page’ to set a limit or I’ll want to hand select which testimonials to display.

Back in Advanced Custom Fields we’ll create three fields to create this functionality.

Creating the block controls custom fields

In this field group I’ve created a button group to allow the user to select between limiting the post loop with a number or selecting from a list of published testimonials.

Both the ‘Testimonial Count’ and ‘Select Testimonials’ fields have a conditional argument to only be displayed based on the selection of the ‘Loop Argument Type’.

The Select Testimonials Post Object field should be set to return just the post ID.

Building the Testimonial Template

Within template-parts/blocks/content-testimonials.php I’ll create my template and add some Php to dynamically set the argument type in the loop.


 * Block Name: Testimonials
 * This is the template that displays the testimonials loop block.

$argType = get_field( 'loop_argument_type' );
if( $argType == "count" ) :
  $args = array( 
    'orderby' => 'title',
    'post_type' => 'testimonials',
    'posts_per_page' => get_field( 'testimonial_count' )
  $testimonials = get_field( 'select_testimonials' );
  $args = array( 
    'orderby' => 'title',
    'post_type' => 'testimonials',
    'post__in' => $testimonials

$the_query = new WP_Query( $args );

Next, I’ll start the loop and populate our testimonial fields in the template.


// Continued code

if ( $the_query->have_posts() ) : while ( $the_query->have_posts() ) : $the_query->the_post(); ?>

  <div class="rounded border-b border-solid border-grey-lighter px-6 py-4 mb-2 max-w-md">
    <div class="flex items-center">
        <img src="<?php echo get_the_post_thumbnail_url(); ?>" class="h-12 w-12 rounded-full" />
        <div class="flex flex-col ml-4">
            <b class="font-bold text-black"><?php the_title(); ?></b>
            <span class="text-grey"><?php echo get_field( 'authors_title', get_the_ID() ); ?></span>
    <p class=" mt-3 mb-1 leading-normal text-base">
      <?php echo get_field( 'quote', get_the_ID() ); ?>

<?php endwhile; ?>
<?php else: __( 'Sorry, there are no testimonials to display', 'wprig' );  endif; ?>

There’s one thing that I need to point out here to save you from some frustration. When looping through posts in a Gutenberg block, you must add the post ID as the second parameter when using ‘get_field()’.

Setting the Post ID as a second parameter

<?php echo get_field( 'quote', get_the_ID() ); ?>

Using the Testimonial Block

I want to add testimonials to my home page, so within the editor I added a testimonial block. I set the Loop Argument Type to Count and then set the Testimonial Count to 3.

Using the new CPT block

If I wanted to hand pick which testimonials I wanted to display, I could set the Loop Argument Type to Select Posts:

Selecting specific posts

This is a multi-select field, so I could add as many as I'd like.

A list of testimonials on the front end

And there we have it! Our custom post type is looped and applied to a custom template which is configurable and reusable as a block throughout any post or page.


Selfish Sales Plug Alert

Want to hire me to build you a custom Gutenberg block for your Gutenberg enabled theme?

Interested in finding out if your WordPress theme is ready and compatible with Gutenberg?

Say hello to me at

Top comments (0)