В этой статье мы рассмотрим, как легко переключать темы оформления на сайте для определённых страниц или разделов.
Иногда бывают такие моменты, что есть необходимость создать для каких-то конкретных страниц, разделов или конкретной страницы. Целей то может быть и много, но задача тут одна. В 8-ке для этого есть theme negotiator. Это такой небольшой сервис который и позволяет определить системе какую тему подключать на той или иной странице, в условиях Drupal 8, на том или ином роутинге.
Тема, которая так или иначе может быть активирована (установлена), должна быть включена в Appearance
Первым делом давайте объявим наш theme negotiator. Это простенький класс всего с двумя необходимыми методами:
applies(RouteMatchInterface $route_match)
- метод который отвечает за условия выбора. Если он возвращает TRUE, тогда вызывается следующий метод, если false, то данный negotiator пропускается. По факту, вся логика выборки должна находиться здесь.determineActiveTheme(RouteMatchInterface $route_match)
- метод вызываемый в случае еслиapplies()
вернул TRUE.
Давайте рассмотрим на примере, например, включив тему Stark для главной страницы. Первым делом надо включить (установить) данную тему в админке. Так как эта тема в ядре, то просто жмем install и идем далее.
Теперь нужно объявить наш класс. Он должен располагаться в /src/Theme
. Назовем
его StarkForFront
и заполним следующим кодом.
<?php
namespace Drupal\dummy\Theme;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\Theme\ThemeNegotiatorInterface;
use Drupal\Core\Path\PathMatcherInterface;
/**
* Sets the Stark for frontpage.
*/
class StarkForFront implements ThemeNegotiatorInterface {
/**
* @var \Drupal\Core\Path\PathMatcherInterface
*/
protected $pathMatcher;
/**
* StarkForFront constructor.
* @param \Drupal\Core\Path\PathMatcherInterface $pathMatcher
*/
public function __construct(PathMatcherInterface $pathMatcher) {
$this->pathMatcher = $pathMatcher;
}
/**
* {@inheritdoc}
*/
public function applies(RouteMatchInterface $routeMatch) {
return $this->pathMatcher->isFrontPage();
}
/**
* {@inheritdoc}
*/
public function determineActiveTheme(RouteMatchInterface $routeMatch) {
# Машинное имя темы, которую необходимо активировать.
return 'stark';
}
}
И последним, вторым, шагом станет то, что мы данный класс добавим в сервисы. Для
этого нужно добавить в корень модуля файл MYMODULE.services.yml
и объявить
свой сервис.
services:
theme.negotiator.stark_for_front:
class: Drupal\dummy\Theme\StarkForFront
arguments: ['@path.matcher']
tags:
- { name: theme_negotiator, priority: -40 }
Как вы можете заметить, мы также можем указывать приоритет. Если сработают сразу два theme negotiator на одной странице, то приоритет отдастся тому, у которого будет больший приоритет. У theme negotiator из ядра приоритет -100, так что имейте это ввиду.
Ну и чтобы убедиться что всё сделали правильно, заходим на главную страницу сайта и смотрим на результат.
Не пугайтесь, это не развалившаяся тема, а Stark, так что всё правильно :)
Вот так вот просто можно переключать темы.
Ну и небольшая подсказка на последок.
public function applies(RouteMatchInterface $route_match) {
if ($route_match->getRouteName() == 'entity.node.canonical') {
$node = $route_match->getParameter('node');
if ($node->bundle() == 'NODE_TYPE') {
return TRUE;
}
}
return FALSE;
}
P.s. Спасибо drupby за подсказку, как оптимизировать то что было, код в статье чутка исправлен.
Комментарии
В applies()
получать \Drupal::request()->headers->get('User-Agent')
и определять нужна мобильная или десктопная тема. Я думаю тут лучше подрубать что-то дополнительно со стороны. Например serbanghita/Mobile-Detect и при помощи него определять мобилка или нет.
Полезная возможность, можно на основе некоторых условий выводить разный дизайн сайта, что можно использовать для повышения его юзабилити.
Большое спасибо, Никита! Очень помогло.
Была задача вывести на отдельной странице (используя небольшой кастомный template) форму добавления перевода для ноды (например, такую /node/47/translations/add/en/da), чтобы можно было изменить внешний вид. Планировалось дать доступ для использования этой формы определенным ролям.
Хотел просто вытащить через \Drupal::formBuilder()->getForm(...). Оказалось, что работы с переводом используется стандартная форма добавления ноды, и через getForm вытаскивается она. И эта стандартная форма переопределяется в модуле "content_translation".
Долго бился, ковырял модуль content_translation - создать такую форму на кастомной странице не получалось.
Случайно наткнулся на эту статью и просто повесил свою тему на на уже существующую форму по существующему роуту для нужных ролей. А далее css, js и hook_form_alter сделали свое дело.
Но все равно было бы полезно знать, как можно было отобразить форму добавления (а также и редактирования) перевода ноды в кастомном темплейте. Буду благодарен за подсказку.
А что нужно написать в applies(), чтобы срабатывало на то, когда в пути (адресной строке сайта) появлялось слово special?
А можно еще пример переключение между Мобильной и Десктопной темами на основе UserAgent'a?