How to alter node url or toUrl function output? How do we alter what's returned from $node->url()?  or $node->toUrl()?

There are many entity reference fields that don't allow referencing more than one entity type or a custom route, such as entity queue or entity reference fields.  For this purpose, so that we can create entity queues that reference other entities other than nodes, I am attempting to create a node with the bundle "redirect", and when the node referenced on the site, it would display the link to the referenced item on a field on that entity field_path (which is a link field).

The problem is that $node->url() or $node->toUrl() is tightly integrated into the node object.  In Drupal 7 we had hook_url_outbound_alter which made this kind of thing easy.  I would like a Drupal 8 equivalent.  So that whenever a url or link to my redirect node is displayed, it is replaced with the value of field_path.  Not just that node/ redirects, but that it displays the redirect.

So how do we alter $node->toUrl() if $node->bundle() == 'redirect'?

I have found I can fix this most places on the site using two hooks:

/**
 * Implements hook_entity_view().
 *
 * Gets the output for extra fields.
 */
function mymodule_preprocess_node(&amp;$variables) {
  if ($variables['node']-&gt;bundle() == 'redirect') {
    if (!$variables['node']-&gt;field_path-&gt;isEmpty()) {
      $redirect = $variables['node']-&gt;field_path-&gt;getValue()[0]['value'];
      $variables['url'] = $redirect;
    }
  }
}

/**
 * Implements hook_link_alter().
 */
function mymodule_link_alter(&amp;$variables) {
  if (empty($variables['options']['external']) &amp;&amp; !empty($variables['options']['entity'])) {
    $entity = $variables['options']['entity'];
    if ($entity-&gt;getEntityTypeId() == 'node' &amp;&amp; $entity-&gt;bundle() == 'redirect') {
      if ($variables['url']-&gt;getRouteName() == "entity.node.canonical" &amp;&amp; !$entity-&gt;field_path-&gt;isEmpty()) {
        $redirect = $entity-&gt;field_path-&gt;getValue()[0]['value'];

        if ($new_url = URL::fromUri('internal:'.$redirect)) {
          $variables['url'] = $new_url;
        }
      }
    }
  }
}


But this doesn't help if someone calls the ->url() function without the link wrapping it.
Path outbound processing still exists: OutboundPathProcessorInterface, check the implementations, like path alias handling. It's a tagged service.

That said, not sure if that's the approach that I'd take, I usually implemented something like that simply by overriding the necessary node templates/preprocess.