Как настроить вертикальное меню в modx evo. PdoMenu — создание меню в MODX. Подключаем активный пункт меню

Как настроить вертикальное меню в modx evo. PdoMenu — создание меню в MODX. Подключаем активный пункт меню

02.07.2020

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

Поэтому одной из основных задач вебмастера стоит создание динамическое меню, чтобы все действия по редактированию структуры меню можно было бы производить из административной панели.

Это можно реализовать с помощью специальных инструментов MODx – сниппетов.

Сниппет – это php код, который запускается в шаблоне MODx и позволяет выводить информацию из базы данных CMS.

Сниппеты разделяются на два вида:

  • кэшируемые;
  • не кэшируемые.

Их отличие в конструкции вызова. Так, например, если мы имеем сниппет с названием «SNIPNAME», то при не кэшируемом вызове конструкция будет иметь следующий вид:

[!SNIPNAME!]

При кэшированном варианте – она будет иметь вид:

[]

Тут может появиться вопрос, зачем же делать сниппет кэшируемым? Дело в том, что при использовании кэша конструкция сохраняется и не происходит постоянное обращение к базе данных, что в свою очередь увеличивает скорость загрузки страниц и уменьшает нагрузку на сервер. Но часто, можно столкнуться с тем, что после занесения в кэш, вебмастер производит какие-то действия, но они не отображаются на сайте, для их отображения нужно предварительно очищать устаревший кэш. Об этом расскажу немного позже. Мы же будем использовать именно не кэшируемый вариант меню.

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

[!Имя_сниппета? &параметр1=`значение параметра` &параметр2=`значение параметра` !]

Знак «?» — дает системе сигнал, что после него следуют параметры, которые нужно применить к сниппету. А сами сниппеты при этом разделяются знаком «&», а значения берутся в обратные кавычки. Если вы поставите неправильные кавычки, то ничего работать не будет.

Как же настроить динамический вывод структуры меню?

Для вывода меню в MODx мы будем использовать сниппет:

[!Wayfinder!]

Использовать его в «чистом виде» у нас не получиться, поскольку для этого нужно наличие вложенных материалов, и отображаться оно будет только на главной. Правильно будет указать id статьи, от которой стоит делать отсчет. С помощью данного метода мы сможем создавать много разных меню, используя для этого id. На практике будет более понятно.

Так как сейчас Родительским пунктом является «Главная» со значением id = 1. То конструкция должна иметь следующий вид:

Такой конструкцией вы сможете вывести меню из дочерных пунктов. Давайте реализуем это на практике.

Идем в раздел «Элементы» — «Управление элементами» — Вкладка «Чанки». Выбираем чанк «HEADER» и находим в нем код, который отвечает за вывод меню.

HOME

  • home
  • about us
  • services
  • projects
  • solutions
  • jobs
  • blog
  • contacts

Давайте вместо этого кода вставим конструкция вышеприведенного сниппета:

[!Wayfinder? &startId=`1`!]

Как видите, меню подключилось, в адресной строке меняется url, правда шаблон остается тот же, мы это поправим в следующих уроках.

Но вот существует две проблемы:

1.) Не выделяется активный пункт меню.

2.) Отсутствует пункт меню «Главная».

Давайте исправим эти недочеты.

Подключаем активный пункт меню

По умолчанию сниппет Wayfinder формирует активный пункт меню с классом «active». Так что нам не придется дописывать дополнительный скрипт, а всего лишь поменять класс в css файле. Для этого переходим в папку с нашим шаблоном — /assets/templates/retina/css/style.css. Учтите, что папка название папки шаблона у вас может отличатся, все зависит от того какое название вы вводили в первых уроках. Открываем этот файл и ищем строчку со стилями для активного пункта меню. У меня это строчка – 190, а вот и сам код:

#navigation a.nav-btn { margin-bottom: 15px; text-decoration: none; padding:0 36px 0 10px; line-height:30px; display:block; background: url(images/navigation.png) repeat-x 0 0; height: 30px; position: relative; }

Заменяем класс «.nav-btn» на «active».

Подключаем «Главная»

И так, как вы поняли, мы вывели дочерные пункты от пункта меню «Главная». Чтобы подтянуть сам этот пункт нужно, чтобы все наше меню было одинакового уровня вложенности.

