Recommended Posts

kixe    808

As described in this post ( the option 'Name Format Children' under the tab 'Family' in template settings doesn't work properly and also not as expected. I had a look inside the code and made some changes which are working properly, which offers much more options, more consistency and less code too.

The result is the following. You have 3 Options for generating name and title, which could be combined in endless variations.
Name is always derived from title, same like creating pages manually.

  • type date: if function detects # character anywhere in the string, conversion will be: deletion of # and string will be used as format parameter for PHP date() function
  • type field: if string is a fieldname of the parent page the value of this field will be used
  • type string: if string doesn't fit to the 2 preceeding it will be taken as it is

All parts (separated by comma) will be composed in the order of setting. You can use unlimited numbers of parts

I made a pull request on github:

Example screenshots

Setting ...

will result in


  • Like 10

Share this post

Link to post
Share on other sites
kixe    808


Yes, the title is generated and the name too, as a derivation from the title. (have a look at the system notice on top of the screenshot) Derivation works completely in the same way, if you add a page manually and type in the page title. I think thats what most user would expect.

You have read the post, where I described, how it is working actually (link in the first post of this topic). This way seems to be unlogical to me.

  • Like 1

Share this post

Link to post
Share on other sites
Ivan Gretsky    804

Yes, I took part in that conversation too. But it seems to me that the way it was supposed to work is to autogenerate name for a page on a pattern at creation time but not from the title. As there is no title on creation yet we could:

  • either generate name from parent fields, dates, custon text + numbers, or
  • apply the pattern on the first save (but not generate the title field by that pattern).

If using your solution we have to:

  • either not use title field for output as you probably would not want to use something like "prefix Wednezday...", or
  • save the page to generate name field value and then change the title once again.

I could misunderstand you as I did not apply you patch to the core.

Share this post

Link to post
Share on other sites
kixe    808

@ Ivan

Thats not true. Now you cannot use any field of the parent page to generate the name. Only the generation from date function is possible now. Try it out!
But with my solution you could use all the parent page fields + date + some string in the order you want it. This is obviously more + inclusion what we have.

About title:
Now you get, whatever you defined in the setting the title 'untitled' or a title generated from date which you maybe want to overwrite anyway! No other possibilities until now!

Maybe I understoud you completely wrong, or you my solution. :rolleyes:  Have a look in github.

  • Like 2

Share this post

Link to post
Share on other sites
aasdev    0

did this ever get merged?  In 2.6.1,  something as simple as title_Y/m/d looks like it ends up being interpreted according to php date().

Share this post

Link to post
Share on other sites
kixe    808

Since there are a lot of topics about the same theme, I decided to write a small module which overwrites the core function ___SetupPageName().
The module allows now to populate the page name

  1. using proprietary date() function. Works like PHP date() with follwing exceptions: 
    Everything between the brackets is detected as format string, meaning no 2nd parameter possible. No need to use quotes around the format string. Spaces not allowed.
  2. from any page property, page field including subfields, parent property, parent field etc. Meaning everything what you get with $page->get(); including dot syntax.

The function will give error and warnings in case of unproper settings, but creates the page with name 'untitled' anyway.

Download here:
Some Examples
The following settings in parent template 'Name Format Children' will

assign name immediately.

  • date(Y)
  • date('Y-m-d')
  • parent.title
  • parent.parent.title

assign name after page saving and/or population of depending field. Overwrites 'untitled' after all fields which are defined in parent template are populated.

  • id (any other page property)
  • pagefieldname, multiple pagefieldnames

show a warning.

  • pagefieldname (value not populated)

show an error.

  • date() // empty, no format assigned
  • date(Y // missing closing bracket
  • date(Y md) // unallowed space
  • notexistingfieldname
  • notexistingproperty
  • existingfield.notexistingsubfield

The function in the module  ___SetupPageName() could be completely copied as is to the core class $pages.

Would be nice to see this in core. :)

Related topics:

Any recommandations after testing welcome. Download here:

Download here:

Edit: small enhancement to prevent display of warning twice.
23.12.15 multiple values possible now
24.12.15 made compatible with PW 3.x
27.12.15 Update Version 1.0.8
09.01.16 Update Version 1.1.0

Edited by kixe
  • Like 15

Share this post

Link to post
Share on other sites
kixe    808

From now you can use multiple values separated by space. Example: "parent.title date(Y) myfield". Page name will remain 'untitled' until last required field is populated.
You will get informed about this by a warning.

Merry Christmas.

  • Like 3

Share this post

Link to post
Share on other sites
adrian    7,650

Hey kixe,

Thank you - this is awesome and solves one of my biggest issues with PageTable fields - getting meaningful page names without the possibility of conflicting names which I don't think the user should ever have to consider.

One minor thing (but critical) - when installing with PW 3.x I get this error:

Catchable fatal error: Argument 1 passed to ProcessWire\Pages::__construct() must be an instance of ProcessWire\ProcessWire, none given, called in /wire/core/Modules.php on line 481 and defined in /wire/core/Pages.php on line 128

It is easily fixed by adding an empty construct method to your module, like this:

public function __construct() {
    // intentionally empty

I am definitely looking forward to using this with all my PageTable fields!

  • Like 2

Share this post

Link to post
Share on other sites
Jon    19


Ive just installed this module but get the following error. Any Ideas?

Error: Call to undefined function _() (line 56 of F:\Programs\wamp\www\tml\site\modules\ProcessSetupPageName\ProcessSetupPageName.module) 

This error message was shown because you are logged in as a Superuser. Error has been logged.
  • Like 1

Share this post

Link to post
Share on other sites
bernhard    1,289

hi kixe,

thank you for your work, i can use this in my current project :)

but i found two bugs:

  • date('d.m.Y H:i:s') forename surname
    gives an error due to the space in date()
  • date('dmY',created) forename surname

i don't need date('Ymd',val), but just tried it and think it would be good to handle this one as well. didn't look at your code but i think the regex should get some fine tuning :)

