I have been working on project and one of the product owners want to modify an url alias, and she notice this:
yes i know its bad, a lot of duplicate unused url alias !
After digging into this to figure out where this came from, i found the following line inside hook_entity_presave, and it's was there for a reason we needed to insert another alias in each entity update:
<?php
\Drupal::service('pathauto.generator')->updateEntityAlias($entity, 'insert');
By the way this line of code it’s equivalent to the following Pathauto configuration:
So if you have one of those two things, after a while you will found hundreds of unused duplicated url alias:
How to delete / Remove duplicate url alias?
To achieve this we use hook_update_N in MODULENAME.install
<?php
/**
* Remove duplicate alias, for articles.
*/
function MODULENAME_update_8801() {
$query = \Drupal::entityQuery('node');
$query->condition('type', 'article', '=');
$nids = $query->execute();
$path_alias_storage = \Drupal::entityTypeManager()->getStorage('path_alias');
foreach ($nids as $nid) {
$actual_alias = \Drupal::service('path.alias_manager')
->getAliasByPath('/node/' . $nid);
// Load all path alias for this node.
$alias_objects = $path_alias_storage->loadByProperties([
'path' => '/node/' . $nid,
]);
// Delete all other alias than the actual one.
foreach ($alias_objects as $alias_object) {
if ($alias_object->get('alias')->value !== $actual_alias) {
$alias_object->delete();
}
}
// Load all new path alias for this node.
$new_alias_objects = $path_alias_storage->loadByProperties([
'path' => '/node/' . $nid,
]);
// Delete duplicate aliases.
if (count($new_alias_objects) > 1) {
array_shift($new_alias_objects);
foreach ($new_alias_objects as $alias_object) {
$alias_object->delete();
}
}
}
}
Let’s break this down:
The first foreach
<?php foreach ($alias_objects as $alias_object) { if ($alias_object->get('alias')->value !== $actual_alias) { $alias_object->delete(); } }
To remove any alias with the same path system and different alias.
The second foreach
<?php if (count($new_alias_objects) > 1) { array_shift($new_alias_objects); foreach ($new_alias_objects as $alias_object) { $alias_object->delete(); } }
To let only one alias, because something you can find more than one url alias with the same alias and path system.
Now just run update database either by going to /update.php or using drush:
drush updb -y
and you are done.