Drupal: How do I programatically create a URL alias for a node that already has an alias on node save?
Asked Answered
H

5

8

I have a custom module that implements hook nodeapi to execute some code when the node is created or updated.

Basically I want to create an alias based off of the automatically generated alias on node save or update.

Right now I'm using a call to path_set_alias and I only want to do this with a specific type of content, "product".

Here is my nodeapi call to get me started

function product_url_helper_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) {

 if($node->type == 'product'){
  switch($op){

     case 'insert':
      _create_alternate_url($node);

     break;

     case 'update':
      _create_alternate_url($node);
     break;

     case 'view':
       //do nothing
     break;

  default:
  break;

  }
 }

 return;
}

Then I have this function, the one I'm trying to get to save my second URL alias for me.

function _create_alternate_url($node){
$aliasExists = db_fetch_object(db_query("SELECT count(dst) as total FROM {url_alias} WHERE dst = 'alternate/".$node->path."'"));
if($aliasExists->total == 0){

    $product_url = $node->path;
 $alternate_url = "alt/" . $node->path;
 $default_node_path = "node/" . $node->nid;

    path_set_alias($default_node_path, $alternate_url, 0, '');

  drupal_set_message("Created Alternate path for Product: " . $node->title . " <br/> Path <a href='/" . $default_node_path ."'>" . $default_node_path . "</a> is now aliased by <a href='/" . $alternate_url . "'>". $alternate_url ."</a>");
 }

This doesn't set the alias though, it just creates a duplicate of the product's original alias. So If i started off with my product being "Green Fern". I would save it, and it would use pathauto to generate products/green-fern then after call my module code and make an alias "alt/products/green-fern" and still make it point back to the "node/nid" path.

However, when I run this code a duplicate in the database is created. So I save Green Fern one time and all of a sudden I see two duplicate records at the end of the url_alias in the database. "products/green-fern" and "products/green-fern"

I feel like I'm thinking about this in a much too comlpex way. My client is aware of the SEO hit they get when making more than one alias point to the same node, they just want it to do this. Halp!

Hedwighedwiga answered 26/1, 2011 at 22:54 Comment(0)
S
6

JR, improving your code in Drupal7, the db_querys are expensive. A better way could be using the lookup_path drupal function:

$urlAlias = drupal_lookup_path('alias',"node/".$node->nid . '/prices');

if urlAlias has no value, then there is no alias for this url, so we can safely create it:

if( urlAlias == '' )
path_set_alias($default_node_path, $alternate_url, 0, '');
Snappish answered 16/10, 2012 at 9:22 Comment(1)
by the way, in drupal7 we should change path_set_alias with path_save($args = array("source" => $non_alias_path, "alias" => $new_aliased_url);)Snappish
H
3

Pathauto is detecting duplicate aliases for the node and overwriting the custom one with the default content type pattern. By default, pathauto will create a new alias and delete an old one when an update action is taken.

If you switch the Update action option to "Create a new alias. Leave the existing alias functioning" on the admin screen, /admin/config/search/path/settings, it will not overwrite the custom alias.

Harding answered 6/11, 2013 at 21:25 Comment(0)
H
2

Tough to tell how complex you'd like the aliases to be, but the pathauto module seems like it would be a simple solution to your problem. It allows you to generate aliases automatically based on tokens.

As a bonus, it places nicely with the path_redirect module, which will set 303 redirects (or whatever redirect you'd like) on duplicate aliases. This will mitigate your SEO concerns somewhat.

Edit:

Are you super-duper sure that your unredacted code is calling the functions correctly? The relevant sections of path_set_alias are:

  if ($pid) {
    // An existing alias.
    // *** You set pid to 0, so this doesn't fire ***
  }
  else if ($path && $alias) {
    // Check for existing aliases.
    if ($alias == drupal_get_path_alias($path, $language)) {
      // There is already such an alias, neutral or in this language.
      // Update the alias based on alias; setting the language if not yet done.
      db_query("UPDATE {url_alias} SET src = '%s', dst = '%s', language = '%s' WHERE dst = '%s'", $path, $alias, $language, $alias);
    }
    else {
      // A new alias. Add it to the database.
      // *** If your code is correct, this is the part that should fire. ***
      db_query("INSERT INTO {url_alias} (src, dst, language) VALUES ('%s', '%s', '%s')", $path, $alias, $language);
    }
  }

If you're working on a test site, you could also try dropping some dpm()s right before the db_querys in node.module to find out what sections of the code are actually firing, and what data is going into them.

Hydrothorax answered 28/1, 2011 at 0:37 Comment(0)
P
0

You are explicitly setting the pid to 0 in the code. I would imagine that the second node this code runs for would return an error. Try changing 0 to NULL in your path_set_alias() call.

Paramour answered 27/1, 2011 at 0:5 Comment(0)
L
0

You can use hook_entity_presave method and create aliases, I have created aliases with node title below

/**
 * Implements hook_entity_presave().
 */
function hook_entity_presave(Drupal\Core\Entity\EntityInterface $entity) {
  if($entity->bundle() == 'news') {
      $title = $entity->label();
      $gen_url = str_replace(' ','-', $title);
      $path_alias = PathAlias::create([
        'path' => '/node/' . $entity->id(),
        'alias' => '/press-room/'.strtolower($gen_url),
      ]);
      $path_alias->save();
  }
}
Lindley answered 7/7, 2023 at 20:31 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.