Share this post

Link to post
Share on other sites
kixe    808

Hi Bernhard,
thanks for the effort you have made testing my module. I think my regex is ok. Maybe I have to modify the detection of multiple fields, which happens before. For now it is a single space character. Since spaces are not allowed in page names you don't need to use spaces in the date function this will be anyway translated later (space -> dash).

Does it make sense to provide a timestamp from a page property or datetime field, since you could handle this in another way?
s a bit painful to use the date() function, contrary to the correct PHP syntax
. Meaning I didn't define any timestamp constants like 'val' or 'created' in the module. To prevent confusion I want to stay using correct date() syntax.

For your second example you can easily use: "created forename surname" and you will get the same result.

I don't understand date('dmY',val). If val is a pagefield, which returns a timestamp please use: 'val forename username' after configuring the output of field 'val' to 'dmY' in the field settings.
If you then need other output formats in the templates you can do:

echo date('Y-m-d h:i',$page->getUnformatted('val'));

Share this post

Link to post
Share on other sites
bernhard    1,289

hi kixe,

sorry - i was unclear.

"think it would be good to handle this one as well" was meant as "would be good to handle this as a wrong input" and maybe give an appropriate error message that helps the user find a correct string. "val" was just a placeholder for any value. as i said i don't need this because i switched to standard name for children + creating title field on page save per custom module.

i agree that there is room for improvement in the core at this special step of naming children automatically :)

Share this post

Link to post
Share on other sites
Juergen    270

I dont know if this is a problem of the module or from PW in general.

The path names on a multilingual site are only changed for the default language and not for the other languages. In my case I use parent title and date. In German (default) it shows me both, but in English I only get the parent title without the date.

Best regards

It is not a big problem because you can change the pathname afterwards via a hook for the other languages.

Edited by Juergen

Share this post

Link to post
Share on other sites
kixe    808

Thanks for reporting this. If I find a little time I will have a deeper look. Multilanguage support isn't tested very well until now.

There are still some other situations where the module doesn't work:

  • If you want to generate name from a file field (selector like 'myimagefield.description') you will get an error.
  • Name generation from a ProfieldsTable column is also not possible.

I agree multilanguage name generation should be supported.

Share this post

Link to post
Share on other sites
Juergen    270

