Based on suggestions by @4k4 in the comments section of the question I have solved this problem by implementing a custom PathProcessor.
I'll share the bare minimum code for making this work in form of a custom module (called term_feed_alias
for the purpose of this example) for which you need 3 files.
term_feed_alias.info.yml
name: 'Term feed alias'
description: 'Provides automatic aliases for taxonomy term feeds'
version: '8.x-1.0'
core_version_requirement: ^8.8 || ^9
type: module
dependencies:
- 'path_alias:path_alias'
term_feed_alias.services.yml
services:
term_feed_alias.path_processor:
class: Drupal\term_feed_alias\PathProcessor\PathProcessorFeedAlias
arguments: ['@path_alias.manager']
tags:
- { name: path_processor_inbound }
- { name: path_processor_outbound }
The service tags can also receive a priority, see https://www.drupal.org/docs/8/api/services-and-dependency-injection/service-tags
This might be needed to integrate the alias logic correctly with other services like translations for example. Also see first comment by @4k4.
scr/PathProcessorFeedAlias.php
<?php
namespace Drupal\term_feed_alias\PathProcessor;
use Drupal\Core\PathProcessor\InboundPathProcessorInterface;
use Drupal\Core\PathProcessor\OutboundPathProcessorInterface;
use Drupal\Core\Render\BubbleableMetadata;
use Drupal\path_alias\AliasManager;
use Symfony\Component\HttpFoundation\Request;
/**
* Provide a path processor to handle aliases for taxonomy term feeds.
*/
class PathProcessorFeedAlias implements InboundPathProcessorInterface, OutboundPathProcessorInterface {
/**
* The alias manager that caches alias lookups based on the request.
*
* @var \Drupal\path_alias\AliasManager
*/
protected $aliasManager;
/**
* Constructs a new PathProcessorFeedAlias instance.
*
* @param \Drupal\path_alias\AliasManager $alias_manager
* The alias manager.
*/
public function __construct(AliasManager $alias_manager) {
$this->aliasManager = $alias_manager;
}
/**
* {@inheritdoc}
*/
public function processInbound($path, Request $request) {
$args = explode('/', trim($path, '/'));
if (end($args) == 'feed') {
array_pop($args);
$system_path = $this->aliasManager->getPathByAlias('/' . implode('/', $args));
return $system_path && strpos($system_path, '/taxonomy/term/') === 0 ? $system_path . '/feed' : $path;
}
return $path;
}
/**
* {@inheritdoc}
*/
public function processOutbound($path, &$options = [], Request $request = NULL, BubbleableMetadata $bubbleable_metadata = NULL) {
$args = explode('/', ltrim($path, '/'));
if ($args[0] == 'taxonomy' && $args[1] == 'term' && end($args) == 'feed') {
array_pop($args);
$alias = $this->aliasManager->getAliasByPath('/' . implode('/', $args));
return '/' . $alias . '/feed';
}
return $path;
}
}