Control Board Design with Slot Filtration and Board Planner Objects

But just exactly how do boards look so nice all the time? It's the use of driver objects that can strictly control how board content is laid out. The easiest way to understand this is to look through how Atomik's Blog board is configured, and learn lessons from that.

Blog Template Driver

The Concrete\Core\Board\Template\Driver\BlogDriver class informs Concrete that it itself contains 5 slots:

public function getTotalSlots(): int
{
    return 5;
}

Additionally, it controls the display of slot number 1 in a very particular way, by implementing the getLayoutPlanner method. This is an optional method available to the blog driver class.

public function getLayoutPlanner(): ?PlannerInterface
{
    return new SlotLayoutPlanner([
        '1' => ['blog_image_left']
    ]);
}

The SlotLayoutPlanner class is a simple class meant to tie a particular slot in a board template to a particular board slot template. What does this means? It means that no matter how many times you regenerate the Atomik blog board, you'll aways get a left-image content element in the first slot, because the only slot template that layout planner will allow to be placed within the slot 1 is the blog_image_left slot template.

So let's look at the blog_image_left slot template driver, found at Concrete\Core\Board\Template\Slot\Driver\BlogImageLeftDriver. It informs the system that it contains one content slot:

public function getTotalContentSlots(): int
{
    return 1;
}

And it also informs the system that within its single content slow, only the content objects with the blog_image_left summary templates may be placed. This is through the use of the slot filterer object:

public function getSlotFilterer(): ?FiltererInterface
{
    $filterer = new SummaryObjectFilterer();
    $filterer->registerSlot(1, [
        'blog_image_left',
    ]);
    return $filterer;
}

This is similar to the board planner object, but it works with summary templates.

Let's contrast this with the Concrete\Core\Boared|Template\Slot\Driver\BlogThreeUpDriver class. When the slot template blog_three_up is placed within a board template slot, **three* content objects will be placed within its content slots:

public function getTotalContentSlots(): int
{
    return 3;
}

Additionally, not just any summary templates may be used for these content objects – only the blog_entry_card summary template will be used for the items in these content slots, because that's what the slot filterer decrees:

public function getSlotFilterer(): ?FiltererInterface
{
    $filterer = new SummaryObjectFilterer();
    $filterer->registerSlot(1, [
        'blog_entry_card',
    ]);
    $filterer->registerSlot(2, [
        'blog_entry_card',
    ]);
    $filterer->registerSlot(3, [
        'blog_entry_card',
    ]);
    return $filterer;
}

When you get down to the details of the blog_entry_card template, it's relatively straightforward. From concrete/themes/atomik/elements/summary/templates/blog_entry_card.php:

<?php defined('C5_EXECUTE') or die("Access Denied."); ?>
<div class="ccm-summary-template-blog-entry-thumbnail">
    <a href="<?=$link?>" class="card">
        <div class="position-relative">
            <div class="card-img-top ccm-summary-template-blog-entry-thumbnail-image-overlay"></div>
            <img class="card-img-top" src="<?=$thumbnail->getThumbnailURL('blog_entry_thumbnail')?>">
        </div>
        <div class="card-body">
            <h5 class="card-title"><?=$title?></h5>
            <?php if ($date) { ?>
                <p class="card-text text-center"><small class="text-muted"><?=date('F d, Y', (string) $date)?></small></p>
            <?php } ?>
        </div>
    </a>
</div>