Меню
Бесплатно
Главная  /  Интернет  /  Изменение верхнего меню. PdoMenu — создание меню в MODX Modx вертикальное меню

Изменение верхнего меню. PdoMenu — создание меню в MODX Modx вертикальное меню

Сниппет генерации меню. Может заменять Wayfinder, и позволяет более гибко указывать параметры.

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

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

Параметры

По умолчанию pdoMenu принимает общие параметры pdoTools и некоторые свои:

Название По умолчанию Описание
&parents Текущий ресурс Список родителей для поиска результатов, через запятую. Если поставить &parents=`0` - выборка не ограничивается. Если id родителя начинается с дефиса, он и его потомки исключаются из выборки.
&level 0 (не ограниченно) Уровень генерируемого меню.
&resources Список ресурсов для вывода в результатах, через запятую. Если id ресурса начинается с дефиса, этот ресурс исключается из выборки.
&templates Список шаблонов для фильтрации результатов, через запятую. Если id шаблона начинается с дефиса, ресурсы с ним исключается из выборки.
&where Массив дополнительных параметров выборки, закодированный в JSON.
&displayStart 0 Включить показ начальных узлов меню. Полезно при указании более одного «parents».
&context Ограничение выборки по контексту ресурсов.
&showHidden 0 Показывать ресурсы, скрытые в меню.
&showUnpublished 0 Показывать неопубликованные ресурсы.
&previewUnpublished 0 Включить показ неопубликованных ресурсов, если у пользователя есть на это разрешение.
&hideSubMenus 0 Спрятать неактивные ветки меню.
&select Список полей для выборки, через запятую. Можно указывать JSON-строку с массивом, например &select=`{"modResource":"id,pagetitle,content"}`
&sortby menuindex Любое поле ресурса для сортировки, включая ТВ-параметр, если он указан в параметре &includeTVs , например &sortby=`{"tvname":"ASC","pagetitle":"DESC"}` . Можно указывать JSON-строку с массивом нескольких полей. Для случайной сортировки укажите &sortby=`RAND()`
&sortdir ASC Направление сортировки: по убыванию или по возрастанию. Если оставить параметры &sortby и &sortdir пустыми, то сортировка будет идти по порядку ресурсов в &resources .
&limit 0 Ограничение количества результатов выборки.
&offset 0 Пропуск результатов от начала. Необходимо использовать вместе с явно указанным &limit
&checkPermissions Укажите, какие разрешения нужно проверять у пользователя при выводе ресурсов, например &checkPermissions=`list` .
&countChildren 0 Точный подсчет количества дочерних ресурсов каждой категории и вывод их в плейсхолдер [[+children]] . Делает дополнительные запросы в БД, поэтому по умолчанию отключен.
&toPlaceholder Если не пусто, сниппет сохранит все данные в плейсхолдер с этим именем вместо вывода на экран.
&plPrefix wf. Префикс для выставляемых плейсхолдеров.
&showLog 0 Показывать дополнительную информацию о работе сниппета. Только для авторизованных в контекcте «mgr».
&fastMode 0 Быстрый режим обработки чанков. Все необработанные теги (условия, сниппеты и т.п.) будут вырезаны.
&cache 0 Кэширование результатов работы сниппета.
&cacheTime 3600 Время актуальности кэша, в секундах.
&scheme -1 Схема формирования url, передаётся в modX::makeUrl(), поэтому возможные варианты нужно . Особый тип uri подставляет значение uri ресурса, без запуска функции.
&useWeblinkUrl 1 Генерировать ссылку с учетом класса ресурса.
&rowIdPrefix Префикс id="" для выставления идентификатора в чанк.
&hereId id текущего ресурса для генерируемого меню. Нужно указывать только если скрипт сам его неверно определяет, например при выводе меню из чанка другого сниппета.
&includeTVs Список ТВ-параметров для выборки, через запятую. Например &includeTVs=`action,time` дадут плейсхолдеры [[+action]] и [[+time]] .
&prepareTVs Список ТВ-параметров, с файлами из источников медиа, для которых нужно сгенерировать полные пути. Если установить &prepareTVs=`1` , будут подготовлены все ТВ, указанные в &includeTVs .
&processTVs Список ТВ-параметров, которые нужно обработать и вывести согласно их настроек в менеджере системы. Если установить &processTVs=`1` , будут обработаны все ТВ, указанные в &includeTVs . Замедляет работу.
&tvPrefix Префикс для ТВ-параметров.

