0

I need to show my website with a "theme" when in header's requests is present a particular key/value.

In Drupal 7 I do this via themekey, but this module does not exist in Drupal 8.

Are there alternatives, or other ways to do this?

0

You can easily recreate your required feature by implementing a custom theme negotiator. This requires a little custom programming.

First, create an own module (in the following example, we'll call it mymodule). Within that module, create a mymodule.services.yml file, that lets Drupal know about your theme negotiator service:

services:
  mymodule.theme_negotiator:
    class: Drupal\mymodule\Theme\MyModuleThemeNegotiator
    arguments: ['@request_stack']
    tags:
      - { name: theme_negotiator, priority: 1000 }

The important parts here are the service tag theme_negotiator and a high enough priority, that ensures the negotiator will be called before any other negotiators. If you want to just change the default theme dynamically but let route specific theme negotiators still apply, use a priority < 0.

As you can see, we also mentioned your custom theme negotiator service class MyModuleThemeNegotiator located in the namespace Drupal\mymodule\Theme, and as argument the current request stack (as we can use it to get the request headers).

So let's create a folder src/Theme in your module and add a MyModuleThemeNegotiator.php like this:

namespace Drupal\mymodule\Theme;

use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\Theme\ThemeNegotiatorInterface;
use Symfony\Component\HttpFoundation\RequestStack;

/**
 * My Custom Theme Negotiator.
 */
class MyModuleThemeNegotiator implements ThemeNegotiatorInterface {

  /**
   * The request stack.
   *
   * @var \Symfony\Component\HttpFoundation\RequestStack
   */
  protected $requestStack;

  /**
   * Constructs a MyModuleThemeNegotiator object.
   *
   * @param \Symfony\Component\HttpFoundation\RequestStack $requestStack
   *   The request stack.
   */
  public function __construct(RequestStack $request_stack) {
    $this->requestStack = $request_stack;
  }

  /**
   * {@inheritdoc}
   */
  public function applies(RouteMatchInterface $route_match) {
    // This method must return TRUE, if your headers
    // fulfill the desired requirements.
    if (
      $this->requestStack->getCurrentRequest()->headers->has('myheader')
      && $value = $this->requestStack->getCurrentRequest()->headers->get('myheader')
      && $value == 'myvalue'
    ) {
      return TRUE;
    }

    return FALSE;
  }

  /**
   * {@inheritdoc}
   */
  public function determineActiveTheme(RouteMatchInterface $route_match) {
    // This method returns the ID of the theme that shall be
    // used, if your theme negotiator applies.
    return 'mytheme';
  }
}

Alter the header/values to match your requirements, clear your caches, and your theme should be applied.

| improve this answer | |
  • In addition to this answer, is it possible to swap the theme based on a node field value? Let's assume you have a content type where you add a dropdownlist with the available themes to select from. When you visit a node, the above service check the value and swap theme based on that value? – user3086053 Dec 10 '19 at 10:19
  • This would be worth a different question and probably has been answered before. Yes it is. Get the node object from the current request in the applies method, check your specific node type and return TRUE if it applies. Then get the node from the request again in determineActiveTheme and return the desired theme from its field value. – Mario Steinitz Dec 10 '19 at 11:48

Not the answer you're looking for? Browse other questions tagged or ask your own question.