• ALL
  • CATEGORIES

Redirecting Drupal 8 users when content is unpublished

Redirects Drupal 8 unpublished content

In Drupal 8 unpublished content is, by default, not accessible to users without the right privileges, who will receive a 403 Forbidden page instead. Although this behaviour is understandable, and good security practice, it can lead to really terrible user experiences and even create issues for SEO performance. In this post I’ll look at solving this problem by redirecting users to appropriate content instead of leaving them with an unexplained 403.

When is unpublished not unpublished?

In my scenario I’m using the experimental content_moderation module, so actually my content can have several different states, even if the content status is unpublished. For example, an ‘Archived’ moderation state where content is unpublished.

It’s easy to see how, in a publishing setup like this, links that point to content that is now unpublished might remain on the web for some time, leading to lots of 403 errors and frustrated users.

I’ve looked at some solutions, for Drupal 7 mainly, which more or less all mess up with the “node/%node” route access callback:

This is from the Unpublished Nodes Redirect module.

I personally don’t like altering core access callbacks. Besides making your code look like spaghetti, while checking user access permissions against a piece of content – which should return Allow or Deny – it actually interrupts the process and redirect.

What if something is wrong with your access service and, by mistake, your code Allows the request?

I opt for a different approach, making use of Drupal 8 Events.

Using Drupal 8 Events for intelligent redirects

Let’s imagine we’re building a site for an entertainments company with a content type of ‘shows’. Each show node is only published on the site for a limited time, after which it is archived.

Our goal is to redirect users to an ‘/all-shows’ landing page instead of the 403 Forbidden page, if the requested show node is unpublished.

Step 1: Find the right Event

First, we must find the right Event to hook into. Here’s the list of Events in core.

RoutingEvents::ALTER

looked like a good candidate, but we don’t want to touch default behaviours. We are happy with our route, we just need to conditionally change the response.

KernelEvents::RESPONSE

is our man.

Step 2: The Redirect On Unpublished Event Service

In order to hook into the event we need an event_subscriber service.

(NB: ResponseSubscriber.php is located in /src/)

The my_module.services.yml file will notify drupal about our service configuration, where to find its class (namespace Drupal\my_module\ResponseSubscriber) and which group our service belongs to (event_subscribe).

The ResponseSubscriber class is where our codes lives. Here we define which event we subscribe to (KernelEvents::RESPONSE) and the callback to call when fired (self method ‘alterResponse’).

You can also use other services to add additional conditions. For example, if you want to redirect only if the user is authenticated (i.e. anonymous users will still get a 403 error):

Summary

We can use Drupal 8’s Events to create intelligent redirects for unpublished content, sending users to relevant pages instead of returning a 403 Forbidden page. If we make use of additional services, we can even create different behaviours for different types of user, tailoring the redirect behaviour for different audiences.

Check the full code on github

Leave a reply

You can use these tags:

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

  1. It’s an awesome article for all the internet people; they will
    get advantage from it I am sure.

  2. joker123 Tembak Ikan says:

    If some one needs expert view regarding running a blog then i suggest him/her to go to see this blog,
    Keep up the good job.

  3. Petro says:

    Thank you very mutch!

  4. John Burch says:

    I had to add :

    use Symfony\Component\HttpKernel\Event\FilterResponseEvent;

    In my D9 ResponseSubscriber.php

Sign up for the Manifesto newsletter and exclusive event invites