---
url: /config.md
---
# Configuration

Every template can contain a **config.json** file describing template properties. Some properties are automatically generated (*plugins*, ...) and others can be modified manually.

## Configuration Reference

**config.json Attributes**

| Attribute | Type | Default | Description |
|---|---|---|---|
| **responsive** | *bool* | **false** | template is responsive -- activates viewport meta tag |
| **webfonts** | *array* | **\[]** | list of WebFonts to load -- Google fonts (`"Name:variants"`) or [custom fonts](#custom-webfonts) (`"custom:name:variants"`) |
| **webfontsPreload** | *array* | **\[]** | list of WebFonts to preload (subset of **webfonts**) |
| **features** | *array* | **\[]** | list of supported special features (*last\_viewed\_products*) |
| **cartSteps** | *array* | **\[]** | checkout steps in the order they appear |
| **typekit** | *string* | --- | Typekit font ID |
| **skipOrderSummary** | *bool* | **false** | skip the *Checkout summary* step |
| **countryBeforeDelivery** | *bool* | **false** | delivery country is selected in the step before delivery method selection |
| **wysiwyg** | *object* | {} | list of CSS classes (and CSS rules) used in the WYSIWYG editor |
| **settings** | *object* | {} | admin-configurable template settings definition |
| **fulltext** | *bool* | **true** | allow search engine indexing |
| **mobile** | *bool* | **false** | template is mobile-only |
| **viewportDesktop** | *int* | --- | viewport width when forcing desktop version on a responsive layout |
| **skipOnFirstPage** | *object* | --- | how many listing items to **skip** on the first page of listings |
| **limitOnFirstPage** | *object* | --- | how many listing items to **display** on the first page of listings |
| **inputInLabel** | *bool* | **true** | wrap *checkbox*/*radio* inside *label* in generated forms |
| **manifest** | *object* | --- | definition for [manifest.json](https://developer.mozilla.org/en-US/docs/Web/Manifest) |
| **allowedPagination** | *array* | --- | list of allowed pagination size values |
| **criticalCss** | *object* | --- | per-page-type critical CSS generation hints (forceInclude, forceExclude, viewports) |
| **variantChoice** | *object* | --- | supported variant selection types |
| **AB** | *object* | --- | [A/B test](/ab-testing) definition (`variants` -- list of variant codes) |

### features

* *last\_viewed\_products*: visited products are stored so they can be listed in the template
* *multiline\_menu\_items*: category names for the menu can be saved with line breaks in the admin
* *upsell\_customer\_note*: upsell supports customer note input
* *upsell\_customer\_upload*: upsell supports customer file upload
* *google\_recaptcha\_enterprise\_cart*: Google reCaptcha Enterprise in the cart

### cartSteps

If the shop uses multiple checkout steps (visible in the URL as e.g. `/Kosik?sekce=adresa`), they must be listed in the configuration. The `/Kosik` (cart) and `/Pokladna` (checkout) paths themselves are not listed -- only the additional query parameters. Each step specifies a code identifying the content of that particular step (content, delivery, address, summary).

```json
{
  "cartSteps": [
    {
      "handles": [
        "content"
      ]
    },
    {
      "handles": [
        "delivery"
      ],
      "query": "dodani"
    },
    {
      "handles": [
        "address"
      ],
      "query": "adresa"
    }
  ]
}
```

### fields

Text types defined in the config are displayed as text fields in the admin panel. Once filled in, they are available in the template via `object.text('vlastni_kod_textu')` (custom text code). The config also specifies the field label shown in the admin and a description of where the text appears and any constraints it may have.

Supported objects: **transport**, **paymentMethod**, **textPage**, **store**, **admin**, **category**, **brand**, **product**, **author**, **upsellGroup**, **article**

Supported formats: **html**, **textarea**, **text**

```json
{
    "fields": {
        "transport": {
            "text": {
                "short" : {
                    "label": "Krátký popisek",
                    "format": "html",
                    "description": "Zobrazuje se košíku po najetí myší na způsob dopravy"
                },
                "long" : {
                    "label": "Dlouhý popis",
                    "format": "html",
                    "description": "Zobrazuje se na informační stránce a může mít 2-3 odstavce"
                }
            },
            "image": {
                "ico" : {
                    "label": "Ikonka výběru",
                    "description": "Zobrazuje se košíku po najetí myší na způsob dopravy"
                }
            }
        }
    }
}
```

### criticalCss

Per-page-type hints for the critical CSS generator. Each key is a page type matching the types returned by `/_random`:

| Page Type | Description |
|---|---|
| **index** | Homepage |
| **product** | Product detail (random products are sampled) |
| **category** | Top-level category listing |
| **subcategory** | Nested category listing |
| **page** | Static text pages |

Each type supports the following options:

| Option | Type | Description |
|---|---|---|
| **forceInclude** | *array* | CSS selectors always included in the output (substring match) |
| **forceExclude** | *array* | CSS selectors always excluded from the output (substring match) |
| **viewports** | *object* | Override default viewport sizes for this type |

Matching is substring-based — `".main-banner"` matches `.main-banner`, `.main-banner__slide`, `.page .main-banner`, etc.

The following selectors are always applied regardless of config:

* **Always included:** `.no-js`, `.global-announcement` (and BEM variants)
* **Always excluded:** `.wf-active` (web fonts loaded after critical render)

Default viewports are **mobile: 380×650** and **desktop: 1000×600**. Per-type viewports override these for that type only:

```json
{
    "criticalCss": {
        "index": {
            "forceInclude": [".main-banner", ".hero-slider"],
            "forceExclude": [".video-player"]
        },
        "product": {
            "forceInclude": [".product-gallery"],
            "viewports": {
                "mobile": { "width": 414, "height": 896 }
            }
        }
    }
}
```

## Custom webfonts

Besides Google fonts, a template can ship its **own WOFF2 fonts**. They are loaded and preloaded by
the same mechanism as Google fonts (a `<link rel="preload">` for entries listed in
**webfontsPreload**, an `@font-face` rule with `font-display: swap`, and a `document.fonts.load()`
gate), and they are served exactly like template images: from disk on *tpltest* and from S3 with a
hashed, long-cache path in production.

**Declaring a custom font** -- add an entry to **webfonts** (and optionally **webfontsPreload**) using
the `custom:` prefix:

```json
{
    "webfonts": [
        "Open Sans:400,700",
        "custom:velo-sans:400,700i"
    ],
    "webfontsPreload": [
        "custom:velo-sans:400"
    ]
}
```

The entry format is `custom:<name>:<variants>`:

* **name** -- becomes the CSS `font-family`. It must be a slug: lowercase letters, digits and dashes
  only (`a-z`, `0-9`, `-`), **no spaces**.
* **variants** -- comma-separated font weights, optionally suffixed with `i` for italic
  (e.g. `400`, `700`, `400i`). `400` maps to `font-weight: normal`.

**Where to put the files** -- store one WOFF2 file per variant under the template's `fonts/`
directory, named `<name>-<variant>.woff2`:

```
fonts/
  velo-sans-400.woff2
  velo-sans-700i.woff2
```

i.e. `fonts/<name>-<variant>.woff2`. **Only WOFF2 is supported.** Reference the font in CSS with its
name, e.g. `font-family: "velo-sans";` -- the `<name>` is just the CSS `font-family` label you choose,
it does not need to match the font file's internal name. The `<variant>` becomes the `@font-face`
`font-weight`/`font-style`, so `font-family: "velo-sans"; font-weight: bold` picks the `700` file.

Notes:

* Custom fonts render via the standard webfonts path. The combined **Google fonts + Typekit** path
  does not invoke this generator, so custom fonts are not emitted when **typekit** is also set.

## Configuration Example

```json
{
    "webfonts":[
        "Open Sans:400,600,700"
    ],
    "webfontsPreload":[
        "Open Sans:400,700"
    ],
    "responsive": true,
    "wysiwyg": [
        {
            "name": "important paragraph",
            "css": "p.wysiwyg_important {color: #F5007E;}"
        },
        {
            "name": "small paragraph",
            "css": "p.wysiwyg_small {font-size:0.9em}"
        }
    ],
    "skipOnFirstPage": {
        "categoryProducts": 1,
        "filteredCategoryProducts": 0,
        "topicArticles": 1,
        "allArticles": 2
    },
    "limitOnFirstPage": {
        "categoryProducts": 1,
        "filteredCategoryProducts": 0,
        "topicArticles": 1,
        "allArticles": 2
    },
    "manifest": {
        "display": "standalone",
        "background_color": "#ff00ff",
        "theme_color": "#ff00ff",
        "tile_color": "#ff00ff",
    },
    "settings": {
        "menu_mode": {
          "label": "Režim menu",
          "context": "global",
          "default": "small",
          "type": "select",
          "group": "Levý sloupec",
          "values": {
            "small": "malé menu",
            "big": "velké menu"
          }
        }
    },
    "criticalCss": {
        "index": {
            "forceInclude": [".main-banner"],
            "forceExclude": [".video-player"]
        },
        "product": {
            "forceInclude": [".product-gallery"]
        }
    },
    "variantChoice": {
        "code": "default",
        "modes": {
            "dropdown": "roletka s názvy",
            "icons": "obrázky s názvem"
        }
    }
}
```

## Settings

The *settings* section lets you define template values that can be configured directly from the admin panel. Use cases include toggling visual elements (e.g. winter theme), setting footer links, or selecting a display mode per category.

**context**

| Value | Description |
|---|---|
| **global** | available across the entire shop |
| **category** | category-specific, configured separately for each category |
| **product\_category** | configured separately for each category, applied on the product detail page |

**type**

| Value | Description |
|---|---|
| **select** | generic dropdown |
| **string** | text (single line, no HTML) |
| **color** | color (hex code) |
| **datetime** | date and time (single `datetime-local` input, returns `\DateTimeImmutable`) |
| **email** | e-mail |
| **text\_page** | text page |
| **article** | article |
| **article\_topic** | article topic |
| **banner\_section** | banner section |
| **upsell\_group** | upsell group |
| **attribute\_group** | attribute group |
| **attribute** | attribute |
| **attribute\_article** | article attribute |
| **attribute\_store** | store attribute |
| **attribute\_customer** | customer attribute |
| **category** | category |
| **product** | product |
| **product\_list** | product selection by properties |
| **product\_rules** | product group rules |
| **url** | any shop URL (including link text and title) |
| **admin** | shop administrator |
| **storage\_center** | storage center |
| **store** | store |
| **working\_hours** | opening hours |
| **image** | uploaded image (SVG/PNG/JPG/...) |

Configuration example:

```js
{
    "settings": {
        "sibebar_mode": {
          "label": "Režim postraního panelu",
          "description": "Přepínání způsobu zobrazení levého sloupce webu",
          "context": "global",
          "default": "small",
          "group": "Levý sloupec",
          "type": "select",
          "values": {
            "small": "malé menu",
            "big": "velké menu"
          }
        },
        "category_mode": {
          "label": "Režim zobrazení kategorie",
          "context": "category", // configured separately for each category
          "default": "default",
          "type": "select",
          "values": {
            "default": "standardní zobrazení",
            "big_banner": "zobrazit s velkým bannerem"
          }
        },
        "product_mode": {
          "label": "Režim zobrazení produkt",
          "context": "product_category", // configured separately for each category, applied on product detail
          "default": "default",
          "type": "select",
          "values": {
            "default": "standardní zobrazení",
            "big_banner": "zobrazit s velkým bannerem"
          }
        },
        "footer_menu": {
          "label": "Položky patičky",
          "context": "global", // site-wide
          "type": "text_page", // select a text page
          "lang": true, // configured separately for each language -- adding lang:true hides the originally set value
          "multiple": true // select multiple pages with ordering (the template receives an array of pages)
        }
    }
}
```

Usage in the template:

```twig
{% if this.templateAttributes.sibebar_mode == 'small' %}
    malý sidebar
{% endif%}
```

## Master Template

A master template serves as a base for other templates. It defines a list of variables that child (slave) templates can override.

Configuration example:

```json
{
    "master" : {
        "tpl": {
            "phone": {
                "name": "Telefon",
                "default": "+420 333 222 111"
            },
            "email": {
                "name": "E-mail",
                "type": "email",
                "language": true,
                "default": "info@example.org"
            },
            "facebook": {
                "name": "Facebook URL",
                "type": "url"
            },
            "showRelevantItems": {
                "name": "Zobrazit nabídku podobných produktů",
                "type": "bool"
            },
            "pageFooterId": {
                "name": "Text v patičce",
                "type": "page"
            },
            "listStyle": {
                "name": "Stype výpisu produktů",
                "type": "select",
                "values" : {
                    "simple": "jednoduchý",
                    "large_image": "velké obrázky",
                }

            }
        },
        "sass": {
            "primary-color": {
                "name": "Hlavní odstín",
                "type": "color",
                "default": "#fff",
                "group": "Barvy"
            }
        },
        "files": {
            "banner.png": "Obrázek v hlavičce"
        },
        "languageFiles": {
            "logo.png": "Logo eshopu"
        }
    }
}
```

To use variables in SASS, add the line `//<SLAVE-CONFIG>//` anywhere in *settings.scss*. During compilation this line is replaced with the configuration variables.

```scss
$pagination-mobile-items: true;
$pagination-arrows: false;
//<SLAVE-CONFIG>//
```

A slave template is activated by deleting all files and adding a **slave.json** file:

```json
{
    "master": "master-template-name"
}
```

## Complete Production Config Example

A realistic config.json extracted from the buran production template, showing all major sections working together. The `master` section defines variables that child (slave) templates can override -- `tpl` for feature toggles accessible via `this.slaveConfig`, and `sass` for SCSS variables organized into groups (Základní nastavení, Tlačítka, Štítky, Oznámení):

```json
{
    "webfonts": [
        "Manrope:500,600,700"
    ],
    "responsive": true,
    "plugins": {
        "jquery": "3.4",
        "foundation": "6.4",
        "swiper": "6.x",
        "jquery-fancybox": "3.5",
        "jquery-validation": "1.19",
        "jquery-ui-slider": "2.0",
        "jquery-ui-dialog": "2.0",
        "svgxuse-polyfill": "1.2"
    },
    "skipOrderSummary": true,
    "cartSteps": [
        { "handles": ["content"] },
        { "handles": ["delivery"], "query": "dodani" },
        { "handles": ["address"], "query": "adresa" }
    ],
    "inputInLabel": false,
    "features": [
        "last_viewed_products",
        "syntax2019",
        "upsell_customer_note",
        "upsell_customer_upload"
    ],
    "variantChoice": {
        "code": "default",
        "modes": {
            "selects": "roletka",
            "icons": "barevná okýnka",
            "text": "textově (default)"
        }
    },
    "manifest": {
        "theme_color": "#0F172A"
    },
    "master": {
        "name": "buran",
        "tpl": {
            "enableCompare": { "label": "Povolit porovnání", "type": "bool" },
            "enableWishlist": { "label": "Povolit Seznam přání", "type": "bool" },
            "enableLoyaltyProgram": { "label": "Povolit věrnostní program", "type": "bool" },
            "enableUpsells": { "label": "Povolit upselly", "type": "bool" },
            "enableGifts": { "label": "Povolit Dárky v košíku", "type": "bool" },
            "enableShops": { "label": "Povolit prodejny", "type": "bool" },
            "enableComments": { "label": "Povolit komentáře u produktů", "type": "bool" },
            "enableReviews": { "label": "Povolit recenze (Heureka, Zbozi, Biano)", "type": "bool" }
        },
        "sass": {
            "config-primary-color": {
                "label": "Barva textu - hlavní (primary) barva",
                "default": "#10b981",
                "group": "Základní nastavení"
            },
            "config-success-color": {
                "label": "Barva textu - hlavní (success) barva",
                "default": "#10b981",
                "group": "Základní nastavení"
            },
            "config-button-background": {
                "label": "Základní tlačítko - barva pozadí",
                "default": "#10b981",
                "group": "Tlačítka"
            },
            "config-button-background-hover": {
                "label": "Základní tlačítko - barva pozadí po najetí myši",
                "default": "#059669",
                "group": "Tlačítka"
            },
            "config-order-button-background": {
                "label": "Tlačítko nákupu - barva pozadí",
                "default": "#10b981",
                "group": "Tlačítka"
            },
            "config-product-label-discount-bg": {
                "label": "Štítek Sleva - barva pozadí",
                "default": "#dc2626",
                "group": "Štítky"
            },
            "config-product-label-new-bg": {
                "label": "Štítek Novinka - barva pozadí",
                "default": "#f5f5f5",
                "group": "Štítky"
            },
            "config-global-announcement-info-background-color": {
                "label": "Informace - barva pozadí",
                "default": "#f0f8ff",
                "group": "Oznámení"
            },
            "config-global-announcement-default-background-color": {
                "label": "Oznámení - barva pozadí",
                "default": "#cbe3c6",
                "group": "Oznámení"
            }
            // ... more color variables for labels, discount badges, etc.
        }
    }
}
```

The `tpl` feature toggles are accessed in templates via `this.slaveConfig`:

::: v-pre

```twig
{% if this.slaveConfig.enableWishlist %}
    {# Show wishlist button #}
{% endif %}
```

:::

## Plugins Reference

Plugins are declared in the `plugins` section of config.json. The platform automatically loads the corresponding JavaScript and CSS for each declared plugin. All plugins listed below are used in the buran production template:

| Plugin | Version | Description |
|---|---|---|
| **jquery** | 3.4 | jQuery library -- required by most other plugins |
| **foundation** | 6.4 | Zurb Foundation responsive framework (grid system with `grid-x`/`cell`, responsive visibility classes like `show-for-medium`, `hide-for-large`) |
| **swiper** | 6.x | Touch-enabled slider/carousel for banners, product carousels, and subcategory strips |
| **jquery-fancybox** | 3.5 | Lightbox for product image galleries and modal popups |
| **jquery-validation** | 1.19 | Client-side form validation (checkout forms, registration, contact) |
| **jquery-ui-slider** | 2.0 | Range slider widget used for price filters (see [filter](filter.md)) |
| **jquery-ui-dialog** | 2.0 | Modal dialog component (login, quick-view, confirmations) |
| **svgxuse-polyfill** | 1.2 | Polyfill for external SVG `<use>` references in older browsers |

## Custom Fields Usage in Templates

Fields defined in the `fields` section of config.json (see [fields](#fields) above) provide custom text and image slots for various objects. Once defined, they can be filled in through the admin panel and accessed in templates.

**Accessing custom text fields:**

::: v-pre

```twig
{# Display short description of a transport method #}
{{ transport.text('short') }}

{# Display custom HTML field on a product #}
{{ product.text('specification') }}

{# Use custom text in conditionals #}
{% if category.text('long') %}
    <div class="category-description">{{ category.text('long') }}</div>
{% endif %}
```

:::

**Accessing custom image fields:**

::: v-pre

```twig
{# Display transport icon as a 40x40 image #}
<i:img src="transport.image('ico')" format="40x40" />

{# Display category banner image #}
<i:img src="category.image('banner')" format="1200x400" />

{# Category icon used in subcategory listing #}
<i:img src="cat.image('ico')" format="80x80" fill loading="lazy" />
```

:::

**Defining fields in config.json:**

The `fields` config specifies text and image slots per object type. The `label` appears in the admin form, `format` controls the editor type, and `description` provides admin guidance:

```json
{
    "fields": {
        "transport": {
            "text": {
                "short": { "label": "Krátký popisek", "format": "html", "description": "Zobrazuje se v košíku" }
            },
            "image": {
                "ico": { "label": "Ikonka výběru", "description": "Zobrazuje se v košíku" }
            }
        },
        "category": {
            "text": {
                "long": { "label": "Úvodní text", "format": "html", "description": "Text nad výpisem" }
            },
            "image": {
                "ico": { "label": "Ikonka kategorie", "description": "Pro podkategorie" }
            }
        }
    }
}
```

Supported objects for custom fields: **transport**, **paymentMethod**, **textPage**, **store**, **admin**, **category**, **brand**, **product**, **author**, **upsellGroup**, **article**

## Critical CSS

Critical CSS is the minimal set of styles needed to render the visible part of a page (above the fold). These styles are inlined directly in the `<head>`, so the browser can paint the page without waiting for the full stylesheet to download. After the full CSS loads (typically under 1 second), the page appearance is corrected.

### How generation works

During deployment, the generator:

1. Fetches a list of random URLs per page type from `/_random` (index, product, category, subcategory, page)
2. Downloads the full `package.min.css`
3. For each URL × device (mobile 380×650, desktop 1000×600):
   * Opens the page in headless Chromium with JavaScript blocked
   * Parses the full CSS and checks which selectors have elements **above the viewport fold**
   * Removes `@media print`, media queries for smaller viewports, unused `@keyframes`
   * Keeps rules for `position: fixed`/`sticky` elements (always visible)
   * Applies `forceInclude`/`forceExclude` from config
4. Merges results across URLs, deduplicates, and runs cleanup (removes transitions, vendor prefixes, `@font-face`, `background-image`)

The output is a JSON object with `css` and `mobileCss` per page type, stored in the template config and served inline.

### Size budget

Critical CSS should stay **under ~14 KB gzipped** to fit within the first TCP roundtrip (congestion window). Larger critical CSS delays First Contentful Paint instead of helping it. If your critical CSS is too large, use `forceExclude` to remove heavy selectors that aren't needed for the initial render.

### When to configure `criticalCss`

**No configuration needed** for most templates. The generator samples random URLs and detects above-fold elements automatically. You only need `criticalCss` in config.json when:

* **Conditional elements** — A component only appears on some pages (e.g., `.main-banner` on the homepage with a banner, `.product-gallery` only on products with multiple images). If the sampled page happens not to have it, the styles will be missing. Use `forceInclude`.
* **Heavy below-fold components** — A large component (e.g., `.video-player`, `.reviews-section`) is technically above the fold on some pages but is not essential for the first paint. Use `forceExclude` to save bytes.
* **Custom viewport needs** — A page type has a non-standard layout that requires different viewport dimensions for accurate extraction.

### Recommended patterns

**Homepage with banners/sliders:**

```json
{
    "criticalCss": {
        "index": {
            "forceInclude": [".main-banner", ".hero-slider"],
            "forceExclude": [".video-player", ".chat-widget"]
        }
    }
}
```

**Product page with conditional gallery:**

```json
{
    "criticalCss": {
        "product": {
            "forceInclude": [".product-gallery", ".product-price"]
        }
    }
}
```

**Multiple types sharing the same pattern:**

```json
{
    "criticalCss": {
        "category": {
            "forceInclude": [".category-banner"]
        },
        "subcategory": {
            "forceInclude": [".category-banner"]
        }
    }
}
```

### Testing critical CSS

* **Quick flash test:** On production, press Ctrl+F5. Critical styles render first, then the full CSS loads. The flash should be brief and the layout should not jump.
* **Force critical mode:** Append `?_forceCritical` to any URL (requires admin login). The page renders using only the critical CSS — this shows exactly what visitors see before the full stylesheet loads.
* **Disable web fonts:** Append `?_disableWebFonts` to see the page without web fonts, matching how the generator sees it.
* **PageSpeed Insights:** [Google PageSpeed](https://developers.google.com/speed/pagespeed/insights/) gives the most realistic performance assessment.

## Favicon

The favicon is not part of the template. It is uploaded in the shop admin separately for each domain.
