4

I have a D8 project where the client wants users to select a route they will follow depending on who they are (let's call the two groups Students and Employers), and then the next time they visit show the home page for the appropriate group.

So for example if they click mydomain.com/students, the next time they visit mydomain.com/ it will redirect them to /students

The users will always be anonymous, so not logged in.

I have seen various solutions to this (e.g. the Front module), but they all seem to be dependent either on user role (no use for anon users), a subdomain or browser locale, none of which help us.

What I have in mind is that when visiting one of the target landing pages (e.g. /students) with a Referrer header of the home page, we set a cookie or session variable. Then when the root URL is requested with no or an external Referrer header (so you can still go to the proper homepage via navigation), we check for this and send a redirect if appropriate. The actual paths used could be saved in config.

I'm sure there is a hook I can use somewhere in core to do this, haven't looked into it in much detail yet, but my biggest concern is caching. If the homepage is cached, the hook would never fire and we wouldn't get the redirect, but at the same time I don't want to disable caching on the homepage.

Any experiences/ideas here would be very much appreciated.

1 Answer 1

4

So... I think I have solved this, although cache testing has not yet been done (any thoughts on how to do this welcome!).

Credit to this post for the outline solution, and also to this one for D8 redirects.

First, I create a custom module called mysite_homepage_redirect - it needs the following mysite_homepage_redirect.services.yml file (apparently a priority > 200 means it gets fired before the cache):

services:
  http_middleware.mysite_homepage_redirect:
    class: Drupal\mysite_homepage_redirect\StackMiddleware\MysiteHomepageRedirect
    tags:
      - { name: http_middleware, priority: 250, responder: true }

Then we need the following in src/mysite_homepage_redirect/StackMiddleware/MysiteHomepageRedirect.php:

<?php

namespace Drupal\mysite_homepage_redirect\StackMiddleware;

use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;


/**
 * Provides a HTTP middleware.
 */
class MysiteHomepageRedirect implements HttpKernelInterface {

  /**
   * Map of pages that should be redirected to from home
   * this coulde ultimately be put into config with an admin screen
   */
  private $navigation_map = array(
    '/employers',
    '/students',
  );

  /**
   * The wrapped HTTP kernel.
   *
   * @var \Symfony\Component\HttpKernel\HttpKernelInterface
   */
  protected $httpKernel;

  /**
   * Constructs a MyModule object.
   *
   * @param \Symfony\Component\HttpKernel\HttpKernelInterface $kernel
   *   The decorated kernel.
   * @param mixed $optional_argument
   *   (optional) An optional argument.
   */
  public function __construct(HttpKernelInterface $http_kernel) {
    $this->httpKernel = $http_kernel;
  }

  /**
   * {@inheritdoc}
   */
  public function handle(Request $request, $type = self::MASTER_REQUEST, $catch = TRUE) {

    $current = $request->server->get('REQUEST_URI');
    $source = $request->server->get('HTTP_REFERER');
    $host = $request->server->get('HTTP_HOST');

    //cut the host string out of the referer
    $x = strpos($source, $host);
    if($x) {
      $source = substr($source, $x + strlen($host));
    }

    $redir = isset($_COOKIE['mysite_homepage_redirect']) ? $_COOKIE['mysite_homepage_redirect'] : false;

    if($current == '/' && strpos($source, $host) === false && $redir) {
      $response = new RedirectResponse($redir, 302);
      $response->send();
      return;
    }
    elseif(in_array($current, $this->navigation_map) && $source == '/') {
      //need to use native setcookie() because user_cookie_save relies on the user module which is not yet loaded
      //expires in 30 days
      setcookie('mysite_homepage_redirect', $current, time() + 86400 * 30);
      \Drupal::logger('mysite_homepage_redirect')->notice("saved redirect cookie: " . $current);
    }

    return $this->httpKernel->handle($request, $type, $catch);
  }
}

That seems to work as expected. The cookie seemed the simplest way to save the redirect. Any further thoughts welcome!

1
  • +1, found this great answer while looking for an example code for my answer. One remark, don't send the response, return it. See for example BanMiddleware::handle
    – 4uk4
    Commented Oct 16, 2019 at 19:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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