Creating Block Extension

Creating block extensions is pretty darn easy but can provide complex solutions to your content needs too. Let's dive in!

Create Your Extension

First things first, we need to create our extension:

php artisan make:addon my_company.extension.awesome_block

Next open up the AwesomeBlockExtension class and make sure it extends \Anomaly\BlocksModule\Block\BlockExtension and defines it's $provides and $category properties so we know what it does:

<?php namespace MyCompany\AwesomeBlockExtension;

use Anomaly\BlocksModule\Block\BlockExtension;

class AwesomeBlockExtension extends BlockExtension
{

    protected $category = 'content';

    protected $provides = 'anomaly.module.blocks::block.awesome';

}

Categories

protected $category = 'content';

You can use any of these built in sections by default:

content
information
component
media
module
social
layout
other

You can also resolve the \Anomaly\BlocksModule\Block\BlockCategories classes register function in the boot method of your service provider to add a category of your own:

$categories->register('example-category', [
    'name'          => 'Name or translatable string.',
    'description'   => 'Description or translatable string.',
]);

Adding Configuration Fields

The easiest way to get user input into a block is by using the Configuration Module which is already pre-setup for you. All you need to do is define your configuration fields in a resources/config/configuration.php file.

<?php

return [
    'cover_image' => [
        'type'   => 'anomaly.field_type.file',
        'config' => [
            'folders' => ['images'],
        ],
    ],
    'content' => [
        'type'   => 'anomaly.field_type.wysiwyg',
        'config' => [
            'configuration' => 'basic',
        ],
    ],
];

Customizing Form Sections

You can define optional form sections for your entire block (aside from the mandatory title field) by defining a resources/config/sections.php file.

Your block, configuration, and stream entry fields are available to you already prefixed.

<?php

return [
    'example' => [
        'fields' => [
            'configuration_cover_image',
            'configuration_content',
        ],
    ],
];

By default fields will stack on top of each other in the order in which they are defined.

Creating A Block Stream

Some data is best stored in a stream rather than in configuration. It's easy to create a stream for your block:

php artisan make:stream blocks awesome_block

blocks is a name I tend to use here but you can name the stream whatever you like.

Just like building other addons - all you have to do now is populate your extension's migrations as needed.

If only using one stream we can now simply define the $model property of our AwesomeBlockExtension class and the stream will be merged into the block automatically for you.

<?php namespace MyCompany\AwesomeBlockExtension;

use Anomaly\BlocksModule\Block\BlockExtension;
use MyCompany\AwesomeBlockExtension\Block\BlockModel;

class AwesomeBlockExtension extends BlockExtension
{

    protected $provides = 'anomaly.module.blocks::block.awesome';

    protected $model = BlockModel::class;

}

If you would like the above stream entry fields in your block's form simply add them to your sections.php using the entry_ prefix:

<?php

return [
    'example' => [
        'fields' => [
            'entry_gallery_repeater',
            'configuration_cover_image',
            'configuration_content',
        ],
    ],
];

Displaying Block Content

To define your block's content view we need to define the $view property of our AwesomeBlockExtension:

<?php namespace MyCompany\AwesomeBlockExtension;

use Anomaly\BlocksModule\Block\BlockExtension;
use MyCompany\AwesomeBlockExtension\Block\BlockModel;

class AwesomeBlockExtension extends BlockExtension
{

    protected $provides = 'anomaly.module.blocks::block.awesome';

    protected $view = 'anomaly.extension.awesome_block::content';

    protected $model = BlockModel::class;

}

Now create your resources/views/content.twig file in the extension directory and create your view using block as the BlockInterface:

<div class="hero">
    {{ file(block.cover_image).make.resize(1200)|raw }}

    {% for item in block.gallery_repeater %}
        {{ item.image.make.resize(48, 48).class('img-rounded')|raw }}
    {% endfor %}

    {{ block.content.render|raw }}
</div>

Looking at the above you can see that configuration and custom entry data are both accessible directly off of the block.

Should you need to access configuration in a non-magic way you can use {{ block.configuration($key) }}. You can also grab settigns, if your extension defines any, the same way {{ block.settings($key) }}.

You can access your block's custom stream entry directly as well using {{ block.entry.$field }} where entry is a polymorphic relation.

Advanced Development

Block Instance Form Builder

Should you need to interact with the multiple form builder responsible for building blocks directly you can override the extend method on your block extension:

public function extend(BlockInstanceFormBuilder $builder)
{
    parent::extend($builder);

    // Do more stuff!
}

Dynamic Views

The getView method is responsible for telling the blocks system what view to use for your block's content.

You could easily override the method and use $block property to return a view dynamically or even a user generated view from the editor field type.

public function getView()
{
    if ($this->block->configuration('something_special')) {
        return 'my_company.extension.awesome_block::alternate_view';
    }

    return $this->view;
}