Динамические страницы (тип dynamic)
Универсальный тип dynamic
📄 Динамические страницы (тип dynamic)
Тип dynamic — это универсальный тип страницы для работы с любыми таблицами данных. Он заменил старые blog и catalog и работает с любой таблицей.
Как это работает
Вы указываете:
source_table— имя таблицы с даннымиtemplate— имя шаблона (без.html.twig)
CMS автоматически:
- Показывает список записей по адресу страницы
- Показывает отдельную запись по адресу
/{url}/{slug}
Настройка в navigation
{
"source_table": "docs",
"template": "docs",
"sort": {"field": "sort_order", "order": "ASC"},
"items_per_page": 50
}
| Поле | Описание |
|---|---|
source_table |
Имя таблицы в БД |
template |
Базовое имя шаблона |
sort.field |
Поле для сортировки |
sort.order |
ASC или DESC |
items_per_page |
Записей на странице (для списка) |
Шаблоны
Для каждого динамического типа нужно два шаблона:
| Режим | Шаблон | Переменные |
|---|---|---|
Список (/url) |
{template}.html.twig |
items, nav_item, current_page, total_pages, total_count |
Запись (/url/{slug}) |
{template}_single.html.twig |
item, nav_item, prev_item, next_item, items |
Список (docs.html.twig)
{% for p in items %}
<a href="{{ url(nav_item.url ~ '/' ~ p.slug) }}">{{ p.title }}</a>
{% endfor %}
Отдельная запись (docs_single.html.twig)
<h1>{{ item.title }}</h1>
<div>{{ item.content|markdown_to_html|raw }}</div>
💡 Новое:
itemsтеперь доступен и в_singleшаблоне — можно строить боковую навигацию по всем записям.
Примеры из реальных проектов
- apidcms.dezajno.ru —
docs→ таблицаdocs, документация - prostostihi.ru —
examples→ таблицаpoetry, примеры стихов
🔧 Авто-поддерживаемые колонки
Dynamic-страницы автоматически работают со следующими колонками в таблице. Если колонка есть — она используется, если нет — пропускается.
| Колонка | Тип | Назначение |
|---|---|---|
slug |
TEXT | URL-идентификатор записи. По нему строится URL отдельной страницы: /{url}/{slug}. Если нет slug — используется id |
status |
TEXT | Фильтрация: в список и на отдельную страницу попадают только записи со status = 'active' |
sort_order |
INTEGER | Порядок сортировки в списке. Приоритетнее created_at. Также используется для prev/next-навигации |
created_at |
DATETIME | Резервная сортировка и prev/next-навигация, если нет sort_order |
views_count |
INTEGER | Новое в v1.3.7: авто-инкремент при каждом просмотре записи. Ничего настраивать не нужно — просто добавьте колонку в таблицу |
Использование views_count
-- Добавить колонку в таблицу
ALTER TABLE my_table ADD COLUMN views_count INTEGER DEFAULT 0;
В шаблоне _single.html.twig:
<span>👁️ {{ item.views_count|default(0) }} просмотров</span>
Значение увеличивается автоматически при каждом открытии страницы записи.
🔍 GET-фильтры (get_filters)
Dynamic-страницы поддерживают фильтрацию через GET-параметры. Настраивается в page_config через ключ get_filters.
Настройка
{
"source_table": "catalog",
"template": "catalog",
"sort": {"field": "sort_order", "order": "ASC"},
"items_per_page": 10,
"get_filters": {
"category": "category",
"tool": "ai_tool",
"difficulty": "difficulty"
}
}
| Ключ | Значение |
|---|---|
get_filters |
Объект: "GET-параметр" => "колонка в таблице" |
Как это работает
- Пользователь переходит по URL
?category=text&tool=GPT - CMS добавляет в SQL:
WHERE category = 'text' AND ai_tool = 'GPT' total_countи пагинация учитывают фильтры- Фильтры комбинируются друг с другом и с
filters(жёсткие фильтры из конфига)
Пример: ссылки-фильтры в Twig
{% set qs_tool = '' %}
{% if _GET.tool %}{% set qs_tool = '&tool=' ~ _GET.tool %}{% endif %}
<a href="?category=text{{ qs_tool }}"
class="{% if _GET.category == 'text' %}active{% endif %}">
Текст
</a>
Переменная
_GETдоступна во всех шаблонах начиная с v1.3.7.
📊 Сортировка (sort_options)
Dynamic-страницы поддерживают переключение сортировки через GET-параметр ?sort=. Настраивается в page_config через ключ sort_options.
Настройка
{
"sort": {"field": "created_at", "order": "DESC"},
"sort_options": {
"newest": {"field": "created_at", "order": "DESC"},
"popular": {"field": "views_count", "order": "DESC"},
"rating": {"field": "copies_count", "order": "DESC"}
}
}
| Ключ | Значение |
|---|---|
sort |
Сортировка по умолчанию (field, order) |
sort_options |
Доступные варианты сортировки: "ключ" => {"field": "...", "order": "ASC/DESC"} |
Как это работает
- Пользователь переходит по URL
?sort=popular - CMS ищет ключ
popularвsort_options - Проверяет, что колонка существует в таблице (защита от инъекций)
- Применяет
ORDER BY views_count DESC - Параметр
sortсохраняется в пагинации и комбинируется с фильтрами
Пример: ссылки сортировки в Twig
{% set qs = '' %}
{% if _GET.category %}{% set qs = qs ~ '&category=' ~ _GET.category %}{% endif %}
<a href="?sort=newest{% if qs %}&{{ qs|trim('&') }}{% endif %}"
class="{% if _GET.sort == 'newest' or _GET.sort is empty %}active{% endif %}">
Сначала новые
</a>
<a href="?sort=popular{% if qs %}&{{ qs|trim('&') }}{% endif %}"
class="{% if _GET.sort == 'popular' %}active{% endif %}">
Популярные
</a>
Безопасность
sort_optionsдолжен быть явно задан вpage_config— без него?sort=игнорируется- Имя колонки валидируется через
PRAGMA table_info— произвольный SQL невозможен -
Существующие проекты без
sort_optionsработают как раньше
🧩 Twig-функции для доступа к данным
В любом шаблоне фронтенда доступны функции для получения данных из других таблиц.
| Функция | Описание |
|---|---|
get_record(table, id) |
Одна запись по ID |
get_records(table, ids) |
Несколько записей: '1,3,5' |
get_all(table, orderBy, orderDir) |
Все записи, с сортировкой |
get_setting(key) |
Значение системной настройки |
Пример: топ-N записей из таблицы
{% set count = 0 %}
{% for item in get_all('catalog', 'copies_count', 'DESC') %}
{% if item.status == 'active' and count < 4 %}
{% set count = count + 1 %}
<a href="/catalog/{{ item.slug }}">{{ item.title }}</a>
{% endif %}
{% endfor %}
json_decode фильтр
Для колонок с JSON-данными используйте фильтр |json_decode:
{% set features = plan.features|json_decode %}
{% for f in features %}<li>{{ f }}</li>{% endfor %}
Функции
get_*и фильтрjson_decodeдоступны начиная с v1.3.7.