Customize admin interface with grids in Sylius

Sylius has a very nice user interface. Sometimes that is not enough! In this article we explore how we can expand the admin interface with some new features. What we want is to display an image for each variant that is listed in the overview for product variants. We will see how to achieve this with some configurations and coding.


Sylius is an open-source e-commerce platform. This means transparency, license to modify and make use of the platform, and data ownership. You may read our previous article if you want to read more about it. Today we will make use of the license to modify!

The Sylius admin interface is full with useful information. From details of sales, orders, and shipments. But everything starts with the items we are selling. In our chosen e-commerce platform we have Products and variants of these. Even a simple product will have a variant. The reason for this is how prices are handled, where a price will be set for a variant and depending on the sales-channel used for it.

Today we will configure the list for product variants by adding a thumbnail field to it. Next time, we can add whatever field we would like powered with this new knowledge.

The examples used throughout this article is based on Sylius v1.12.0, with PHP 8.0, and loaded with example data via bin/console sylius:fixtures:load.

Here's the list we want to add the new Thumbnail column to.

A table with 6 columns (name, code, enabled, inventory, position, actions)

Adding new column to a Product Variant list

A basic concept to keep in mind is that Sylius has templates for each part of the admin interface as well as configurations for most of them. We have the option to override or add to them as we see fit.

Add a new grid-configuration

Our first task will be to identify the name of the grid that manages this table. The best place to look for this is to look in the vendor directory and find the grid configurations in the AdminBundle: vendor/sylius/sylius/src/Sylius/Bundle/AdminBundle/Resources/config/grids.

We find multiple grid configurations where each file is named so it will be easy for us to find the correct one.

A list of YAML-files under Resources - config - app - grids. A file called product_variant.yaml is highlighted.

The file we are looking for is product_variant.yml. Looking into the file can ascertain that the grid-name we want is sylius_admin_product_variant.


We will hook into this grid and define our new column. Let’s add a new file (grids.yaml) to our project: ./config/packages/grids.yaml:

                    type: twig
                    label: app.ui.thumbnail
                        template: ”ProductVariant/Grid/_thumbnail.html.twig"

This configurations tells Sylius to inject a new field to the sylius_admin_product_variant grid. It will look for a field in ProductVariant by the name of thumbnail and pass it to a form type which will be responsible to parse it. 

Adding a ”dynamic field”

The way that the grid-parser can access a field is by using its corresponding getter-method. So if we are looking for a field called thumbnail, the grid-parser will try to use getThumbnail() on a ProductVariant instance. In actuality, this means that we are exposing methods, not fields. And we will actually add the getThumbnail-method without adding a thumbnail field.


//… add this method where it suits you.
public function getThumbnail(): ?ProductImageInterface
        $image = null;

        // Try to first find any image
        if ($this->images->first() !== false) {
            $image = $this->images->first();

        return $image;

The method will return first available image and if none is available it will return false. This image will then be passed to a twig-template that we will build. Any data that the grid-parser receives from our getter-method will be stored in a variable called data. So let’s build the template to display the image.

Add template for thumbnail

Twig is a template-language to generate HTML markup with some predefined logic structures and functions. We will make use of this to generate a snippet of markup where it will have an image pointing to either the product variant image or a placeholder.


{% if data is defined and data is not empty %}
    {% set path = data.path|imagine_filter(filter|default('sylius_small')) %}
{% else %}
    {% set path = asset('assets/admin/img/50x50.png') %}
{% endif %}

<img src="{{ path }}" alt="" class="ui bordered image sylius-grid-image" />

We do a check that data exists and actually has any content. If no content exists we will use a Sylius-placeholder. If we have content, we will generate a small image with the help of a Twig-function imagine_filter ( The function takes a configuration and resizes and crops an image accordingly. In our case we tell it to use sylius_small.

sylius_small is configured in Sylius’s Core Bundle with the following configuration:

       thumbnail: { size: [120, 90], mode: outbound }

Our template templates/ProductVariant/Grid/_thumbnail.html.twig has the path and name to correctly be loaded in the grid-configuration. In our configuration we pass an options-key with the template-path to it in the grids.yaml-file.

If we visit our Sylius admin page and view the variants grid (example /admin/products/19/variants/), it should look something like this now:

A list of product variants with 7 columns (name, code, enabled, inventory, position, app.ui.thumbnail, actions). The new column app.ui.thumbnail contains placeholder images.

We have a new column (app.ui.thumbnail) and image-placeholders. So we can see that our grid configuration is being loaded and inserted into the correct grid. Now it’s time to clean it up.

Add translation

Let’s add a translation-file so Sylius may parser app.ui.thumbnail and insert the correct value for English. Create a new folder called translations in your project root (if you don’t already have on). In this folder create a new file: messages.en.yaml. ”messages” is a translation-file for most common uses, and for the locale ”en”. We add our translation-keys to it:

        thumbnail: Thumbnail

Reloading the list will replace "app.ui.thumbnail" with "Thumbnail". If it doesn’t show up, you may be required to run php bin/console cache:clear in your terminal and then reload the list.

Now onto the missing thumbnails. The default Sylius fixture that has been used as a showcase here does not load images for any variants. So we will add a few of them.

Add images to Product Variants

Adding images to the variants requires us to make use of the admin interface. We go to the Product page for the variants we want to add images to. In our example, this is Beige scrappy summer dress. If we were at the variants-list we click the previous item in the breadcrumb area.

Breadcrumb component: Administration - products - beige strappy summer dress (highlighted) - variants

This will take us to the edit-page for the product.  The first tab on display is the ”Details” tab. We will select the last item in the tab-navigation: ”Media”.

Veritcal tab navigation (details - taxonomy - attributes - associations - media)

Each media item will have a Type, File, and associated product variants. We will choose a couple of variants that will be associated with the media item (image).

A form to edit a media item. A field called Product variants allows for selecting variants that the item should be associated with.

Each item we click on in the dropdown menu will add each as a new selected item. When we are satisfied we click on ”Save changes”.

From the edit-page we can go back to the variant list. We click on ”Mange variants” -> ”List variants”.

Navigation options: list variants - create - generate.

Our final result! We have added a new column to the variant list. We have done this by injecting a new field to an existing grid, added a new method on ProductVariant, handled data passed from the grid-parser to a Twig template, added a translation-key for app.ui.thumbnail, and finally; we added images to variants.

A table of product variants. The column Thumbnail now has both image of product or a placeholder.