CoolCMS API

ThemeSettingFormTrait uses trait:short

Form of the "Website appearance" screen: the front end branch of template selection.

The selection logic (hidden field pair, validation against the catalog, card grid) lives in ThemePickerTrait, shared with the admin settings. Only the three setting keys and the front end templates directory stay here.

IMPORTANT: the edited keys belong to SettingPresenter::HIDDEN_KEYS; otherwise they could also be changed from the general settings as plain text fields, from two places with two different validations.

Table of Contents

Constants

PICKER_MODULE  : mixed = 1
Settings of both appearances live in the System module.

Methods

addThemePickerFields()  : void
Adds the hidden field pair that a click on a preview fills.
createComponentEditForm()  : Form
saveThemePickerSettings()  : bool
Saves the map from {@see themePickerSettings()}; FALSE = nothing was saved.
themePickerDirRel()  : string
themePickerGroups()  : array<int, array{slug: string, labelKey: string, themes: list, variants: list}>}>
Templates grouped for rendering. Each variant carries its preview and an "is currently set" flag.
themePickerKeys()  : array{theme: string, path: string, skin: string}
Front end branch keys. `theme.frontend.skin` is empty for the base color.
themePickerSettings()  : array<string, string>|null
Validates the submitted pair and builds a map "setting key => value", or returns NULL and writes the error into the form.
saveThemeSettingForm()  : bool
themeGroups()  : array<int, array<string, mixed>>
Templates for the card grid; the screen passes them to `@themePicker.latte`.
themePickerAssetUrl()  : string|null
Returns the relative path to the preview if the file exists and is not empty, otherwise NULL.
themePickerChoices()  : array<string, array<int, string>>
Offered pairs: template name => list of its skins (`''` = base color).
themePickerCover()  : array{skin: string, label: ?string, color: ?string, preview: ?string, previewFull: ?string, active: bool}
Variant shown by the card in the grid: the selected one, otherwise the base color.
themePickerDir()  : string
Returns the absolute directory with the templates of this branch.
themePickerGallery()  : array<int, array{view: string, url: string}>
Screenshots for the template gallery: large samples opened by a click on the thumbnail.
themePickerNames()  : array<int, string>
Names of the offered templates for the form rule.
themePickerPreviewFullUrl()  : string|null
Returns the URL of the whole-page thumbnail for the (template, skin) pair, or NULL when the file is missing.
themePickerPreviewUrl()  : string|null
Returns the preview URL for the (template, skin) pair, or NULL when the file is missing.
themePickerValue()  : string
Value of a key from module 1 as a string ('' = key missing or not a scalar).

Constants

PICKER_MODULE

Settings of both appearances live in the System module.

private mixed PICKER_MODULE = 1

IMPORTANT: the keys cannot be renumbered even on the admin branch: ThemeRepository::pick() reads them hard-coded from $apiResponse[1].

Methods

addThemePickerFields()

Adds the hidden field pair that a click on a preview fills.

protected addThemePickerFields(Form $form) : void

IMPORTANT: both fields are hidden and JavaScript writes their values, so validation against the catalog is mandatory, not cosmetic: anyone can post anything into a hidden field and an invalid pair would store a nonexistent template (a site without appearance on the front end, a crash on variantExists() on null in the admin).

NOTE: the rule guards only the template. A skin means something only within its template (two templates may have a skin of the same name), so the whole pair is verified in themePickerSettings(), where the catalog and the template name are at hand.

NOTE: an error of a hidden field is shown in the admin only as a form error (nothing to highlight at the field), so the template must print {$form->getErrors()}.

The default value is set directly on the control, not via setDefaults(): Nette treats the second parameter of addHidden() as the default and setDefaults() did not override it for a hidden field, so the field stayed empty and the screen claimed nothing was selected. On submit the request value wins anyway.

Parameters
$form : Form

saveThemePickerSettings()

Saves the map from {@see themePickerSettings()}; FALSE = nothing was saved.

protected saveThemePickerSettings(array<string, string> $settings[, array<int, Setting> $extra = [] ]) : bool

IMPORTANT: the template / path / skin triple is indivisible, so it is saved in one transaction (SettingManager::saveBatch()). Saving key by key would leave a new template with an old path after a failure of the second key. $extra adds further form keys (e.g. paging) to the same transaction.

IMPORTANT: is_public of an existing row is not overwritten by a save, so the theme keys keep the flag that front end rendering and the admin login depend on. A new key would be created with is_public = 0, which is why each of them is seeded by an SQL script and not by the first save.

Parameters
$settings : array<string, string>
$extra : array<int, Setting> = []
Return values
bool

themePickerGroups()

Templates grouped for rendering. Each variant carries its preview and an "is currently set" flag.

protected themePickerGroups() : array<int, array{slug: string, labelKey: string, themes: list, variants: list}>}>

The first variant is always the base color of the template; the others are its skins. The screen builds a grid of cards (one card = one template) and a modal with all variants of that template.

cover is the variant shown by the card in the grid: the selected one, otherwise the base color. After picking another color the card thus shows the appearance that will really be stored. It is computed here, not in the template, where it would be a loop searching for active in the middle of rendering.

