(опрос) А как вы строите меню сайта?

В связи с тем, что в бекенде WayFinder морально устаревает, а со стороны фронтенда появляются более сложные задачи вёрстки меню, например комбинаций многоколоночных выпадающих пунктов (с особой вёрсткой) с обычными, комбинаций «mouseover» с нажатиями, не говоря о десктопных и мобильных версиях итд.
Вобщем всё сложнее структурируемо и шаблонизируемо, что ассоциация меню с деревом сайта с галочкой «показывать в меню» становится более запутывающей, то назрел вопрос, а как вы теперь строите и шаблонизируете меню сайта?

Целесообразен ли переход, как во всяких Joomla-х, на некое отдельное хранение меню, в частности, самое простое, что приходит на ум — дополнительная рабочая папка в дереве, где пункты меню собраны ссылками (очень ли плохо ли это для поисковиков?) и им в ТВ прописаны определённые свойства (многоколоночность, наличие подменю итд). Варианты уместить это всё более компактно в multi TV, или некие другие способы хранения данных (списки ID в чанках, полях EvoBabel для мультиязычных сайтов, GlobalPlaceholders), но чтобы потом можно было объяснить заказчику, обеспечив свободу в управлении.

Что касается сниппетов, тут проблем меньше, помимо самого WayFinder, есть варианты DLBuildMenu, DocLister c вложенным вызовом, обработчики multi TV, ...? Или может уже есть специальные сниппеты, назначающие пункты меню?

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

— Заодно, похожий вопрос. Бывают в папках с документами (например, папка «Проекты» со списком) — всякие рабочие папки (или подпапки) — всякий ajax, настройки отображений, категории, сборник поддокументов для доп. блоков (например, «новости этого проекта», или «руководство»), итд… Их как бы хочется отовсюду скрыть (если к примеру сам список проектов отображается много где). Было бы неплохо, наподобие с галочкой «Показывать в меню», иметь галочку «Рабочая папка», позволяющую скрыть этот документ как из меню, так и из всех выборок DocLister. НО, если перейти к другому способу построения меню, то на эти нужды можно приспособить как раз галочку «Показывать в меню»))

32 комментария

avatar
Большинство проблем с меню возникают из-за кривой структуры сайта. В нормальных условиях достаточно «показывать в меню» + условия выборки, в том числе и для служебных папок.

Способ со ссылками вполне рабочий, можно еще использовать Selector.

А со сложными меню проблема больше в шаблонизации и решить ее так, чтобы всем хорошо было, очень тяжело.
avatar
Спасибо за ответ. Если документы-ссылки нормально воспринимаются поисковиками, то да, доп.дерево становится нормальным решением.
avatar
«Целесообразен ли переход, как во всяких Joomla-х, на некое отдельное хранение меню,» — когда-то в Джумле именно эта, так сказать, фишка меня дико раздражала. Зачем плодить сущности без необходимости?

И про всякие много-колоночные супер-мега-меню: в 99% случаев, такие мега-меню нужны только для шаблонов, которые вы разрабатываете для продажи на Themeforest. Тамошние покупатели ценят «ляпоту» ))

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

Если у сайта хорошо проработана структура и навигация — такие меню не понадобятся.

Я считаю (об этом говорит мой многолетний UX- и SEO-опыт), что лучшая навигация — одноуровневая, максимум 2-х уровневая, не более 6-ти пунктов в каждом уровне.

А если уж у вас сайт на 3 миллиона позиций, и все-таки необходимы многоколоночные списки разделов — то в мобильник вы их все равно не впихнёте, придется что-то придумывать. А на десктопе такой список лучше вывести просто в виде ссылок на странице.
Комментарий отредактирован 2016-12-08 14:55:44 пользователем Aharito
avatar
Те же эмоции были когда-то насчёт Джумлы, и это обусловило мой выбор MODx :)

