Creating URL Redirects with Migrate Module

New versions of websites often have new content organizations with new URL patterns. When old content is assigned a new URL it's almost always desirable to redirect traffic from the content's old URL to its new URL. The redirect preserves external links to the site content (i.e., prevents "link rot") and helps maintain search engine page ranking.

If the Drupal Migrate module is used to create the content for the new site there's an easy code addition for creating the redirect at the same time as the content is created. This method uses the code described in the post: Programatically Create 301 Redirects.

The Migrate framework calls the complete method when an entity, for example a node, is successfully created. Information on the complete method can be found in this documentation: Commonly implemented Migration methods.

The complete method is passed the entity created and the row data used to create it. This provides a place to create a redirect using the Redirect module.

In the following example, the old path is part of the row data. Depending on your situation this information could alternatively come from a pre-generated lookup or separate function call.

<?php
class ExampleMigration extends Migration {
 
 
//
  // Migratation code
  //

  /**
   * Definition for Migration complete() method
   */
 
function complete($entity, $row) {
   
// Create a redirect from the old path to the new one
   
if (isset($row->old_path)) {
     
// Create an object with our redirect parameters
     
$redirect = new stdClass();
     
$redirect->source = $row->old_path;           // From URL
     
$redirect->source_options = array();
     
$redirect->redirect = 'node/'. $entity->nid// To URL
     
$redirect->redirect_options = array();
     
$redirect->status_code = 0;                   // Redirect Status
     
$redirect->type = 'redirect';
     
$redirect->language = LANGUAGE_NONE;
   
     
// Create the redirect
     
redirect_save($redirect);
    }
  }
 
}
?>

Comments

I ran into this myself a few days ago and it was good to see we both came to the same solution (thanks to your other blog post on http://www.group42.ca/programatically_create_301_redirects).

Hello !

Thank you very much ! The code works well !
I'm using migrate_d2d and within a Node migration class such as DrupalNode6Migration, I just needed to change $row->old_path to $row->path so that the source Drupal site's node's path is used.

Here is a rollback method for a custom MigrateDestinationNode class (use it with $this->destination = new MyMigrateDestinationNode($this->destinationType);):

/**
* Destination class implementing migration into nodes.
*/
class MyMigrateDestinationNode extends MigrateDestinationNode {

/**
* Rollback redirect URLs for given rollbacked nodes.
*
* @param $nids
* Array of node IDs to be deleted.
*
* @see redirect_delete_by_path (which is too approximate and risks deleteing node/1 and node/10 altogether...)
*/
public function bulkRollback(array $nids) {
$this->redirect_delete_by_nids($nids);

parent::bulkRollback($nids);
}

/**
* Rollback for individual nodes.
*
* @param $entity_id
*/
public function completeRollback($entity_id) {
$this->redirect_delete_by_nids((array) $entity_id);
}

public function redirect_delete_by_nids(array $nids) {
$node_urls = array();

foreach($nids as $nid) {
$node_urls[] = 'node/' . $nid;
}

$rids_query = db_select('redirect', 'r');
$rids_query->addField('r', 'rid');
$rids_query->condition('r.redirect', $node_urls, 'IN');
$rids = $rids_query->execute()->fetchCol();

if ($rids) {
return redirect_delete_multiple($rids);
}
}
}

Have a nice day,

Jonathan-David

Thanks for sharing the code!

The redirect module has been patched to support the migrate module. It can be as simple as:

<?php
$this->addFieldMapping('migrate_redirects', 'old_legacy_path');
?>

See https://drupal.org/node/1116408.

That's great news! Thanks for the heads up.