2

I migrated a site not using Drupal to Drupal. Now I need to make sure that some legacy URLs are redirecting to the right node URL.
The node has the node ID (nid), the legacy ID (field_leg_id), the item ID (item_id), the title (headline_of_the_item), and the body.

The legacy URL example.com/type1/201203080034 should redirect to the new URL example.com/type1/2012/03/08/headline_of_the_item/item_id.

201203080034 is the legacy ID corresponding to 20120308 in the new URL.

How do I redirect users to the new node when I just have the legacy ID?
update

 // Redirect based on legacy ID.
$query = db_query("select lid.entity_id, lid.field_legacy_id_value, sid.field_site_content_id_value     
                   from field_data_field_legacy_id lid     
                   inner join field_revision_field_site_content_id sid on lid.entity_id = sid.entity_id          
                   where lid.field_legacy_id_value = $content_id       
                   LIMIT 1");

while ($row = db_fetch_object($query)) {
  $s_id = $row->sid.field_site_content_id_value;
  $item = node_load($s_id);
  if ($item) {
    drupal_goto("node/{$item->nid}", array(), 301);
  }
}

}

This is giving me 500 error. Tried to debug it without success.

update based on @greendemiurge Below is what worked for me.

   function my_item_redirect_item() {
       $args = arg();
       $content_id = end($args);
       $item = my_item_by_legacy_id($content_id);
      if ($item) {
         drupal_goto("node/{$item->nid}", array(), 301);
      }
   }

   function my_item_by_legacy_id($id) {
   // First, check if we have an imported item with this $id (field_legacy_id).
   $query = new EntityFieldQuery();

   $query->entityCondition('entity_type', 'node')
         ->fieldCondition('field_legacy_id', 'value', $id, '=')
         ->range(0, 1)
         ->addMetaData('account', user_load(1));

   $result = $query->execute();

   if (isset($result['node'])) {
      $nids = array_keys($result['node']);
      return node_load($nids[0]);
   }

 // Check if there is a node with Nid = $id
 return node_load($id);
} 

2 Answers 2

2

The first question on this is, how many URLs do you need to redirect? If it is a small number you may be better off using .htaccess. I doubt this is the case given your patterns.

The next question is, is there enough info in the old pattern to resolve to a current node, or do you need to create the mappings yourself?

If there is enough info, it may be possible to use Match redirect - https://www.drupal.org/project/match_redirect. If that isn't exactly what you need you may want to implement some custom code based on match_redirect_init() in that module.

edit
The above additions give me enough to make a couple suggestions: First, the query would be better off done as a db_select or an entity field query for the standard reasons. More important than that it is much more efficient, if possible, to let SQL do the matching and not the while loop.

Second, the hook that seems to work best for me is hook_menu_get_item_alter(). Others with more experience in menu routing may want to give some feedback on this approach, but it does work for me in a sandbox.

So, assuming a module called 'custom', this is what seems to work for me:

function custom_menu_get_item_alter(&$router_item, $path, $original_map) {
  $query = new EntityFieldQuery();

  // $path is everything after your base URL. I am assuming that this is what
  // you have in field_legacy_id.
  $query
    ->entityCondition('entity_type', 'node', '=')
    ->propertyCondition('status', 1, '=')
    ->fieldCondition('field_legacy_id', $path);

  $results = $query->execute();
  $results = array_keys($results['node']);
  $result = reset($results);

  if (!empty($result)) {
    $node = node_load($result);

    // This will retain your aliased path if you are using one. Important for
    // SEO, especially if you are using a 301.
    $path = drupal_get_path_alias("node/{$node}");
    drupal_goto($path, array(), 301);
  }
}

I wasn't able to test this ahead using your described setup, so it may need some tweaking. Please let me know if you need additional info.

5
  • Thanks but there is not enough info in the old pattern to resolve to a current node. I updated my question with what I tried without success.
    – mamesaye
    Commented Apr 24, 2016 at 3:28
  • I updated my reply. Hope it helps. Commented Apr 25, 2016 at 14:30
  • Your answer was really helpful. U made my day :), thanks. Will update my answer with what worked for me based on your answer. Hope it help someone.
    – mamesaye
    Commented Apr 25, 2016 at 15:27
  • Really glad to hear it! Commented Apr 25, 2016 at 15:28
  • see my answer below.
    – tenken
    Commented Apr 25, 2016 at 17:31
1

This works for me. I need to check current_path to assure thats the raw url parameter and menu_get_item to assure that we're looking at the a random url as opposed to /node/10 vs 1234-legacy-url.

function legacyredirect_menu_get_item_alter(&$router_item, $path, $original_map) {
    $query = new EntityFieldQuery();

    $path = current_path();

    $query
        ->entityCondition('entity_type', 'node', '=')
        ->propertyCondition('status', 1, '=')
        ->addTag('nicedpq')
        ->fieldCondition('field_legacy_content_id', 'value', $path);
    $results = $query->execute();

    if (isset($results['node'])  && !menu_get_item($path)) {
        $results = array_keys($results['node']);
        $result = reset($results);
        if (!empty($result)) {
            $node = node_load($result);

            // This will retain your aliased path if you are using one. Important for
            // SEO, especially if you are using a 301.
            $path2 = drupal_get_path_alias("node/" . $node->nid);
            header("Location: $path2", 301);
            exit;
        }
    }
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.