URLs output by Drupal can be altered by a tagged service that uses a class which implements two interfaces: OutboundPathProcessorInterface
and InboundPathProcessorInterface
. (I use links for Drupal 9 documentation pages simply because the Drupal 10 documentation pages do not yet show all the parameter descriptions.)
You can use the code used for the path_alias.path_processor service (the one that handles path aliases) as example code.
.services.yml
services:
path_alias.path_processor:
class: Drupal\path_alias\PathProcessor\AliasPathProcessor
tags:
- { name: path_processor_inbound, priority: 100 }
- { name: path_processor_outbound, priority: 300 }
arguments: ['@path_alias.manager']
Service class
class AliasPathProcessor implements InboundPathProcessorInterface, OutboundPathProcessorInterface {
/**
* An alias manager for looking up the system path.
*
* @var \Drupal\path_alias\AliasManagerInterface
*/
protected $aliasManager;
/**
* Constructs a AliasPathProcessor object.
*
* @param \Drupal\path_alias\AliasManagerInterface $alias_manager
* An alias manager for looking up the system path.
*/
public function __construct(AliasManagerInterface $alias_manager) {
$this->aliasManager = $alias_manager;
}
/**
* {@inheritdoc}
*/
public function processInbound($path, Request $request) {
$path = $this->aliasManager->getPathByAlias($path);
return $path;
}
/**
* {@inheritdoc}
*/
public function processOutbound($path, &$options = [], Request $request = NULL, BubbleableMetadata $bubbleable_metadata = NULL) {
if (empty($options['alias'])) {
$langcode = isset($options['language']) ? $options['language']->getId() : NULL;
$path = $this->aliasManager->getAliasByPath($path, $langcode);
// Ensure the resulting path has at most one leading slash, to prevent it
// becoming an external URL without a protocol like //example.com. This
// is done in \Drupal\Core\Routing\UrlGenerator::generateFromRoute()
// also, to protect against this problem in arbitrary path processors,
// but it is duplicated here to protect any other URL generation code
// that might call this method separately.
if (strpos($path, '//') === 0) {
$path = '/' . ltrim($path, '/');
}
}
return $path;
}
}
processOutbound()
changes the URLs output by Drupal. The query values are passed in $options['query']
. To change the keys value to keyword, you just need to use code similar to the following one.
if (isset($options['query']['keys'])) {
$keys = $options['query']['keys'];
unset($options['query']['keys']);
$options['query']['keyword'] = $keys;
}
You also need to check the path is the one you expect, for example with if ($path == '/search/node') { /* … */ }
.
processInbound()
changes the URLs received from Drupal before it can handle them. The query parameters are returned from $request->query->get()
(for example, $request->query->get('keyword')
). A query parameter is set with $request->query->set()
(for example, $request->query->set('keyword', $request->query->get('keys'))
).
You will also need to set the priority of your path_processor_inbound lower than the one used by path_alias.path_processor (so it is executed after it), and the priority of your path_processor_outbound higher than the one used by path_alias.path_processor (so it is executed before it, and it gets the original path, not the path alias, in $path
).
This method works also in the case the search page showing the results is overridden by a view.