Skip to content

Visual Subcategories

Availability: Category page context


The visual_subcategories module displays a set of subcategories for a given category. It supports grid and slider (carousel) display modes, configurable headings, and responsiveness. Subcategories can be filtered to hide empty ones, and the module supports custom colors and show-more functionality for mobile in the grid view.

Configuration parameters

shouldDisplayUnderline

int If set to 1, the header will have an underline.

shouldDisplayHeading

int If set to 1, the heading will be rendered.

levelHeader

int Section level of a header describing the size and importance of the element in a given context. You can read more about heading elements here. We provide the following levels for the header module: - 2 for the h2 heading - 3 for the h3 heading - 4 for the h4 heading - 5 for the h5 heading - 6 for the h6 heading

textHeader

string The text for the heading.

shouldHideEmptySubcategories

int If set to 1, only subcategories with products are displayed.

numberOfSubcategoriesToShow

int Maximum number of subcategories to display.

desktopProductsCountPerRow

int Number of subcategories per row on desktop resolution.

laptopProductsCountPerRow

int Number of subcategories per row on laptop resolution.

tabletProductsCountPerRow

int Number of subcategories per row on tablet resolution.

phoneProductsCountPerRow

int Number of subcategories per row on mobile resolution.

displayMode

string Determines how the list of subcategories will be displayed. carousel for a slider, grid for a grid list.

backgroundColor

string Custom background color for tiles.

textColor

string Custom text color for tiles.

Module source code

{% from "@macros/image.twig" import image %}
{% from "@macros/slider.twig" import slider %}
{% from "@macros/list_grid.twig" import list_grid %}
{% from "@macros/category_tile.twig" import category_tile %}

{% set hasUnderline = moduleConfig.shouldDisplayUnderline == 1 %}
{% set isHeadingRenderable = moduleConfig.shouldDisplayHeading == 1 and moduleConfig.levelHeader and moduleConfig.textHeader %}
{% set levelHeader = moduleConfig.levelHeader|default(2) %}

{% set moreSubcategoriesMobileCount = 6 %}

{% if category_id %}
    {% set activeCategory = ObjectApi.getCategory(category_id) %}

    {% if moduleConfig.shouldHideEmptySubcategories == 1 %}
        {% set subcategoriesToDisplay = activeCategory.subcategories|filter(subcategory => subcategory.productsInSubTree|length > 0) %}
    {% else %}
        {% set subcategoriesToDisplay = activeCategory.subcategories %}
    {% endif %}
{% endif %}

{% set shouldDisplayModule = subcategoriesToDisplay|find(subcategory => subcategory.thumbnailImageUrl|length > 0) %}

{% set numOfSubcategories = subcategoriesToDisplay|length > moduleConfig.numberOfSubcategoriesToShow ? moduleConfig.numberOfSubcategoriesToShow : subcategoriesToDisplay|length %}
{% set perPageDesktop = numOfSubcategories < moduleConfig.desktopProductsCountPerRow ? numOfSubcategories : moduleConfig.desktopProductsCountPerRow %}
{% set perPageLaptop = numOfSubcategories < moduleConfig.laptopProductsCountPerRow ? numOfSubcategories : moduleConfig.laptopProductsCountPerRow %}
{% set perPageTablet = numOfSubcategories < moduleConfig.tabletProductsCountPerRow ? numOfSubcategories : moduleConfig.tabletProductsCountPerRow %}
{% set perPageMobile = numOfSubcategories < moduleConfig.phoneProductsCountPerRow ? numOfSubcategories : moduleConfig.phoneProductsCountPerRow %}

{%
    set visualSubcategoriesSliderSettings = {
        "perPage": perPageDesktop,
        "arrows": true,
        "arrowsPosition": "below",
        "hasArrowsOnMobile": true,
        "breakpoints": {
            1440: {
                "perPage": perPageLaptop,
                "arrows": true,
                "arrowsPosition": "below"
            },
            1000: {
                "perPage": perPageTablet,
                "arrows": true,
                "arrowsPosition": "below"
            },
            576: {
                "perPage": perPageMobile
            }
        },
        "i18n": {
            "prev": translate("Previous subcategory"),
            "next": translate("Next subcategory"),
            "first": translate("Next subcategory"),
            "last": translate("Previous subcategory")
        }
    }
%}

