Summary of updates

This latest version on the dev branch includes several tweaks, bug fixes and some nice optimizations. Below is a summary of what's been added in 3.0.45:

  • Major updates to Page field configuration (will cover these separately below).

  • Several optimizations to our hooks system (WireHooks class) to make it even faster.

  • Optimizations to PageTable and Repeater to prevent some pages from getting cached in memory when working at large scale.

  • Improvements to the “custom (field=value)” searches in InputfieldSelector and Lister/ListerPro.

  • Make the “parent” property of Page objects lazy-loading, so that it is no longer loaded unless requested via $page->parent() or $page->parent. Prior to that, it only stores the parent_id. This helps at large scale when a lot of pages need to be loaded with different parents.

  • Update InputfieldRepeater and Lister with the ability to process inline scripts, per request on GitHub.

  • Update the wireRegion() aka region() function to support automatic prepend or append. This is done by initializing the region with region('++name','') for prepend or region('name++','') for append. Further calls with just region('name','value') automatically prepend/append as specified in the first call.

  • Rewrite the Selectors::stringHasSelector() method to make it more accurate (this is used throughout the core).

  • Add support for load time filtering for Page fields, consistent with the new syntax we introduced a couple months ago for other fields. Meaning, now you can do $filtered = $page->page_field("selector") to filter the value before it gets loaded.

Major updates to Page field configuration

The Page reference field is perhaps one of the most important in ProcessWire. But our configuration for Page fields hadn't really changed much since the first release of ProcessWire 2.0. There were definitely things that could be made more clear here, especially for people new to ProcessWire. This week I took the opportunity to redo that part to make it more friendly and more powerful.

Details tab

The Details tab asks you what type of value you want the Page field to be, and now includes API-reference links for those that want more information about the types. The Details tab now also shows you simple usage consistent with the type you've selected. The “allow unpublished pages” option has been moved from the Advanced tab to the Details tab.

Input tab

The Inputfield type selection has been moved to the top, and context-specific settings appear directly below it when applicable. The Inputfield type selections are now grouped in 3 different option groups to make selection more clear: 1) Single page selection; 2) Multi-page selection; and 3) Sortable multi-page selection. If you select an Inputfield type that may not be compatible with other settings (like PageListSelect types) a new info box opens telling you of the special needs.

The “Selectable pages” section is now a lot more clear and includes new options as well. It finally includes a “Custom find” option that lets you use InputfieldSelector to specify what pages are selectable. The makes for more beginner-friendly field configuration relative to using the “Selector string” option. Though we've left the Selector string option there as well, since there are still cases where it can be more powerful.

Selectable pages – “Custom PHP code” changes

We've changed the “Custom PHP code to find pages” option so that it no longer lets you enter PHP code directly in the field configuration. Instead, it instructs you to add your custom PHP code to the /site/ready.php file by using a hook. This method is also backwards compatible with past versions of ProcessWire, and more powerful FTW. For those that are already using the old Custom PHP code option, it will continue working on existing installations. But from this point forward it won't work on new installations, so you'll want to use the new Custom PHP code hook instead.

Why the change? The reality is supporting code entry for loading custom pages was quite convenient, but also the one place I felt was a potential weak point for security – if (and only if) a superuser account was ever broken into. While this kind of access is generally acceptable for a superuser, if we can provide a safer alternative (like the hook) I think that's better. So this is about being uncompromising on security with the core. For 3rd party modules (like Hanna code), I feel differently – it's optional, you install it and know it's there, and so you have a choice. But when a required Fieldtype in the core has it, that's not a choice, so I thought we could do better.

Worth noting is that the new hook method is more efficient, faster, and a whole lot more powerful. Meaning, you can build more complex page selections than you could have with the older custom PHP code option. This is because you are in a full-blown API environment with your custom PHP code now, rather than in a limited single-line eval.

Fun with API calls

I'm always looking for ways to make common API usage simpler and shorter. While I like verbosity when it comes to most of the development I do, I also like getting those API calls as short and sweet as possible as a fun challenge sometimes. It's also great when comparing ProcessWire's syntax with other systems–there are pretty much always simpler, shorter and more concise possibilities with ProcessWire than with other systems. And that's a positive thing. Here's a few examples of ways you can shorten API calls in PW. Take note that I'm not suggesting you adjust your approach to use the more concise examples, just pointing out some fun alternatives.

Find some pages

// the usual recommended way
$items = $pages->find('template=basic-page');

// a shorter way
$items = $pages('template=basic-page');

// if using the Functions API, you can also do this
$items = pages('template=basic-page'); 

Render a list of those pages (PageArray)

// the usual recommended way
foreach($items as $item) {
  echo "<li><a href=$item->url>$item->title</a></li>";

// a shorter way
echo $items->each('<li><a href={url}>{title}</a></li>');

// even shorter (3.0.45+)
echo $items('<li><a href={url}>{title}</a></li>');

The shortest example above works because calling a PageArray as a function with a string argument like the one above makes it delegate to the each() method automatically. You can do this with other PageArrays too, like $page->my_page_field('...');

Render a title, author and date header for a $page

// the usual recommended way
echo "<h1>$page->title</h1>";
echo "<h2>$page->author</h2>";
echo "<h3>$page->date</h3>";

// a shorter way
echo $page->get('

// even shorter
echo $page('

The shortest example above works because calling any Page object as a function sends the argument to $page->get(). Meaning, a call to $page('title') would return the value of the title field. But if the given string contains {vars} in it, then the get() method delegates to the Page::getMarkup() method, which is what translates those {vars}.

That's all for this week! Hope that you all have a great weekend and week getting ready for the holidays, and enjoy reading the ProcessWire Weekly this weekend.


  • Yannick Albert

    Yannick Albert 1 month ago 30

    Just a thought, in addition to "calling a PageArray as a function with a string..." to get a string, would nice if we could "call a PageArray as a function with an array" to get json?

    • LostKobrakai

      LostKobrakai 1 month ago 50

      Not json, but it could be a short variant for explode():

      $arrayData = $pages('template=basic-page')->explode(['id', 'title']);
      $json = json_encode($arrayData);

Post a Comment

Your e-mail is kept confidential and not included with your comment. Website is optional.