Redirecting Drupal 8 users when content is unpublished
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.
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.
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):
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.