Sonata Page 5: Hide blocks within shared blocks.

If you're using the SonataPage bundle, you may have noticed that some of the blocks offered are unnecessary or non-functional.

We'll discuss how to hide these blocks from the list cleanly, with a configuration file, and by overriding the admin templates of SonataPage.

image

1 – The Configuration

We need to create a list of services that we don't want to display. This list will naturally go into the parameters of our services file:

#config/services.yaml
parameters:

    sonata_page_excluded_blocks:
        - 'sonata.media.block.gallery_list'
        - 'sonata.media.block.feature_media'
        - 'sonata.media.block.gallery'

To find out the name of the service to exclude, it's quite simple, it's in the URL when you click on it in the shared blocks creation view.

2 – Twig function to Retrieve Our Parameter

To hide the blocks, we're going to override SonataPage's templates. So we need to retrieve our configuration directly in our template. Therefore, we're going to create a Twig extension for our project. It's quite common, you probably already have one.

#src/Twig/Extension/AppExtension.php
<?php
namespace App\Twig;

use Twig\Extension\AbstractExtension;
use Twig\TwigFunction;

class AppExtension extends AbstractExtension
{
    private $sonata_page_excluded_blocks;

    public function __construct(array $sonata_page_excluded_blocks)
    {
        $this->sonata_page_excluded_blocks = $sonata_page_excluded_blocks;
    }

    public function getFunctions(): array
    {
        return [
            new TwigFunction('sonata_page_excluded_blocks', [$this, 'getSonataPageExcludedBlocks']),
        ];
    }

    public function getSonataPageExcludedBlocks(): array
    {
        return $this->sonata_page_excluded_blocks;
    }
}

Then we need to reference it in the services.

services:
    App\Twig\AppExtension:
        arguments:
            $sonata_page_excluded_blocks: '%sonata_page_excluded_blocks%'

3 – Overriding Templates

As you know, all templates can be overridden. Just locate the template within your bundle. Generally, you just need to check the list of Twig templates in the profiler. It's very often the first one.

image-2


We see that our template is stored in:
vendor/sonata-project/page-bundle/src/Resources/views/BlockAdmin/select_type.html.twig

To override it, just put it in our template directory with the path:
templates/bundles/NomDuBundle/FolderAfterViews/…/YourFile.html.twig

Which gives us:
templates/bundles/SonataPageBundle/BlockAdmin/select_type.html.twig


Once the file is copied, if we reload the page, we should find the correct file in the list of templates on our Twig tab of the profiler.

image-1

4 – Overriding the Block List in Our Template

We just have to retrieve our list of configured blocks from our parameters and recreate the variable used to create the array, without our blocks to exclude.

        {% set excluded_blocks = sonata_page_excluded_blocks() %}
        {% set filteredBlockServices = [] %}
        {% for key, service in blockServices %}
            {% if key not in excluded_blocks %}
                {% set filteredBlockServices = filteredBlockServices|merge({(key): service}) %}
            {% endif %}
        {% endfor %}
        {% set blockServices = filteredBlockServices %}

This gives us:

{#
templates/bundles/_SonataPageBundle/BlockAdmin/select_type.html.twig

#}

{% extends '@SonataAdmin/CRUD/action.html.twig' %}

{% block title %}{{ 'title_select_block_type'|trans({}, 'SonataPageBundle') }}{% endblock %}

{% block content %}
    <div class="box box-success">
        <div class="box-header">
            <h3 class="box-title">
                {{ 'title_select_block_type'|trans({}, 'SonataPageBundle') }}
            </h3>
        </div>

        {# surcharge pour exclude des blocs #}
        {% set excluded_blocks = sonata_page_excluded_blocks() %}
        {% set filteredBlockServices = [] %}
        {% for key, service in blockServices %}
            {% if key not in excluded_blocks %}
                {% set filteredBlockServices = filteredBlockServices|merge({(key): service}) %}
            {% endif %}
        {% endfor %}
        {% set blockServices = filteredBlockServices %}
        {# fin de surcharge pour exclude des blocs #}


        <div class="box-body">
            {% for code, blockService in blockServices %}
                <div class="col-lg-2 col-md-3 col-sm-4 col-xs-6">
                    <a  href="{{ admin.generateUrl('create', {'type': code}) }}"
                        class="btn btn-app btn-block sonata-block-type"
                        data-toggle="tooltip"
                        data-placement="top"
                        {% if blockService.metadata.description %}
                            title="{{ blockService.metadata.description|trans({}, blockService.metadata.domain|default('SonataBlockBundle')) }}"
                        {% endif %}
                            >
                        {% if not blockService.metadata.image %}
                            <i class="{{ blockService.metadata.option('class') }}" ></i>
                        {% else %}
                            <img src="{{ asset(blockService.metadata.image) }}" style="max-height: 20px; max-width: 100px;"/>
                            <br />
                        {% endif %}
                        <span>{{ blockService.metadata.title|trans({}, blockService.metadata.domain|default('SonataBlockBundle')) }}</span>
                    </a>
                </div>
            {% else %}
                <span class="alert alert-info">{{ 'no_type_available'|trans({}, 'SonataPageBundle') }}</span>
            {% endfor %}

            <div class="clearfix"></div>
        </div>
    </div>
{% endblock %}

And if we reload the page, we should have the list, cleansed of our blocks.

Selection_011

Instead of

bloc

6 – Overriding the Block List in the Page Composer

For the page composer, it's exactly the same manipulation. The file to override is:
vendor/sonata-project/page-bundle/src/Resources/views/PageAdmin/compose_container_show.html.twig

This gives us:
/templates/bundles/SonataPageBundle/PageAdmin/compose_container_show.html.twig

We put exactly the same code, which gives us a complete file following:

{#
/templates/bundles/SonataPageBundle/PageAdmin/compose_container_show.html.twig
#}
<div class="page-composer__container__view block-view-{{ container.id }}"
     data-block-id="{{ container.id }}"
>
    <h2 class="page-composer__container__view__header">{{ container.name }}</h2>

    <span class="page-composer__container__view__notice">{{ 'notice'|trans({}, 'SonataPageBundle') }}</span>

    {# surcharge pour exclude des blocs #}
    {% set excluded_blocks = sonata_page_excluded_blocks() %}
    {% set filteredBlockServices = [] %}
    {% for key, service in blockServices %}
        {% if key not in excluded_blocks %}
            {% set filteredBlockServices = filteredBlockServices|merge({(key): service}) %}
        {% endif %}
    {% endfor %}
    {% set blockServices = filteredBlockServices %}
    {# fin de surcharge pour exclude des blocs #}

    <div class="page-composer__block-type-selector">
        <label>{{ 'composer.block.add.type'|trans({}, 'SonataPageBundle') }}</label>
        <select class="page-composer__block-type-selector__select" style="width: auto">
            {% for blockServiceId, blockService in blockServices %}
                <option value="{{ blockServiceId }}">{{ blockService.metadata.title|trans({}, blockService.metadata.domain|default('SonataBlockBundle')) }}</option>
            {% endfor %}
        </select>
        <a class="btn btn-action btn-small page-composer__block-type-selector__confirm"
           href="{{ admin.generateObjectUrl('sonata.page.admin.block.create', page, {'composer': true}) }}"
        ><i class="fa fa-plus"></i></a>
        <span class="page-composer__block-type-selector__loader">{{ 'loading'|trans({}, 'SonataPageBundle') }}</span>

        <small class="page-composer__container__child-count pull-right">
            {{ 'blocks'|trans({}, 'SonataPageBundle') }} <span class="badge">{{ container.children|length }}</span>
        </small>
    </div>

    <ul class="page-composer__container__children">
        {% for child in container.children %}
            {% include '@SonataPage/BlockAdmin/compose_preview.html.twig' with {
                'blockService': attribute(blockServices, child.type) ?? null
            } %}
        {% endfor %}
    </ul>
</div>

image-3