Create a Content Widget Type

We are going to illustrate how to create a content widget type to render the copyright. It should have an option to control the display format (short or long).

You can create a content widget type in four steps outlined below.

1. Extend AbstractContentWidgetType

To implement a new content widget, create a class that stores content widget type configuration and renders the content widget. The class should extend AbstractContentWidgetType.

 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
<?php

namespace ACME\Bundle\CopyrightBundle\ContentWidget;

use Oro\Bundle\CMSBundle\ContentWidget\AbstractContentWidgetType;
use Oro\Bundle\CMSBundle\Entity\ContentWidget;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\Extension\Core\Type\FormType;
use Symfony\Component\Form\FormFactoryInterface;
use Symfony\Component\Form\FormInterface;

class CopyrightContentWidgetType extends AbstractContentWidgetType
{
    public static function getName(): string
    {
        return 'copyright';
    }

    public function getLabel(): string
    {
        return 'acme.copyright.content_widget.copyright.label';
    }

    public function getSettingsForm(ContentWidget $contentWidget, FormFactoryInterface $formFactory): ?FormInterface
    {
        return $formFactory->createBuilder(FormType::class, $contentWidget)
            ->add('isShort', CheckboxType::class, ['label' => 'acme.copyright.settings.is_short.label', 'required' => false])
            ->getForm();
    }

    public function getDefaultTemplate(ContentWidget $contentWidget, Environment $twig): string
    {
        return $twig->render('@ACMECopyright/CopyrightContentWidget/widget.html.twig', $contentWidget->getSettings());
    }
}

Note

When you want to use an existing form type in you content widget type:

1
2
3
4
    public function getSettingsForm(ContentWidget $contentWidget, FormFactoryInterface $formFactory): ?FormInterface
    {
        return $formFactory->create(FormType::class);
    }

The form type has the following code:

 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
<?php

namespace ACME\Bundle\CopyrightBundle\Form\Type;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\FormBuilderInterface;

/**
 * Copyright content widget form type.
 */
class CopyrightContentWidgetType extends AbstractType
{
    /**
     * {@inheritdoc}
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add(
            'isShort',
            CheckboxType::class,
            ['label' => 'acme.copyright.settings.is_short.label', 'required' => false]
        );
    }
}

It should be registered in a service container with the oro_cms.content_widget.type tag.

1
2
3
4
services:
    ACME\Bundle\CopyrightBundle\ContentWidget\CopyrightContentWidgetType:
        tags:
            - {name: 'oro_cms.content_widget.type'}

Note

When autoconfiguration is enabled, tagging the service manually is unnecessary.

1
2
3
4
5
services:
    _defaults:
        autoconfigure: true

    ACME\Bundle\CopyrightBundle\ContentWidget\CopyrightContentWidgetType: ~

Add translations to strings in a template.

1
2
3
4
5
6
7
acme.copyright:
    content_widget:
        copyright:
            label: 'Copyright'

    settings:
        is_short.label: 'Short'

2. Create a Template to Render the Widget in the Storefront

Create a template to render the content widget on the storefront.

1
2
{%- set copyright = isShort ? 'acme.copyright.text.short' : 'acme.copyright.text.default' -%}
<copy>{{ copyright|trans({ '%year%': 'now'|date('Y') }) }}</copy>

Add translations to strings in the template.

1
2
3
4
acme.copyright:
    text:
        default: '(c) %year%. All rights reserved'
        short: '(c) %year%'

3. (Optionally) Render the Widget Info in the Back-Office

3.1 Create a Template

1
2
3
{% import 'OroUIBundle::macros.html.twig' as UI %}

{{ UI.renderProperty('acme.copyright.settings.is_short.label'|trans, settings.isShort ? 'Yes'|trans : 'No'|trans) }}

3.2 Implement the getAdditionalInformationBlock Method in the Content Widget Type

1
2
3
4
5
6
7
    protected function getAdditionalInformationBlock(ContentWidget $contentWidget, Environment $twig): string
    {
        return $twig->render(
            '@ACMECopyright/CopyrightContentWidget/view.html.twig',
            ['settings' => $contentWidget->getSettings()]
        );
    }

Note

To pass additional data to the template, you can override getBackOfficeViewSubBlocks method. The example below illustrates how to add two blocks with two subblocks in each block.

 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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
<?php

namespace ACME\Bundle\CopyrightBundle\ContentWidget;

use Oro\Bundle\CMSBundle\ContentWidget\AbstractContentWidgetType;
use Oro\Bundle\CMSBundle\Entity\ContentWidget;
use Twig\Environment;

/**
 * Type for the copyright widgets.
 */
class CopyrightContentWidgetType extends AbstractContentWidgetType
{
    public function getBackOfficeViewSubBlocks(ContentWidget $contentWidget, Environment $twig): array
    {
        return [
            [
                'title' => 'oro.cms.contentwidget.sections.additional_information_block1.label',
                'subblocks' => [
                    [
                        'data' => [
                            $twig->render(
                                '@ACMECopyright/CopyrightContentWidget/acme_template1.html.twig',
                                ['settings' => $contentWidget->getSettings()]
                            ),
                        ]
                    ],
                    [
                        'data' => [
                            $twig->render(
                                '@ACMECopyright/CopyrightContentWidget/acme_template2.html.twig',
                                ['settings' => $contentWidget->getSettings()]
                            ),
                        ]
                    ],
                ]
            ],
            [
                'title' => 'oro.cms.contentwidget.sections.additional_information_block2.label',
                'subblocks' => [
                    [
                        'data' => [
                            $twig->render(
                                '@ACMECopyright/CopyrightContentWidget/acme_template3.html.twig',
                                ['settings' => $contentWidget->getSettings()]
                            ),
                        ]
                    ],
                    [
                        'data' => [
                            $twig->render(
                                '@ACMECopyright/CopyrightContentWidget/acme_template4.html.twig',
                                ['settings' => $contentWidget->getSettings()]
                            ),
                        ]
                    ],
                ]
            ],
        ];
    }
}

4. (Optionally) Pass Custom Data to the Template when Rendering Widget in the Storefront

Override getWidgetData method in the Content Widget Type.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?php

namespace ACME\Bundle\CopyrightBundle\ContentWidget;

use Oro\Bundle\CMSBundle\ContentWidget\AbstractContentWidgetType;
use Oro\Bundle\CMSBundle\Entity\ContentWidget;
use Oro\Bundle\ProductBundle\Entity\Product;

/**
 * Type for the copyright widgets.
 */
class CopyrightContentWidgetType extends AbstractContentWidgetType
{
    ...

