Skip to content

Create custom Page block

In addition to existing blocks which you can use in a Page, you can also create custom blocks.

To do this, add block configuration in a YAML file, under the ibexa_fieldtype_page configuration key.

Clear the persistence cache

Persistence cache must be cleared after any modifications have been made to the block config in Page Builder, such as adding, removing or altering the Page blocks, block attributes, validators or views configuration.

To clear the persistence cache run ./bin/console cache:pool:clear [cache-pool] command. The default cache-pool is named cache.tagaware.filesystem. The default cache-pool when running redis is named cache.redis. If you have customized the persistence cache configuration, the name of your cache pool might be different.

In prod mode, you also need to clear the symfony cache by running ./bin/console c:c. In dev mode, the Symfony cache will be rebuilt automatically.

The following example shows how to create a block that showcases an event.

Configure block

First, add the following YAML configuration:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
ibexa_fieldtype_page:
    blocks:
        event:
            name: Event Block
            category: Custom
            thumbnail: /bundles/ibexaicons/img/all-icons.svg#date
            attributes:
                name:
                    type: text
                    name: Event name
                    validators:
                        not_blank:
                            message: Please provide a name
                category:
                    type: select
                    name: Select a category
                    value: visual
                    options:
                        multiple: true
                        choices:
                            'Music': music
                            'Visual arts': visual
                            'Sports': sports
                event:
                    type: embed
                    name: Event
                    validators:
                        not_blank:
                            message: Please select an event
                        content_type:
                            message: Please select an event
                            options:
                                types: ['event']
                        regexp:
                            message: Choose a content item
                            options:
                                pattern: '/[0-9]+/'

event is the internal name for the block, and name indicates the name under which the block is available in the interface. You also set up the category in the Elements panel that the block appears in. In this case, it doesn't show with the rest of the built-in blocks, but in a separate "Custom" category. The thumbnail for the block can be one of the pre-existing icons, like in the example above, or you can use a custom SVG file.

A block can have multiple attributes that you edit when adding it to a Page. In this example, you configure three attributes: name of the event, category it belongs to, and an event content item that you select and embed.

For a list of all available attribute types, see Page block attributes.

Each attribute can have validators. The not_blank validators in the example ensure that the user fills in the two block fields. The content_type validator in the example ensure that the user choose a content item of the content type event. The regexp validator ensure that the final value looks like a content ID.

Add block templates

A block can have different templates that you select when adding it to a Page.

To configure block templates, add them to block configuration:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
ibexa_fieldtype_page:
    blocks:
        event:
            views:
                default:
                    template: '@ibexadesign/blocks/event/template.html.twig'
                    name: Default view
                    priority: -255
                featured:
                    template: '@ibexadesign/blocks/event/featured_template.html.twig'
                    name: Featured view
                    priority: 50

Provide the templates in the indicated folder, in this case in templates/themes/<your_theme>/blocks/event.

For example the featured_template.html.twig file can look like this:

1
2
3
4
5
6
<h1>{{ name }}</h1>
<p>{{ category }}</p>
{{ render(controller('ibexa_content::viewAction', {
    'contentId': event,
    'viewType': 'embed'
})) }}

The templates have access to all block attributes, as you can see above in the name, category and event variables.

Priority of templates indicates the order in which they're presented in Page Builder. The template with the greatest priority is used as the default one.

Add block JavaScript

If your block is animated with JavaScript, you may have to take precaution to keep it working when previewed in Back Office's Page Builder.

If you use an event related to the page being loaded to trigger the initialisation of your custom block, a freshly added block doesn't work in the Page Builder preview. For example, the DOMContentLoaded event isn't fired when a block is dragged into the page as the DOM is already loaded.

The Page Builder fires body events that you can listen to initialize your block:

  • ibexa-render-block-preview event is fired when the page is loaded in the Page Builder, when a block is added, when a block is deleted, and when a block setting modification is submitted.
  • ibexa-post-update-blocks-preview event is fired when a block setting modification is submitted, this event has a detail property listing the reloaded modified block IDs and their configs.

In the following code, the same initCustomBlocks function is attached to two event listeners. One listener to call the function when a page is loaded (as a regular front page or as a page edited in the Page Builder). The other one to call it when a block is added or configured in the Page Builder. This initCustomBlocks function finds the custom blocks to loop through them, initializes some JavaScript when the block isn't already initialized, and flag the block as initialized. For example, it could initialize carousel blocks with the addition of event listeners to navigation arrows, and the start of an automatic sliding.

