szabesz

addHookMethod example for Pageimage(s)

Recommended Posts

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
  • Like 10

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;
});

 

  • Like 4

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,

  • Like 4

Share this post


Link to post
Share on other sites

Additional tip related to displaying placeholder images:

Above I just hard coded a placeholder image to be shown which might be all what someone needs. However, there are times when we want to let the editors change that picture or we just want it to show up in the admin too. In that case we can use ProcessWire's "Default value (when empty)" setting:

placeholder-image.thumb.jpg.2d3eb16903b24207a5a719b1403b37a2.jpg

  • Like 1

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 dragan
      $this->addHookBefore('InputfieldTextarea::render', function($event) { $field = $event->object; if($field->name == 'body_offer') { $del = ''; foreach($this->wire->pages->get(11229)->textblocks as $item) { $field->entityEncodeText = false; $body = str_replace(PHP_EOL, '', $item->body); $body = addslashes($body); $title = $item->title; $field->description .= $del . "<a href=\"#\" class=\"ckesnippet\" data-snippet=\"$body\">$title</a>"; $del = ' | '; } } $js = wire('config')->urls->templates . 'scripts/ckesnippets.js'; $event->return = str_replace("</html>", "\n<script type='text/javascript' src='$js'></script>\n</html>", $event->return); }); I'm trying to add custom text-blocks from repeater fields into CKEditor. I've stolen the whole idea (and code) from @bernhard

      Problem is: The links are actually being rendered, but the Javascript is not loaded, i.e. the $event->return line doesn't seem to work. If I inspect the HTML, my additional script-tag is nowhere to be seen. I don't get any errors either. Running latest PW dev + PHP 7.1.19.
    • By Noel Boss
      I use a PageTable field to make edits to children of pages more intuitive…
      To register the hooks, insert the following Snippet inside your init function in your module (or add it to your init.php file):
      /** * Initialize the module. * * ProcessWire calls this when the module is loaded. For 'autoload' modules, this will be called * when ProcessWire's API is ready. As a result, this is a good place to attach hooks. */ public function init() { // Prefill pageTable field $this->wire()->addHookBefore('InputfieldPageTable::render', $this, 'addChildrenToPageTableFieldsHook'); $this->wire()->addHookBefore('InputfieldPageTableAjax::checkAjax', $this, 'addChildrenToPageTableFieldsHook'); } Then, add this hook method:
      /** * Fill pagetable fields with children before editing…. * * @param HookEvent $event */ public function addChildrenToPageTableFieldsHook(HookEvent $event) { $field = $event->object; // on ajax, the first hook has no fieldname if (!$field->name) { return; } // get the edited backend page $editID = $this->wire('input')->get->int('id'); if (!$editID && $this->wire('process') instanceof WirePageEditor) { $editID = $this->wire('process')->getPage()->id; } $page = wire('pages')->get($editID); // disable output formating – without this, the ajax request will not populate the field $page->of(false); // you could also insert a check to only do this with sepcific field names… // $page->set($field->name, $page->children('template=DesiredTemplate')); // just specific templates $page->set($field->name, $page->children); } Now whenever there is a page-table field on your page, it gets populated with the children
    • By Sten
      Hello,

      I still did not solve my problem about Hebrew letters. In fact, it is ok for Russian for example to have a transliteration of characters (one to one) but in languages like Hebrew, Arabic, it is better to slugify with phonetic like here :
      use EasySlugger\Utf8Slugger; $slug = Utf8Slugger::slugify('日本語'); // slug = ri-ben-yu $slug = Utf8Slugger::slugify('العَرَبِيةُ‎‎'); // slug = alrbyt $slug = Utf8Slugger::slugify('עברית'); // slug = bryt So I am planning to insert https://github.com/javiereguiluz/EasySlugger
      Should I create a module or just add a hook ?
       
      I am a PW newbie.
      Thanks for your help
       
    • By Andreas Augustin
      hello,
      I want to build a custom validator on my multilang site.
      I added following hook, but I get only the default language value. How can I access the values of the other languages?
       
       
      public function init() { $this->addHookAfter("InputfieldTextarea::processInput", $this, "validateShortlinks"); } public function validateShortlinks($event) { $field = $event->object; $text = $field->value; // only the default language, how can I get the other languages? }  
    • By benbyf
      Hello, having trouble getting PW to save my user or field in cron hook.
      It seems to report the same field info each time unchanged. It should be counting down in seconds.
      public function init() { // set to every30Seconds in settings $this->defaultInterval = $this->cron_check; // add hooks to CRON $this->addHookAfter("LazyCron::{$this->defaultInterval}", $this, 'checkUserSubscription'); } public function ___checkUserSubscription(HookEvent $e){ // seconds since last lazycron $seconds = $e->arguments[0]; $log = wire('log'); $field = $this->exclusiveRole; // users with specific role and field $users = $this->users->find("roles=$field"); foreach ($users as $user) { // get stored time $currentTime = $user->get($this->fieldName); // if time not null if($currentTime){ // evalute stored time minus time past $resultTime = intval($currentTime) - intval($seconds); $log->message("result ".$resultTime); // save user page $user->set($this->fieldName, $resultTime); $this->users->save($user); } } }