Вкусные URL'ы в Drupal

Аватар пользователя OldWarrior OldWarrior 12 апреля 2007 в 1:39

Доработанная и исправленная статья о формировании красивых синонимов URL в Drupal. Рассматривается возможность совместного использования модулей Path, Pathauto и CCK.

В начале был Path.

Вероятно, вы уже знаете, что в Drupal встроен модуль Path (по умолчанию выключен), позволяющий создавать синонимы (то есть - псевдонимы или алиасы) для документов. После включения модуля при создании или редактировании документа становится доступным дополнительное поле «Настройки адресов». В этом поле можно указать альтернативный синоним URL для документа. То есть, если страница «Мои друзья» на вашем сайте имеет фактический адрес www.mysite.com/node/17, а вам нужно, чтобы адрес был вроде www.mysite.com/aboutme/myfriends, то всё, что следует сделать - просто указать синоним aboutme/myfriends в этом поле (именно так, то есть - всё, что ниже «корневого» слеша):

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

Всё это так, и написано об этом тоже уже много. Но мне этого недостаточно. Я искал возможность максимально автоматизировать формирование алиасов, вместе с тем сохранив определённую гибкость в их создании. Попробую объяснить, что же именно я хотел.

Задачи.

Итак, я бы хотел:

  1. Сделать формирование всех алиасов максимально прозрачным, с тем, чтобы ввод синонима URL или не требовался (пусть Drupal сделает это за меня) или же был предельно простым.
  2. Мне нравится, когда URL'ы включают в себя расширение «.html». Согласен, это мега-архаизм и излишество, но такая уж у меня слабость. В общем, я хочу, чтобы все сформированные Drupal’ом ссылки на моем сайте имели на своём конце старое доброе «.html».
  3. Заставить Drupal формировать синонимы URL, учитывающие принадлежность документа к определенной категории (т.е. термину таксономии) и соответственно наследующие синоним, ранее определённый мною для этой категории.
  4. Наконец, определить различные правила формирования синонимов для различных типов содержания.
    • Например, я бы хотел, чтобы для блоговых нодов это было наподобие: blog/5.html, ..., blog/25.html, ..., blog/278.html, и т.д. и т.п. То есть URL должен включать в себя nid документа (или, возможно, дату).
    • Для других же, статических типов содержания, мне нужна была возможность явно указать синоним непосредственно документа (например, «myarticle»), а на Drupal переложить все заботы, связанные с формированием и включением в URL синонима категории (или полного «пути») перед документом и любимого мною «.html» на конце. В итоге должно было получаться что-то вроде articles/all/myarticle.html.

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

Автопилот: Pathauto.

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

Шаблон представляет собой комбинацию из динамических компонентов или фрагментов статического текста. Доступные для включения в шаблоны компоненты перечислены в довольно объёмном списке, находящемся ниже этих полей. В качестве таковых, например, могут выступать: заголовок документа, дата и время его создания, название категории или словаря, синоним категории, название меню, к которому относится документ и ещё ряд других компонентов. Я не буду здесь приводить этот список, он действительно длинный, но всё же советую вам внимательно с ним ознакомиться

Кроме того, в Pathauto встроен механизм транслитерации заголовков документов для компонента [title]. При желании вы сможете автоматически получать URL’ы вроде «kak-ya-otdihal-s-druzyami-na-more», базирующиеся на тексте заголовка. Для корректной работы этого механизма с русским языком следует переименовать файл i18n-ascii.example.txt в папке модуля в i18n-ascii.txt.

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

Итак, Pathauto допускает использование синонимов категорий ([catalias]) в качестве компонента шаблонов. Это хорошо, и значит, я смогу использовать эту особенность для формирования «пути» к документу, включающего в себя синоним термина таксономии, к которой относится материал. Также есть возможность сформировать URL’ы, комбинирующие синоним категории («путь») и дату создания документа, или его nid или ещё какой-либо компонент, и, наконец, моё любимое «.html» (!) в конце. На первый взгляд в нём есть всё то, что я хотел.

