szabesz

addHookMethod example for Pageimage(s)

4 posts in this topic

Hi PW fanatics ;)

In this post I share two of my addHookMethods for those interested. As you surely already know (if not, time to take a look at it) the Wire::addHookMethod() and the Wire::addHookProperty() API methods can be used to "breath some extra OOP" into your projects.

Using addHookMethods and addHookProperty are alternatives to "Using custom page types in ProcessWire".

The methods I want to share: basically the idea here is to get the URL pointing to images uploaded in the admin without writing much code in the template files. With methods like these below, it does not matter what Formatted value is set to the images, because some predefined defaults are used in all circumstances.

#1 Example
template file code:

<?php $img_src = $latest_article->siteFeaturedImage(); ?>
<img src="<?= $img_src ?>" alt="<?= $page->title ?>">

addHookMethod goes into /site/init.php

<?php 
/* Returns URL of the original Pageimage of Article.
 * Image field's value can be either null (default missing image), Pageimage or Pageimages.
 * 
 * @return string 
 */
$wire->addHookMethod('Page::siteFeaturedImage', function($event) {
	$page = $event->object;
	if ($page->template != "article") {
		throw new WireException("Page::siteFeaturedImage() only works on 'Pages of article template', Page ID=$page is not such!");
	}
	$article_featured = $page->getUnformatted('article_featured'); //always a Pageimages array
	if (count($article_featured)) {
		$img_url = $article_featured->first()->url;
	} else {
		$img_url = urls()->templates . "assets/img/missing-article_image.jpg"; //we show this when image is not available
	}
	$event->return = $img_url;
});
?>

#2 Example
template file code:

<?php $img600_src = $page->siteProductImageMaxSize(600, 600, ['rotate' => 180]); ?>
<img src="<?= $img600_src ?>" alt="<?= $page->title ?>">

addHookMethod goes into /site/init.php

<?php 
/* Generates image variations for Product images. Returns URL of Pageimage.
 * Image field's value can be either null (default missing image), Pageimage or Pageimages.
 * 
 * @param int arguments[0] Max allowed width
 * @param int arguments[1] Max allowed height
 * @param array arguments[2] See `Pageimage::size()` method for options
 * @return string 
 */
$wire->addHookMethod('Page::siteProductImageMaxSize', function($event) {
	$page = $event->object;
	if ($page->template != "product") {
		throw new WireException("Page::siteProductImageMaxSize() only works on 'Pages of product template', Page ID=$page is not such!");
	}
	$width = isset($event->arguments[0]) ? $event->arguments[0] : 48; //default width
	$height = isset($event->arguments[1]) ? $event->arguments[1] : 48; //default height
	$options = isset($event->arguments[2]) ? $event->arguments[2] : $options = array(); //default empty options
	$product_image = $page->getUnformatted('product_image'); //always a Pageimages array
	if (count($product_image)) {
		$img_url = $product_image->first()->maxSize($width, $height, $options)->url;
	} else {
		$img_url = urls()->templates . "assets/img/product-missing-image.jpg"; //we show this when image is not available
	}
	$event->return = $img_url;
});
?>

BTW, you can find more examples here:

Have a nice weekend!

Edited by szabesz
code updated, thanks Robin
9 people like this

Share this post


Link to post
Share on other sites

Nice tutorial, thanks!

You could simplify the methods a little by making sure you always get the Images field as a Pageimages array, e.g.

$wire->addHookMethod('Page::siteFeaturedImage', function($event) {
    $page = $event->object;
    if ($page->template != "article") {
        throw new WireException("Page::siteFeaturedImage() only works on 'Pages of article template', Page ID=$page is not such!");
    }
    $article_featured = $page->getUnformatted('article_featured'); // always a Pageimages array
    if (count($article_featured)) {
        $img_url = $article_featured->first()->url;
    } else {
        $img_url = urls()->templates . "assets/img/missing-article_image.jpg"; //we show this when image is not available
    }
    $event->return = $img_url;
});

 

4 people like this

Share this post


Link to post
Share on other sites
7 hours ago, Robin S said:

by making sure you always get the Images field as a Pageimages array

Aha, yes! Thank you! I keep forgetting that we have unformatted values too. I updated both methods in my original post.
Cheers,

4 people like this

Share this post


Link to post
Share on other sites

Thank you! This is very useful because I'm not a php expert. Welcome everyone!

2 people like this

Share this post