Return values
array<int, array{slug: string, labelKey: string, themes: list, variants: list}>}>

themePickerKeys()

Front end branch keys. `theme.frontend.skin` is empty for the base color.

protected themePickerKeys() : array{theme: string, path: string, skin: string}
Return values
array{theme: string, path: string, skin: string}

themePickerSettings()

Validates the submitted pair and builds a map "setting key => value", or returns NULL and writes the error into the form.

protected themePickerSettings(ArrayHash<string|int, mixed> $values, Form $form) : array<string, string>|null

IMPORTANT: the whole pair is verified, not only the template. A skin is valid only within its template, so "an existing skin" alone means nothing. The catalog is also re-read from the file system: a template deleted between render and submit must not reach the settings.

IMPORTANT: failure is reported by Form::addError(), not flashMessage(). A failed save is not redirected (the form must stay filled), but a flash renders only after a redirect, so the message would never show and the rejection would look like nothing happened.

Parameters
$values : ArrayHash<string|int, mixed>
$form : Form
Return values
array<string, string>|null

saveThemeSettingForm()

private saveThemeSettingForm(ArrayHash<string|int, mixed> $values, Form $form) : bool
Parameters
$values : ArrayHash<string|int, mixed>
$form : Form
Return values
bool

themeGroups()

Templates for the card grid; the screen passes them to `@themePicker.latte`.

private themeGroups() : array<int, array<string, mixed>>
Return values
array<int, array<string, mixed>>

themePickerAssetUrl()

Returns the relative path to the preview if the file exists and is not empty, otherwise NULL.

private themePickerAssetUrl(string $relative) : string|null

IMPORTANT: the size is checked too. An interrupted generation leaves a zero-byte file for which is_file() returns true, and the screen would render a broken image.

NOTE: the relative path is also the public URL (/www/ is part of template asset addresses), so the prefix is not stripped.

Parameters
$relative : string
Return values
string|null

themePickerChoices()

Offered pairs: template name => list of its skins (`''` = base color).

private themePickerChoices() : array<string, array<int, string>>

NOTE: duplicate colors are not dropped here, unlike the visitor switcher where two equal dots side by side would look like a bug. Here every variant has its own screenshot, so two skins of the same color are two different previews.

Return values
array<string, array<int, string>>

themePickerCover()

Variant shown by the card in the grid: the selected one, otherwise the base color.

private themePickerCover(array<int, array{skin: string, label: ?string, color: ?string, preview: ?string, previewFull: ?string, active: bool, duplicateColor: bool}> $variants) : array{skin: string, label: ?string, color: ?string, preview: ?string, previewFull: ?string, active: bool}

NOTE: the list is never empty; ThemeCatalog::variants() puts the base color first even for a template without any skin.

Parameters
$variants : array<int, array{skin: string, label: ?string, color: ?string, preview: ?string, previewFull: ?string, active: bool, duplicateColor: bool}>
Return values
array{skin: string, label: ?string, color: ?string, preview: ?string, previewFull: ?string, active: bool}

themePickerDir()

Returns the absolute directory with the templates of this branch.

private themePickerDir() : string

IMPORTANT: it is not taken from $this->themeResolver: in the admin that holds the theme of the admin branch and its frontendThemesDir() returns NULL there. The catalog therefore receives the path.

Return values
string

themePickerGallery()

Screenshots for the template gallery: large samples opened by a click on the thumbnail.

private themePickerGallery(string $theme) : array<int, array{view: string, url: string}>

The order is fixed and is also the order of the switches in the gallery. A missing file is skipped, so a template without a generated gallery does not break the screen.

NOTE: only the base color of the template is used; the gallery shows the layout, not the shade, and the screen tells the user so in a label.

Parameters
$theme : string
Return values
array<int, array{view: string, url: string}>

themePickerNames()

Names of the offered templates for the form rule.

private themePickerNames() : array<int, string>
Return values
array<int, string>

themePickerPreviewFullUrl()

Returns the URL of the whole-page thumbnail for the (template, skin) pair, or NULL when the file is missing.

private themePickerPreviewFullUrl(string $theme, string $skin) : string|null

NOTE: it is a separate file, not a crop of the large one: the large preview is only a crop of the header and hero, so the rest of the page cannot be taken from it, and that is what the strip on the card shows.

Parameters
$theme : string
$skin : string
Return values
string|null

themePickerPreviewUrl()

Returns the preview URL for the (template, skin) pair, or NULL when the file is missing.

private themePickerPreviewUrl(string $theme, string $skin) : string|null

The base color has preview.webp next to theme.json, skins live in previews/<skin>.webp; bin/theme-previews.php generates them. WebP, not PNG: a website screenshot is photographic and lossless PNG took six times more space.

A missing file is not an error: the variant renders without an image, only with the color and a label, so a new template or skin never breaks the screen.

Parameters
$theme : string
$skin : string
Return values
string|null

themePickerValue()

Value of a key from module 1 as a string ('' = key missing or not a scalar).

private themePickerValue(string $key) : string
Parameters
$key : string
Return values
string
On this page

Search results