Convert relative paths to absolute URLs in Drupal 8

Consider the following real-life Drupal development scenarios:

  • A blog which provides the RSS feed to its readers;
  • A Drupal app feeding the data to an external application via REST;
  • A newsletter generated from the site’s content.

Try to guess one common problem we need to solve in all of the above.

The «consumer» of our data, be it an RSS reader, client-side JS app or email client will inevitably start receiving broken images and(or) URLs in our content, as in Drupal by default all URLs (embedded via WYSIWYG, entity references, internal links etc.) are relative to the docroot.

There are many solutions to this little problem, each ranging from a few to hundreds of lines of code, but I have one little trick in mind which will make your life much easier.

Anytime you want to ensure the data you send to an external consumer contains absolute URLs, just feed it to Html::transformRootRelativeUrlsToAbsolute() (link) method to let it handle the conversion process for images and links on the fly.

To be more specific, let’s imagine we’re sending a newsletter via Swiftmailer which provides a way to hook into the HTML before the data is sent. The code below is a drop in solution if you use Swiftmailer. For other cases the implementation will be different, albeit similar (and most likely sitting in a proper class instead of a hook).

<?php

use Drupal\Component\Utility\Html;  
use Drupal\core\Render\Markup;  
use Symfony\Component\HttpFoundation\Request;

/**
 * Implements hook_preprocess_swiftmailer().
 */
function mymodule_preprocess_swiftmailer(&$variables) {

 // There are better ways to grab the $base_url for sure.
 $base_url = Request::createFromGlobals()->getSchemeAndHttpHost();

 // Convert the whole message body. Returns string.
 $converted = Html::transformRootRelativeUrlsToAbsolute($variables[’body’], $base_url);

 // In case you need an instance of Markup class prepare it here. 
 $variables[’body’] = Markup::create($converted);
}