Link to post
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

  • Recently Browsing   0 members

    No registered users viewing this page.

  • Similar Content

    • By Davidov
      Good Day!
      I am a beginer of processwire project. Thanks developers for your great work. this CMS is very Good!
      I have a question: how get Pageimage object of PageArray from "Page" (PageArray) field type?
      I have too tamplates: affiliates and their teachers. The template of affiliates have a field "teachers_list" wich is "Page" (PageArray) type.
      When I vaffiliate teachers in a cycle, I can not access the teacher photo object and change its size.   I get an error returning: " Fatal error: Call to a member function maxWidth() on null ". When i trying get URL attribute : $teacherItem->teacher_photo->url, i receive message: " Trying to get property of non-object ".   But this code works: $teacherItem->teacher_photo["url"].   The print_r function outputs the following information: "ProcessWire \ Pageimage Object ([changes] => Array ([0] => formatted) [hooks] => Array ([Pageimage :: pim2Load] => PageImageManipulator02-> getPageImageManipulator02 () in PageImageManipulator02.module ) [Data] => Array ([basename] => p16.jpg [description] => .... - ..... [tags] => [formatted] => 1 [modified] => 1487079115 [created ] => 1487079115))".   my PHP code: foreach ($page->teacher_list as $teacherItem): $out .= " <tr> <td class=\"alignTop\"> /* !!! my truble */ <img src=\"{$teacherItem->teacher_photo->maxWidth(250)->url}\" /> /* !!! my truble */ </td> <td class=\"alignTop\"> <div class=\"teach_style12\"> <strong>$teacherItem->fio</strong><br/> $teacherItem->degree<br/> $teacherItem->headline_detail </div> <div class=\"teach_style9\"> $teacherItem->body </div> </td> </tr>"; endforeach; Please, help me. Where is my error?
       
    • By Qualtext
      Hi community,
      i want to add a selector to every pages->find() method. I found this hook solution, and Ryan mentioned this somewhere in this forum.
      https://processwire.com/api/ref/pages/find/
      $this->addHookBefore('Pages::find', function(HookEvent $event) { // Get the object the event occurred on, if needed $pages = $event->object; // Get values of arguments sent to hook (and optionally modify them) $selector = $event->arguments(0); $options = $event->arguments(1); /* Your code here, perhaps modifying arguments */ // Populate back arguments (if you have modified them) $event->arguments(0, $selector); $event->arguments(1, $options); });  If i try to add something to the given $selector, the error occurs: Exception: Unknown Selector operator: '' -- was your selector value properly escaped?
      But the syntax is right, isn´t it?
      $this->addHookBefore('Pages::find', function(HookEvent $event) { // Get the object the event occurred on, if needed $pages = $event->object; // Get values of arguments sent to hook (and optionally modify them) $selector = $event->arguments(0); $options = $event->arguments(1); /* Your code here, perhaps modifying arguments */ $selector.= ", loremipsum_field!=1"; /* <----------------------- */ // Populate back arguments (if you have modified them) $event->arguments(0, $selector); $event->arguments(1, $options); }); What i am doing wrong?
      Thank you for your advice!
       
    • By didhavn
      Hey all. 
      This might sound a bit strange but I am looking for a solution to hook into page edit and remove or disable the two save buttons including their dropdown options. 
      I managed to partly remove the buttons, but the dropdowns remained. However, I would prefer a solution with disabled buttons but have no idea how to achieve this. 
      I hope somebody of you can tell me how to remove or disable these buttons. 
      Thanks a lot in advance 
    • By gebeer
      Hello,
      I read about conditional hooks and wanted to utilize them. In the process of trying to implement them I found that they do not get called.
      So I reduced my hook to a minimum
      wire()->addHookAfter('Page::changed', function($event) { die('changed'); }); And nothing happens at all. Also with Page::changed(title) or Page(template=basic-page)::changed(title) no luck.
      In the code comment in Wire.php it says: "Hookable method that is called whenever a property has changed while change tracking is enabled"
      I see that change tracking is enabled as
      wire()->addHookAfter('Pages::saveReady', function($event) { if($event->arguments[0]->isChanged('title')) die('changed'); }); is working.
      The hookable method ___changed() in Wire.php is empty.
      I tried this on 2 different installs PW 3.0.61 and 3.0.62
      Can anyone please confirm or let me know if I'm doing anything wrong here. Thank you.
    • By ---
      So I discovered in this topic (
      ) that I can cancel all hooks after my own hook. Now I want something like that.
       
      I want my hook which is called on page render to cancel all other events, also the after page render and the before page render methods, is this possible?
      This only need to be done when some conditions are met.
       
      /** method replaces original page::render method and is called with hook priority one */ method onPageRender (HookEvent $event) { if (my condition is true) { $this->cancelHooks = true; // to cancel all hooks to page::render // how to cancel after Page::render events // how to cancel before Page::render events } } Is this possible at all?