2

So let's say I have a basic page node.

I want to have this as an entity reference inside another content type - let's say an event content type.

So let's say that the event content has a url like baseurl.com/eventblahblahblah

When a user clicks over to the basic page that is the reference on node eventblahblahblah, I want them to go to baseurl.com/eventblahblahblah/basicpagenodehere - this needs to be the URL in the browser.

In addition, basicpagenodehere can be in multiple references - so if basicpagenodehere is also referenced by event2blah, then I want it to also be located at the url baseurl.com/event2blah/basicpagenodehere

I'm looking at possibly doing this with alterRoute -

class RouteSubscriber extends RouteSubscriberBase {
  /**
   * {@inheritdoc}
   */
  public function alterRoutes(RouteCollection $collection) {
  }
}

But I'm not sure if this is the correct place to do it.

This link suggests maybe PathProcessor, but I don't think that would change the actual URL on the node at the end of processing:

How to alter and rewritte current path programmatically in Drupal 8?

So how do I set a dynamic URL based on referring node?

1 Answer 1

6

The routing system is probably not the right place for this, you would need to rebuild the routing table whenever the content is changed, which is very slow.

PathProcessor is the right tool. By the way, path aliases are also implemented in a PathProcessor, the aliases are coming from a lookup table. You can change the path in and outbound dynamically or with your own lookup table if you need it for performance reasons.

Better for SEO would be a redirect to avoid duplicate content, but this changes the url in the browser, what you don't want.


Example for the symmetrical inbound/outbound (asked in the comments):

  public function processInbound($path, Request $request) {
    if (strpos($path, '/foo/') === 0) {
      $path = preg_replace('#^/foo#', '', $path);
    }
    return $path;
  }

  public function processOutbound($path, &$options = array(), Request $request = NULL, BubbleableMetadata $bubbleable_metadata = NULL) {
    $path = '/foo' . $path;
    return $path;
  }

This will add /foo to all paths.

One way to approach this could be, you get the child node node/x in the outbound processor as input, the parent node id from the current route. Then you get the title from each of both nodes and put the path together.

For inbound I suggest a third fix path parameter, so that you can identify this kind of path right away and scrap all but the title from the child node, query the node id and you are back where you started at /node/x.

19
  • When I change the outbound, I keep getting "path not found" - even when I change the inbound to the same thing. Am I misunderstanding what I am doing here? The outbound definitely changes the URL, but does not seem to correctly path to the node.
    – Jack Ryan
    Mar 2, 2017 at 18:59
  • Yes, you have to do this symmetrically, inbound and outbound. But you can test this independ from each other. You can start with inbound by testing the url baseurl.com/eventblahblahblah/basicpagenodehere in the browser and debug how this gets changed inbound to the canonical url from the node.
    – 4uk4
    Mar 2, 2017 at 19:14
  • Hrm, when I try symmetrically, I get "The website encountered an unexpected error. Please try again later." along with this: a:6:{s:5:"%type";s:61:"Symfony\Component\Routing\Exception\ResourceNotFoundException";s:8:"@message";s:58:"None of the routers in the chain matched url - I think we're on the right track but it seems like a custom router might be necessary too?
    – Jack Ryan
    Mar 2, 2017 at 19:22
  • All I've changed in ::processOutbound & ::processInbound is that I added "/foo" to the path when returned for testing purposes.
    – Jack Ryan
    Mar 2, 2017 at 19:23
  • 1
    but if you use aliases you have to set a priority higher than 100 for inbound, because the aliases only work if /foo has been removed before
    – 4uk4
    Mar 6, 2017 at 16:44

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.