Migrate URL aliases to Drupal 8 including pathauto

Urls are an extremely important part of your website. They define the structure of your site and allow search engines to index your content. Because of this, it is critical to keep urls pointing to the same content when you migrate your website to Drupal 8.

For this post, I will assume you are familiar with creating custom migrations in Drupal 8. If you are new to migrations or need more information on creating custom migrations, please see the Migrate API documentation on drupal.org.

First, let’s look at migrating url aliases directly from an older version of Drupal. You can include the path field mapping in the process section of your in your custom node migration.

1
2
process:
  path: alias

This will map the source alias field to the Drupal 8 path (url alias). However, the core node migration sources for Drupal 6 and Drupal 7 do not include the alias field. This is because url aliases can be migrated separately in their own migration (see core/modules/path/migration_templates/d6_url_aliases and core/modules/path/migration_templates/d7_url_aliases). I find it simpler in most custom migrations to include the alias as part of the node migration. You can do this by extending the node source class and adding the alias field.

In your custom migration module, create a new class at /src/Plugin/migrate/source/Node.php that extends the D6 or D7 Node source. Then query the old database directly from the prepareRow() method to retrieve the url alias.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
<?php
/**
 * @file
 * Contains \Drupal\my_module\Plugin\migrate\source\Node.
 */
 
namespace Drupal\my_module\Plugin\migrate\source;
 
use Drupal\migrate\Row;
use Drupal\node\Plugin\migrate\source\d6\Node as D6Node;

/**
 * Custom node source including url aliases.
 *
 * @MigrateSource(
 *   id = "my_module_node"
 * )
 */
class Node extends D6Node {

  /**
   * {@inheritdoc}
   */
  public function fields() {
    return ['alias' => $this->t('Path alias')] + parent::fields();
  }

  /**
   * {@inheritdoc}
   */
  public function prepareRow(Row $row) {
    // Include path alias.
    $nid = $row->getSourceProperty('nid');
    $query = $this->select('url_alias', 'ua')
      ->fields('ua', ['dst']);
    $query->condition('ua.src', 'node/' . $nid);
    $alias = $query->execute()->fetchField();
    if (!empty($alias)) {
      $row->setSourceProperty('alias', '/' . $alias);
    }
    return parent::prepareRow($row);
  } 

}

For a Drupal 7 source, extend Drupal\node\Plugin\migrate\source\d7\Node and change the prepareRow() method to read from the Drupal 7 url_alias table.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php
/**
 * {@inheritdoc}
 */
public function prepareRow(Row $row) {
  // Include path alias.
  $nid = $row->getSourceProperty('nid');
  $query = $this->select('url_alias', 'ua')
    ->fields('ua', ['alias']);
  $query->condition('ua.source', 'node/' . $nid);
  $alias = $query->execute()->fetchField();
  if (!empty($alias)) {
    $row->setSourceProperty('alias', '/' . $alias);
  }
  return parent::prepareRow($row);
} 

This works great unless you are using the Pathauto module in you new Drupal 8 website. Pathauto is a common module that automatically creates a url aliases for new content based on predefined patterns. Pathauto will automatically generate a url alias when new content is added. This can cause problems during a migration because Pathauto will overwrite the source alias by default. You can disable pathauto in your migration by setting the 'path/pathauto' subfield mapping to a default value: 0. You will also need to change the alias mapping to use the subfield 'path/alias'.

1
2
3
4
5
process:
  'path/pathauto': 
    plugin: default_value
    default_value: 0 # Disable pathauto.
  'path/alias': alias
Tweet

Comments:

Subscribe & Contact

Know how to listen, and you will profit even from those who talk badly.
~ Plutarch ~