Но к сожалению, хитровыдуманные и многоколоночные меню это тренд, по крайней мере в Интернет-магазинах (http://www.lamoda.ru/ www.mediamarkt.ru), пользователь привыкает, значит и клиент, и, чтобы MODx не отставать, хочешь-не-хочешь, придётся рано или поздно подстроиться и чего-то выдумать)
avatar
У Ламоды и Медиамаркта сотни тысяч, миллионы товаров. Может, им это и нужно.

А насчет клиента… вы имеете в виду заказчика? ну, тут да — бывает, что никакие аргументы не помогают.
avatar
Касаемо стилизации и сложных раздвигушек — выпадушек использую и странные конфиги, и вложенные вызовы DocLister, GetField и т.п. В-общем, без изысков и достаточно просто

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

Менеджер меню в Joomla — это вещь, после которой только молиться, поститься и слушать радио «Радонеж»
avatar
wayfinder прекрасно справляется если мастерски владеешь css, кроме того есть шаблоны rowTpl и тд, что в принципе снимает вопрос махинаций с версткой (хотя я крайне редко их использую, обхожусь стилями)
JS использую только для разворачивания меню на мобилках

P.S. фраза «морально устаревает» как правило используется когда нет других аргументов
Комментарий отредактирован 2016-12-09 11:32:53 пользователем gtx59
avatar
Сложные меню всегда были и будут частными случаями, реализация которых зависит уже не только от инструментов, но и от самого вебразработчика.
avatar
(Сужу по постам сообщества) вроде как, от Ditto отказались в пользу DocLister из-за неудовлетворительной скорости работы, WayFinder, как я понимаю, из той же серии, те же темы про BreadCrumbs. Я использую старые WF и BC, наряду с DL, но может целесообразно уже посмотреть на DLBuildMenu, DLCrumbs итд.
avatar
Непривычно только от Wayfinder отказаться поначалу (:
avatar
Вообще не вижу проблем с Wayfinder. У него столько настроек шаблонов и стилей, что можно легко сделать меню почти любого вида. Ну а особо хитро свёрстанные и раздутые, как тут уже и сказали — это редкие индивидуальные случаи.
Причем, работает он быстро и всё в один-два запроса. Ставил я для некоторых случаев посложнее DLBuildMenu, так он делает несколько десятков запросов, а то и полторы сотни. Спасибо, не надо. В таких особых случаях лучше и своё что-то написать под конкретную задачу.
Для какой-то ситуации надо было мне извернуться с навигацией и пришлось расширить Wayfinder дополнительным событием на получение данных. Что-то типа prepare в DocLister. Указываем сниппет-обработчик в параметрах и, когда основные данные уже получены, можем с ними дополнительно поколдовать (изменить, добавить) и вернуть в Wayfinder для вывода.
avatar
Ставил я для некоторых случаев посложнее DLBuildMenu, так он делает несколько десятков запросов, а то и полторы сотни. Спасибо, не надо.
Что-то я такого не наблюдал. Да и откуда бы взяться сотне запросов? там же идет предобработка на PHP, а потом один вызов ДокЛистера.
Комментарий отредактирован 2016-12-10 05:22:24 пользователем Aharito
avatar
Такая ситуация возникала в случаях выборки на несколько уровней вложенности и с дополнительными параметрами. То есть там, где действительно требовалось что-то особенное в навигации. Вот и получилось, что DLBuildMenu мне не помог, а со всеми частыми навигационными задачами справляется Wayfinder. Поэтому я так и не понял зачем использовать DLBuildMenu.
avatar
В DLBuildMenu просто неоткуда брать полторы сотни запросов.
Пример в студию)
А использовать его удобно хотя-бы потому, что там есть prepare для особо извращенных случаев.
avatar
Извините, но уже найду примеров, так как в такой ситуации оставлять страницу было нельзя и задача была решена другим способом. Возможно, даже через prepare в Wayfinder.
Я рад, что кого-то полностью устраивает DLBuildMenu и ещё более рад тому, что существуют разные возможности решения задач.
avatar
Ну например взять вызов DocLister'а c &documents=`и тут список из 10 например документов через запятую`, то сколько будет вызовов, если есть с ТВ? :) причём вопрос, как думаете, он преобразовывает список в запросе в вид IN(список) или делает запрос для каждого документа? :)
Комментарий отредактирован 2017-01-25 15:52:27 пользователем zabudkin
avatar
У меня таких ситуаций нет. Искусственно лень создавать, и код лень смотреть.

Ну и как, в IN или нет? и чем в такой ситуации WF лучше?
avatar
На каждый документ вызов с JOIN для тв :)))
А Wayfinder я без понятия (но думаю, что там явно IN), я просто лопату кинул в огород @Agelnash :)) (не в обиду @Agelnash'у), чтобы покапал и оптимизировал, все ведь рады будут.

Просто, если делать с &parent и с &addWhereList,
либо с &filters=`AND(content:id:in: тут список через запятую` !])`, то намного шустрее.

НО! САМОЕ ШУСТРОЕ, это ONETABLE и addWhereList :) естественно, за что @Agelnash'у огромное благодарствие! ;)
Комментарий отредактирован 2017-01-25 17:07:15 пользователем zabudkin
avatar
Дело в том, что JOIN — оптимально для фильтрации по ТВ. То, что на каждый документ вызов — надо смотреть, здесь я не готов ничего сказать.

А вот у WF может и IN, но там нет фильтрации по ТВ.
avatar
О! пока я отвечал, вы коммент отредактировали.
avatar
А Agel_Nash по его словам Эво забросил, и больше не желает ничего оптимизировать )
avatar
Ну и ладно )
avatar
У меня почему-то выбирает одним запросом (да и с чего бы было по-другому). Если убрать сортировку по тв, то и джойна не будет в запросе:

$modx->runSnippet('DocLister',['idType'=>'documents','tvList'=>'image','documents'=>'1,2,3,4,5,6,7,8,9,10','debug'=>1,'orderBy'=>'image ASC']);


action time: 7,0E-5 · total time: 0,00052
SELECT 
  id, 
  name 
FROM 
  `test`.`modx_site_tmplvars`
action time: 0,00076 · total time: 0,00082
SELECT 
  c.* 
FROM 
  `test`.`modx_site_content` as `c` 
  LEFT JOIN `test`.`modx_site_tmplvar_contentvalues` as `dltv_image_1` on `dltv_image_1`.`contentid` = `c`.`id` 
  AND `dltv_image_1`.`tmplvarid` = 5 
WHERE 
  c.id IN (
    '1', '2', '3', '4', '5', '6', '7', '8', 
    '9', '10'
  ) 
  AND c.deleted = 0 
  AND c.published = 1 
GROUP BY 
  c.id 
ORDER BY 
  `dltv_image_1`.`value` ASC
action time: 0,00027 · total time: 0,00164
SELECT 
  tmplvarid, 
  value, 
  contentid 
FROM 
  `test`.`modx_site_tmplvar_contentvalues` 
WHERE 
  contentid IN(
    '1', '2', '4', '8', '9', '10', '3', '5', 
    '6', '7'
  ) 
  AND tmplvarid IN(5)
action time: 6,0E-5 · total time: 0,00194
SELECT 
  id, 
  name, 
  default_text as value, 
  display, 
  display_params, 
  type 
FROM 
  `test`.`modx_site_tmplvars` 
WHERE 
  id IN(5)


C &parents и &addWhereList основной запрос сильно не меняется, поэтому опять не понятно, с чего бы такой вызов был быстрее (при том, что общее количество запросов с &parents больше):

action time: 0,00127 · total time: 0,00131
SELECT 
  c.* 
FROM 
  `test`.`modx_site_content` as `c` 
  LEFT JOIN `test`.`modx_site_tmplvar_contentvalues` as `dltv_image_1` on `dltv_image_1`.`contentid` = `c`.`id` 
  AND `dltv_image_1`.`tmplvarid` = 5 
WHERE 
  c.id IN (1, 2, 3, 4, 5, 6, 7, 8, 9, 10) 
  AND c.parent IN ('0', '2', '4', '6', '7') 
  AND c.id NOT IN('0', '2', '4', '6', '7') 
  AND c.deleted = 0 
  AND c.published = 1 
GROUP BY 
  c.id 
ORDER BY 
  `dltv_image_1`.`value` ASC
avatar
Видимо моя ошибка в том, что я использую OrderBy и SortBy и не по одному полю? Но они вроде не должны влиять, они же тупо копируются в Where? так?
avatar
Да, я добавил в orderBy несколько полей, все верно выбралось. Неправильный запрос еще может получиться, но чтобы 10 запросов — никак нет.
avatar
А у меня нет! :)
запрос на каждый документ…
[!DocLister?  &display=`[+GET_display:ifempty=`12`+]` &paginate=`offset`
	&id=`products` &parents=`64` &PrevNextAlwaysShow=`0` &display=`30` 
    &parentField=`parentTOP` &table=`carts_products` &controller=`onetable`
	&pageAdjacents=`4`
	&TplNextP=`@CODE: <li><a id="button-next" class="[+GET_ajax+]" data-levajax="#products" href="[+link+]">Следующая</a></li>`
	&TplPrevP=`@CODE: <li><a id="button-prev" class="[+GET_ajax+]" data-levajax="#products" href="[+link+]">Предыдущая</a></li>`
	&TplPage=`@CODE: <li><a class="[+GET_ajax+]" data-levajax="#products" href="[+link+]">[+num+]</a></li>`
	&TplCurrentPage=`@CODE: <li><a id="button-prev" class="[+GET_ajax+]" data-levajax="#products" href="[+link+]"><b>[+num+]</b></a></li>`
	&TplWrapPaginate=`@CODE: <div class="[+class+]"><ul class="pager">[+wrap+]</ul></div>`
	&orderBy=`TPrice ASC`
	&addWhereList=`zID='[*id*]' AND deleted=0 AND ZMOD='Активна' AND TIMGstatus='1'	
	AND pagetitle  LIKE '%[+GET_search+]%'
	AND zC  LIKE '%[+GET_cat+]%'`		
    &tpl=`tplPublicListTovarsCUSTOM` !]
<@ENDIF>	
avatar
А в tplPublicListTovarsCUSTOM что?
avatar
<a name="tovar[+id+]">
 <div id="tovar[+id+]"  class="product-card">
	<div class="image">
	
   [!if? &is=`[+TSizes+]:!empty`
	  &then=`
    <div class="overlay2"  style="background-color: white; opacity: 0.7;">
		<p align="center"  style="background-color: white; opacity: 0.7;font-size:0.9em;" class="text-info" title="Доступные размеры"><b>
			[+TSizes+]</b>		
	</div>
	`!]		
	[!if? &is=`[+TColors+]:!empty`
	  &then=`
	<div class="overlay3" style="background-color: white; opacity: 0.7;">
		<p align="center" class="text-info"   style="background-color: white; opacity: 0.7;font-size:0.9em;" title="Доступные цвета">
			[+TColors+]		
	</div>
	`!]

			 <div class="product-image">
				<a class="various"  data-fancybox-group="products" data-fancybox-type="iframe"
					hrefold="product.html?pid=[+id+]" href="[~[+id+]~]?preview=yes">
					<img class="img-responsive main-img" 
						src="[+TIMGu+]" data-toggle="tooltip" title="[+pagetitle+]" alt=""></a>				
			 </div>
			<div class="overlay">
			<p class="text-danger text-right">
				<b><span style="background-color:rgb(251,213,181);">
				  [+TPrice+] <i style="font-size:0.7em;" class="fa fa-rub"></i>  
				</b></span>
			</div>	
[!if? &is=`[+Stars+]:>:0`
 &then=`
	        <div class="overlay">					
				<input  id="rating[+id+]"  name="rating[+id+]" class="rating-loading rating-lev" value="[+Stars+]" title="[+Stars+]/5" dir="ltr" data-size="lev">
				<script>					
$(document).on('ready', function(){
    $("#rating[+id+]").rating({
		clearCaption: 'Нет оценок',
displayOnly: true});
					});								
				</script>							
				</div>	
` !]		 
	 </div>

		    <div class="product-info">
	<a href="[~[+id+]~]" data-toggle="tooltip" 
	  title="[+TOpis+]">
	[+pagetitle+]</a>
				
   </div>
 </div>
</a>
avatar
Если включено использовать AliasListing только для Папок, тогда будут на каждый документ запросы для построения ссылок.
avatar
Да, только для папок. А разве иначе тормозней не будет?!
avatar
Будет после какого-то количества документов. Здесь в общем-то можно бороться с количеством запросов, задать &makeUrl=`0` и сформировать ссылки вручную. Например, так: [~[+parent+]~][+alias+].html
Комментарий отредактирован 2017-01-25 22:23:02 пользователем Pathologic
avatar
У меня по 10000+ документов, как лучше сделать?
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.