Однако, не всё. Если вы помните, я также хотел иметь возможность создавать свои синонимы для некоторых типов материалов. Но как «научить» Pathauto добавлять к автоматически формируемому «пути» мой синоним?

Здесь есть одна проблема, которая перечёркивает многие преимущества модуля, по крайней мере - в моём случае. Pathauto формирует всё, что от него требуется, но при этом обновляет все системные синонимы документа, привязывая вновь созданные модулем. И, к сожалению, модуль Pathauto не может использовать ранее назначенный синоним документа как компонент шаблона. Таким образом, все ваши попытки непосредственно указать синоним в поле «Настройка адресов» после первого же сохранения документа будут сведены на нет. А что делать, если, как я уже писал, я хочу сам назначать синонимы для документов определённого типа?

Выходит, что модуль Pathauto в чистом виде идеально подходит для автоматических машинно-правильных адресов. В моём случае это пригодилось бы при формировании URL'ов для блоговых нодов или других видов динамического содержания. Но для тех материалов, которые мне хотелось бы подавать как статические страницы, мне нужно нечто большее.

Гибкий рецепт: Path + Pathauto + CCK.

Каков же выход?

Выход в поиске способа предоставить модулю Pathauto информацию о предпочтительном URL документа. Эта информация должна быть сохранена вместе с документом, но отдельно от стандартного поля настройки адреса. Здесь мне поможет мощный инструмент для создания пользовательских полей в нодах Drupal'а - модуль CCK. Этот модуль позволяет добавлять различные виды полей к любым типам содержания и сохранять введенные в них данные в базе, как дополнительные данные для каждого нода. Это именно то, что мне нужно, поскольку CCK экспортирует имена полей в Pathauto в качестве возможных компонентов для шаблона преобразования.

  • Итак, устанавливаю модуль CCK. Поскольку CCK является не отдельным модулем, а группой таковых (каждый из которых служит для создания и управления отдельным типом полей), то на странице управления модулями Drupal я включаю только два модуля из набора: Content и Text.
  • После включения модуля на странице описания любого из имеющихся типов содержания появляется дополнительный пункт меню – «Fields».
  • Для моих целей удобнее всего использовать тип содержания Page. Но я, пожалуй, создам новый тип содержания для своих статических страниц. Просто чтобы не было путаницы.
  • Создаю новый тип документов, называю его, скажем – MyStaticPage и присваиваю ему машинное имя my_static_page. Затем открываю страницу добавления дополнительных полей CCK для этого типа.
  • Добавляю новое поле типа Text, называю его, скажем: MyURL.
  • В свойствах поля указываю – «Обязательно». Это значит, что поле должно быть обязательно заполнено пользователем (ведь мы же не хотим, чтобы Pathauto формировал «отсебятину» в случае пустого поля, верно?).
  • Теперь при создании или изменении материалов типа MyStaticPage нам доступно специальное поле для ввода URL, в нём я и буду указывать мой синоним для документа.
  • Перехожу к модулю Pathauto. В настройках «Node path settings» теперь появилось новое поле «Pattern for all MyStaticPage paths:». Вот здесь-то нам и нужно указать ...что? Смотрим ниже список всех доступных компонентов. Вот оно: «[field_myurl]».
  • Этот компонент использует информацию, сохранённую в нашем новом текстовом поле, его нам и нужно указать. Вводим шаблон: «[catalias]/[field_myurl].html».
  • Для остальных, «нестатических», типов ставлю шаблон «[catalias]/[nid].html». То есть, это просто id документа внутри Drupal’а, мне так нравится. Можете поменять на дату, или на что-то другое.
  • Поскольку теперь мне нужно обновить таблицу синонимов Drupal’а для имеющихся документов, я включаю опцию «Bulk update node paths» (можете пропустить, если у вас ещё нет документов), а также опцию «Create feed aliases» для формирования таких же синонимов в RSS фидере.
  • Мне не нужно автоматическое формирование синонимов категорий (я предпочитаю их указывать сам), а потому во избежание путаницы я очищаю все поля в секции «Category path settings».
  • Сохраняю настройки.