    public function getWidgetData(ContentWidget $contentWidget): array
    {
        // For example, fetch the product from entity manager to pass it to the template
        $product = $this->doctrine->getManagerForClass(Product::class)
              ->find(Product::class, $contentWidget->getSettings()['productId']);

        return ['contentWidget' => $contentWidget, 'product' => $product];
    }
}

5. (Optionally) Add Content Widget Templates

It is possible to provide multiple templates for some content widget types. This allows the user to select which template to use when creating a content widget instance.

If there is a least one template defined, a list of all templates collected from all themes for this widget type is displayed on the content widget create/edit form drop-down.

During rendering on the storefront, if the template selected by the user is not available in the current theme, the widget is rendered using its default template (set in the getDefaultTemplate method). To add a new layout template for a widget type, follow the steps below:

5.1 Add Template Definition to Theme Configuration

Create a widgets.yml file for certain theme (e.g., blank) in the config folder Resources/views/layouts/blank/config/widgets.yml:

1
2
3
layouts:
    copyright:
        first: 'acme.copyright.content_widget.copyright.label'
  • copyright stands for the widget type to which template is added.
  • first key represents a particular theme with its name (translation key) as a value.

5.2 Add Layout Update File and Template

Create a layout update file in the appropriate content widget folder inside the desired theme. Keep in mind that all widget layout update files should follow a naming convention: content_widget/{your_unique_widget_type_name}, e.g.,: Resources/views/layouts/blank/content_widget/copyright/content_widget.yml.

1
2
3
4
5
layout:
    actions:
        - '@setBlockTheme':
            themes: 'content_widget.html.twig'
...

Follow the same steps with templates for the layout update with customized markup Resources/views/layouts/blank/content_widget/copyright/content_widget.html.twig:

1
2
3
{% block _copyright_content_widget_layout_name_widget %}
    <p>{{ block_widget(block) }}</p>
{% endblock %}

The widget template for the Copyright widget should be available after clearing the cache. To define templates for other themes, apply the same actions making sure you place files in the appropriate theme folders and follow the naming conventions.

Now an administrator can create content widgets of a new type from the UI by following steps outlined in the Content Widgets User Guide user documentation.