Для начала проверяем, открыт ли доступ к корневой папке. Для этого переходим в раздел «Инструменты» — «Конфигурация» — Вкладка «Пользователи». В ней находим параметр – «Разрешить доступ к корневой папке » и ставим значение в «Да».

После этого выбираем пункт, допустим «Услуги», заходим на страницу его редактирования и внизу нажимаем на иконку, как показано на скриншоте.

После нажатия вам нужно выбрать родительский пункт меню в левой колонке материалов, мы выбираем коневую папку. Скриншот ниже.

Кликаем на ней и сохраняем нашу статью. Сам материал должен переместиться на один уровень с «Главной».

Это действие нужно проделать со всеми подпунктами. У вас должна выйти следующая структура.

Если вы сейчас обновите страницу вашего сайта, то ваше меню исчезнет. Все потому, что изменился id родительской категории. Давайте подправим его. Для этого идем в раздел «Элементы» — «Управление элементами» — Вкладка «Чанки». Выбираем чанк «HEADER» и находим в нем код:

[!Wayfinder? &startId=`1`!]

И изменяем на:

Все, меню полностью готово и соответствует шаблону.

Если вы заметили, то по шаблону можно увидеть, что в футере у нас есть меню, которое в точности повторяет пункты только что созданного нами варианта. Поэтому, я предлагаю сразу подправить и этот блок. Для этого идем в раздел «Элементы» — «Управление элементами» — Вкладка «Чанки» выбираем чанк «FOOTER». В нем находим код, отвечающий за вывод нижнего меню, и вместо него вставляем уже знакомую нам конструкцию.

[!Wayfinder? &startId=`0`!]

Вот, что у вас должно получится.

На этом сегодня все. Если будут вопросы, пишите их в комментариях, я постараюсь на них ответить. До следующих уроков.

Дата публикации: 07.02.2011

В этом несложном уроке я покажу, как настраивается меню.

Однажды меня попросили исправить баг с меню на одном сайте - некоторые пункты упорно не хотели выстраиваться в ряд, а вместо этого вылезали в неожиданных местах страницы при наведении курсора. Баг заключался не в кривом css, как я предположила сначала, а в криво настроенном вызове Wayfinder.

Что такое Wayfinder - это сниппет, который используется, когда нужно вывести список документов раздела/ов. В результате работы сниппета генерируется ненумерованный список. При помощи различных параметров с этим списком можно сделать все, что угодно:) Подробнее вы можете почитать в документации , или набрав в Google - “wayfinder modx wiki”.

Важные примечания:

1. О том, что такое MODx, как установить MODx, как организовать структуру документов, как из html сделать шаблон, что такое чанк и проч. вопросы новичков в этом уроке я не рассматриваю.

2. Плейсхолдеры, которые я буду использовать в уроке, указаны в том формате, который «понимает» Evo версия. В чем разница, смотрите пример:

Итак, разберем создание меню по шагам.

Шаг 1

Для урока набросала вот такое меню:

Здесь для наглядности я применила разные стили к разным уровням меню. На том сайте, где фиксила баг с меню, было примерно так же - у каждого уровня меню свой стиль.

Верстаем - подробности верстки в рамки данного урока не входят, вот такой код у меня получился:

Полюбовавшись кодом, определяем для себя, какой класс в нашем меню за что отвечает (это если ковыряетесь в чужом коде, в своем и так должно быть ясно ):

ul class="menu" - класс всего меню
li class="top" - класс пунктов меню верхнего уровня
a class="top_link" - класс для ссылок в пунктах верхнего уровня
ul class="sub" - класс для подменю
ну и span class="down" для оформления пунктов верхнего уровня

Шаг 2. Создаем три документа

Продукция
- Доставка
- Поставщики
У документа «Продукция» создаем дочерние документы: «Сыворотка правды», «Средство Макропулоса», «Универсальные средства».

Шаг 3. Выносим меню в отдельный чанк

В шаблоне, в том месте где у вас должно быть меню, убираем весь лишний код (сам html код меню), вместо него пишем

{{ menu}}

Тем самым мы выносим меню в отдельный чанк. Потом создаем новый чанк и называем его menu . Пока в содержимое чанка можно скопировать код меню, который вы сверстали. Для наглядности.

Зайдите в админке в «Сайт»-> “Просмотр” - чтобы проверить, что все нормально с путями к файлу стилей и картинкам.

