Мы часто видим разбивку навигации на крупных порталах или интернет-магазинах, где меню включает в себя десятки пунктов различной вложенности. Также иногда требуется продублировать меню в развернутом виде в какой-либо нижней позиции страницы сайта.
В этой статье я приведу свой способ разбивки навигации на колонки для футера. На абсолютную универсальность и правильность не претендую, но, возможно, кому-то этот способ покажется полезным.
В нескольких предыдущих статьях мы уже делили на части самые различные элементы в различных частях шаблона: блоки вступительного текста в блогах, таблицы в списках материалов категории, списки статей категории в модулях. Поэтому, если кому-то нужно более подробно выяснить, что и для чего делается, могут прочесть соответствующие статьи. Здесь же я, по возможности кратко, приведу алгоритм реализации разбивки на примере альтернативного шаблона модуля меню.
Начинаем, как обычно, с создания альтернативного шаблона модуля меню mod_menu. Создаем в папке текущего шаблона сайта соответствующую папку и помещаем в нее копию файла www/modules/mod_menu/tmpl/default.php, предварительно переименовав его, например, в bottommenu.php.
P. S. :
В данном случае альтернативный шаблон меню выполняет конкретную задачу — разбивает выбранное в настройках меню на три колонки, представляя его в развернутом виде (без скрытия/развертывания по клику вложенных уровней) и начиная с корневых пунктов. Так же, в данном случае не требуется полного дублирования всех параметров меню (изображения не выводятся). Но, вы можете добавлять элементы в зависимости от вашей задачи, или же начать разбивку на колонки от 2-го уровня вложенности. Общий принцип действий останется тем же и будет работать без проблем.
Способ описан на примере joomla 3.8.10, но реализовать его можно для mod_menu любой версии. Поэтому лучше не копировать представленный здесь код целиком, как есть, а делать по аналогии, внимательно сверяя с дефолтным кодом модуля вашей версии joomla.
Альтернативный шаблон модуля может работать неправильно, если на сайте работают плагины, осуществляющие переразметку html кода меню на лету, либо удаляющие непредусмотренные системой (или их функционалом) атрибуты тегов меню (например, плагин Screen Reader). Но это уже частные случаи, где нужно выяснять, как работает каждое подобное приложение.
Создаем меню, если требуется. Затем переходим во вкладку управления модулями в административной панели управления Joomla. Далее создаем или копируем существующий модуль меню, установив в качестве альтернативного шаблона наш bottommenu.
Теперь можно приступить к правке кода.
В начале файла, можно после строки
defined('_JEXEC') or die;
добавляем переменные:
$counter = -1; // Счетчик родительских итемов (значение -1 будет всегда, независимо от того, какой уровень делим)
$columns = array(); // Массив колонок
$bufer = ''; // Текстовый буфер для сбора содержимого одной колонки
$countcol = 3; // Количество колонок
Далее, внимательно ищем и исправляем весь код, отвечающий за html разметку и вывод элементов так, чтобы все они оказались частью нашей переменной-буфера.
Например, было так:
echo '<li class="' . $class . '">';
а стало, вот так:
$bufer .= '<li class="' . $class . '">';
Теперь важный момент: вот этот код в операторе switch
require JModuleHelper::getLayoutPath('mod_menu', 'default_' . $item->type);
require JModuleHelper::getLayoutPath('mod_menu', 'default_url');
вытаскивает и сразу выводит на страницу содержимое пунктов меню, что нам не нужно. Поэтому я представила весь код оператора таким образом (возможно, здесь есть другой, неизвестный мне вариант):
// переменные параметров пункта меню (если нужны картинки или другие параметры, их нужно перечислить здесь)
$url = ($item->flink)? $item->flink : '#'; // ссылка
$rel = ($item->anchor_rel)? ' rel="'.$item->anchor_rel.'"' : ''; // атрибут rel
$target = ($item->browserNav == 1)? ' target="_blank"' : ''; // атрибут target
$title = $item->anchor_title ? ' title="' . $item->anchor_title . '"' : ''; // атрибут title
$anchor_css = $item->anchor_css ?: ''; // класс элемента
switch ($item->type) :
case 'separator':
$bufer .= '<span class="separator '.$anchor_css.'" '.$title.'>'.$item->title.'</span>';
break;
case 'component':
$bufer .= '<a href="'.$url.'"'.$target.$rel.'>'.$item->title.'</a>';
break;
case 'heading':
$bufer .= '<span class="nav-header '.$anchor_css.'"'.$title.'>'.$item->title.'</span>';
break;
case 'url':
$bufer .= '<a href="'.$url.'"'.$target.$rel.'>'.$item->title.'</a>';
break;
default:
$bufer .= '<a href="'.$url.'"'.$target.$rel.'>'.$item->title.'</a>';
break;
endswitch;
Далее, после описания условий
// The next item is deeper.
if ($item->deeper)
{
$bufer .= '<ul class="nav-child unstyled small">';
}
// The next item is shallower.
elseif ($item->shallower)
{
$bufer .= '</li>';
$bufer .= str_repeat('</ul></li>', $item->level_diff);
}
// The next item is on the same level.
else
{
$bufer .= '</li>';
}
определяем текущее значение нашего счетчика с помощью следующего кода:
if ($item->level == 1 ) { // Значение $item->level зависит от того, какой уровень вложенности разбиваем
$counter++;
} else {
$counter = $counter;
}
Мы изменяем значения счетчика строго по условию (когда нам попадается нужный уровень вложенности, который будем разбивать), поэтому мы не можем расположить его в коде ниже той части, которая собственно и отвечает за формирование наших колонок, и поэтому мы и присваивали ему начальное значение -1.
Теперь собираем содержимое для будущих колонок (этот код должен располагаться до закрывающей скобки foreach):
// Если счетчик достиг максимального значения (количества колонок) – сбрасываем на 0, иначе – оставляем его значение как есть
$counter = ($counter > $countcol-1) ? 0 : $counter;
for ($i = 0; $i < $countcol; $i++){
// Выясняем, есть ли колонка, если нет – создаем и присваиваем ей пустое значение
if (isset ($columns[$i])) {
$columns[$i] = $columns[$i];
} else {
$columns[$i] = '';
}
// Пополняем соответствующую колонку текущим содержимым буфера
if ($i == $counter){
$columns[$i] .= $bufer;
}
}
$bufer = '';
Все. Контент раскидали и осталось его вывести. Для этого после закрывающей скобки foreach добавляем следующий код:
for ($i = 0; $i < $countcol; $i++){ // Выводим колонки добавляя необходимые блоки-обертки
echo '<li class="column"><ul class="column-item">'.$columns[$i].'</ul></li>';
}
Сохраняем файл и проверяем на сайте, что получилось.
Приведу основные стили для быстрого и более удобного просмотра результата.
.column {
display: block;
text-align: left;
float: left;
height: auto;
width: 30%;
}
.column + .column {
margin-left: 4.2%;
}
@media (max-width: 767px) {
.column {
float: none;
width: auto;
}
.column + .column {
margin-left: inherit;
margin-top: 1.5em;
}
}
Если все работает правильно, можно приступить к стилизации модуля в соответствии с шаблоном сайта.