Jump to content

Recommended Posts

Posted

I already checked the CaptainHook cheatsheet - only the httpUrl method for PageFiles is hookable. It looks as if hooking the counterpart for pages is not possible ?

I currently use httpUrl at many places in the code but the URLs need to be rewritten. When hooks are not appropriate: Is there a way to add a custom method for all pages (e.g. $page->myCustomPath()) which actually returns the URL I need?

Posted

When you want to change a page's url or httpUrl in a hook you do this by hooking Page::path - the URLs are derived from the path.

The classic post about this is Ryan's CMSCritic case study: 

So for a hook like this...

$wire->addHookBefore('Page::path', function(HookEvent $event) {
	$page = $event->object;
	if($page->template == 'news_item') {
		$event->replace = true;
		$event->return = "/my-custom-path/$page->name/";
	}
});

...the results are...

2019-06-11_110639.png.dcf2681c17c1c5118fa417205965ee29.png

  • 6 years later...
Posted

Gemini AI Pro is crazy good these days. I was stuck why the replace hook had no effect, and this solved it (courtesy of Gemini from Google is in italic):

The reason your hook is firing (as proven by your bd() output) but $p->path, $p->url, and $p->httpUrl are reverting back to the original /parent/ path is due to a hook priority conflict, usually caused by ProcessWire's Multi-Language modules (or an SEO/routing module).

Here is exactly what is happening under the hood:

  1. Your addHookBefore runs, sets $event->replace = true, and sets $event->return to /blog/.
  2. ProcessWire skips its native Page::path() method because of the replace flag.
  3. However, another module (like LanguageSupportPageNames) has an addHookAfter attached to Page::path.
  4. That module runs after your code, looks at the $page object, recalculates the original path from the database tree, and silently overwrites your $event->return before it finally gets handed back to your $p->url call.

To fix this, you need to change your hook to an addHookAfter, remove the replace flag, and bump the priority so your code is the absolute last thing to run.

Change your hook to the following:

$wire->addHookAfter('Page::path', function (HookEvent $event) {
    $page = $event->object;

    if ($page->template == 'original-parent') {
        // Overwrite whatever the core (or other modules) generated
        $event->return = "/blog/$page->name/";
    }
}, ['priority' => 1000]); // Priority > 100 ensures this runs AFTER core modules

And yes, I have multilingual support installed, and this solution works.

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
  • Recently Browsing   0 members

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