Skip to content

Create custom catalog filter

Catalog filters let you narrow down the products from the PIM that are available in the given catalog.

Besides the built-in catalog filters, you can also create custom ones. The following example shows how to create a filter that selects products with the entered name.

Create filter class

To create a custom catalog filter, first you need to create a filter class in App\CatalogFilter\ProductNameFilter.

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

declare(strict_types=1);

namespace App\CatalogFilter;

use Ibexa\Contracts\ProductCatalog\CatalogFilters\FilterDefinitionInterface;
use Ibexa\Contracts\ProductCatalog\Values\Product\Query\Criterion\ProductName;
use Ibexa\Contracts\ProductCatalog\Values\Product\Query\CriterionInterface;

final class ProductNameFilter implements FilterDefinitionInterface
{
    public function getIdentifier(): string
    {
        return 'product_name';
    }

    public function getName(): string
    {
        return 'Product name';
    }

    public function supports(CriterionInterface $criterion): bool
    {
        return $criterion instanceof ProductName;
    }

    public static function getTranslationMessages(): array
    {
        return [];
    }

    public function getGroupName(): string
    {
        return 'Custom filters';
    }
}

The filter must implement Ibexa\Contracts\ProductCatalog\CatalogFilters\FilterDefinitionInterface, provide the filter identifier and name, and the group in which it is displayed in the editing menu.

The example above uses the built-in ProductName Search Criterion.

Create form mapper

Next, you need to add a form mapper: ProductNameFilterFormMapper that maps the input from the filter form to the data model:

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

declare(strict_types=1);

namespace App\CatalogFilter;

use Ibexa\Bundle\ProductCatalog\Form\Type\TagifyType;
use Ibexa\Contracts\ProductCatalog\CatalogFilters\FilterDefinitionInterface;
use Ibexa\Contracts\ProductCatalog\CatalogFilters\FilterFormMapperInterface;
use Symfony\Component\Form\FormBuilderInterface;

final class ProductNameFilterFormMapper implements FilterFormMapperInterface
{
    public function __construct()
    {
    }

    public function createFilterForm(
        FilterDefinitionInterface $filterDefinition,
        FormBuilderInterface $builder,
        array $context = []
    ): void {
        $builder->add(
            $filterDefinition->getIdentifier(),
            TagifyType::class,
            [
                'label' => 'Product name',
                'block_prefix' => 'catalog_criteria_product_name',
                'translation_domain' => 'product_catalog',
            ]
        );

        $builder->get($filterDefinition->getIdentifier())
            ->addModelTransformer(
                new DataTransformer\ProductNameCriterionTransformer()
            );
    }

    public function supports(FilterDefinitionInterface $filterDefinition): bool
    {
        return $filterDefinition instanceof ProductNameFilter;
    }
}

The filter can use the built-in ProductName Criterion, but you still need a data transformer for the data entered when editing the catalog (line 35).

Before you add a data transformer, register the required services.

Register services

Register the filter and its mapper as services. Tag the filter with ibexa.product_catalog.catalog_filter and the form mapper with ibexa.product_catalog.catalog_filter.form_mapper:

1
2
3
4
5
6
7
8
9
services:
    App\CatalogFilter\ProductNameFilter:
        tags:
            - name: ibexa.product_catalog.catalog_filter
              alias: product_name

    App\CatalogFilter\ProductNameFilterFormMapper:
        tags:
            -   name: ibexa.product_catalog.catalog_filter.form_mapper

Create data transformer

Now, create ProductNameCriterionTransformer in src/CatalogFilter/DataTransformer:

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

declare(strict_types=1);

namespace App\CatalogFilter\DataTransformer;

use Ibexa\Contracts\ProductCatalog\Values\Product\Query\Criterion\ProductName;
use Symfony\Component\Form\DataTransformerInterface;
use Symfony\Component\Form\Exception\TransformationFailedException;

final class ProductNameCriterionTransformer implements DataTransformerInterface
{
    public function transform($value): ?string
    {
        if (null === $value) {
            return null;
        }

        if (!$value instanceof ProductName) {
            throw new TransformationFailedException('Expected a ' . ProductName::class . ' object.');
        }

        return $value->getName();
    }

    public function reverseTransform($value): ?ProductName
    {
        if ($value === null) {
            return null;
        }

        if (!is_string($value)) {
            throw new TransformationFailedException('Invalid data, expected a string value');
        }

        return new ProductName($value);
    }
}

Provide templates

Now, provide the templates for the catalog editing view in the Back Office.

You need two templates: one for the filter form, and one for the filter badge in the product list.

First, add a form_field_override.html.twig template to templates/themes/admin/product_catalog:

1
2
3
4
5
{% extends '@ibexadesign/product_catalog/form_fields.html.twig' %}

{%- block catalog_criteria_product_name_row -%}
    {{- block('catalog_taggify_panel') -}}
{%- endblock -%}

Here, you use the same built-in template that is used for example for the product code filter. It is placed in a template block corresponding to your custom filter, catalog_criteria_product_name_values.

To ensure the template is used as a Back Office form theme, add the following configuration:

1
2
3
twig:
    form_themes:
        - '@ibexadesign/product_catalog/form_field_override.html.twig'

Next, add a template that handles the display of the filter badge on the list of the currently filtered products. Add catalog_filters_blocks.html.twig to templates/themes/admin/product_catalog:

1
2
3
{% block catalog_criteria_product_name_values %}
    {% include '@ibexadesign/product_catalog/catalog/edit/list_filter_taggify.html.twig' with { criteria } %}
{% endblock %}

To ensure this template is used to render the catalog filter form, add the following configuration:

1
2
3
4
5
6
7
ibexa:
    system:
        default:
            product_catalog:
                catalogs:
                    filter_preview_templates:
                        - { template: "@ibexadesign/product_catalog/catalog_filters_blocks.html.twig", priority: 10 }

Check results

Finally, you can check the results of our work. Go to Product catalog -> Catalogs and create a new catalog. From the filter list, select Product name, type the name of an existing product and click Save.

Custom Product Name catalog filter