Получилось? Ок, но это еще не меню. Вдохнём в него жизнь при помощи Wayfinder.

Шаг 4

Удалите все содержимое чанка menu и вместо этого вызовите сниппет Wayfinder.
Пока напишем так:

[[ Wayfinder? &startId=`0`]]

параметр startId - указывает, с какого документа начинать формировать список. У нас указан 0 - это значит, что список формируется с корня дерева документов.

Посмотрим, что получилось:

Это - рабочее и живое меню. Переименовывайте документы, удаляйте, добавляйте - меню будет формироваться в соответствии с деревом документов.

Шаг 5

5.1. Tеперь приводим внешний вид меню в норму

Wayfinder по умолчанию формирует простой код () , все классы списков и элементов задаются специальными параметрами при вызове.

В начале урока мы определяли, какие css-классы в нашем меню за что отвечают. У Wayfinder имеются нужные нам параметры: outerClass - класс для контейнера меню. Сопоставив с нашей вёрсткой, получаем такой вызов Wayfinder:

[[ Wayfinder? &startId=`0` &level=`2` &outerClass=`menu`]]

помимо параметров с классами указываем уровень вложенности - &level=`2` .

Отмечаем недостатки - нет классов для пунктов меню верхнего уровня, нет тегов и класса для подменю.
Все эти недостатки исправляются добавлением соответствующих параметров к вызову Wayfinder.

5.2. Добавляем классы к пунктам верхнего уровня и теги

