Use different Views / Views Displays for some Vocabularies/Terms in Drupal 8

In Drupal 8 the taxonomy term pages are views. By default the View “taxonomy_term” is used if a taxonomy term is requested (/taxonomy/term/TID). This view can be adjusted to fit your needs. But sometimes you like to change the output / view only one some terms or for all terms in some vocabulary.

Currently there is no easy way to do that. Because always this one view is used and all changes inside the view has an impact on all terms. And if more views are on the system path /taxonomy/term/{taxonomy_term}, also only one is used for all terms. No way to say, please use this view for the particular vocabulary otherwise this view.

My way to achieve that was to replace the default controller for the taxonomy term path with my one and handle the view switch inside these controller class.

Altering the routing

The altering of routes in D8 are described here: https://www.drupal.org/node/2187643

Of course you must change the my_module inside the snippets to the name of your module.

// my_module/src/Routing/RouteSubscriber.php
 
<?php
/**
 * @file
 * Contains \Drupal\my_module\Routing\RouteSubscriber.
 */
 
namespace Drupal\my_module\Routing;
 
use Drupal\Core\Routing\RouteSubscriberBase;
use Symfony\Component\Routing\RouteCollection;
use Drupal\Core\Routing\RoutingEvents;
 
/**
 * Listens to the dynamic route events.
 */
class RouteSubscriber extends RouteSubscriberBase {
 
  /**
   * {@inheritdoc}
   */
  public function alterRoutes(RouteCollection $collection) {
    if ($route = $collection->get('entity.taxonomy_term.canonical')) {
      $route->setDefault('_controller', '\Drupal\my_module\Controller\TaxonomyTermViewPageController::handle');
    }
  }
 
  /**
   * {@inheritdoc}
   */
  public static function getSubscribedEvents() {
    $events = parent::getSubscribedEvents();
 
    // Come after views.
    $events[RoutingEvents::ALTER] = array('onAlterRoutes', -180);
 
    return $events;
  }
 
}
// my_module/my_module.services.yml

services:
  my_module.route_subscriber:
    class: Drupal\my_module\Routing\RouteSubscriber
    tags:
      - { name: event_subscriber }

After clearing the cache now our controller TaxonomyTermViewPageController::handle will be used if a taxonomy term page is requested.

Our TaxonomyTermViewPageController Controller

Inside the new controller we can implement our custom logic to used different Views or Views displays. Depending on what you want to achieve.

// my_module/src/Controller/TaxonomyTermViewPageController.php
 
<?php
 
/**
 * @file
 * Contains \Drupal\my_module\Controller\TaxonomyTermViewPageController.
 */
 
namespace Drupal\my_module\Controller;
 
use Drupal\views\Routing\ViewPageController;
use Drupal\Core\Routing\RouteMatchInterface;
 
/**
 * Class TaxonomyTermViewPageController.
 *
 * @package Drupal\my_module\Controller
 */
class TaxonomyTermViewPageController extends ViewPageController {
 
  /**
   * {@inheritdoc}
   */
  public function handle($view_id, $display_id, RouteMatchInterface $route_match) {
    // Drupal Defaults.
    $view_id = 'taxonomy_term';
    $display_id = 'page_1';
 
    // Entity of the requested term.
    $term = $route_match->getParameter('taxonomy_term');
 
    // Get the vid (vocabulary machine name) of the current term.
    $vid = $term->get('vid')->first()->getValue();
    $vid = $vid['target_id'];
 
    // If the vocabulary is 'foo' use the 'foo_view' view. What should of course be created in Views. :)
    if ($vid == 'foo') {
      // Change view.
      $view_id = 'foo_view';
    }
 
    // Also you can change the display. E.g. if you have created another display inside the main "taxonomy_term" view.
    if ($vid == 'foo') {
      // Use another view display.
      $display_id = 'page_2';
    }
 
    return parent::handle($view_id, $display_id, $route_match);
  }
 
}