1
2
3
4
5
6
document.addEventListener('DOMContentLoaded', function(event) {
    initCustomBlocks();
});
document.getElementsByTagName('body')[0].addEventListener('ibexa-render-block-preview', function(event) {
    initCustomBlocks();
});

Note

For the addition of your custom block's JS and CSS files, see Assets.

If you consider using React JavaScript library, see React App block.

Add pre-render event listener

If you need to compute variables to pass to the template, you can listen or subscribe to the block pre-render event.

For example, the following event subscriber loads the event content item and passes it to the template as event_content:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<?php declare(strict_types=1);

namespace App\Event\Subscriber;

use Ibexa\Contracts\Core\Repository\ContentService;
use Ibexa\FieldTypePage\FieldType\Page\Block\Renderer\BlockRenderEvents;
use Ibexa\FieldTypePage\FieldType\Page\Block\Renderer\Event\PreRenderEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

class BlockEmbedEventEventSubscriber implements EventSubscriberInterface
{
    private ContentService $contentService;

    public function __construct(ContentService $contentService)
    {
        $this->contentService = $contentService;
    }

    public static function getSubscribedEvents(): array
    {
        return [
            BlockRenderEvents::getBlockPreRenderEventName('event') => 'onBlockPreRender',
        ];
    }

    public function onBlockPreRender(PreRenderEvent $event): void
    {
        $renderRequest = $event->getRenderRequest();
        $parameters = $event->getRenderRequest()->getParameters();
        $parameters['event_content'] = $this->contentService->loadContent($parameters['event']);
        $renderRequest->setParameters($parameters);
    }
}

The block view template could now use ibexa_render(event_content, {'viewType': 'embed'}) instead of render(controller('ibexa_content::viewAction', {'contentId': event, 'viewType': 'embed'})), other content Twig functions, or field Twig functions.

For more information, see Block events.

Add edit template

You can also customize the template for the block settings modal. Do this under the configuration_template configuration key:

1
2
3
4
5
6
7
ibexa_fieldtype_page:
    blocks:
        event:
            name: Event Block
            category: Custom
            thumbnail: /bundles/ibexaicons/img/all-icons.svg#date
            configuration_template: '@ibexadesign/blocks/event/config.html.twig'

Place the edit template in templates/themes/<your_theme>/blocks/event/config.html.twig:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
{% extends '@IbexaPageBuilder/page_builder/block/config.html.twig' %}

{% block content %}
    {% set form_templates = [_self] %}
    {{ parent() }}
{% endblock %}

{% block basic_tab_content %}
    <div class="ibexa-block-config__fields">
        {{ form_row(form.name) }}
        {% if attributes_per_category['default'] is defined %}
            <ol>
                {% for identifier in attributes_per_category['default'] %}
                    {% block config_entry %}
                        <li>
                            {{ form_row(form.attributes[identifier]) }}
                        </li>
                    {% endblock %}
                {% endfor %}
            </ol>
        {% endif %}
    </div>
{% endblock %}

{% block block_configuration_attribute_embed_widget %}
    {% set attr = attr|merge({'hidden': true}) %}
    {{ form_widget(form, {'attr': attr})}}
    <div class="ibexa-pb-block-embed-field">
        {% include '@IbexaPageBuilder/page_builder/block/config/embed_button.html.twig' with {
            udw_config_name: 'block_event_embed',
            data_open_udw: 'data-open-udw-embed'
        } %}
        {% include '@IbexaPageBuilder/page_builder/block/config/embed_preview.html.twig' %}
    </div>
{% endblock %}

This example template overrides the embed attribute widget to customize the Universal Discovery Widget (UDW). It adds itself to the form_templates and defines a block_configuration_attribute_embed_widget block. The following UDW configuration is used so only an event typed content item can be selected:

1
2
3
4
5
6
7
8
ibexa:
    system:
        default:
            universal_discovery_widget_module:
                configuration:
                    block_event_embed:
                        multiple: false
                        allowed_content_types: ['event']

For more information, see UDW configuration.

Your custom page block is now registered in the system.

Caution

To use the new block in Page Builder, add it to the list of available blocks in a given content type's settings. This can be done manually in Page field settings or by using the migration action add_block_to_available_blocks.