Параметры шаблонов

Эти параметры устанавливают чанки, которые содержат шаблоны для генерации меню.

Название Описание
&tplOuter Чанк оформления всего блока меню. По умолчанию: @INLINE
    [[+wrapper]]
&tpl Чанк оформления пункта меню. Если не указан, то содержимое полей ресурса будет распечатано на экран. По умолчанию: @INLINE
  • [[+menutitle]][[+wrapper]]
  • &tplHere Чанк оформления текущего пункта меню.
    &tplStart Чанк оформления корневого пункта, при условии, что включен &displayStart . По умолчанию: @INLINE

    [[+menutitle]]

    [[+wrapper]]
    &tplParentRow Чанк оформления родителя с потомками, не подпадающего под условия &tplCategoryFolder . Например: @INLINE
    &tplParentRowHere Чанк оформления текущего документа, если он содержит потомков.
    &tplParentRowActive Чанк оформления родителей с потомками в активной ветке меню.
    &tplCategoryFolder Специальный чанк оформления категории. Категорией считается родитель с потомками, у которого указан пустой шаблон или rel="category" в поле link_attributes .
    &tplInner Чанк оформления всего блока подпунктов меню. Если пуст - будет использовать &tplOuter . Например: @INLINE
    &tplInnerRow Чанк оформления подпункта меню. Например: @INLINE
    &tplInnerHere Чанк оформления активного подпункта меню.

    Параметры CSS классов

    Эти параметры задают значение плейсхолдеров [[+classnames]] и [[+classes]] для различных элементов меню. Плейсхолдер [[+classnames]] выводит только название класса без атрибута class="" , в отличие от плейсхолдера [[+classes]] .

    Примеры

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

    []

    Вывод с исключением определенных родителей и проверкой разрешений пользователя:

    []

    Вывод меню сразу из двух родителей, с показом корневых точек:

    []

    Вывод двух уровней ресурсов с подсчетом количества вложенных:

    []` &tplParentRow=`@INLINE

  • [[+menutitle]] ([[+children]])
  • [[+wrapper]]` &countChildren=`1` ]]



    Wayfinder служит для организации списков ссылок для MODX. Благодаря поддержке шаблонов позволяет выводить списки в любом необходимом виде:
    • Меню в виде списка, таблицы, изображений, с иконками и т.д.
    • Статичные меню
    • Меню с различными эффектами (выпадающие, раскрывающиеся и т.д.)
    • Карта сайта
    Пример вызова:


    &rowTpl=`rowTpl`
    &outerTpl=`outerTpl`
    &hereClass=`active`
    &rowClass=`eNav_li`]]

    Параметры снипета:

    &startId - id родительской страницы, если указать 0 будет от корня сайта. По умолчанию стоит значение id активной страницы

    &displayStart - показывать документ со startId в заголовке меню, по умолчанию false

    &level - глубина вложенности, по умолчанию 0 - все уровни

    &limit - ограничение количества страниц в выводе (по умолчанию 0 - без ограничений)

    &ignoreHidden - игнорировать чек бокс страницы "Показывать в меню", т.е. если указать 1, выведет все страницы. По умолчанию 0. Выводятся только те страницы, у которых отмечен чек бокс "Показывать в меню"

    &ph - имя подстановщика, заменяющего непосредственно выводимые результаты. По умолчанию 0.

    &debug - режим отладки (по умолчанию 0)

    &hideSubMenus - раскрывать только активное подменю (по умолчанию 0)

    &removeNewLines - убирает символ переноса строки при выводе (по умолчанию 0)

    &textOfLinks - для названия ссылки меню. Возможные варианты: menutitle, id, pagetitle, description, parent, alias, longtitle, introtext . По умолчанию menutitle

    &titleOfLinks - для title ссылки меню.Варианты: menutitle, id, pagetitle, description, parent, alias, longtitle, introtext. По умолчанию pagetitle

    &rowIdPrefix - устанавливает id (rowIdPrefix + docId)для каждого элемента. По умолчанию 0

    &includeDocs - id документов через запятую, которые будут включены в меню (по умолчанию не указывается)

    &excludeDocs - id документов через запятую, которые будут исключены из меню (по умолчанию 0)

    &contexts - контекст для генерации меню. По умолчанию текущий.

    &startIdContext - Индентификатор контекста из которого берутся документы для формирования результата.

    &config - Внешний PHP файл, для хранения конфигурации Wayfinder (пример: core/components/wayfinder/configs).

    &scheme - Формат для генерации URL. Возможные значения (основанны на вызове makeURL API):

    1: (значение по умолчанию) URL по отношению к site_url;

    0: смотрите http;

    1: смотрите https;

    full: абсолютный URL начинающийся с site_url;

    abs: абсолютный URL начинающийся с base_url;

    http: абсолютный URL, заданный принуждённо в http-схеме;


    https: абсолютный URL, заданный принуждённо в https-схеме.

    &sortBy - Поле, по которому происходит сортировка. (по умолчанию menuindex)

    Варианты:

    id, menutitle, pagetitle, introtext, menuindex, published, hidemenu, parent, isfolder, description, alias, longtitle, type, template

    &sortOrder - Порядок сортировки. "ASC" или "DESC". По умолчанию ASC

    &where - JSON-стиль параметров фильтрации (Соответствует where в MySQL) . Например, когда необходимо скрыть блог или новости из дополнения Articles: &where=`[{"class_key:!=": "Article"}]`
    Примеры:
    вывод только папок: & where = `isfolder = 1

    &hereId - Определять текущий ID для использования в сниппете. Используйте значение [[*id]] если шаблон указан с помощью параметра hereTpl и activeRowParentTpl не применяеться корректно в пункте меню. По умолчанию текущий ид.
    Нужно указывать только если скрипт сам его неверно определяет, например, при выводе меню из чанка другого сниппета.

    &hereTpl - Шаблон hereTpl используется в момент, когда текущий пункт отображается в меню.
    Возможные плэйсхолдеры:
    [[+wf.classes]] - место для указания используемого CSS-класса (включает class=" ")
    [[+wf.classnames]] - содержит только название CSS-класса (не включает class=" ")
    [[+wf.link]] - адрес (href) для ссылки
    [[+wf.title]] - текст для title ссылки
    [[+wf.linktext]] - текст названия ссылки
    [[+wf.wrapper]] - место для вывода подменю
    [[+wf.id]] - вывод уникального идентификатора (id)
    [[+wf.attributes]] - вывод дополнительных атрибутов ссылки
    [[+wf.docid]] - идентификатор документа для текущего элемента
    [[+wf.subitemcount]] -количество элементов в папке
    [[+wf.description]] - выводит значения поля описания
    [[+wf.introtext]] - выводит значения поля интротекста

    Пример шаблона: [[+wf.linktext]][[+wf.wrapper]]

    Параметры шаблона

    Эти параметры указывают чанки, которые содержат шаблоны, которые будут генерировать вывод Wayfinder.

    В текущей версии Wayfinder для MODX Revolution, вы можете получить доступ к вашим кастомным TV используя плейсхолдеры префикса wf. , например [[+my_TV]]

    На момент написания статьи, будут возвращены только исходные значения TV - они не будут форматироваться. Например, если вашим TV является изображение - обычное использование такое TV внутри вашего шаблона будет возвращать полный полный тег изображения, но внутри шаблона Wayfinder - будет возвращён только путь к изображению.

    Если вы хотите обрабатывать TV, вы можете сделать это вызовом сниппета в пределах шаблона ряда Wayfinder (&rowTpl . Например ваш TV изображения называется icon и обычно для вывода в шаблоне используется примерно такой код:

    ... ...

    Но так как это не позволит вам обрабатывать TV, нужно заменить его на:

    ... ...

    И теперь внутри сниппета processTV помещаем следующий PHP код:

    getObject("modResource", $myId); return $doc->getTVValue($myTV);

    В результате возвращается полностью обработаное TV изображения.

    &outerTpl

    Название чанка содержащий шаблон внешнего контейнера.

    Доступные плейсхолдеры:

    • wf.classes - выводит классы взятый с набора параметров Wayfinder (включая атрибут class="")
    • wf.classnames - вывод названия классов (без class="")
    • wf.wrapper - вывод внутреннего содержимого (row).
      [[+wf.wrapper]]

    Параметр &innerTpl содержит такой же набор плейсхолдеров что и &outerTpl .

    &rowTpl

    Название чанка содержащий шаблон для элементов ряда меню.

    Доступные плейсхолдеры:

    • wf.classes - вывод классов (включая атрибут class="")
    • wf.classnames - вывод соответствующих классов (без class="")
    • wf.link - значение атрибута href="" для ссылки меню
    • wf.title - имя текста заголовка для ссылки от поля указанного в параметре &titleOfLinks
    • wf.linktext - текст для действующей ссылки, указанном в поле, переданным в параметре &textOfLinks
    • wf.wrapper - вывод внутреннего содержимого, например подменю
    • wf.id - вывод уникального ID атрибута. Вам нужно указать параметр &rowIdPrefix для того чтобы этот заполнитель мог получить значение. Значением является префикс + docId.
    • wf.attributes - выводит ссылку атрибутов для текущего элемента
    • wf.docid - идентификатор документа текущего элемента
    • wf.description - описание для текущего элемента
    • wf.level - текущий уровень вложенности

    Пример использования:

    [[+wf.linktext]][[+wf.wrapper]]

    Ещё один вариант:

  • [[+wf.linktext]] - [[+wf.description]] [[+wf.wrapper]]

  • Примеры

    Первого уровня


    [[!Wayfinder? &startId=`0` &level=`1`
    &rowTpl=`rowTpl`
    &outerTpl=`outerTpl`
    &hereClass=`active`
    &rowClass=`eNav_li`]]

    Код чанка outerTpl



      [[+wf.wrapper]]

    Код чанка rowTpl



      [[+wf.wrapper]]

    Второго уровня (в этом примере меню и пункты подменю были визуально на одном уровне

    [[!Wayfinder? &startId=`0` &level=`2`
    &rowTpl=`rowTplFooterMenu`
    &outerTpl=`outerTplFooterMenu`
    &innerTpl=`innerTplFooterMenu`
    &innerRowTpl=`innerRowTplFooterMenu`
    &hereClass=`active`]]

    Код чанка outerTplFooterMenu



    [[+wf.wrapper]]

    код чанка rowTplFooterMenu




    • [[+wf.title]]


    • [[+wf.wrapper]]

    код чанка innerTplFooterMenu

    [[+wf.wrapper]]

    код чанка innerRowTplFooterMenu



  • [[+wf.title]]


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

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

    Дальнейшее повествование будет подразумевать, что читатель обладает минимальным знанием 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!

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

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

    Это можно реализовать с помощью специальных инструментов 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`!]

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

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

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

    Создавать динамическое меню в MODX мы будем при помощи сниппета PdoMenu из пакета pdoTools . Перед тем как начать ознакомьтесь с основной документацией.

    Документация по pdoMenu

    Параметры

    Параметры шаблонов

    Параметры CSS классов

    Официальные примеры


    официальную документацию можете почитать здесь . А сейчас разберем самые типовые вызовы меню.

    Вызов PdoMenu

    Вариант 1 . На месте этого статического меню вызовем сниппет pdoMenu , для этого в дереве ресурсов, на вкладке “Элементы ” в разделе сниппеты разверните ветку pdoTools , далее нажмите на pdoMenu левой кнопкой мыши (не отпускайте кнопку) и перетащите этот сниппет в место, где вы хотите вызвать меню, далее в открывшемся окошке заполните необходимые параметры и нажмите «Сохранить «.

    Вариант 2 . Просто вручную пишем вызов.

    Типовые примеры

    Обычное одноуровневое меню

    К примеру у нас самое обычное меню, со следующей html разметкой.

    Получился вот такой код с вызовом меню:

    • &parents=`0` — список родителей (в моем случае я не ограничиваю выборку, так как я все равно выведу только определенные страницы);
    • &level=`1` — уровень вложенности (в данном случае ее нет);
    • &resources=`2,3,4,5` — список ресурсов которые нужно вывести в меню;
    • &firstClass=`0` — класс для первого пункта меню (не какого);
    • &lastClass=`0` — класс последнего пункта меню (не какого);
    • &outerClass=`top-menu` — класс обертки меню (подставляется в ul);
    • &hereClass=`current-menu-item` — класс для активного пункта меню (подставляется в li);
    • &rowClass=`menu-item` — класс одной строки меню (подставляется в li).

    Двухуровневое кастомное bootstrap меню

    Статический html код выглядит так:

    Код его вывода будет таким:

    Так же в следующем уроке я приведу еще пару выводов выпадающих меню, на основе bootstrap ( и , это для тех кто не уловил суть. Ну а далее сделаем .

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