You can do it in the module. Here is the code of an module which changes the path names for multilingual site.

 * ProcessWire 2.x 
 * Copyright (C) 2014 by Ryan Cramer 
 * Licensed under GNU/GPL v2, see LICENSE.TXT
class CorrectPagenames extends WireData implements Module
    public static function getModuleInfo()
        return array(
            'title' => 'CorrectPagenames',
            'version' => 1,
            'summary' => 'Output custom path names multilingual',
            'singular' => true, // Limit the module to a single instance
            'autoload' => true // Load the module with every call to ProcessWire 
    public function init()
        // init() is called when the module is loaded.
        // saveReady is a hook after processing the previous changes of the page,
        // but just before those changes are saved to the database.
        // It's called for each page that's being saved, no matter if it's in
        // the backend or in your templates via the api.

        $this->addHookBefore('Pages::saveReady', $this, 'beforeSaveReady');

    public function beforeSaveReady($event)
        $page = $event->arguments[0];
        //create custom path name for children events
            $datestart  = $page->publish_from;  // I use the publish from date for the path name
            $datestart  = date('Y-m-d', $datestart);
            $eventtitle = $page->parent->title; // I also use the parent title for the path name
            $page->name = $eventtitle . '-' . $datestart; //putting it all together for the default language
            foreach ($this->languages as $lang) { //multilanguage starts here
                if ($lang->isDefault())
                $lname               = $lang->id;
                $pageName            = $page->title->getLanguageValue($lang);
                $pageName            = $pageName . '-' . $datestart;// create custom path for other languages
                $pagelanguage        = "name" . $lang;
                $page->$pagelanguage = $pageName; //this sets the path name for each language 

You can take a look on how to achive it (as an inspiration ;) )

Best regards

  • Like 2

Share this post

Link to post
Share on other sites
Filkaboy    2


I have install this module on PW 3.0.12 and when I try to edit a template, this error popup..​

Fatal error: Using $this when not in object context in /site/modules/ProcessSetupPageName-master/ProcessSetupPageName.module on line 68

Do you have any idea why I have this error?

Thank you

  • 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 bernhard
      hi everybody,
      this is a preview of a module that i'm working on for quite a long time. I needed it for an intranet office management application that i'm still working on. It makes it very easy to create very customized Datatables using the awesome jquery datatables plugin (
      EARLY ALPHA release!
      It's very likely that there will lots of changes to this module that may cause breaking your implementations.
      Module source
      sorry, removed as it changes too frequently; closed alpha - contact me if you think you can contribute
      The module is intended to be used on the backend. Loading styles is at the moment only done via adding files to the $config->styles/scripts arrays. Also the communicaton to javascript is done via the $config->js() method that is built into the admin and would have to be implemented manually on frontend use. But it would not be difficult of course
      Nothing special here, just download + install
      edit: removed some parts, because i made a complete rewrite of the module! (see last posting in the thread)
      Customization example:
      in the screencast you see an example that i'm using in a process module. i put the table inside an InputfieldMarkup just to have the same look&feel all around the admin. you see that you could also use this module to create tables quickly and easily using @kongondo s runtime markup module.
      complete PHP code:
      $this->headline('Kundenliste'); $form = $modules->get('InputfieldForm'); // init datatables module $dt2 = $modules->get('RockDataTables2'); // setup columns // name $col = new dtCol(); $col->name = 'name'; $col->title = 'Name'; $col->data = function($page) { return $page->title; }; $dt2->cols->add($col); // type $col = new dtCol(); $col->name = 'type'; $col->data = function($page) { return $page->rockcontact_type->title; }; $dt2->cols->add($col); // modified $col = new dtCol(); $col->name = 'modified'; $col->data = function($page) { $obj = new stdClass(); $obj->timestamp = $page->modified; $obj->display = date('d.m.Y', $page->modified); return $obj; }; $dt2->cols->add($col); // setup table $dt2->id = 'dt_kundenliste'; $dt2->js('/site/modules/ProcessRockProjects/dt_kundenliste.js'); $f = $modules->get('InputfieldMarkup'); $f->value = $dt2->render(); $form->add($f); // ################################## // ajax request -> return data // non-ajax -> render form + table // ################################## if($config->ajax) { echo $dt2->getJSON($pages->find('template=rockcontact, sort=random, limit=10000')); die(); } else $out .= $form->render(); return $out; what is interesting here is this part:
      // modified $col = new dtCol(); $col->name = 'modified'; $col->data = function($page) { $obj = new stdClass(); $obj->timestamp = $page->modified; $obj->display = date('d.m.Y', $page->modified); return $obj; }; $dt2->cols->add($col); datatables support orthogonal data ( a date column is a good example, because you need to DISPLAY a formatted date (like 10.02.2017) but you need to be able to SORT this column by a different value (timestamp). its very easy to accomplish this by providing both values in your json. Btw: You could also just transfer the timestamp and do the formatting on the client-side via javascript. Next Example will show ho this would work. Both cases can be necessary, it's just an example here.
      [...] removed
      Why i created this module:
      of course i know @Soma s module but i needed a lot more features and the newer datatables version. also i like to define all the columns as objects and have everything on one place. lister & markupadmindatatable: nice for basic tables but lacks of features to modify the appearance of the cell values (like rendering icons, background colors and so on) datatables provides a great frontend API for filtering, showing/hiding columns, getting data, modifying it... it also plays well together with frontend charts like google chart api in this case:
      todo / roadmap:
      all kinds of column filters (like seen in the example above that shows an older and bloated version of this module) support for ajax filters and pagination (currently all filtering and sorting is done on the client side. i tried it with up to 50.000 rows and got reasonable results. initial loading took around 10sec. but of course this heavily depends on the complexity of your table and your data.  
    • By Robin S
      Allows non-superusers to trash pages directly from Page List (if they have page-delete permission for that page).
      Not much to say really - the module adds a "Trash" option to the extra actions for pages in Page List. It looks and works just like the Trash action available to superusers.
      Up to you whether you think non-superusers should be trusted with simpler trashing. For most cases I like the default behaviour where editors have to jump through some more hoops - I want them to think carefully about what they are doing. But if an editor needs to trash several pages then this module might reduce frustration.
      @tpr, by now you can probably predict what I'm going to say...
      ...something to merge into AdminOnSteroids?
    • By zaib
      I've a page "blog" which have child pages (blog posts). Right now I've 11 pages (blog posts) and I'm fetching all the posts in my "blog" pages which displaying fine, Issue is only 10 results are showing this is how I'm fetching
      $entries = $pages->find("template=blog-entry"); foreach($entries as $entry){ <a href='{$entry->url}'>$entry->title</a> }  
    • By horst
      Wire Mail SMTP

      An extension to the new WireMail base class that uses SMTP-transport

      This module integrates EmailMessage, SMTP and SASL php-libraries from Manuel Lemos into ProcessWire. I use this continously evolved libraries for about 10 years now and there was never a reason or occasion not to do so. I use it nearly every day in my office for automated composing and sending personalized messages with attachments, requests for Disposition Notifications, etc. Also I have used it for sending personalized Bulkmails many times.

      The WireMailSmtp module extends the new email-related WireMail base class introduced in ProcessWire 2.4.1 (while this writing, the dev-branch only).
      Here are Ryans announcement.

      Current Version 0.2.5
      get it from the Modules Directory Install and Configure

      Download the module into your site/modules/ directory and install it.

      In the config page you fill in settings for the SMTP server and optionaly the (default) sender, like email address, name and signature.
      You can test the smtp settings directly there. If it says "SUCCESS! SMTP settings appear to work correctly." you are ready to start using it in templates, modules or bootstrap scripts.

      Usage Examples
      The simplest way to use it:
      $numSent = wireMail($to, $from, $subject, $textBody); $numSent = wireMail($to, '', $subject, $textBody); // or with a default sender emailaddress on config page This will send a plain text message to each recipient.
      You may also use the object oriented style:
      $mail = wireMail(); // calling an empty wireMail() returns a wireMail object $mail->to($toEmail, $toName); $mail->from = $yourEmailaddress; // if you don't have set a default sender in config // or if you want to override that $mail->subject($subject); $mail->body($textBody); $numSent = $mail->send(); Or chained, like everywhere in ProcessWire:
      $mail = wireMail(); $numSent = $mail->to($toEmail)->subject($subject)->body($textBody)->send(); Additionaly to the basics there are more options available with WireMailSmtp. The main difference compared to the WireMail BaseClass is the sendSingle option. With it you can set only one To-Recipient but additional CC-Recipients.
      $mail = wireMail(); $mail->sendSingle(true)->to($toEmail, $toName)->cc(array('', '', '')); $numSent = $mail->subject($subject)->body($textBody)->send(); The same as function call with options array:
      $options = array( 'sendSingle' => true, 'cc' => array('', '', '') ); $numSent = wireMail($to, '', $subject, $textBody, $options); There are methods to your disposal to check if you have the right WireMail-Class and if the SMTP-settings are working:
      $mail = wireMail(); if($mail->className != 'WireMailSmtp') { // Uups, wrong WireMail-Class: do something to inform the user and quit echo "<p>Couldn't get the right WireMail-Module (WireMailSmtp). found: {$mail->className}</p>"; return; } if(!$mail->testConnection()) { // Connection not working: echo "<p>Couldn't connect to the SMTP server. Please check the {$mail->className} modules config settings!</p>"; return; } Following are a ...

      List of all options and features

      testConnection () - returns true on success, false on failures

      sendSingle ( true | false ) - default is false

      sendBulk ( true | false ) - default is false, Set this to true if you have lots of recipients (50+)

      to ($recipients) - one emailaddress or array with multiple emailaddresses

      cc ($recipients) - only available with mode sendSingle, one emailaddress or array with multiple emailaddresses

      bcc ($recipients) - one emailaddress or array with multiple emailaddresses

      from = '' - emailaddress, can be set in module config (called Sender Emailaddress) but it can be overwritten here

      fromName = 'Name Surname' - optional, can be set in module config (called Sender Name) but it can be overwritten here

      priority (3) - 1 = Highest | 2 = High | 3 = Normal | 4 = Low | 5 = Lowest

      dispositionNotification () or notification () - request a Disposition Notification

      subject ($subject) - subject of the message

      body ($textBody) - use this one alone to create and send plainText emailmessages

      bodyHTML ($htmlBody) - use this to create a Multipart Alternative Emailmessage (containing a HTML-Part and a Plaintext-Part as fallback)

      addSignature ( true | false ) - the default-behave is selectable in config screen, this can be overridden here
      (only available if a signature is defined in the config screen)

      attachment ($filename, $alternativeBasename = "") - add attachment file, optionally alternative basename

      send () - send the message(s) and return number of successful sent messages

      getResult () - returns a dump (array) with all recipients (to, cc, bcc) and settings you have selected with the message, the message subject and body, and lists of successfull addresses and failed addresses,

      logActivity ($logmessage) - you may log success if you want

      logError ($logmessage) - you may log warnings, too. - Errors are logged automaticaly
      useSentLog (true | false) - intended for usage with e.g. third party newsletter modules - tells the send() method to make usage of the sentLog-methods - the following three sentLog methods are hookable, e.g. if you don't want log into files you may provide your own storage, or add additional functionality here

      sentLogReset ()  - starts a new LogSession - Best usage would be interactively once when setting up a new Newsletter

      sentLogGet ()  - is called automaticly within the send() method - returns an array containing all previously used emailaddresses

      sentLogAdd ($emailaddress)  - is called automaticly within the send() method
    • By MilenKo
      Hello all. I know it might sound silly, but wanted to check how are you guys proceeding if in the theme development you have a need of some fields that are repeating in several templates. For example, I am having an image field that can be used as the site logo in "Settings" template or as to show the page image in the markup of the inner page template or else. I am aware, that if I leave the resizing in the markup, than the field can be used on multiple templates, but the field has some specific label/description, notes and/or placeholder that would be not-related. 
      Sticking to the logo example, I have a label saying: Add your logo image here. So if I use the same field for something else, the same text would show while editing the new next page calling for image.
      How are you guys taking care of this? Are you creating specific fields for every aspect of your theme or there are some tricks I am missing in the big picture?
      P.S. Besides the descriptive text of the field some might require to have a single image and some an array (e.g. you don't need to upload multiple logos, unless you want to randomize or call one based on some criterias, but for a gallery - sure I would have multiple)