Автоматическая генерация алиасов для динамических страниц views

При создании алиасов урлов с помощью модуля Pathauto можно заменить системные пути для нод и для пользователей на человекопонятные урлы. Для нод по-умолчанию создаются алиасы content/[node:title], а для юзеров - users/[user:name]. Но если добавить вьюсом страницы-вкладки, принимающие в качестве аргумента айдишники нод или юзеров, то алиасы к ним применены не будут. И в результате на сайте образуются страницы с урлами типа /user/%uid/articles(/user/%uid/photos) или /node/%nid/poll. Чтобы данную ситуацию исправить и создавать алиасы и этим страницам при создании новых материалов или пользователей, можно воспользоваться модулем Rules либо сделать это с помощью модуля Sub-pathauto. Но данную задачу можно решить и написанием небольшого кастомного модуля.

Напишем свой модуль, который будет создавать алиасы для двух динамических страниц - /user/%/articles и /user/%/photos , созданных модулем views.

Для начала нужно с помощью hook_pathauto создать на странице настроек шаблонов алиасов /admin/config/search/path/patterns новую группу. В эту группу будут входить поля для ввода шаблонов к необходимым нам страницам:


/**
 * Implements hook_pathauto().
 */
function mymodule_pathauto($op) {
  switch ($op) {
    case 'settings':
      $settings = array();
      $settings['module'] = 'mymodule';
      // Добавляем группу токенов необходимых для создания шаблонов
      $settings['token_type'] = 'user';
      // Задаем имя новой группы (отображается в админке)
      $settings['groupheader'] = t('Additional user paths');
      $settings['patterndescr'] = t('Default pattern');
      // В поле по-дефолту для шаблона записываем пустую cтроку
      $settings['patterndefault'] = '';
      // Задаем имя callback-функции для массового обновления алиасов.
      $settings['batch_update_callback'] = 'mymodule_pathauto_bulkupdate';

      $path = array(
        'mymodule_user_articles' => 'User articles path',
        'mymodule_user_photos' => 'User photos path',
      );

      $langs = array_keys(language_list());
      foreach ($path as $k => $p) {
        foreach ($langs as $lang) {
          $path[$k . '_' . $lang] = $p . ' for language ' . $lang;
        }
        unset($path[$k]);
      }
      $settings['patternitems'] = $path;
      return (object) $settings;
  }
}

pathauto1.png

Далее имплементируем hook_user_insert, чтобы при создании нового пользователя создавались алиасы и для наших страниц. Алиасы создаются вспомогательной функцией mymodule_create_alias():


/**
 * Implements hook_user_insert().
 */
function mymodule_user_insert(&$edit, $user, $category) {
  mymodule_create_alias($user, 'insert');
}

При обновлении профиля пользователя обновляем и алиасы при необходимости:


/**
 * Implements hook_user_update().
 */
function mymodule_user_update(&$edit, $user, $category) {
  mymodule_create_alias($user, 'update');
}

При удалении пользователя удаляем и алиасы его страниц:


/**
 * Implements hook_user_delete().
 */
function mymodule_user_delete($user) {
  module_load_include('inc', 'pathauto');
  pathauto_path_delete_all('user/' . $user->uid . '/articles');
  pathauto_path_delete_all('user/' . $user->uid . '/photos');
}

Создаем вспомогательную функцию для создания и обновления алиасов:


/**
 *  Create alias for a user custom urls.
 */
function mymodule_create_alias($user, $op) {
  $langs = array_keys(language_list());
  module_load_include('inc', 'pathauto');
  foreach ($langs as $lang) {
    pathauto_create_alias('mymodule', $op, 'user/' . $user->uid . '/articles' , array('user' => $user), 'mymodule_user_articles_' . $lang, $lang);
    pathauto_create_alias('mymodule', $op, 'user/' . $user->uid . '/photos' , array('user' => $user), 'mymodule_user_photos_' . $lang, $lang);
  }
}

Далее с помощью hook_pathauto_bulkupdate добавляем возможность массового обновления алиасов для нужных нам страниц:


/**
 * Implements hook_pathauto_bulkupdate.
 */
function mymodule_pathauto_bulkupdate() {
  if (!isset($context['sandbox']['current'])) {
    $context['sandbox']['count'] = 0;
    $context['sandbox']['current'] = 0;
  }

  $query = db_select('user', 'u');
  $query->addField('u', 'uid');
  $query->leftJoin('url_alias', 'ua', " ua.source LIKE CONCAT('user/', u.uid, '/%')");
  $query->isNull('ua.source');
  $query->condition('u,uid', $context['sandbox']['current'], '>');
  $query->orderBy('u.uid');
  $query->addTag('pathauto_bulk_update');
  $query->addMetaData('entity', 'user');

  if (!isset($context['sandbox']['total'])) {
    $context['sandbox']['total'] = $query->countQuery()->execute()->fetchField();
    if (!$context['sandbox']['total']) {
      $context['finished'] = 1;
      return;
    }
  }

  $query->range(0, 25);
  $uids = $query->execute()->fetchCol();

  $users = user_load_multiple($uids);
  foreach ($users as $user) {
    mymodule_create_alias($user, 'bulkupdate');
  }
  $context['sandbox']['count'] += count($uids);
  $context['sandbox']['current'] = max($uids);
  $context['message'] = t('Updated alias for user @uid.', array('@uid' => end($uids)));

  if ($context['sandbox']['count'] != $context['sandbox']['total']) {
    $context['finished'] = $context['sandbox']['count'] / $context['sandbox']['total'];
  }
}

Массовое обновление алиасов можно будет выполнить в админке на странице /admin/config/search/path/update_bulk, отметив чекбоксом созданную группу.

pathauto2.png

Также обновление алиасов можно сделать с помощью drush, выполнив для этого команду


drush php-eval '_pathauto_include() ; mymodule_pathauto_bulkupdate()'

Теперь все страницы-вкладки будут иметь урлы users/[user:name]/photos и users/[user:name]/articles.