Categories
Gutenberg

Using render_callback for the edit function

Have you ever wondered if there was an easy way to have a simple WP_Query as a custom Gutenberg block? There is!

Today I’m going to talk about my most recent discovery. How to make the render_callback argument from register_block_type() display in the editor side so I don’t have to worry about replicating logic in JS.

I’ve written about this function before. This may help you better understand why and how we are using this function here.

The render_callback argument sets or overrides the markup of your block when you display it in the front-end. That means that you can have a block render the front-end from PHP.

This callback is useful if you want to build something like a “related posts” kind of block that is based on a category or something. For me, it was a custom post type calling related posts that had a term for a custom taxonomy that matched the custom post type slug. It sounds more complicated than it actually is.

global $post;
$current_post_slug = $post->post_name;
$related_posts_query = new WP_Query( array(
  'posts_per_page' => 4,
  'tax_query' => array(
    array(
      'taxonomy' => 'pre_capability',
      'field' => 'slug',
      'terms' => $current_post_slug
    )
  )
) );

But Fernando… We can make REST API calls and create the template in JS. Yes! Yes, we can. Yet, do you want to rebuild your template part in JS and make updates to both the JS and PHP templates? I don’t think so.

This callback only works in the front-end

Well, that is true. The render_callback will only take care of the front-end rendering of your block. This is especially useful when you want to override how a block will render in the front-end.

But there are ways to make it work in the editor too so you can have a fair representation of your page’s content. That is the main goal of Gutenberg. Make your editor look as close as possible to your front-end.

During my research, I came across the <ServerSideRender /> component. Include this in your edit function and it will use what you add to your callback to render. You can still have your block attributes and can even add <InspectorControls> for your block options.

ServerSideRender is a component used for server-side rendering a preview of dynamic blocks to display in the editor. Server-side rendering in a block’s edit function should be limited to blocks that are heavily dependent on existing PHP rendering logic that is heavily intertwined with data, particularly when there are no endpoints available.

@wordpress/server-side-render documentation

Is this the best way of doing this?

I can’t say for sure if it is or isn’t. There may be a better way of doing this. This is the easiest way I could find of achieving the goal in under 15 minutes.

You can read more on this component here.

If you know of a better way of doing this, please let me know in the comments or hit me up on Twitter.

Our final code

This is how my example block would look like.

const { __ } = wp.i18n;
const { registerBlockType } = wp.blocks;
const { serverSideRender: ServerSideRender } = wp;

registerBlockType( 'fc/related-posts', {
	title: __( 'Related Posts', 'fc' ),
	category: 'layout',
	edit: () => {
		return (
			<ServerSideRender block="fc/related-posts" />
		);
	},
	save: () => null
} );
add_action( 'init', function() {
  register_block_type( 'fc/related-posts', array(
    'render_callback' => function() {
      global $post;
      $current_post_slug = $post->post_name;
      $related_posts_query = new WP_Query( array(
        'posts_per_page' => 4,
		'tax_query' => array(
          array(
            'taxonomy' => 'pre_capability',
            'field' => 'slug',
            'terms' => $current_post_slug
          )
        )
      ) );
      if ( ! $related_posts_query->have_posts() ) {
        return false;
      }

      ob_start();
      ?>
      <h2><?php echo esc_html__( 'Related Posts', 'fc' ); ?></h2>
      <div class="grid-x grid-margin-x">
        <?php
        while ( $related_posts_query->have_posts() ) {
          $related_posts_query->the_post(); ?>
          <div class="cell small-12 medium-3">
            <?php get_template_part( 'template-parts/card', '' ); ?>
          </div>
        <?php
        }
        wp_reset_postdata(); ?>
      </div>
      <?php
      return ob_get_clean();
    }
  ));
));

If you enjoyed this post, make sure you share it with your friends on your social media.

Also make sure to hit me up on Twitter or any other social network.

By Fernando Claussen

Fernando Claussen is a WordPress developer who brings his front-end background to help businesses thrive. He began his development career in a small agency in Brazil working with the finest companies in Brazil that ranged from small shops to hotel chains. Fernando is especially known for his contributions to the Trew Knowledge team and the GDPR WordPress plugin.

Leave a Reply