Разработка кастомного шаблона Sulu
Недавно к нам обратился клиент с задачей: страница услуги должна содержать блоки «Текст», «Изображение+текст», «Призыв к действию» и боковую панель с формой обратной связи. Стандартные шаблоны Sulu не предоставляли такой комбинации — пришлось бы хакерить админку или создавать кастомный шаблон. Мы разработали решение за 2 дня: XML-схема с нужными типами блоков, Twig-шаблон для рендеринга и кастомный контроллер для подгрузки отзывов. Теперь менеджер собирает страницу из готовых блоков за минуты. Наша команда имеет 5+ лет опыта работы с Sulu CMS и реализовала 20+ проектов, что гарантирует отсутствие багов и соответствие требованиям. Такая гибкость позволяет нашим клиентам экономить до 30% бюджета на поддержку сайта за счёт отказа от хаков. При разработке 5–8 кастомных шаблонов для корпоративного сайта экономия может достигать 40% по сравнению с покупкой готового решения.
Почему кастомный шаблон Sulu лучше стандартного?
Стандартные шаблоны покрывают базовые потребности. Но для уникальных страниц часто требуются поля, которых нет в «коробке». Кастомный шаблон позволяет:
- Добавить любые типы полей: текстовые редакторы, медиа, блоки с произвольной структурой.
- Создать несколько макетов для одного типа страницы.
- Подключить кастомный контроллер для загрузки дополнительных данных (например, связанных записей или отзывов).
- Управлять представлением через Twig-шаблоны без ограничений.
В результате — гибкость, невозможная при использовании стандартных решений, и снижение затрат на поддержку до 30–50% за счёт отказа от кастылей. Согласно документации Sulu, кастомные контроллеры экономят время на интеграциях.
Как разработать кастомный шаблон Sulu?
Процесс включает несколько этапов:
- Анализ требований к странице и согласование структуры.
- Проектирование XML-схемы с полями и блоками.
- Разработка Twig-шаблона с учётом дизайна.
- Написание кастомного контроллера (если нужны дополнительные данные).
- Интеграция с существующей темой и тестирование.
- Деплой на сервер и финальная проверка.
- Передача документации и обучение.
Сроки зависят от сложности. Ниже — ориентировочные сроки для разных типов шаблонов.
| Тип шаблона | Количество уникальных блоков | Срок разработки |
|---|---|---|
| Простой (текст, медиа) | 2–4 | 1–2 дня |
| Средний (блочный редактор, кастомные поля) | 5–8 | 2–3 дня |
| Сложный (кастомный контроллер, интеграции) | 8+ | 3–5 дней |
Сравнение стандартного и кастомного шаблона
| Критерий | Стандартный шаблон | Кастомный шаблон |
|---|---|---|
| Количество полей | Ограничено | Любоe |
| Типы блоков | Только текст | Текст, медиа, CTA, галерея и т.д. |
| Контроллер | Только DefaultController | Кастомный с любой логикой |
| Гибкость | Низкая | Высокая |
Пример XML-шаблона
<template xmlns="http://schemas.sulu.io/template/template"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://schemas.sulu.io/template/template
http://schemas.sulu.io/template/template-1.0.xsd">
<key>service</key>
<view>pages/service</view>
<controller>App\Controller\Website\ServiceController::indexAction</controller>
<cacheLifetime type="seconds">1800</cacheLifetime>
<properties>
<property name="title" type="text_line" mandatory="true">
<meta><title lang="ru">Заголовок</title></meta>
<tag name="sulu.rlp.part"/>
</property>
<property name="intro" type="text_area" colspan="12">
<meta><title lang="ru">Вступительный текст</title></meta>
<params>
<param name="rows" value="3"/>
</params>
</property>
<block name="content_blocks" default-type="text" colspan="12">
<meta><title lang="ru">Блоки контента</title></meta>
<types>
<type name="text">
<meta><title lang="ru">Текст</title></meta>
<properties>
<property name="text" type="text_editor">
<meta><title lang="ru">Текст</title></meta>
</property>
</properties>
</type>
<type name="image_text">
<meta><title lang="ru">Изображение + текст</title></meta>
<properties>
<property name="image" type="single_media_selection">
<meta><title lang="ru">Изображение</title></meta>
</property>
<property name="text" type="text_editor">
<meta><title lang="ru">Текст</title></meta>
</property>
<property name="image_position" type="select">
<meta><title lang="ru">Позиция изображения</title></meta>
<params>
<param name="values" type="collection">
<param name="left" title="Слева"/>
<param name="right" title="Справа"/>
</param>
</params>
</property>
</properties>
</type>
<type name="cta">
<meta><title lang="ru">Призыв к действию</title></meta>
<properties>
<property name="heading" type="text_line">
<meta><title lang="ru">Заголовок</title></meta>
</property>
<property name="button_text" type="text_line">
<meta><title lang="ru">Текст кнопки</title></meta>
</property>
<property name="button_link" type="text_line">
<meta><title lang="ru">Ссылка</title></meta>
</property>
</properties>
</type>
</types>
</block>
<section name="sidebar">
<meta><title lang="ru">Боковая панель</title></meta>
<properties>
<property name="show_form" type="checkbox">
<meta><title lang="ru">Показать форму обратной связи</title></meta>
<params>
<param name="defaultValue" value="true"/>
</params>
</property>
<property name="related_services" type="smart_content">
<meta><title lang="ru">Похожие услуги</title></meta>
<params>
<param name="provider" value="pages"/>
<param name="types" value="service"/>
<param name="max_per_page" value="4"/>
</params>
</property>
</properties>
</section>
</properties>
</template>
Twig-шаблон
{% extends 'base.html.twig' %}
{% block title %}{{ content.title }} | {{ app.request.host }}{% endblock %}
{% block body %}
<div class="page-service">
<h1>{{ content.title }}</h1>
{% for block in content.content_blocks %}
<div class="block block--{{ block.type }}">
{% if block.type == 'text' %}
{{ block.text|raw }}
{% elseif block.type == 'image_text' %}
<img src="{{ sulu_resolve_media(block.image, locale).thumbnails['service-block'] }}" alt="" loading="lazy">
{{ block.text|raw }}
{% elseif block.type == 'cta' %}
<h2>{{ block.heading }}</h2>
<a href="{{ block.button_link }}" class="btn">{{ block.button_text }}</a>
{% endif %}
</div>
{% endfor %}
</div>
{% endblock %}
Кастомный контроллер
class ServiceController extends AbstractController
{
public function indexAction(StructureInterface $structure): Response
{
$testimonials = $this->testimonials->findByService($structure->getUuid(), limit: 3);
return $this->render('pages/service.html.twig', [
'content' => $structure->getContent(),
'testimonials' => $testimonials,
]);
}
}
Регистрация шаблона в webspace
<templates>
<template type="page">service</template>
</templates>
После добавления шаблона — сбросить кэш и переиндексировать:
php bin/console cache:clear
php bin/console sulu:document:initialize
Типичные сложности и их решения
-
Шаблон не применяется — чаще всего забывают зарегистрировать ключ в webspace или сбросить кэш. Всегда проверяйте наличие записи в конфиге и выполняйте
cache:clear. -
Неверная ссылка на контроллер — укажите полное имя класса и метод, иначе Sulu не найдёт контроллер. Используйте
debug:routerдля проверки. -
Блоки не отображаются — убедитесь, что в Twig шаблоне для каждого типа блока прописана соответствующая логика. Частая ошибка — отсутствие проверки
typeв цикле.
Что входит в работу
- XML-схема с полями и блоками
- Twig-шаблон с адаптивной версткой
- Кастомный контроллер (при необходимости)
- Интеграция с CMS и настройка прав доступа
- Документация по структуре шаблона
- Обучение контент-менеджеров работе с блоками
- Гарантия качества и поддержка после деплоя
Мы предоставляем кастомную вёрстку Sulu и разработку Sulu сайтов под ключ. Наши решения для кастомного шаблона Sulu полностью соответствуют вашим требованиям и экономят бюджет.
Сроки и как заказать
Один шаблон с блочным редактором, кастомным контроллером и Twig занимает 2–3 дня. Полный комплект шаблонов (5–8 типов) для корпоративного сайта — 1,5–2 недели. Стоимость рассчитывается индивидуально в зависимости от сложности и объёма работ.
Свяжитесь с нами для обсуждения вашего проекта — мы подготовим детальное предложение. Получите консультацию по разработке кастомного шаблона Sulu уже сегодня.