{%
    set gridSettings = {
        phoneItemsCountPerRow: perPageMobile,
        smallTabletItemsCountPerRow: perPageTablet,
        tabletItemsCountPerRow: perPageTablet,
        laptopItemsCountPerRow: perPageLaptop,
        desktopItemsCountPerRow: perPageDesktop,
    }
%}

{% if shouldDisplayModule %}
    {% set subcategoriesTemplate %}
        {% set subcategoryLevelHeader = levelHeader|number_format + 1  %}

        {% for subcategory in subcategoriesToDisplay %}
            {% if loop.index <= numOfSubcategories %}
                {% if moduleConfig.displayMode == "carousel" %}
                    <li class="splide__slide">
                {% endif %}
                    {{ category_tile(
                        subcategory,
                        moduleConfig|merge({
                            levelHeader: subcategoryLevelHeader,
                            hasParentHeading: isHeadingRenderable
                        }))
                    }}
                {% if moduleConfig.displayMode == "carousel" %}
                    </li>
                {% endif %}
            {% endif %}
        {% endfor %}
    {% endset %}

    <nav
        class="visual-subcategories"
        aria-label="{{ translate("Visual subcategories") }}"
        style="
            {% if moduleConfig.backgroundColor %}--visualSubcategoriesTileBgColor: {{ moduleConfig.backgroundColor }};{% endif %}
            {% if moduleConfig.textColor %}--visualSubcategoriesTileTextColor: {{ moduleConfig.textColor }};{% endif %}
        "
    >
        <h{{ levelHeader }}
            class="
                visual-subcategories__header
                header
                header_h{{ levelHeader }}
                {% if hasUnderline %} header_underline {% endif %}
                {% if not isHeadingRenderable %}sr-only{% endif %}
            "
        >
            <span {% if hasUnderline %} class="header_highlight" {% endif %}>
                {{ moduleConfig.textHeader }}
            </span>
        </h{{ levelHeader }}>

        {% if moduleConfig.displayMode == "carousel" %}
            {{
                slider(subcategoriesTemplate, {
                    id: "visual-subcategories-#{moduleInstance}",
                    sliderConfig: visualSubcategoriesSliderSettings,
                    visibleItems: numOfSubcategories,
                    arrowConfigProps: {
                        position: "right"
                    }
                })
            }}
        {% else %}
            <h-show-more count="{{ moreSubcategoriesMobileCount }}" mobile-only>
                {{
                    list_grid(subcategoriesTemplate, {
                        grid: gridSettings,
                        className: "visual-subcategories__tile-grid"
                    })
                }}

                <h-show-more-button class="link link_secondary d-block mt-xs-3">
                    {{ translate("Show more subcategories (%s)", subcategoriesToDisplay|length - moreSubcategoriesMobileCount) }}
                </h-show-more-button>
            <h-show-more>
        {% endif %}
    </nav>
{% endif %}

Macros reference

Webcomponents reference

Used styles

Module configuration schema

[
    {
        "label": "General settings",
        "state": "unfolded",
        "elements": [
            {
                "type": "infobox",
                "name": "infobox",
                "options": {
                    "type": "blank",
                    "message": "#### Related settings in the admin panel%s- adding images to [categories and subcategories](%s), adding and changing subcategory display order",
                    "placeholderValues": [
                        "\n",
                        "\/admin\/categories"
                    ]
                }
            },
            {
                "type": "infobox",
                "name": "warning",
                "options": {
                    "type": "warning",
                    "message": "The module will be shown if at least one subcategory has a photo."
                }
            },
            {
                "name": "shouldDisplayHeading",
                "type": "checkbox",
                "label": "Display heading",
                "supportsTranslations": true,
                "defaultValue": 0,
                "children": [
                    {
                        "name": "textHeader",
                        "type": "text",
                        "relations": [
                            {
                                "parentName": "shouldDisplayHeading",
                                "parentValueToActionsMap": [
                                    {
                                        "value": 0,
                                        "actions": [
                                            "setHiddenAndOptional",
                                            "setDisabled"
                                        ]
                                    },
                                    {
                                        "value": 1,
                                        "actions": [
                                            "setVisibleAndRequired",
                                            "setAvailable"
                                        ]
                                    }
                                ]
                            }
                        ],
                        "label": "Module heading content",
                        "supportsTranslations": true
                    },
                    {
                        "name": "levelHeader",
                        "type": "select",
                        "hint": "The numbers 2 to 6 indicate the hierarchy of headings, with H2 being the most important and H6 being the least. H1 is reserved for the page title. If you need to add a page title, use the \"Page title\" module.",
                        "relations": [
                            {
                                "parentName": "shouldDisplayHeading",
                                "parentValueToActionsMap": [
                                    {
                                        "value": 0,
                                        "actions": [
                                            "setHidden",
                                            "setDisabled"
                                        ]
                                    },
                                    {
                                        "value": 1,
                                        "actions": [
                                            "setVisible",
                                            "setAvailable"
                                        ]
                                    }
                                ]
                            }
                        ],
                        "options": {
                            "isWithSearch": 0,
                            "selectOptions": [
                                {
                                    "key": "2",
                                    "label": "H2"
                                },
                                {
                                    "key": "3",
                                    "label": "H3"
                                },
                                {
                                    "key": "4",
                                    "label": "H4"
                                },
                                {
                                    "key": "5",
                                    "label": "H5"
                                },
                                {
                                    "key": "6",
                                    "label": "H6"
                                }
                            ]
                        },
                        "label": "Heading level",
                        "defaultValue": "2"
                    },
                    {
                        "name": "shouldDisplayUnderline",
                        "type": "checkbox",
                        "relations": [
                            {
                                "parentName": "shouldDisplayHeading",
                                "parentValueToActionsMap": [
                                    {
                                        "value": 0,
                                        "actions": [
                                            "setHidden",
                                            "setDisabled"
                                        ]
                                    },
                                    {
                                        "value": 1,
                                        "actions": [
                                            "setVisible",
                                            "setAvailable"
                                        ]
                                    }
                                ]
                            }
                        ],
                        "label": "Add underline below the heading",
                        "defaultValue": 1
                    }
                ]
            },
            {
                "name" : "displayMode",
                "type" : "radio",
                "label" : "Subcategory display mode",
                "defaultValue" : "carousel",
                "options": {
                    "radioOptions" : [
                        { "key" : "carousel", "label" : "Carousel (scrollable subcategories)" },
                        { "key" : "gallery", "label" : "Gallery (all subcategories visible)" }
                    ]
                }
            },
            {
                "name" : "namePosition",
                "type" : "select",
                "label" : "Subcategory name position",
                "defaultValue" : "under",
                "options": {
                    "selectOptions" : [
                        { "key" : "under", "label" : "Below image" },
                        { "key" : "above", "label" : "Above image" }
                    ]
                }
            },
            {
                "name" : "nameAlignment",
                "type" : "select",
                "label" : "Subcategory name alignment",
                "defaultValue" : "center",
                "options": {
                    "selectOptions" : [
                        { "key" : "left", "label" : "Left <<to_left>>" },
                        { "key" : "center", "label" : "Center" },
                        { "key" : "right", "label" : "Right <<to_right>>" }
                    ]
                }
            },
            {
                "type": "checkbox",
                "name": "shouldDisplayNumberOfProducts",
                "label": "Display product count",
                "defaultValue": 0
            },
            {
                "type": "checkbox",
                "name": "shouldHideEmptySubcategories",
                "label": "Hide empty subcategories",
                "defaultValue": 1
            },
            {
                "type": "checkbox",
                "name": "shouldShortenLongNames",
                "label": "Shorten long subcategory names",
                "defaultValue": 1
            },
            {
                "type": "number",
                "name": "numberOfSubcategoriesToShow",
                "label": "Number of subcategories in module",
                "isRequired": 1,
                "defaultValue": 12,
                "hint": "By default, the first 12 subcategories will be displayed according to the order set in Category settings. If there are more subcategories, the list will be limited to the selected number.",
                "validators": [
                    { "type": "int" },
                    { "type": "greaterEqThan", "options": { "min": 1 } },
                    { "type": "lessEqThan", "options": { "max": 16 } }
                ]
            },
            {
                "type": "header",
                "name": "headerMobile",
                "label": "Mobile",
                "options": {
                    "icon": "phone"
                },
                "children": [
                    {
                        "type": "number",
                        "name": "phoneProductsCountPerRow",
                        "label": "Number of subcategories per row",
                        "labelDescription": "Max. 3.",
                        "defaultValue": 2,
                        "validators": [
                            { "type": "int" },
                            { "type": "greaterEqThan", "options": { "min": 1 } },
                            { "type": "lessEqThan", "options": { "max": 3 } }
                        ]
                    }
                ]
            },
            {
                "type": "header",
                "name": "headerTablet",
                "label": "Tablet",
                "options": {
                    "icon": "tablet"
                },
                "children": [
                    {
                        "type": "number",
                        "name": "tabletProductsCountPerRow",
                        "label": "Number of subcategories per row",
                        "labelDescription": "Max. 6.",
                        "defaultValue": 4,
                        "validators": [
                            { "type": "int" },
                            { "type": "greaterEqThan", "options": { "min": 1 } },
                            { "type": "lessEqThan", "options": { "max": 6 } }
                        ]
                    }
                ]
            },
            {
                "type": "header",
                "name": "headerLaptop",
                "label": "Laptop",
                "options": {
                    "icon": "laptop"
                },
                "children": [
                    {
                        "type": "number",
                        "name": "laptopProductsCountPerRow",
                        "label": "Number of subcategories per row",
                        "labelDescription": "Max. 8.",
                        "defaultValue": 6,
                        "validators": [
                            { "type": "int" },
                            { "type": "greaterEqThan", "options": { "min": 1 } },
                            { "type": "lessEqThan", "options": { "max": 8 } }
                        ]
                    }
                ]
            },
            {
                "type": "header",
                "name": "headerDesktop",
                "label": "Desktop",
                "options": {
                    "icon": "desktop"
                },
                "children": [
                    {
                        "type": "number",
                        "name": "desktopProductsCountPerRow",
                        "label": "Number of subcategories per row",
                        "labelDescription": "Max. 10.",
                        "defaultValue": 6,
                        "validators": [
                            { "type": "int" },
                            { "type": "greaterEqThan", "options": { "min": 1 } },
                            { "type": "lessEqThan", "options": { "max": 10 } }
                        ]
                    }
                ]
            }
        ]
    },
    {
        "state": "unfolded",
        "label": "Module appearance",
        "elements": [
            {
                "name": "textColor",
                "type": "colorPicker",
                "label": "Text color in module",
                "defaultValue": "@globalFontColor",
                "options": {
                    "allowVariables": true
                }
            },
            {
                "name": "backgroundColor",
                "type": "colorPicker",
                "label": "Background color behind photo",
                "labelDescription": "For photos with transparency",
                "defaultValue": "@globalBodyBackgroundColor",
                "options": {
                    "allowVariables": true
                }
            }
        ]
    },
    {
        "state": "unfolded",
        "label": "CSS",
        "elements": [
            {
                "type": "text",
                "name": "classNames",
                "label": "CSS class",
                "labelDescription": "Enter the class name without a dot at the beginning. You can add multiple classes by separating them with spaces."
            }
        ]
    }
]