Создайте URL-адрес в стиле StackExchange
Я ищу способ создать то, что я называю URL-адресом в стиле StackExchange, с помощью Drupal 7. В моем определении это означает:
- Узел имеет псевдоним пути, содержащий как уникальный идентификатор, так и название узла. Например, если я пишу рассказ, и каждая глава является узлом, глава 4 (озаглавленная "День, когда я стал омаром") получит www.example.com/chapter/4/the-day-i-became-a-lobster .
- Если пользователь знает главу, но не название, он может просто перейти к www.example.com/chapter/4, который перенаправит на www.example.com/chapter/4/the-day-i-became-a-lobster .
- Если заголовок изменится(www.example.com/chapter/4/the-day-i-became-a-lobster становится www.example.com/chapter/4/the-day-i-became-a-penguin), или если URL-адрес введен с ошибкой (www.example.com/chapter/4/the-day-i-become-a-lobster), старый или неправильный URL-адрес перенаправляется на новый/правильный URL-адрес.
Я хочу такого поведения, потому что:
- В некоторых случаях мои пользователи знают продукт номер, но не название. Таким образом, они могут легко определить URL-адрес.
- Наличие заголовка в URL-адресе полезно для SEO и пользовательского опыта.
Я думаю, что лучшим подходом было бы создать полный URL-адрес с использованием Pathauto и настроить механизм перенаправления, который срабатывает, когда путь начинается с "глава/[идентификатор]", но это неверный псевдоним пути.
Конечно, я могу создать пользовательский модуль, реализующий hook_menu для пути "глава/%", поиск правильного узел главы и вызовите drupal_goto, но, возможно, есть лучшие методы. Как бы вы это сделали?
PS. Я разместил аналогичный вопрос в очереди вопросов Перенаправление, потому что этот модуль выглядит связанным и очень перспективным.
2 answers
Я написал пользовательский модуль, чтобы сделать именно это. Я использую Pathauto для автоматического создания псевдонимов для своих узлов в виде questions/123/title-of-node-here
. Следующий код создает страницу /custom404
. Я настраиваю свою "страницу по умолчанию 404 (не найдена)" (в информации о сайте) на custom404
. Модуль выбирает идентификатор узла из URL-адреса, проверяет его существование, а затем перенаправляет на node/%nid
. Наконец, модуль Глобального перенаправления возьмет на себя управление и перенаправит пользователя на канонический URL-адрес.
/**
* Implements hook_menu().
*/
function custommodule_menu() {
$items = array();
$items['custom404'] = array(
'title' => 'Page not found',
'access callback' => TRUE,
'page callback' => 'custommodule_page',
'type' => MENU_LOCAL_TASK
);
return $items;
}
function custommodule_page() {
$path = _custommodule_request_path();
$parts = explode('/', $path);
// The following lines matche a path alias to a content type
// map /questions/%nid/%title to the 'question' content type
_custommodule_match_nid($parts, 'questions', 'question');
// map /websites/%nid/%title to the 'website' content type
_custommodule_match_nid($parts, 'websites', 'website');
drupal_set_title(t('Page not found'));
return ' ';
}
/**
* custommodule_request_path() is copied from globalredirect_request_path
*/
function _custommodule_request_path() {
if (isset($_SERVER['REQUEST_URI'])) {
if (isset($_REQUEST['q'])) {
$path = $_REQUEST['q'];
}
else {
// This is a request using a clean URL. Extract the path from REQUEST_URI.
$request_path = strtok($_SERVER['REQUEST_URI'], '?');
$base_path_len = strlen(rtrim(dirname($_SERVER['SCRIPT_NAME']), '\/'));
// Unescape and strip $base_path prefix, leaving q without a leading slash.
$path = substr(urldecode($request_path), $base_path_len + 1);
}
}
else {
// This is the front page.
$path = '';
}
// Under certain conditions Apache's RewriteRule directive prepends the value
// assigned to $_GET['q'] with a slash. Moreover we can always have a trailing
// slash in place, hence we need to normalize $_GET['q'].
$path = ltrim($path, '/');
return $path;
}
function _custommodule_match_nid($parts, $path_root, $node_type) {
if (count($parts) >= 2 && $parts[0] == $path_root && ctype_digit($parts[1])) {
$id = $parts[1];
$args = array(
':nid' => $id,
':type' => $node_type,
);
if (db_query('SELECT count(nid) FROM {node} WHERE nid = :nid AND type = :type AND status = 1', $args)->fetchField()) {
if ($alias = drupal_get_path_alias('node/'.$id)) {
_custommodule_goto($alias);
}
}
}
}
function _custommodule_goto($path) {
$options = array(
'fragment' => '',
'query' => NULL,
'absolute' => FALSE,
'alias' => FALSE,
'prefix' => '',
'external' => FALSE,
);
unset($_GET['destination']);
drupal_goto($path, $options, 301);
}
Я выбрал более простой подход, написав модуль Drupal 7, который вставляет дополнительный псевдоним без заголовка при вставке узла. Он в основном перенаправляет /content/123
на /content/123/title
(канонический псевдоним).
<?php
/**
* Implements hook_node_insert().
*/
function custom_url_redirect_node_insert($node) {
// Insert Content Type and Path Prefix here.
// 'contentType' => 'pathPrefix'
$entries = array(
'recipe' => 'recipe',
'blog' => 'blog',
);
foreach ($entries as $contentType => $pathPrefix) {
if ($node->type == $contentType) {
$alias = $pathPrefix . '/' . $node->nid;
$isAlias = drupal_lookup_path('source', $alias);
if ($isAlias == NULL) {
$node->path['alias'] = $alias;
};
}
}
}
Обновление: Дополнительные сведения.
Оригинальный плакат с просьбой скопировать шаблон URL-адреса StackExchange (/question/{id}/title-name
) через Drupal. Это отличный шаблон, потому что он позволяет улучшить SEO и позволяет именам заголовков не перезаписывать друг друга.
Для этого вам понадобится кому:
- Установите модуль Глобального перенаправления
- Включить "Создать новый псевдоним. Оставьте существующий псевдоним функционирующим". в Настройках пути (
/admin/config/search/path/settings
) - Добавьте шаблон
question/[node:nid]/[node:title]
в свой тип контента в Шаблонах путей (/admin/config/search/path/patterns
)
Он выведет ваш тип контента как /question/{nid}/title-name
.
Проблема здесь, как говорится в плакате, заключается в том, что вы не можете получить доступ к своему контенту по уникальному идентификатору, такому как /question/{nid}
.
Вот где пригодится этот модуль. Оно добавляет /question/{nid}
в качестве псевдонима URL-адреса при каждой вставке нового узла. В Drupal это будет выглядеть примерно так:
Alias | System Path
------------------------+-------------
/question/123/new-title | node/123 //updated alias, canonical
/question/123/old-title | node/123 //old alias
/question/123 | node/123 //alias added via module
Глобальное перенаправление перенаправит все псевдонимы на системный путь (/node/123
), а из системного пути он будет искать канонический псевдоним (/question/123/new-title
).