В этой статье я расскажу о навигации на finar.ru Сердцем навигации сайта станет довольно необычная штука. Не строгая "древовидная" сортировка по разделам, и не бесформенное "облако тегов", а некий их симбиоз - древовидные теги. Вся эта система работает уже сейчас и ее можно посмотреть по адресу SiteMap.SiteMap
Корневая идея навигации сайта в следующем: есть классические "структурные" страницы, служащие каким-то практическим целям, вроде рассказа об услугах веб-студии или портфолио, и есть База. База - это единое пространство для всего. Для любого контента, мыслей, идей, рассказов, видеороликов, технических советов, находок, ссылок, статей и так далее. В Базу попадает все, что я (и не только я) хочу выложить в Сеть. База безгранична, также как сознание, и должна подлежать безграничному числу критериев сортировки.
Как некий поток сознания, База не может предъявлять к своему контенту каких-либо строгих требований, она должна адаптироваться к любому материалу, а сам материал не должен содержать никаких жестких однозначных структурных связей с окружающим контентом. В Базе контент как бы плавает в безграничном пространстве и связывается в стихийные образования самыми разными способами.
К контенту нет никаких требований, кроме наличия хотя бы одного тэга. Тэги - простые слова - целиком и полностью описывают тематическую направленность контента и его связь с окружающим контентом, и являются единственным "настройками". Доступ к материалу в навигации сайта будет определяться только его тэгами, и ничем больше.
Как это придумано
Структура тематических тэгов может выглядеть так:
- Веб-технологии
- видео
- ...
Здесь тэг "веб-разработка" выводит все статьи по веб-разработке, а также по netcat и pmwiki. Кроме того, параллельно существует вторая группа тэгов, различающих типы материалов:
- блог
- FAQ
- лекции
- ...
Обязательным являются только тэги первой (тематической) группы, т.к. невозможно написать пост ни о чем (т.е., конечно, возможно, но не на этом сайте :)). Только после проставления тематического тэга материал появится на сайте в общей структуре. Тип материала при этом может быть не определен. Группы тэгов, а также уровни их вложенности, служат дополнительными критериями сортировки и фильтрации материалов. Так, в разделе Веб-технологии может быть реализована дополнительная сортировка как по вложенным тематическим тэгам (netcat, pmwiki и т.д.), так и по типовым (блоги, FAQ и т.д.) Кроме того, группы тэгов можно использовать просто как пассивные метки при выводе списка материалов.
Тэги отвечают не только за тематическую сортировку, но и за навигацию, и могут использоваться для создания уникальной навигации в каждом конкретном случае. Так, навигация внутри тэга "видео" будет отличаться от "веб-разработки", а в "блогах" те же материалы будут представляться по-блоговски.
Да, разумеется каждый материал может получить любое число тэгов, быть сразу и блогом, и лекцией, и про pmwiki, и про видео. При этом он появится в навигации каждого из этих тэгов, причем в каждом случае будет анонсирован именно так, как это наиболее удобно для этого тэга.
SiteMap.SiteMap решает задачу глобальной навигации, собирая все тэги в одном месте и позволяя увидеть всю картину сайта целиком.
Тэги в PmWiki
Чтобы объяснить технический способ реализации задумки, необходимо сначала слегка углубиться в концепцию тэгов PmWiki. В PmWiki тэгов нет. Вместо них приняты категории - страницы специальной группы ("Category", по-умолчанию), являющиеся специальными ссылочными репозиториями. Единственное отличие категорий от остальных страниц в том, что создать ссылку на них можно сокращенным синтаксисом, вот таким [[!PmWiki]]
В остальном, никаких отличий от любых других страниц нет.
Чтобы страница "попала" в категорию, достаточно где-либо в ней сделать ссылку на эту категорию. Чтобы категория заработала, достаточно в качестве содержания этой страницы вывести "обратные ссылки", т.е. все страницы, которые ссылаются на нее. Чтобы полностью автоматизировать работу категорий, этот функционал надо прописать в GroupHeader или GroupFooter для всей группы. В этом случае, даже при полном отсутствии контента, существующая страница Категории вернет список ссылающихся на нее страниц. Таким образом, чтобы создать новую категорию от автора будет требоваться только два действия: создать ссылку на нее в контенте страницы и, если такая категория еще не создана, создать соответствующую страницу с пустым контентом. Последнее действие также можно автоматизировать примерно вот таким кодом в config.php:
$AutoCreate['/^Category\./'] = array( 'ctime' => $Now, 'text' => $page['text'] );
Категории никак не отличаются от прочих страниц, ссылки на них ничем не отличаются от других ссылок, а потому они все вместе вперемешку хранятся в отдельном поле "targets" физического файла wiki-страницы (в директории /wiki.d).
Все это здорово, предложенное решение прелесть какое простое, но есть следующие недостатки:
- чтобы страница, ссылающаяся на категорию, не попала в нее, необходимо использовать сложный синтаксис
[[{Category.Subject$PageUrl}|ссылка]]
- чтобы назначить категорию, в контенте страницы необходимо поставить ссылку на нее (можно обойти, например, поместив "ссылку" в ConditionalMarkup
(:if:)
) - наконец, и это самое существенное, предполагается, что блок вывода списка категорий, к которым относится страница, будет реализован в контенте страницы. Это нехорошо с архитектурной точки зрения: контент смешивается с дизайном сайта. Ведь блок с категориями (тэгами) должен быть как-то визуально оформлен? Практика показала, что лучше всего, если в верстке страницы тэги будут жить в отдельном слое (div'е), никак не связанном с основным контентом. Даже если категоризировать статью с помощью скрытых ссылок, они попадут в одно поле с прочими ссылками этой страницы, и вывести их отдельно не получится.
Решить эти проблемы в дефолтной конфигурации PmWiki, похоже, невозможно, но тут на помощь приходит Tagger , локализующий последние две.
PmWiki Tagger
Перед подключением плагина в конфиге системы определяются переменные - "группы тэгов":
##step2: создаем систему навигации $TaggerGroups['Type'] = 'Type'; $TaggerGroups['Theme'] = 'Theme'; include_once("$FarmD/cookbook/tagger.php");
Их может быть бесконечное число. Что делает tagger.php? Если Page Text Variable, заданная на странице, совпадает с определенной в конфиге, то tagger.php добавляет в поле targets страницы значения вида PTV.var1 PTV.var2
, где PTV - название переменной, varN - значения.
Пример:
{:Theme:Video,Web:}{:Type:FAQ:}
(замените фигурные скобки круглыми при копировании). Синтаксис совпадает с определением переменных страницы, поэтому команды никак не будут отображены в контенте. В поле targets данной страницы, наряду со ссылками из "тела" статьи, будут записаны следующие значения: Theme.Video, Theme.Web, Type.FAQ
При этом мы остаемся в рамках концепции PmWiki: чтобы вывести все статьи категории Theme.Video, достаточно сделать pagelist по всем страницам, ссылающимся на данную (примерно так: (:pagelist link={*$FullName} list=normal:)
)
Но это еще не все: tagger.php умеет также "распарсивать" обратно поле targets, вычленяя из многих ссылок, записанных там, свои категории. Для каждой страницы автоматически создаются переменные вида PTVLinked, содержащие ссылки на соответствующие категории.
Так, в нашем примере командой $ThemeLinked из массива значений поля targets мы выведем ссылки на Theme.Video и Theme.Web заголовкам этих страниц. Очень удобно. Этот код можно встроить в шаблон вашего дизайна в любом месте, просто включив обработку wiki-кода в этом месте.
Недостатки tagger.php:
- невозможность выделить настройку в отдельное ~GUI-поле, но он, похоже, неустраним, т.к. поле target содержит также и другие ссылки со страницы, т.е. запись в него должна происходить в момент сохранения страницы исходя из ее содержания. Если, конечно, мы хотим остаться в рамках ядра и концепции системы и не планируем выносить Категории в отдельную переменную (т.е. не в targets);
- одна наследственная проблема остается: чтобы страница, ссылающаяся на категорию, не попала в нее, необходимо использовать сложный синтаксис
[[{Category.Subject$PageUrl}|ссылка]]
; - сыроватый парсер: определение категорий должно находиться в конце страницы, по одной категории на строчку и без пробелов до и после определения;
- сыроватый парсер 2: парсит категории даже если они помечены как исходный код
Как это сделано
На самом деле, tagger.php лишь обеспечивает более удобный способ создания категорий, и при всей своей полезности не имеет почти никакого отношения к задуманной структуре навигации, о реализации которой я собирался рассказать.
Но после всего сказанного, мне что-то лень подробно рассказывать об этом. Думаю, получив всю эту предварительную информацию, с фактическим устройством навигации вы легко разберетесь самостоятельно, просто изучив исходные коды карты сайта и разных тэгов.
Отмечу лишь пару моментов:
- иерархическая вложенность тэгов обеспечивается именным наследованием - вложенный тэг всегда состоит из имени родителя и суффикса
- т.к. в PmWiki пока еще не реализовано (но скоро должно!) использование Wildcards для параметра link команды pagelist, выборка статей в тэгах происходит довольно некрасивым образом примерно вот так:
$:Theme=*Web*
(выбираем все страницы, в контентных переменных которых (PTV) содержится конструкция, удовлетворяющая условию с регулярными выражением "*" - любое число любых символов). При появлении Wildcards эти несуразности следует заменить на что-то вродеlink=Theme.Web*
. Ну а пока кэширование нас спасет!
Оставить комментарий