Finar.ru
web.finar.ru
video.finar.ru
Темы для BootstrapNew!

Кровеносная система finar.ru - мультитэги с древовидной структурой

как все сделано

Автор: Филипп Казаков, дата: 2011-02-01, просмотров 5367
Тэги

В этой статье я расскажу о навигации на 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).

Все это здорово, предложенное решение прелесть какое простое, но есть следующие недостатки:

  1. чтобы страница, ссылающаяся на категорию, не попала в нее, необходимо использовать сложный синтаксис [[{Category.Subject$PageUrl}|ссылка]]
  2. чтобы назначить категорию, в контенте страницы необходимо поставить ссылку на нее (можно обойти, например, поместив "ссылку" в ConditionalMarkup (:if:))
  3. наконец, и это самое существенное, предполагается, что блок вывода списка категорий, к которым относится страница, будет реализован в контенте страницы. Это нехорошо с архитектурной точки зрения: контент смешивается с дизайном сайта. Ведь блок с категориями (тэгами) должен быть как-то визуально оформлен? Практика показала, что лучше всего, если в верстке страницы тэги будут жить в отдельном слое (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:

  1. невозможность выделить настройку в отдельное ~GUI-поле, но он, похоже, неустраним, т.к. поле target содержит также и другие ссылки со страницы, т.е. запись в него должна происходить в момент сохранения страницы исходя из ее содержания. Если, конечно, мы хотим остаться в рамках ядра и концепции системы и не планируем выносить Категории в отдельную переменную (т.е. не в targets);
  2. одна наследственная проблема остается: чтобы страница, ссылающаяся на категорию, не попала в нее, необходимо использовать сложный синтаксис [[{Category.Subject$PageUrl}|ссылка]];
  3. сыроватый парсер: определение категорий должно находиться в конце страницы, по одной категории на строчку и без пробелов до и после определения;
  4. сыроватый парсер 2: парсит категории даже если они помечены как исходный код

Как это сделано

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

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

Отмечу лишь пару моментов:

  1. иерархическая вложенность тэгов обеспечивается именным наследованием - вложенный тэг всегда состоит из имени родителя и суффикса
  2. т.к. в PmWiki пока еще не реализовано (но скоро должно!) использование Wildcards для параметра link команды pagelist, выборка статей в тэгах происходит довольно некрасивым образом примерно вот так: $:Theme=*Web* (выбираем все страницы, в контентных переменных которых (PTV) содержится конструкция, удовлетворяющая условию с регулярными выражением "*" - любое число любых символов). При появлении Wildcards эти несуразности следует заменить на что-то вроде link=Theme.Web*. Ну а пока кэширование нас спасет!

Оставить комментарий 


Ваше имя:
->