ryan Posted October 30, 2013 Share Posted October 30, 2013 In this tutorial we make a simple function that becomes part of every PageArray. Once hooked to the PageArray class, you can call this function from anything returned from $pages->find(), $page->children(), or your own page references like $page->categories from the blog profile, etc. It essentially becomes a new function available to you from any PageArray anywhere in your site. First, lets look at what convenience the hook function adds and how we might use it. We'll call the hook function "renderLinks", but you could of course call it whatever you wanted. We call that renderLinks() function from any PageArray, and it returns a string representing that PageArray as a list of links. By default, this renderLinks() functions separates each page with a comma, and outputs the page's title as the anchor text. We can change that to be anything by specifying arguments to the call. The first argument is the delimiter, which defaults to a comma ", " if not specified. The second argument is the name of the field to output, which defaults to "title" if not specified. Next are 3 examples of how this renderLinks hook function could be used. Usage Examples: Example 1: render a comma-separated list of links: echo $pages->find("parent=/")->renderLinks(); Output: <a href='/about/'>About Us</a>, <a href='/contact/'>Contact Us</a>, <a href='/site-map/'>Site Map</a> Example 2: render a <ul> of $categories links: <ul> <li> <?php echo $page->categories->renderLinks('</li><li>', 'title'); ?> </li> </ul> Output: <ul> <li><a href='/categories/category1/'>Category 1</a></li> <li><a href='/categories/category2/'>Category 2</a></li> <li><a href='/categories/category3/'>Category 3</a></li> </ul> Example 3: render a breadcrumb trail: <p class='breadcrumbs'> <?= $page->parents->renderLinks(' / ') ?> </p> Output: <p class='breadcrumbs'> <a href='/parent1/'>Parent 1</a> / <a href='/parent1/parent2/'>Parent 2</a> / <a href='/parent1/parent2/parent3/'>Parent 3</a> </p> Those examples above show some of the potential of how you might use such a function. Next is the hook function itself. In order to be available to all templates in your site, it needs to be defined somewhere consistent that is always loaded... Where to put the hook function: If using the basic profile (that comes with ProcessWire) you could put the hook function at the top of your /site/templates/head.inc file. If using the Foundation or Skyscrapers profile, you could put the hook function in your /site/templates/_init.php file. This is the method that I use. If using something else, you could create a /site/templates/_init.php file with your hook function(s) in it, and then edit your /site/config.php to point to it with the $config->prependTemplateFile = '_init.php'; so that it is automatically loaded on every request. Note that the name "_init.php" is not required, you can name it whatever you want. You could put it in an autoload module... but that might be overkill here. The actual hook function: wire()->addHook("PageArray::renderLinks", function(HookEvent $event) { // first argument is the delimiter - what separates each link (default=comma) $delimiter = $event->arguments(0); if(empty($delimiter)) $delimiter = ", "; // second argument is the property to render from each $page (default=title) $property = $event->arguments(1); if(empty($property)) $property = "title"; // $out contains the output this function returns $out = ''; // loop through each item in the PageArray and render the links foreach($event->object as $page) { $value = $page->get($property); if(!strlen($value)) continue; // skip empty values if(strlen($out)) $out .= $delimiter; if($page->viewable()) { // if page is viewable, make it a link $out .= "<a href='$page->url'>$value</a>"; } else { // if page is not viewable, just display the value $out .= $value; } } // populate the return value $event->return = $out; }); If using PHP before 5.3, or using an older version of ProcessWire, you'll need to change the first line to this (below). This syntax also works with newer versions as well, but it's not as pretty as the new syntax. wire()->addHook("PageArray::renderLinks", null, 'hookRenderLinks'); function hookRenderLinks(HookEvent $event) { 25 Link to comment Share on other sites More sharing options...
owzim Posted October 31, 2013 Share Posted October 31, 2013 Ryan, great insight. I recently wondered if one could extend the PW API, did not know it's as easy as this. Link to comment Share on other sites More sharing options...
Soma Posted October 31, 2013 Share Posted October 31, 2013 You didn't knew this?! Where have you been? 1 Link to comment Share on other sites More sharing options...
owzim Posted October 31, 2013 Share Posted October 31, 2013 You didn't knew this?! Where have you been? No, I always saw hooks as sth. to be added before or after some actions (and I already used them for that), but not to create new methods. I have wrapped those into my own static class methods until now =) That said I have not been actively looking into module development and hooks too much so far. Well, things are clearer now. Link to comment Share on other sites More sharing options...
Soma Posted October 31, 2013 Share Posted October 31, 2013 Then you haven't studied the HelloWorld.module that comes as example? Hmm... it was the first thing I checked out when starting looking into modules and there's all examples also adding properties and methods. It's what definately blew my mind and made me stay with PW after all Edit: I don't mean to put you down or something was just wondering and I'm glad you found out now! 3 Link to comment Share on other sites More sharing options...
hollyvalero Posted February 17, 2020 Share Posted February 17, 2020 Making my semi-monthly attempt to get into hooks ? I tried adding Ryan's renderLinks to ready.php at one of my sites... and then tried various versions of the usage, like: echo $pages->find("parent=/")->renderLinks(); in the templates. I take it as a sign of progress that I am past the 500 server error, but the output I get is the single word "array" this is not urgent of course, but wondering if someone can point me in the right direction? Link to comment Share on other sites More sharing options...
dragan Posted February 20, 2020 Share Posted February 20, 2020 @hollyvalero I tried it as well (hook is also in site/ready.php), and everything works just fine. Just copy-and-pasted the hook, and used the list example, and adjusted the selector. It even works within a partial I load via include_once() and cache the output with MarkupCache ? Do you run an ancient PHP version, by any chance? See Ryan's note about PHP < 5.3 Also, did you find any hints with Tracy Debugger? Link to comment Share on other sites More sharing options...
hollyvalero Posted February 20, 2020 Share Posted February 20, 2020 16 minutes ago, dragan said: @hollyvalero I tried it as well (hook is also in site/ready.php), and everything works just fine. Just copy-and-pasted the hook, and used the list example, and adjusted the selector. It even works within a partial I load via include_once() and cache the output with MarkupCache ? Do you run an ancient PHP version, by any chance? See Ryan's note about PHP < 5.3 Also, did you find any hints with Tracy Debugger? Well, that explains it. I had ready.php in the templates folder, not up a level in the /site/ folder. I figured it had to be something stupid and I was right ? At least now I can get into hooks more... thank you! Link to comment Share on other sites More sharing options...
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now