Recently I had to generate term-specific aliases (aliases that are different from the default alias pattern set for Article entities). This is how to do it:
1. Enable the Pathauto module
2. Set the default URL alias pattern for your content type in order to fire the hook
3. Implement hook_pathauto_alias_alter() in your .module file.
Example module structure:
mymodule/
- mymodule.info.yml
- mymodule.module
- src/
- ArticlePathAlias.php
I like to keep .module clean and simple and because of that I store the main logic in src/ArticlePathAlias.php file.
The mymodule.info.yml this is just a regular .info file.
4. Add the following to your mymodule.module file:
use Drupal\mymodule\ArticlePathAlias;
/**
* Implements hook_pathauto_alias_alter().
*/
function mymodule_pathauto_alias_alter(&$alias, array &$context) {
if ($new_alias = (new ArticlePathAlias())->generate($context)) {
$alias = $new_alias;
}
}
5. Add the following to your src/ArticlePathAlias.php file:
<?php
namespace Drupal\mymodule;
use Drupal\Component\Utility\Html;
use Drupal\taxonomy\Entity\Term;
/**
* Generate URL aliases for articles.
*/
class ArticlePathAlias {
protected $terms = [
'Term name 1' => 'custom/alias',
'Term name 2' => 'custom2/alias',
'Term name 3' => 'custom3/alias',
];
protected $pattern = '/%term%/%year%/%monthnum%/%day%/%postname%';
public function generate($context) {
if ($context['bundle'] === 'article' && ($context['op'] == 'insert' || $context['op'] == 'update')) {
return $this->assembleAlias($context['data']['node']);
}
}
protected function assembleAlias($entity) {
$date = new \DateTime(date('c', $entity->getCreatedTime()));
$parameters = [
'%year%' => $date->format('Y'),
'%monthnum%' => $date->format('m'),
'%day%' => $date->format('d'),
'%postname%' => Html::cleanCssIdentifier($entity->getTitle()),
'%term%' => $this->findTermAlias($entity),
];
if (!empty($parameters['%term%'])) {
return str_replace(array_keys($parameters), array_values($parameters), $this->pattern);
}
}
protected function findTermAlias($entity) {
// Make sure to change `field_keywords` to the field you would like to check.
if ($keywords = $entity->get('field_keywords')->getValue()) {
foreach ($keywords as $data) {
$term = Term::load($data['target_id']);
$name = $term->getName();
if (in_array($name, array_keys($this->terms))) {
return $this->terms[$name];
}
}
}
}
}
The code above will generate /%term%/%year%/%monthnum%/%day%/%postname% alias or (/custom/alias/2017/07/21/test-title) depending on the term.
Make sure you change field_keywords to your own taxonomy term reference field. Also change $context['bundle'] === 'article' to entity type that will trigger custom alias.