Темы WordPress и пустые заголовки виджетов

  • 11.05.15
  • 15:47
  • 2243
  • 0

Ситуация: имеется готовая вёрстка, виджеты в которой выполнены не совсем стандартно для WordPress: их содержимое заключено в блок, следующий за блоком заголовка. В общих чертах это выглядит так:

Вёрстка такова, что перенос div.widget-title в div.widget-body невозможен. Отсутствие любого из них дизайн также не предусматривает.

Проблема: когда заголовок пуст, обрамляющий его код обычно не выдаётся, и параметры сайдбара before_widget и after_widget оказываются несбалансированными — первый открывает один блок, второй закрывает два:

Задача: заставить виджеты с пустыми заголовками отображаться корректно.

Теория

Каждый виджет в WordPress формируется четырьмя фрагментами кода, задаваемыми темой:

  • before_widget и after_widget обрамляют весь виджет;
  • before_title и after_title обрамляют заголовок и находятся внутри обрамления виджета.

Перед выводом заголовок фильтруется хуком widget_title. Если в итоге он оказывается пуст — его обрамление не выдаётся. Некоторые виджеты этим правилам не следуют: их заголовок может не фильтроваться или не выводиться, что в данном случае способно нарушить структуру всей страницы.

Поэтому параметры before_widget и after_widget необходимо сбалансировать. Также желательно обеспечить приемлемый вид для «нестандартных» виджетов.

Решение

Пустые заголовки следует заменять пробелами при помощи фильтра 'widget_title':

Здесь предполагается, что приоритет остальных обработчиков фильтра не превышает 255. Число взято наугад, значение по умолчанию — 10.

Такой подход затрагивает все виджеты без исключения. Если же он допустим не во всех сайдбарах темы, потребуются провести дополнительные манипуляции:

  • по хуку 'widgets_init' с приоритетом не ниже 100 необходимо создать глобальный хеш вида $id_base => 'Class_Name' для всех зарегистрированных классов виджетов;
  • в фильтре 'widget_title':
    • взять идентификатор обрабатываемого виджета из экземпляра его класса:
    • получить идентификатор сайдбара:
    • из идентификатора сайдбара определить, должен ли изменяться пустой заголовок.

Т. е. код может быть таким:

Нестандартные виджеты и балансировка

В отношении виджетов, не следующих стандартам, опасность представляет отсутствие фильтрации заголовка, так как before_widget и after_widget не сбалансированы. Балансировка достигается добавлением пустого блока (или пустых блоков) между фрагментами before_widget и before_title: открывающие теги относятся к before_widget, закрывающие — к before_title:

В общем случае, когда after_widget закрывает на N блоков больше, чем открывает before_widget, следует добавлять вложенные N блоков.

Теперь без заголовка виджет, не проводящий фильтрацию, будет выглядеть так:

Смягчение отсутствия блоков тела и заголовка виджета

Добавленный блок div.blank-block должен быть стилизован таким образом, чтобы его высота, рамки, вертикальные поля и отступы проявлялись только в нестандартных виджетах. В полноценных же эти свойства должны отсутствовать, иначе блок будет заметен. Отвечающий таким требованиям селектор можно записать как минимум двумя способами:

  1. при помощи псевдо-класса :last-child, если блок тела виджета является последним в блоке виджета div.widget (как в приведённом выше примере);
  2. с использованием псевдо-классов :not(:empty), если за блоком тела виджета следуют другие блоки — футер виджета, например;

Второй вариант срабатывает на блоках, содержащих хотя бы один символ — любой, включая пробельный (пробел, табуляция, перенос строки). Поэтому в виджете с заголовком пустой блок должен быть абсолютно пуст. Это надо учитывать в параметрах сайдбара: before_widget должен завершаться открывающим тегом холостого блока, а before_title — начинаться закрывающим:

Штатные виджеты WordPress между этими параметрами ничего не выводят, а остальные, как правило, используют их в качестве эталона. Тем не менее исключения опять-таки возможны. Чтобы с ними справиться, можно предусмотреть, напр., такой js-костыль:

В общем случае, когда добавлены N вложенных блоков, псевдо-класс :last-child следует относить к самому внешнему, а :not(:empty) — к самому внутреннему.

Оба псевдо-класса относятся к CSS3. Селекторы с ними могут выглядеть некорректно для устаревших или проблемных браузеров. Поэтому к таким селекторам следует отнести только те стили, что влияют на размеры и видимость пустого блока и потому не могут фигурировать среди заданных непосредственно для div.blank-block.

По той же причине нельзя встраивать селектор CSS3 в наборы селекторов более ранних стандартов: если браузер его не поймёт, весь набор будет проигнорирован. (Такое желание может возникнуть при стилизации непустого «холостого блока» стилями блока тела виджета).

Вместо этого стили .widget-body должны быть продублированы и разнесены по селекторам div.blank-block с псевдо-классом и без. К первому относятся вертикальные отступы, поля и рамки, ко второму — всё остальное, а также удаление рамок и обнуление вертикальных полей, отступов и минимальной высоты.

Замечание 1 (для пользователей LESS): часто используемая в подобных случаях директива :extend добавляет дополняемый селектор в набор к дополняющему. Чтобы этого избежать, вместо :extend(... .widget-body) следует использовать селектор .widget-body в качестве миксина:

Замечание 2: вариант, когда div.blank-block полностью наследует div.widget-body, а div.blank-block:empty содержит обнуление отступов, рамок и т. п., очень не удобен зависимостью от CSS3: в браузерах без поддержки псевдо-класса :empty «пустые блоки» скрываться не будут. Поэтому такой вариант не рассматривается.

Замечание 3: эти предостережения могут не иметь значения для ресурсов, не предусматривающих работу без поддержки CSS3.

Ниже приведены два варианта вёрстки виджета, подобного рассмотренному в задаче: слева (синий) использует псевдо-класс :last-child, справа (красный) — псевдо-класс :not(:empty).

:last-child

Заголовок
Тело виджета находится здесь.
Пустой блок не заметен.
виджет без заголовка и тела обладает отступами и рамкой.
Пустой блок с пробелом
Здесь пустой блок оказывается нечувствителен к своему содержимому.
виджет без заголовка и тела с футером — отступы и рамка отсутствуют.
Виджет с футером
Контент виджета находится тут.

:not(:empty)

Заголовок
Тело виджета находится тут.
Пустой блок не заметен.
виджет без заголовка и тела обладает отступами и рамкой.
Пустой блок с пробелом
В этом случае блок имеет ненулевые вертикальные отступы и портит виджет.
виджет без заголовка и тела с футером — нормальные отступы.
Виджет с футером
Контент виджета находится здесь.

Код примера доступен здесь.

Оставить комментарий

Добавить комментарий