Для этого есть переменная rowTpl , которая описывает шаблон для пункта меню, делаем такой шаблон, для этого создаем чанк под названием parent:

  • [ +wf.linktext+][ +wf.wrapper+]
  • В вызове Wayfinder добавляем &rowTpl=`parent` .
    Не забываем проверять исходный код - уже почти все хорошо, осталось подменю.

    Для настройки подменю используем переменную innerRowTpl .

    Создаем чанк inner :

  • [ +wf.linktext+][ +wf.wrapper+]
  • Добавляем в вызов Wayfinder переменную innerRowTpl=`inner` и переменную, которая указывает класс для контейнера подменю &innerClass=`sub` .

    Окончательный вызов Wayfinder выглядит так:

    [ ]

    Всё, наше меню готово. Успехов!

    В прошлых уроках мы уже создавали MODX меню: 1й — и 2й — Вывод стандартного выпадающего MODX меню с использованием Bootstrap. Сегодня мы научимся выводить многоуровневые Bootstrap меню с неограниченно степенью вложенности (3х уровневое меню, 4х, 5ти и т.д.).

    Для примера я выведу 5-ти уровневое Bootstrap меню, вы же его сможете сделать и 3х уровневым и 7ми уровневым, хоть 10, поменяв значение level на нужное вам!

    Вывод многоуровневого Bootstrap меню (с неограниченной вложенностью) в MODX при помощи PdoMenu.

    Вывод многоуровневого меню будет таким:

    []>[[+wrapper]]` &tplInner=`@INLINE

    ` &tplParentRow=`@INLINE
  • [[+menutitle]][[+wrapper]]
  • ` ]]

    Из коробки оно работать не будет. так как Bootstrap 3 по умолчанию поддерживает только 2 уровня вложенности, и для того что бы расширить уровень вложенности bootstrap 3 меню, необходимо подключить js файл со следующим содержанием.

    (function($){ $(document).ready(function(){ $("ul.dropdown-menu ").on("click", function(event) { event.preventDefault(); event.stopPropagation(); $(this).parent().siblings().removeClass("open"); $(this).parent().toggleClass("open"); }); }); })(jQuery);

    После того начнется открываться 3й, 4й и т.д. уровни вложенности. В принципе все, но есть одно но, данное меню будет открываться вниз все уровни, а это по-моему не особо правильно и красиво, но это поправимо при помощи CSS.

    В моем случае получилось 2 строки CSS кода, чтобы уровни выпадали в бок.

    Ul.dropdown-menu {left: 100%;top: -8px;} li.submenu1.dropdown.open>ul.dropdown-menu {left: 0%; top: 100%;}

    У вас может получить немного другой (но идентичный этому) код и количество его строчек может быть больше в случае если у вас несколько веток меню с подменю. Ну и еще по мелочи придется поправить css под свой вкус, моя цель показать основу. Как найти нужные css классы в коде, к которым нужно применить стили показано в видео, ну а если быть точнее то там показан весь процесс создания многоуровневого меню.

    В моем видео вышло вот такое меню

    Если вам нужно повернуть треугольнички в выпадающем меню (они направлены в низ, когда выпадают элементы влево), что бы получилось вот так.

    Тогда добавьте следующий css код:

    Li.submenu2.dropdown>a>span.caret { -moz-transform: rotate(-95deg); -ms-transform: rotate(-95deg); -webkit-transform: rotate(-95deg); -o-transform: rotate(-95deg); transform: rotate(-95deg); } li.submenu3.dropdown>a>span.caret { -moz-transform: rotate(-95deg); -ms-transform: rotate(-95deg); -webkit-transform: rotate(-95deg); -o-transform: rotate(-95deg); transform: rotate(-95deg); } li.submenu4.dropdown>a>span.caret { -moz-transform: rotate(-95deg); -ms-transform: rotate(-95deg); -webkit-transform: rotate(-95deg); -o-transform: rotate(-95deg); transform: rotate(-95deg); }

    Сегодня мы сделаем меню для нашего блога с помощью сниппета Wayfinder (документацию по сниппету Wayfinder). Верхняя навигация и главная у нас на блоге состоит из двух частей:

    • Мобильная
    • Обычная

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

    &outerTpl=` wayOuterTpl` - чанк обертка основного списка

    &innerTpl=` wayInnerTpl` - чанк обертка выпадающего списка

    &rowTpl=` wayRowTpl`- чанк вывод элементов списка

  • [ [+wf.linktext] ]
  • &parentRowTpl=`wayHasChildTpl` - чанк вывод элементов списка-родителей

    И привожу вызов сниппета в чанке header:

    [ ]

    &startId=`0` - задаем начало прохода сниппета, в нашем случае от корня сайта.
    &level=`2` - количество уровней в нашем меню.

    Следующий шаг – вывод нашего мобильного меню. Принцип подобный тому, что я выше изложил, здесь нам тоже понадобится 4 чанка.

    &outerTpl=`wayOuterMobileTpl` - чанк обертка основного списка.

    &innerTpl=`wayInnerMobileTpl` - чанк обертка внутреннего списка.

    [ [+wf.wrapper] ]

    &rowTpl=`wayRowMobileTpl` - чанк вывод элементов списка.

    [ [+wf.wrapper] ]

    &innerRowTpl=`wayInnerRowMobileTpl` - чанк вывод элементов внутреннего списка.

    [ [+wf.wrapper] ]

    Вызов Wayfinder примет следующий вид:

    [ ]

    Все тоже самое, только изменились чанки. Теперь у нас есть мобильная навигация, проверить ее можете с помощью инструмента Responsive Web Design Tester для Opera и Chrome.

    Привожу полный код чанка header:

    Наша навигация готова! В видео мы еще рассмотрели создание меню категорий в блоге. Так как принцип один и тот же, то здесь рассматривать я не стал, смотрите видео) До встречи в следующих уроках!

    Но ведь это не для нас;).

    Мы же сделаем все с нуля. Зачем нам (мне) это понадобилось, ведь есть уже готовые варианты? Потому что мне так больше нравится. Потому что я считаю подобный подход наиболее верным. Потому что, умея разрабатывать свое, мы без труда сможем разобраться в чужом коде, изменить, исправить ошибки или дополнить его необходимым в конкретном случае функционалом. Да и, в конце концов, сделать свое - это зачастую так приятно!

    Дальнейшее повествование будет подразумевать, что читатель обладает минимальным знанием PHP программирования. Теоретически те люди, которые совсем не понимают код, смогут скопировать код и воспроизвести все те действия, о которых пойдет речь ниже. Однако, возможно, для них будет лучше использовать готовые сниппеты а-ля Ditto, поскольку они предоставляют кучу возможностей для внешнего конфигурирования, не влезая в основной код.

    Я не хочу дискутировать на тему, что лучше для пользователя - брать готовое или разрабатывать свое... И в том, и в другом случае есть свои плюсы и минусы. Лично для меня плюсов во втором варианте больше. Также и каждый из читателей определится сам.

    Итак, взглянем вновь на наш . Поскольку разных программных частей в нашем сайте довольно много, а начинать с чего-то нужно, поэтому запрограммируем…

    Верхнее меню

    Под термином "верхнее меню" я понимаю набор ссылок на страницы в верхней части сайта (см. рисунок ниже):

    Первый пример создания сниппета я опишу очень подробно, в дальнейшем я буду останавливаться в основном на наиболее существенных деталях.

    Сравним с нашим деревом сайта в системе управления, которое мы построили в предыдущей статье:

    Как видно из рисунка, в дереве сайта выделяются четыре документа (а именно "Блог", "Об авторах", "Фотографии" и "Обратная связь"), которые и создадут впоследствии ссылки в верхнем меню.

    Также напомню, мы заранее скрыли документы, которые не хотим показывать в меню. Например, в настройках документа с названием "Поиск по сайту" убрали флажок "Показывать в меню", а оставшиеся два документа "Ссылки" и "Категории" мы скрыли на сайте, убрав флажок в настройках документа "Публиковать" (закладка "Настройки страницы" в настройках документа).

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

    Перейдем теперь к вопросу отображения наших действий непосредственно на сайте.

    Большую часть программ на сайте выполняют т.н. " ", т.е. отдельные куски кода (их также можно понимать как отдельные функции или подпрограммы) на PHP. Поэтому, чтобы реализовать в MODx вывод верхнего меню, мы также должны создать новый сниппет, запрограммировать его и добавить вызов этого сниппета в шаблоне в нужном месте.

    Зайдем в систему управления, откроем закладку "Ресурсы" -> "Управление ресурсами" -> закладка "Сниппеты" и нажмем на ссылку "Новый сниппет". В поле "Название сниппета" впишем "TopMenu" без кавычек и пока просто сохраним пустой сниппет без кода. После сохранения мы увидим название нашего сниппета на закладке "Сниппеты".

    Напомню, что в нашем шаблоне верхнее меню мы вынесли в чанк "TOPMENU". Переключимся на закладку "Чанки" и откроем чанк " ". В содержимом этого чанка мы увидим следующий код:


    • Блог

    • Об авторах

    • Фотографии

    • Обратная связь

    Этот код как раз и создает наше меню. Закомментируем его и добавим вызов сниппета "TopMenu" в чанке:


    []

    Здесь снова придется немного отвлечься, чтобы пояснить смысл этой конструкции []. Дело в том, что именно с помощью конструкций вида [] или [!SnippetName!] мы можем делать вызовы сниппетов в любом месте своих шаблонов, чанков и даже просто на любой отдельной странице сайта.

    При этом конструкция [] обозначает вызов кэшируемого сниппета, т.е. вызов динамической подпрограммы, результат выполнения которой будет подсчитан и выполнен один раз, а впоследствии при загрузке страницы, где вызывается данный сниппет, результат будет неизменным, т.к. повторный вызов сниппета уже не происходит. Таким образом, мы экономим ресурсы своего веб-сервера (а это всегда имеет очень важное значение при высокой посещаемости ресурса).

    Однако существуют ситуации, когда необходимо все время выполнять код сниппета заново и кэшировать результаты нельзя. В таких случаях используется конструкция [!SnippetName!], которая всегда заставит сниппет выполняться без кэширования. По аналогии, данная конструкция называется вызовом некэшируемого сниппета.

    Итак, сохраним чанк "TOPMENU" и обновим страницу сайта. Хм, как ни странно, но верхнее меню исчезло. Но так ли это удивительно на самом деле? Закомментировав HTML код меню в чанке, мы скрыли его отображение в браузере (проверьте это, взглянув в исходный код HTML страницы). А наш сниппет "TopMenu" ничего не делает, поскольку в него еще ничего не добавлено. Исправим же этот недостаток:).

    Перейдем снова на закладку "Сниппеты", откроем созданный сниппет "TopMenu" и попробуем протестировать его возможности… Терпение, мои продвинутые читатели, не всем знакомы эти детали.

    Для начала напишем простейший код (обычный PHP код):

    echo "Testing…";
    ?>

    Перед сохранением выберем "Продолжить редактирование", т.к. нам придется еще не раз изменить содержимое нашего сниппета, и после этого сохраним сниппет. Обновим страницу сайта и увидим на месте верхнего меню… ну, по правде говоря, на первый взгляд мы не увидим почти никаких изменений, кроме слегка расширившегося синего фона меню. Нажмем "CRTL+A", чтобы выделить весь текст на странице сайта, и увидим, что все-таки наш сниппет вывел на месте меню текст "Testing…", просто цвет текста совпадает с цветом фона.

    Изменим код сниппета на следующий:

    echo "Testing...";
    ?>

    Теперь мы ясно видим, что сниппет наш работает и даже (!) выводит некоторый текст. Что-ж, это прекрасно, но маловато для нашей задачи, поскольку мы должны добиться, чтобы наш сниппет выводил ссылки из системы управления, причем в точно таком же HTML коде, который мы закомментировали в чанке "TOPMENU".

    И снова небольшое отвлечение...

    Вся система взаимосвязей документов в MODx построена по принципу: каждый "родительский документ" содержит от нуля до множества "дочерних документов" ("parent" -> "childs").

    Каждый документ в базе данных MODx имеет свой уникальный идентификатор "ID" - это то число, которое мы видим в скобках в дереве сайта рядом с каждым из документов.

    Кстати говоря, этот уникальный идентификатор несет лишь одно единственное значение - он однозначно определяет конкретный документ в системе управления и ничего более ! Специально делаю акцент на этом факте, поскольку встречал неоднократные попытки изменить эти идентификаторы в самых разнообразных целях... Запомнить нужно сразу, что это просто бессмысленно, поэтому не пытайтесь менять эти цифры. На них вообще не стоит обращать много внимания, обычно эти цифры используются просто для генерации ссылок на определенные документы.

    В базе данных MODx для каждого документа также создано специальное поле "parent". Значением данного поля является число, обозначающее либо уникальный идентификатор родительского документа, либо, если документ находится в корне дерева, нуль. Таким образом, всегда можно однозначно определить, какой именно документ является для данного родительским.

    Чтобы наглядно увидеть то, о чем мы сейчас говорили, откройте phpMyAdmin, выберите свою базу данных и найдите таблицу {PREFIX}site_content, где {PREFIX} - Ваш префикс, который Вы ввели при установке. Вы увидите множество полей, в которых сохраняются определенные данные документов, в том числе "ID" - уникальный идентификатор, "parent" - номер родительского документа, "pagetitle" - заголовок страницы и другие.

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

    Используя SQL язык, подобный запрос описывается как-то так (Вы можете попробовать ввести данный запрос в поле ввода SQL в phpMyAdmin, предварительно заменив "modx_" на свой префикс):

    SELECT *
    FROM `modx_site_content`
    WHERE `parent` = 0;

    Однако такой запрос возвратит нам абсолютно все документы из корня сайта, что не совсем правильно, исходя из основной задачи - вывести ссылки только на те документы, которые имеют:

    • опубликованный статус (в БД за этот пункт отвечает поле "published", где значение = 1 обозначает, что документ опубликован, а значение = 0 - неопубликован).
    • неудаленные (поле "deleted", где 1 - удален, а 0 - не удален),
    • и у которых установлена опция "Показывать в меню" (поле "hidemenu", где 1 - скрывать, а 0 - показывать в меню).

    Кроме того, забегая немного вперед, мы сразу отсортируем документы по параметру "Позиция в меню", который будет определять позицию каждой ссылки в нашем меню.

    Ну, с точки зрения SQL, это совсем несложная задача и решается она так:

    SELECT *
    FROM `modx_site_content`
    WHERE `published` = 1
    AND `parent` = 0
    AND `deleted` = 0
    AND `hidemenu` = 0
    ORDER BY `menuindex` ASC;

    Теоретически все SQL запросы можно выполнять в сниппетах напрямую с помощью PHP скриптов, подключая каждый раз базу данных заново и делая множество других рутинных операций, повторяя их раз за разом… Но, согласитесь, это нивелировало бы смысл использования фреймворка, коим безусловно является наша система управления, т.к. MODx, помимо прочих своих достоинств, предоставляет готовый набор средств программного интерфейса (API, Application Programming Interface). API - это программные функции, которые унифицируют и облегчают многие процессы обработки данных.

    Используем одну из упомянутых функций API "getDocumentChildren " в нашем сниппете. Функция "getDocumentChildren" получает в виде параметров следующие данные:

    • $id - номер родительского документа,
    • $active - выбирать только опубликованные или неопубликованные документы (1 или 0 соответственно),
    • $deleted - выбирать только удаленные или неудаленные документы (1 | 0),
    • $fields - поля, которые выбираются из БД,
    • $where - специальные условия, т.е. условие WHERE в SQL запросе,
    • $sort - поле, по которому должна проводиться сортировка результатов
    • $direction - направление сортировки, может принимать значения ASC или DESC, т.е. сортировка от меньшего к большему значению или наоборот
    • $limit - ограничение запроса, т.е. условие LIMIT в SQL запросе

    $results = $modx->getDocumentChildren(
    $id = 0,
    $active = 1,
    $deleted = 0,
    $where = "hidemenu = 0",
    $sort="menuindex",
    $dir="ASC",
    $limit
    );

    Print("

    Foreach($results as $key => $value) {
    print_r($value);
    }

    Print("");
    ?>

    Сохраните сниппет и обновите страницу. В результате выполнения обновленного сниппета "TopMenu" Вы увидите список из массивов и их значений, отсортированный по значениям поля "menuindex" от меньшего значения к большему. Попробуйте поменять параметр $dir="ASC" на $dir="DESC" - в результате массивы перестроятся и первым документом будет выведен документ с наибольшим значением поля "menuindex".

    Программистам со стажем, наверное, понятно, что полученный результат уже дает все, что нужно, чтобы построить готовое меню со ссылками. Ну, почти все. В любом случае я таки продолжу: перепишем код PHP, чтобы максимально приблизиться к желаемому результату.

    $results = $modx->getDocumentChildren(
    $id = 0,
    $active = 1,
    $deleted = 0,
    "id, pagetitle, published, menuindex, deleted, hidemenu, menutitle",
    $where = "hidemenu = 0",
    $sort="menuindex",
    $dir="ASC",
    $limit
    );

    $items = "";
    $output = "";

    Foreach($results as $key => $value) {
    $items .= "


  • ".$value["pagetitle"]."
  • \n";
    }

    If ($items != "") {
    $output = "

      \n";
      $output .= $items;
      $output .= "
    \n";
    }

    Return $output;

    Детально код разбирать не будем, поскольку это самый обычный PHP код, не более того. Если кому-то не понятен смысл каких-либо конструкций, прошу в комментарии, а лучше - на соответствующие форумы поддержки.

    Сохраним новый код сниппета и обновим страницу. В результате выполнения кода мы увидим практически то, что и хотели получить:

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

    Однако это еще не все. Многие уже наверняка заметили, что ссылки есть, но ссылок нет... Парадокс:). Я имею ввиду, что названия документов в меню выводятся, однако ссылки на них не работают. Это логично, поскольку пока в коде ссылок выводится "#" вместо реальных путей.

    Чтобы решить эту задачку, необходимо узнать еще об одной крайне полезной возможности MODx: адрес любой внутренней страницы сайта можно получить с помощью следующей конструкции [~id~], где id - это уникальный номер нужного документа, т.е. тот самый номер, указанный в скобках рядом с названием каждого документа в дереве сайта. Таким образом, добавив такую конструкцию [~1~] в шаблоне/чанке/содержимом страницы,

      • index – алиас документа "Блог", если мы ввели "index" как алиас документа, либо
      • 1.html, если мы не вводили ничего в поле "Псевдоним" для документа "Блог"
    • если дружественные ссылки отключены, то увидим текст index.php?id=1

    Перепишем сниппет, используя эту информацию:

    $results = $modx->getDocumentChildren(
    $id = 0,
    $active = 1,
    $deleted = 0,
    "id, pagetitle, published, menuindex, deleted, hidemenu, menutitle",
    $where = "hidemenu = 0",
    $sort="menuindex",
    $dir="ASC",
    $limit
    );

    $items = "";
    $output = "";

    Foreach($results as $key => $value) {
    $items .= "


  • ".$value["pagetitle"]."
  • \n";
    }

    If ($items != "") {
    $output = "

      \n";
      $output .= $items;
      $output .= "
    \n";
    }

    Return $output;

    Таким образом, мы изменили # на [~".$value["id"]."~], т.е. фактически для каждого документа из массива подставляется его уникальный ID внутри конструкции [~id~]. В результате мы получаем меню с работающими ссылками.

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

    Чтобы добиться этого, мы снова приоткроем секреты MODx CMS:). В API скрыта функция $modx->documentIdentifier , которая возвращает значение уникального идентификатора текущей страницы. Она нам понадобится для определения активной страницы и выделения ее в меню:

    $results = $modx-> getDocumentChildren (
    $id = 0,
    $active = 1,
    $deleted = 0,
    "id, pagetitle, published, menuindex, deleted, hidemenu, menutitle",
    $where = "hidemenu = 0",
    $sort="menuindex",
    $dir="ASC",
    $limit
    );

    $cid = $modx->documentIdentifier;

    $items = "";
    $output = "";

    Foreach($results as $key => $value) {
    if ($value["id"] == $cid) {
    $active = " id=\"active\"";
    }
    else {
    $active = "";
    }
    $items .= "
    ".$value["pagetitle"]."
    \n";
    }

    If ($items != "") {
    $output = "

      \n";
      $output .= $items;
      $output .= "
    \n";
    }

    Return $output;

    Ну как, получилось? Получилось!

    Но Вы же не подумали, что на этом все и закончится? И правильно. Мы ставим себе самую высокую планку, мы хотим задействовать максимум возможностей MODx. А поэтому еще одна небольшая деталь, которую мы упустили.

    Посмотрим внимательно на название полей, которые мы запрашиваем с помощью функции getDocumentChildren: "id, pagetitle, published, menuindex, deleted, hidemenu, menutitle". Среди них есть такое поле, как "menutitle". Как следует из названия, в данном поле может храниться заголовок меню . В системе управления также имеется поле ввода "Пункт меню". Это поле заполнять необязательно. Однако логика в том, что если это поле заполнено, то мы должны заменить текст ссылки в меню на введенный пользователем. Ну, так сделаем это:

    /********************************
    Название: TopMenu
    Цель: Вывод верхнего меню
    Проект: Демосайт MODx
    ********************************/

    $results = $modx->getDocumentChildren(
    $id = 0, // ID родительского документа
    $active = 1, // Выбираем только опубликованные документы
    $deleted = 0, // Выбираем только неудаленные документы
    "id, pagetitle, published, menuindex, deleted, hidemenu, menutitle", // Выбираем поля из БД
    $where = "hidemenu = 0", // Выбираем только те документы, которые нужно публиковать в меню
    $sort="menuindex", // Сортируем документы по полю menuindex
    $dir="ASC", // Сортируем документы по возрастанию
    $limit = "" // Ограничения не устанавливаем (параметр LIMIT в SQL запросе)
    );

    $cid = $modx->documentIdentifier; //получаем ID текущей страницы

    $items = "";
    $output = "";

    Foreach($results as $key => $value) {
    if ($value["id"] == $cid) {
    $active = " id=\"active\"";
    }
    else {
    $active = "";
    }
    if ($value["menutitle"] != "") {
    $title = $value["menutitle"];
    }
    else {
    $title = $value["pagetitle"];
    }
    $items .= "
    ".$title."
    \n"; //собираем пункты меню
    }

    // Если удалось найти хотя бы один пункт меню,
    // создаем HTML код меню
    if ($items != "") {
    $output = "

      \n";
      $output .= $items;
      $output .= "
    \n";
    }

    // Возвращаем результат работы сниппета
    return $output;

    Попробуйте теперь ввести какой-нибудь текст в поле ввода "Пункт меню" любого документа... Все работает? Замечательно!

    P.S.: Возможно, некоторые читатели будут удивлены, что при переходе по ссылкам нашего меню содержимое страниц не изменяется, хотя вроде бы, судя по пути в адресе браузера, мы переходим на новые страницы… Поверьте, это абсолютно нормально, т.к. абсолютно все страницы на текущий момент используют один и тот же шаблон. В этом шаблоне фактически мы пока сделали динамическим только верхнее меню, все остальные детали остаются неизменными. Мы обязательно займемся этим позже, а пока - без паники;).

    Заключение:

    Итак, еще одна статья подошла к своему логическому завершению.

    Итоги обучения:

    • Мы попробовали разобраться в назначении некоторых полей ввода документов MODx и рассмотрели хранение этой информации в базе данных;
    • Узнали о новых специальных конструкциях MODx: [], [!SnippetName!], [~id~];
    • Узнали о наличии специального API и воспользовались некоторыми функциями API;
    • И на основе этих знаний создали свой новый сниппет в MODx!


    © 2024 beasthackerz.ru - Браузеры. Аудио. Жесткий диск. Программы. Локальная сеть. Windows