Jump to content

A simple way to have your hook methods inside your custom Page classes


Robin S
 Share

Recommended Posts

Since ProcessWire v3.0.152 we have been able to use custom Page classes: https://processwire.com/blog/posts/pw-3.0.152/#new-ability-to-specify-custom-page-classes

Some PW users have said that they would like to have all their hooks relating to a particular Page class contained within their custom Page class file (in /site/classes/), to keep things tidy and organised. But custom Page classes do not have methods that fire on states like "init" or "ready", and it also wouldn't be ideal to attach hooks within a Page class because the class can be instantiated multiple times and therefore such hooks would be attached multiple times.

I understand @bernhard has a feature that addresses this need built into his RockMigrations module, so check that out. And here's another approach, where hooks are attached in the places where you would normally attach them (e.g. in /site/ready.php or /site/init.php, or in the init() or ready() methods of some custom module) but the method that executes in the hook exists within your custom Page classes.

 

Step 1

In /site/classes/DefaultPage.php, add the method shown below:

class DefaultPage extends Page {
	
	// Call any Page methods with names that match the HookEvent object and method
	public function callHookMethods(HookEvent $event) {
		$objectName = $event->object->className;
		$methodName = $objectName . '_' . $event->method;
		if(!method_exists($this, $methodName)) return;
		$this->$methodName($event);
	}

}

This method looks for other Page method names that match the HookEvent object and method and if any exist it calls them. Hooks are attached using the format "Class::method" and this format wouldn't be valid for a method name, so an underscore is used instead of the two colons. E.g. "ProcessPageEdit::buildFormContent" would become "ProcessPageEdit_buildFormContent".

 

Step 2

In any of your custom Page class files, add methods named to match the hookable methods you want to target. These custom Page classes should extend DefaultPage.

In the example below I'm targeting hookable methods Pages::saveReady and ProcessPageEdit::buildFormContent in the BasicPagePage class.

class BasicPagePage extends DefaultPage {

	public function Pages_saveReady(HookEvent $event) {
		// Show a message in the PW admin
		$this->wire()->message("About to save page named: $this->name");
	}

	public function ProcessPageEdit_buildFormContent(HookEvent $event) {
		/** @var InputfieldWrapper $wrapper */
		$wrapper = $event->return;

		// Add a custom markup field to Page Edit
		/** @var InputfieldMarkup $f */
		$f = $this->wire()->modules->get('InputfieldMarkup');
		$f->label = 'My custom markup';
		$f->value = 'Hello!';
		$wrapper->insertAfter($f, 'title');
	}

}

 

Step 3

Attach hooks in the places where you normally would. You need to attach a hook for each hookable method you are targeting in your custom Page classes, but the hook code itself is minimal and where multiple Page classes target the same hookable method you only need it attach it once.

In the example below I'm attaching hooks in /site/ready.php.

$pages->addHookAfter('saveReady', function(HookEvent $event) {
	/** @var DefaultPage $page */
	$page = $event->arguments(0);
	if($page instanceof DefaultPage) $page->callHookMethods($event);
});

$wire->addHookAfter('ProcessPageEdit::buildFormContent', function(HookEvent $event) {
	/** @var ProcessPageEdit $ppe */
	$ppe = $event->object;
	/** @var DefaultPage $page */
	$page = $ppe->getPage();
	if($page instanceof DefaultPage) $page->callHookMethods($event);
});

Each hook only need to establish a $page object (often this is available as an argument to the hookable method) and if it's an instance of DefaultPage then it simply calls $page->callHookMethods($event), and any relevant hook-targeting methods for that particular Page class will fire.

Here's the result of my two hook-targeting methods in BasicPagePage.php when I save a page of this class in Page Edit:

image.png.125de952847acb02b0fdb08264ad1484.png

 

  • Like 4
  • Thanks 2
Link to comment
Share on other sites

Hi @Robin S. Please also take a look at my request "automatically call the init method on custom page classes"  https://github.com/processwire/processwire-requests/issues/456 and maybe leave a thumbs up.

Your method requires changes to /site/ready.php or /site/init.php files. I think self-initiating custom page files are way better, so for example, a blogPage.php custom page class file would automatically create all fields and provide custom methods like `localDate`. This way, you can simply copy the file to a new project, and everything will be set up automatically without needing additional changes to other files.

  • Like 5
Link to comment
Share on other sites

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...