Создайте URL-адрес в стиле StackExchange


Я ищу способ создать то, что я называю URL-адресом в стиле StackExchange, с помощью Drupal 7. В моем определении это означает:

  1. Узел имеет псевдоним пути, содержащий как уникальный идентификатор, так и название узла. Например, если я пишу рассказ, и каждая глава является узлом, глава 4 (озаглавленная "День, когда я стал омаром") получит www.example.com/chapter/4/the-day-i-became-a-lobster .
  2. Если пользователь знает главу, но не название, он может просто перейти к www.example.com/chapter/4, который перенаправит на www.example.com/chapter/4/the-day-i-became-a-lobster .
  3. Если заголовок изменится(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. Я разместил аналогичный вопрос в очереди вопросов Перенаправление, потому что этот модуль выглядит связанным и очень перспективным.

Author: marcvangend, 2011-07-10

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);
}
 5
Author: Greg, 2011-07-10 22:20:53

Я выбрал более простой подход, написав модуль 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).

 0
Author: timofey.com, 2013-05-19 06:37:09