[Sage 10] Advice on including and building Gutenberg Blocks within the theme

Hey all,

I don’t know whether or not I’m looking for a well know solution or not.

I would like to create and use custom Gutenberg blocks withing my Sage 10 Theme. Some preferences I would like to accomplice:

  • Have a block within the theme (read: no plugin) For example a post grid block
  • In the editor I would like to set arguments with block and InspectorControls . For example the amount of posts or what type of grid (read: template)
  • With the arguments get dynamic input selectors. For example to filter posts on one or more taxonomies plus it’s terms.
  • Also use the block outside the editor. For example use the same post grid template to use on a archive template blade page.

Any pointers are welcome. Are there boilerplates for this? Or is this already build-in?

You should take a look at this package by Log1x - its superb: https://github.com/Log1x/acf-composer

(Make sure you install WP Cli globally first though as it uses this to run ‘wp acorn’ commands within your theme)

Once installed, you could have a PostList block which you can customise for custom post types and taxonomies, so, in: app > Blocks > PostList.php

<?php

namespace App\Blocks;

use Log1x\AcfComposer\Block;
use StoutLogic\AcfBuilder\FieldsBuilder;

class SimplePostList extends Block
{
    /**
     * The block name.
     *
     * @var string
     */
    public $name = 'Simple Post List';

    /**
     * The block description.
     *
     * @var string
     */
    public $description = 'Customizable generic list of posts.';

    /**
     * The block category.
     *
     * @var string
     */
    public $category = 'formatting';

    /**
     * The block icon.
     *
     * @var string|array
     */
    public $icon = 'editor-ul';

    /**
     * The block post types.
     *
     * @var array
     */
    public $post_types = [];

    /**
     * The supported block features.
     *
     * @var array
     */
    public $supports = [
        'align' => true,
        'align_text' => false,
        'align_content' => false,
        'mode' => false,
        'multiple' => true,
        'jsx' => true,
    ];

    /**
     * Data to be passed to the block before rendering.
     *
     * @return array
     */
    public function with()
    {
        return [
            'posts' => $this->posts(),
        ];
    }

     /**
     * The widget field group.
     *
     * @return array
     */
    public function fields()
    {
        $postList = new FieldsBuilder('simple_post_list');

        $postList
            ->addSelect('filter')
                ->addChoices(
                    ['none' => 'None'],
                    ['post_type' => 'Post Type'],
                    ['category' => 'Category']
                )

            ->addRange('count', ['min' => 1, 'max' => 250])
                ->setLabel('Number of Posts')
                ->setDefaultValue('5')

            ->addSelect('order')
                ->setLabel('Post Order')
                ->addChoices(
                    ['date' => 'Published'],
                    ['modified' => 'Modified'],
                    ['title' => 'Title'],
                    ['rand' => 'Random']
                )

            ->addButtonGroup('sort')
                ->setLabel('Sorting')
                ->addChoices(['asc' => 'Ascending', 'desc' => 'Descending'])
                ->setDefaultValue('desc')

            ->addSelect('post_type')
                ->conditional('filter', '==', 'post_type')
                ->addChoices(
                    ['post' => 'Post'],
                    ['page' => 'Page'],
                )

            ->addTaxonomy('category', ['taxonomy' => 'category'])
                ->conditional('filter', '==', 'category');

        return $postList->build();
    }

    /**
     * Return the queried posts.
     *
     * @return array
     */
    public function posts()
    {
        return collect(
            get_posts([
                'post_type' => get_field('post_type', $this->widget->id) ?? 'post',
                'posts_per_page' => get_field('count', $this->widget->id) == 0 ?
                    -1 : get_field('count', $this->widget->id),
                'orderby' => get_field('order', $this->widget->id) ?? 'date',
                'order' => get_field('sort', $this->widget->id) ?? 'desc',
                'category__and' => get_field('category', $this->widget->id) ?? null,
            ])
        )->map(function ($item) {
            return (object) [
                'title' => get_the_title($item),
                'url' => get_the_permalink($item),
            ];
        })->filter();
    }
}

then in: views > blocks > post-list.blade.php

@if (! empty($posts))
  <div class="{{ $block->classes }} my-4 first:mt-0 last:mb-0">
    <ul class="ml-0 {{ $posts->count() >= 20 ? 'sm:col-count-2' : '' }}">
      @foreach($posts->all() as $post)
        <li class="pl-0">
          <a class="{{ $block->preview ? 'pointer-events-none' : '' }}" href="{{ $post->url }}">
            {!! $post->title !!}
          </a>
        </li>
      @endforeach
    </ul>
  </div>
@endif

Just make sure file naming is reflective on blocks as it uses ‘PascalCase’ for app > block > FileName.php eg:

app > Blocks > PostList.php

and then your view will be ‘kebab-case / dash-case’ eg.

views > blocks > post-list.blade.php

and you can also use blade includes for view blocks so they become available for both theme blade templates, and also for Gutenberg eg:

<div class="{{ $block->classes }}">

  @include('partials.components.my-blade-component')

  <div>
    <InnerBlocks />
  </div>
</div>
3 Likes

Thanks @fabianwurk for your suggestion. I happened to stumble across this repo yesterday. Took me all day to figure out it requires ACF Pro. (Might have been nice beeing mencioned in the readme : ) Only took me 7 hours to figure it out. It worked instantly after I tried it with a pro version from a different project.

I think I’ll go look for a gutenberg version and not a ACF block solution. I don’t like to add another paid dependency to the pile. 2 years back with the 25 bucks for a lifetime I would have done in a heartbeat.

I just found those two skimming trough GitHub:

Also, nice code example. Thanks, learned a lot from that.

1 Like

Yeah Tim, probably assumes most users of Sage will have ACF Pro already. But please keep us posted on how you get on with those other non acf dependent options. :+1:

1 Like

There is an OpenSource alternative to ACF PRO, which seems to have improved quite a lot:
https://carbonfields.net/
It also supports Gutenberg Blocks.

1 Like

Will do. I’m now tinkering with https://github.com/Log1x/poet also from @Log1x.
No luck so far : ) The blocks are not showing. So it’s back to the documentation. (also not for a clean sage 10 installation) We’ll see.
I’ll post back when I get a non-acf version to work.

1 Like

Oh nice. I’ve never heard of it. I will check this out for sure. Too bad ACF has too big of a monopoly to switch already. (for example support from Yoast) Good find, thanks!

There is a plugin for Carbon-Yoast integration:

This topic was automatically closed after 42 days. New replies are no longer allowed.