Jump to content

[SOLVED] URL Hooks and URL segments


gebeer
 Share

Recommended Posts

Hi, I've been using the URL hooks feature quite extensively since it has been introduced and generally this is working fine.

Now I have a case where URL segments are activated for the home page because I need to rewrite some URLs for pages that live under a certain parent to make them live under home. Those pages have custom page paths modified through Page::path hooks. This is all working fine.

But now I wanted to introduce a new route for outputting files through a URL hook $wire->addHook('/files/{filename}). And this hook never fires. Accessing URLs like /files/my-file.pdf leads to a 404. The reason seems to be that home template has URL segments enabled. As soon as I disable them, my URL hook is working.

I can't find any mention of this in the URL hook or URL segments  documentation.

I tried higher hook priority on my URL hook so that it kicks in before my ProcessPageView::execute hook which handles the URL segments for the home page. Didn't work.

I am assuming that before a 404 is thrown when none of the URL segments is handled, my URL hook would kick in. But obviously this is not the case.

I know that I could add the logic for handling the files output inside my ProcessPageView::execute hook. But that one is quite complex already and for separation of concerns I'd rather prefer to have that logic in a separate hook.

Anyways, I wanted to ask if someone has come across a similar situation or if any of you know that the observed behaviour (URL hooks not working when URL segments are active on home template) is to be expected.

Link to comment
Share on other sites

2 hours ago, gebeer said:

I am assuming that before a 404 is thrown when none of the URL segments is handled, my URL hook would kick in. But obviously this is not the case.

Sounds like a bug to me and might be worth creating an issue on github?

Other than that: Have you tried limiting allowed url segments via regex?

Just tried with a regex that allows all url segments except ones starting with "test" and it worked:

regex:^(?!test).*$

In home.php

bd($input->urlSegment1);

And the hook in init.php:

$wire->addHookAfter("/test/{file}", function ($e) {
  bd($e->file);
});

/foo/bar/ --> shows "foo"

/test/foo.jpg --> shows "foo.jpg"

  • Like 3
Link to comment
Share on other sites

Depending on how you're handling unrecognized URLs, this could be a feature (sort of). If you enable all URL segments and don't throw 404 with the Wire404Exception::codeFunction code (or via wire404() function), no further hooks will (or should) be executed.

See wire404() function docs (and/or function definition) for more details.

... though if you're already handling them as described above, then it's likely a bug 😄

  • Like 3
Link to comment
Share on other sites

1 hour ago, bernhard said:

Just tried with a regex that allows all url segments except ones starting with "test" and it worked:

regex:^(?!test).*$

 

Thank you. Actually I had already tried that but didn't mention it in my post. Unfortunately it didn't work in my scenario. I'll try to replicate it on a fairly blank multilang install and see how it goes.

EDIT: what I also didn't mention is that in my multilang scenarion the homepage of the default language is redirected to /en/ through the setting in LanguageSupportPageNames.

Link to comment
Share on other sites

Thanks to everyone for your valuable input. Here are my findings after having tested this on a fairly virgin multilang install with root URL in default language redirected to /en/ through LanguageSupportPageNames setting and URL segements enabled on the home template.

After putting in anything in the URL segment whiltelist, the URL hook works.

And of course, like @bernhard suggested the regex option makes total sense.

51 minutes ago, WillyC said:

ga beer --
u.try this in home.php  ?

if ( $input->urlSegment1 === 'files' ) wire404();

 

Great idea if you control behaviour from within the template file. And this also proofs that URL hooks are kicking in right befor showing the 404 page.

52 minutes ago, teppo said:

If you enable all URL segments and don't throw 404 with the Wire404Exception::codeFunction code (or via wire404() function), no further hooks will (or should) be executed.

I enabled all segments by leaving the whitelist empty. Then in my PageView::execute hook, that handles display of pages by URL segment, I am throwing a 404 with `throw new Wire404Exception();`
This throws an Exception and doesn't show 404 or execute my URL hook. Seems like we can use wire404() or throw new Wire404Exception only in template files? My hook is triggered inside init() of an autoload module. 

My conclusion: if you have URL segments enabled on the home page and want a URL hook to execute, you need to have a whitelist for URL segments defined.

Thanks again to everyone. Now if you can tell me how I can throw a 404 without getting an Exception in my autoload module, that would be awesome 🙂

 

  • Like 2
Link to comment
Share on other sites

On 5/5/2023 at 4:14 PM, gebeer said:

Now if you can tell me how I can throw a 404 without getting an Exception in my autoload module, that would be awesome 🙂

That's going to be a problem. ProcessPageView::execute is responsible for calling ProcessPageView::renderPage or ProcessPageView::renderNoPage, which are the two methods responsible for catching and handling 404 exception. In this case you're preventing the core from doing what it would normally do.

Instead of looking for workarounds (which may not exist), it's easier to just handle segments in templates, or define allowed segments (as discussed above). If you need to serve a page from an URL below home page that doesn't match an actual page, and this needs to happen in a module, it's better to leave URL segments out of the equation (just keep them disabled) and instead use URL hooks or hook to ProcessPageView::pageNotFound.

  • Like 4
Link to comment
Share on other sites

16 minutes ago, teppo said:

That's going to be a problem. ProcessPageView::execute is responsible for calling ProcessPageView::renderPage or ProcessPageView::renderNoPage, which are the two methods responsible for catching and handling 404 exception. In this case you're preventing the core from doing what it would normally do.

Instead of looking for workarounds (which may not exist), it's easier to just handle segments in templates, or defining allowed segments (as discussed above). If you need to serve a page from an URL below home page that doesn't match an actual page, and this needs to happen in a module, it's better to leave URL segments out of the equation (just keep them disabled) and instead use URL hooks or hook to ProcessPageView::pageNotFound.

Very enlightening info. Thank you! I'm not going to be able to handle that in home.php. But given your info, I'll try to hook into ProcessPageView::pageNotFound instead and see how it goes.

Link to comment
Share on other sites

A little update. @teppowas spot on. Having my logic inside a hook to PageView::execute was not a good idea. I refactored it, put simple URL segment logic in home.php while keeping the processing of the segments inside a module. This makes life much easier because I can throw 404s and therefore have URL hooks working as they should.

Thanks again everyone for your input on this. Very much appreciated. 

  • Like 3
Link to comment
Share on other sites

  • gebeer changed the title to [SOLVED] URL Hooks and URL segments

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...