Теперь URL'ы всех новых страниц типа MyStaticPage будут автоматически формироваться Drupal'ом, комбинируя синонимы категорий, в которые они включены, и синонимы, определенные мною в поле MyURL при создании документа.

Последнее «но».

Осталось ещё одно «но». Модуль CCK при отображении документа с пользовательскими полями выводит также название поля и его содержание, что не есть хорошо. Они отображаются как в теле тезауруса, так и при просмотре документа.

Настройки модуля, к сожалению, не допускают возможности скрыть содержание поля при просмотре документа. Но выход всё-таки есть. Модуль CCK позволяет подключать собственные шаблоны для визуализации полей модуля, в которых при желании можно просто ...ничего не выводить. Это позволит отключить отображение и названия поля и его данных. Для этого потребуется простейшая модификация файла template.php из вашей темы оформления. Эта процедура описана в файле readme.txt, находящемся в папке модуля CCK: modules/cck/theme/readme.txt, на основании этого файла я и опишу все последующие шаги.

Итак, находим в папке modules/cck/theme/ файл template.php. Как видите, он содержит единственную функцию phptemplate_field:

function phptemplate_field(&$node, &$field, &$items, $teaser, $page) {
  $variables = array(
    'node' => $node,
    'field' => $field,
    'field_type' => $field['type'],
    'field_name' => $field['field_name'],
    'label' => $field['widget']['label'],
    'items' => $items,
    'teaser' => $teaser,
    'page' => $page,
  );
}

Аккуратно копируем весь код функции и вставляем в конец файла template.php текущей темы оформления. Сохраняем файл. Добавленная функция переопределяет стандартную процедуру вывода полей CCK и «сообщает» модулю CCK, что забота о выводе полей теперь ложится на пользователя.

В соответствии с описанием, в папке текущей темы также нужно создать файл field-field_myurl.tpl.php (помните, что поле в моём примере выше называется field_myurl?). Этот файл - просто шаблон, в котором можно определить, как именно поле CCK будет отображаться в браузере, то есть, HTML-обвязку выводимых данных поля. Поскольку нам ничего не нужно выводить (мы хотим скрыть поле), то создаём пустой файл, а лучше - вообще ничего не создаём (ничего страшного не произойдёт). Для интереса можете посмотреть как может выглядеть шаблон вывода поля, открыв файл modules/cck/theme/field-field_body.tpl.php.

На этом настройка закончена. Помните о том, что, поскольку мы переопределили функцию вывода полей CCK, в будущем вам придётся создавать шаблоны вывода для всех новых полей CCK, иначе они отображаться не будут. Либо определить дополнительно общий шаблон для вывода полей CCK (field.tpl.php). Подробности - в файле modules/cck/theme/readme.txt.

Что же касается меня, то я совершил святотатство, надругавшись над своим модулем content.module из набора CCK, и вообще отключил вывод полей на уровне кода модуля. Я могу себе это позволить, поскольку поля CCK у меня пока больше нигде не используются. При необходимости я вернусь к способу скрытия полей CCK с помощью тем.

Комментарии

Аватар пользователя B.X B.X 12 апреля 2007 в 4:29

когда мне хотелось того же, то меня остановило то, что страницы node?page=1 всё равно так и показываются... шаблонов для них в модуле pathauto нет... например: http://things.net.ru/node?page=1 и комментарии также... никаких настроек для комментариев...

Аватар пользователя OldWarrior OldWarrior 12 апреля 2007 в 5:55

Ну... Лично я не вижу в этом ничего страшного. В этой статье в первую очередь я рассматривал возможность сформировать хорошие синонимы для ссылок на документы сайта.

Разбивка на страницы ведь очень условна, я просто не вижу смысла "красиво" именовать по определению динамический контекст. То, что вчера находилось на второй странице через месяц может оказаться на десятой. А современные поисковые боты без труда преодолеют такой синтаксис запросов к страницам и там уже "найдут" "красивые" ссылки :).

Но я согласен с тем, что с точки зрения "красоты" URL хорошо было бы также избавиться от "node?page=1" в пейджинаторе, заменив их на что-то вроде: "/page1, /page2, /page3" и т.д. и т.п.

В отношении комментариев - лично меня устраивает формат /blog/25.html#comment-1, а такой вид ссылок на комментарии как раз и получится после описанных в статье шагов.

Аватар пользователя nilard@drupal.org nilard@drupal.org 12 апреля 2007 в 7:08

В CCK с версии 1.3 (кажется) появилась настройка видимости полей, поэтому теперь в тему не надо лезть, чтобы скрыть поле и/или его заголовок. Очень удобно.

Аватар пользователя OldWarrior OldWarrior 12 апреля 2007 в 8:31

А ведь действительно так. Я пропустил это событие. Начиная с версии 1.3 можно скрыть и заголовок поля и его содержание средствами интерфейса модуля CCK. Причём можно устанавливать параметры отображения поля раздельно для тезауруса и полного тела документа.

Аватар пользователя OldWarrior OldWarrior 12 апреля 2007 в 9:20

Хы! Только что проверил: поле, скрытие средствами CCK 1.4 передаёт пустую строку в Pathauto. Так что эта фича здесь бесполезна.

Аватар пользователя B.X B.X 13 апреля 2007 в 2:51

"о я согласен с тем, что с точки зрения "красоты" URL хорошо было бы также избавиться от "node?page=1" в пейджинаторе, заменив их на что-то вроде: "/page1, /page2, /page3" и т.д. и т.п."

или /page_1.html, /page_2.html интересно, почему создатели pathauto об этом не подумали?

Аватар пользователя OldWarrior OldWarrior 13 апреля 2007 в 7:18

интересно, почему создатели pathauto об этом не подумали?

Pathauto здесь не виноват, он всего лишь своеобразная "надстройка" над стандартным модулем Path и ограничен возможностями последнего.

Теоретически можно попробовать избавиться от "node?page=" и получить адреса вроде "/page/2", модифицировав файл /includes/pager.inc, а также создав дополнительное правило для rewrite engine в файле .htaccess. В первом можно попытаться найти процедуру, отвечающую за вывод ссылок в "страничнике" и изменить вывод, допустим, на /page/number_of_page, а во втором - написать правило, преобразующее запросы /page/number_of_page в стандартные /node?page=number_of_page.

Это не призыв, а просто мысль :). Тем более, я не "копал" pager.inc, а потому не уверен, что это возможно. "Навскидку" проблема видится здесь в том, что пейджинаторы используются при разбивке разных типов содержания и разными модулями.

Аватар пользователя OldWarrior OldWarrior 13 апреля 2007 в 23:03

Вышел ССК 1.5

Он также передаёт пустую строку в Pathauto, я проверил.
Так что единственный выход - темизация.

Аватар пользователя Murz Murz 21 ноября 2007 в 16:34

А можно ли каким-нибудь образом добиться чтобы pathauto строил иерархию вложенных материалов с помощью поля CCK?
У меня есть несколько вложенных материлов типа book, хотелось бы построить урлы по типу book1-cckfield/page1-cckfield/subpage1-cckfield/
У pathauto есть такие возможности для названий [bookpath] или для термов [termpath], а как сделать это через поле CCK - так и не разобрался.

Аватар пользователя Химический Али Химический Али 29 апреля 2009 в 17:45

Не понял цель написания "Гибкий рецепт: Path + Pathauto + CCK.". Разве при включенном модуле Path\PathAuto при добавлении материала нельзя задать свой адрес? Ответ: можно.

Аватар пользователя OldWarrior OldWarrior 21 сентября 2009 в 9:57

Посмотрите на дату написания поста, пожалуйста.
В то время PathAuto, к сожалению, ещё не был таким умным и просто заменял все введенные URL'ы на формируемые автоматически.