Starting with Drupal 8.8.0, custom URL aliases are now implemented via a new path_alias
revisionable content entity type provided by the new (required) path_alias
module (see related change record).
The path.alias_storage
service has been kept in place for backwards compatibility, and its hook have been deprecated.
The following code changes are recommended in order to fully utilize the new system and prepare your code for Drupal 9:
Use path alias objects instead of path arrays
Given a deprecated path alias array with the following structure:
$alias = [
'source' => '/a/system/path',
'alias' => '/a-path-alias',
'langcode' => 'en',
];
Using a new path alias entity object:
- To create new alias:
$path_alias = \Drupal::entityTypeManager()->getStorage('path_alias')->create([ 'path' => '/a/system/path', 'alias' => '/a-path-alias', 'langcode' => Language::LANGCODE_NOT_SPECIFIED, ]); $path_alias->save();
$alias['source']
becomes$path_alias->getPath()
$alias['alias']
becomes$path_alias->getAlias()
$alias['langcode']
becomes$path_alias->language()->getId()
Hooks
Regular entity hooks should be used instead of the old path-specific ones:
Before:
hook_path_insert($path)
hook_path_update($path)
hook_path_delete($path)
After:
hook_entity_insert(Drupal\Core\Entity\EntityInterface $entity)
hook_path_alias_insert(Drupal\path_alias\PathAliasInterface $path_alias)
hook_entity_update(Drupal\Core\Entity\EntityInterface $entity)
hook_path_alias_update(Drupal\path_alias\PathAliasInterface $path_alias)
hook_entity_delete(Drupal\Core\Entity\EntityInterface $entity)
hook_path_alias_delete(Drupal\path_alias\PathAliasInterface $path_alias)
The deprecated hook implementations from Drupal core have been converted as follows:
menu_link_content_path_insert() -> menu_link_content_path_alias_insert()
menu_link_content_path_update() -> menu_link_content_path_alias_update()
menu_link_content_path_delete() -> menu_link_content_path_alias_delete()
system_path_insert() -> PathAlias::postSave()
system_path_update() -> PathAlias::postSave()
system_path_delete() -> PathAlias::postDelete()
Alias storage
Before:
\Drupal::service('path.alias_storage')->load($conditions)
\Drupal::service('path.alias_storage')->save($source, $alias, $langcode = LanguageInterface::LANGCODE_NOT_SPECIFIED, $pid = NULL)
\Drupal::service('path.alias_storage')->delete($conditions)
After:
\Drupal::entityTypeManager()->getStorage('path_alias')->load($id)
\Drupal::entityTypeManager()->getStorage('path_alias')->loadByProperties(array $values)
\Drupal::entityTypeManager()->getStorage('path_alias')->save($path_alias)
\Drupal::entityTypeManager()->getStorage('path_alias')->delete([$path_alias])
Forms
The following table lists all the previous form classes and their IDs, along with their replacements.
Previous form class | Previous form ID | New form class | New form ID | |
---|---|---|---|---|
Drupal\path\Form\AddForm |
path_admin_add |
-> | Drupal\path\PathAliasForm |
path_alias_form |
Drupal\path\Form\EditForm |
path_admin_edit |
-> | Drupal\path\PathAliasForm |
path_alias_form |
Drupal\path\Form\DeleteForm |
path_alias_delete |
-> | Drupal\Core\Entity\ContentEntityDeleteForm |
path_alias_delete_form |
Drupal\path\Form\PathFormBase |
N/A | -> | Drupal\path\PathAliasForm |
N/A |
Custom code needs to be updated for any hook_form_alter()
or hook_form_FORM_ID_alter()
implementations that were using the previous form IDs. For example, a hook_form_path_admin_add_alter() implementation of hook_form_FORM_ID_alter()
for the path_admin_add
form ID needs to be renamed to hook_form_path_alias_form_alter().
Additionally, the following routes have been deprecated and replaced by generic entity routes:
Previous route name | New route name |
---|---|
path.admin_add |
entity.path_alias.add_form |
path.admin_edit |
entity.path_alias.edit_form |
path.delete |
entity.path_alias.delete_form |
path.admin_overview |
entity.path_alias.collection |
The path.admin_overview_filter
route has also been deprecated, and it's functionality has been folded into the generic entity.path_alias.collection
route, by using a search
request query parameter.
Migrations
The custom url_alias
(\Drupal\path\Plugin\migrate\destination\UrlAlias
) migrate destination plugin has been deprecated in favor of the generic entity-based entity:path_alias
destination plugin. The Drupal 6 and 7 source plugins have also been updated accordingly.
Important notice for contributed and custom module's Kernel tests:
In order to allow Kernel tests to work on both Drupal 8.8 as well as previous minor releases (e.g. 8.7 and 8.6), the path_alias
entity type schema needs to specifically installed in the test's setUp()
method, like so:
if (\Drupal::entityTypeManager()->hasDefinition('path_alias')) {
$this->installEntitySchema('path_alias');
}
Important notice for contributed and custom module's Upgrade tests:
In order to allow Upgrade tests to work on both Drupal 8.8 as well as previous minor releases (e.g. 8.7 and 8.6), your test cannot call drupalGet
or drupalLogin
before the runUpdates
call if your dump is created with a Core version before 8.8.
Comments
Table storage
Just want to flag that the alias storage moves in this update from the
url_alias
table topath_alias
andpath_alias_revision
tables. The oldpath_alias
table is either dropped or renamed for backup purposes. If you have code querying directly againsturl_alias
table, that will need to be updated.Take note of the "delete" method
Thanks for this. It's helpful, but I ran into an issue following one of the examples.
if you do this example from AliasStorage:
$pathAlias = \Drupal::entityTypeManager()->getStorage('path_alias')->load($id) // FYI, that $id is the 'pid' value in a returned path array, or the ->id() in a path object
then do this ...
... you will get a WSOD/Fatal error/500/etc.
To delete, wrap $pathAlias in an array:
I almost went mad trying to delete a path. Don't go mad, wrap it in an array. It works.
Thanks for finding this!
I updated the change record to use an array for the
delete()
code example :)New Migrate Process Plugin!
This change also introduced a very useful migrate process plugin called
null_coalesce
(NullCoalesce). It returns the first non null value from a source array. It's great for titles where a missing value would result in a sql error. The same code can give stubs a meaningful title (the id) instead of a weird hash.