Skip to content

Instantly share code, notes, and snippets.

@jhedstrom
Created April 22, 2022 15:38
Show Gist options
  • Save jhedstrom/1bfce59799afde80bf3efaae3be7a068 to your computer and use it in GitHub Desktop.
Save jhedstrom/1bfce59799afde80bf3efaae3be7a068 to your computer and use it in GitHub Desktop.
Redirect canonical node page
<?php
namespace Drupal\mymodule\EventSubscriber;
use Drupal\mymodule\ExternalRedirectHelper;
use Drupal\Core\Routing\TrustedRedirectResponse;
use Drupal\node\NodeInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\HttpKernel\KernelEvents;
/**
* Event subscriber to redirect canonical pages to external links.
*/
class ExternalRedirect implements EventSubscriberInterface {
/**
* The external redirect helper service.
*
* @var \Drupal\mymodule\ExternalRedirectHelper
*/
protected $redirectHelper;
/**
* Construct the event subscriber.
*
* @param \Drupal\mymodule\ExternalRedirectHelper $helper
* The external redirect helper service.
*/
public function __construct(ExternalRedirectHelper $helper) {
$this->redirectHelper = $helper;
}
/**
* Redirect canonical pages if the node has an external URL set.
*
* @param \Symfony\Component\HttpKernel\Event\RequestEvent $event
* The request event.
*/
public function redirectExternalLinks(RequestEvent $event) {
$request = $event->getRequest();
// Don't redirect on node edit pages and such.
if ($request->attributes->get('_route') !== 'entity.node.canonical') {
return;
}
// Get node object.
$node = $request->attributes->get('node');
if ($node instanceof NodeInterface && $this->redirectHelper->shouldRedirect($node)) {
$uri = $this->redirectHelper->getRedirectUrl($node);
$response = new TrustedRedirectResponse($uri, Response::HTTP_MOVED_PERMANENTLY);
$event->setResponse($response);
}
}
/**
* {@inheritdoc}
*/
public static function getSubscribedEvents() {
return [
KernelEvents::REQUEST => ['redirectExternalLinks', 10],
];
}
}
<?php
namespace Drupal\mymodule;
use Drupal\Core\Session\AccountProxyInterface;
use Drupal\node\NodeInterface;
/**
* Utility methods for handling external content redirects.
*/
class ExternalRedirectHelper {
/**
* Node types that can have external URLs defined.
*
* @var string[]
*/
const EXTERNAL_NODE_TYPES = [
'external_link',
];
/**
* The name of the field defining the external URL.
*
* @var string
*/
const EXTERNAL_URL_FIELD_NAME = 'field_external_link';
/**
* The current user.
*
* @var \Drupal\Core\Session\AccountProxyInterface
* The current user.
*/
protected $currentUser;
/**
* Construct the utility service.
*
* @param \Drupal\Core\Session\AccountProxyInterface $account
* The current user.
*/
public function __construct(AccountProxyInterface $account) {
$this->currentUser = $account;
}
/**
* Determine if the given node contains external content to redirect to.
*
* Will not redirect if the current user has access to edit the node.
*
* @param \Drupal\node\NodeInterface $node
* The content node.
*
* @return bool
* Returns TRUE if the given content should be redirected.
*/
public function shouldRedirect(NodeInterface $node):bool {
return !$node->access('update', $this->currentUser)
&& $this->isExternalContent($node);
}
/**
* Determine if the given content is external.
*
* @param \Drupal\node\NodeInterface $node
* The content node.
*
* @return bool
* Returns TRUE if the content is external.
*/
public function isExternalContent(NodeInterface $node):bool {
return in_array($node->getType(), static::EXTERNAL_NODE_TYPES)
&& $node->hasField(static::EXTERNAL_URL_FIELD_NAME)
&& !$node->get(static::EXTERNAL_URL_FIELD_NAME)->isEmpty()
&& !empty($node->get(static::EXTERNAL_URL_FIELD_NAME)->uri);
}
/**
* Get the redirect URL.
*
* @param \Drupal\node\NodeInterface $node
*
* @return string
* The external URI.
*/
public function getRedirectUrl(NodeInterface $node):string {
return $node->get(static::EXTERNAL_URL_FIELD_NAME)->uri;
}
}
<?php
/**
* Implements hook_ENTITY_TYPE_view_alter().
*/
function mymodule_node_view_alter(array &$build, NodeInterface $node, EntityViewDisplayInterface $display) {
$helper = \Drupal::service('mymodule.redirect_helper');
if ($build['#view_mode'] === 'full' && $helper->isExternalContent($node)) {
$url = $helper->getRedirectUrl($node);
\Drupal::messenger()->addWarning(t('This content will redirect to <a href="@url">@url</a> for anonymous users.', ['@url' => $url]));
}
}
services:
mymodule.redirect_helper:
class: Drupal\mymodule\ExternalRedirectHelper
arguments: ['@current_user']
mymodule.event_subscriber:
class: Drupal\mymodule\EventSubscriber\ExternalRedirect
arguments: ['@mymodule.redirect_helper']
tags:
- { name: event_subscriber }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment