Jump to content

[SOLVED] Auto numbering and increment value of the field of new child pages in context of parent page reference field


Recommended Posts

I need to have working some specific structure of data I did not find anywhere on forums yet.

For simplicity I will specify what I would like to have working:
There is a page with child pages. I could name it for example "houses".
All children pages are using same template (house) with page reference field to another page children(floors).
Referenced page for example "floors" has children that all are using their same specific template (floor). On this template is page title or name, other fields and integer field of floor number (floor_number).
When new child of this page is created I need to have that integer field automatically populated from 1, but only in context of referenced page.
So when I create house named house1 and then in editing of house1 I create for example 3 floors I would like to have floor(title of page) 1(integer field), floor 2, floor 3 but only for that house1.
Name of floor could be page title or name and it is text ("floor") and number is just integer field (1,2,3).
When I add more houses I could have for example have NewHouse (name of page) with basement 1 and floor 2.
I could add BigHouse also with basement 1, floor 2 and floor 3 .... etc..

When creating that floors I would like to use quick creating multiple new items which allows input page select multiple - so I just want to input floors on several rows and hit save.
In that moment could be nice to have all that new floors automatically numbered from 1 on that integer field (floor_number)
I want to use Page Reference field with input Page List Select Multiple.

How could this be accomplished ?
Is there some good way how to make that integer field to increase automatically but only for specific ref.page ?

Thanks very much of any idea or help with this

Link to comment
Share on other sites

Just to clarify a few things... is this the overall structure you have/want to accomplish?

├── Homepage
├── Houses (template: houses)
│   ├── Small House (template: house)
│   ├── Medium House (template: house)
│   ├── Big Mamas House (template: house)
│   │   └── ref_floors: (page reference field: "parent=floors, template=floor")
│   │       ├── Basement
│   │       ├── 1st Floor
│   │       ├── 2nd Floor
│   │       └── 3rd Floor
│   ├── ...
│   └── Super Large House (template: house)
├── Floors (template: floors)
│   ├── Cellar (template: floor)
│   ├── Basement (template: floor)
│   ├── 1st Floor (template: floor)
│   ├── 2nd Floor (template: floor)
│   ├── ...
│   └── Attic (template: floor)
└── ...

If so... could you mark and add more details where you need some kind of logic/automation, please.
And those additional fields where you want to add custom content if and where needed.

  • Like 1
Link to comment
Share on other sites

Hi.
I updated structure in quoted schema from you:

├── Homepage
├── Houses (template: houses)
│   ├── Small House (template: house)
│   ├── Medium House (template: house)
│   ├── Big Mamas House (template: house)
│   │   └── ref_floors: (page reference field: "parent=floors, template=floor") --> field with increment from floor template
│   │       ├── 1 Basement 
│   │       ├── 2 1st Floor
│   │       ├── 3 2nd Floor
│   │       └── 4 3rd Floor
│   ├── ...
│   └── Super Large House (template: house)
├── Floors (template: floors) --> here in template floor is field "number" (integer) -- > need to increment from 1 for each house page
│   ├── 1 Cellar (template: floor) --> format is "number" "name" (not needed in this order)
│   ├── 2 Basement (template: floor)
│   ├── 3 1st Floor (template: floor)
│   ├── 4 2nd Floor (template: floor)
│   ├── ...
│   └── x Attic (template: floor)
└── ...

Real structure is with lots of more fields in templates, but for some base schema and functions this is main part...

Is that more clear ?

Link to comment
Share on other sites

Is there a specific reason you need to use this page-tree structure? It seems to me that one particular floor can only ever belong to one particular house. You could better enforce this constraint by having the floors be children of their houses or by having a single-page-reference field in the floors referencing their house. I would strongly prefer the first option, but it would change your URLs.

Reasons you should change your structure to floors being children of their houses:

  1. It correctly models the 1:n relationship. Vitally, it doesn’t allow one floor to belong to multiple houses!
  2. You may not even need the custom floor number field because you can just use “sort” (sort starts at 0, so +1 accordingly).
  3. Adding pages from a separate parent through a Page Reference Field is weird and dangerous for your use case. For example, if you enter “Ground Floor” and a page called “Ground Floor” already exists (seems likely), it will silently use the existing page and not create a new one.
  4. Your URLs will be nicer in every way. Your current setup will have to create unique names for every ground floor, so you’ll eventually have /floors/ground-floor-27/ as opposed to /city-hall/ground-floor/.
  5. If you really like the /floor/ground-floor/ URLs, you can use path hook trickery to fake them. This is much less of a hassle than your approach.

Here’s a hook you could use to generate numbers for pages added through Page Reference Field, but I’m telling you right now: don’t do this!

$this->addHookAfter("InputfieldPage::processInputAddPages", function(HookEvent $event)
{
    $inputfield = $event->object;
    $floors = $inputfield->value;

    $c = 0;
    foreach ($floors as $floor) {
        $c++;
        if ($floor->_added === true || $floor->floor_number <= 0)
            $floor->setAndSave('floor_number', $c, [ 'quiet' => true ]);
    }
});

These are just my 2 cents without knowing all considerations of your project, so I may be completely off. There may also be better and more robust ways to achieve what you want than this little hook

  • Like 1
Link to comment
Share on other sites

6 hours ago, Jan Romero said:

Is there a specific reason you need to use this page-tree structure? It seems to me that one particular floor can only ever belong to one particular house. You could better enforce this constraint by having the floors be children of their houses or by having a single-page-reference field in the floors referencing their house. I would strongly prefer the first option, but it would change your URLs.

Reasons you should change your structure to floors being children of their houses:

  1. It correctly models the 1:n relationship. Vitally, it doesn’t allow one floor to belong to multiple houses!
  2. You may not even need the custom floor number field because you can just use “sort” (sort starts at 0, so +1 accordingly).
  3. Adding pages from a separate parent through a Page Reference Field is weird and dangerous for your use case. For example, if you enter “Ground Floor” and a page called “Ground Floor” already exists (seems likely), it will silently use the existing page and not create a new one.
  4. Your URLs will be nicer in every way. Your current setup will have to create unique names for every ground floor, so you’ll eventually have /floors/ground-floor-27/ as opposed to /city-hall/ground-floor/.
  5. If you really like the /floor/ground-floor/ URLs, you can use path hook trickery to fake them. This is much less of a hassle than your approach.

Here’s a hook you could use to generate numbers for pages added through Page Reference Field, but I’m telling you right now: don’t do this!

$this->addHookAfter("InputfieldPage::processInputAddPages", function(HookEvent $event)
{
    $inputfield = $event->object;
    $floors = $inputfield->value;

    $c = 0;
    foreach ($floors as $floor) {
        $c++;
        if ($floor->_added === true || $floor->floor_number <= 0)
            $floor->setAndSave('floor_number', $c, [ 'quiet' => true ]);
    }
});

These are just my 2 cents without knowing all considerations of your project, so I may be completely off. There may also be better and more robust ways to achieve what you want than this little hook

Hi.
I have to specify that example with house and floors was just to explain what I need. I hoped that it will help anyone to explain what I need.
My project is more complicated but your approach is certainly right and I have to accept that I would like to have data in my project in ideal situation you noticed...
For better understanding of whole context I will explain my project more and hope you will catch the idea:

It is currently in development and it is system build completely on PW installed on dedicated machine on local network and primary intended for intranet use or access by VPN.
Main task is evidence of my customer contracts, products, suppliers and other data.
I had to import to PW quite lots of data from old system which was built on MS Access db.
I exported tables from Access and imported them as child pages using module BatchChildEditor.
Now I have for example page with about 1200 children(1.type of contracts) and there is corresponding another page with about 5000 children (contract specific product items).
There is also another page with about 8000 children (2.type of contracts and corresponding page with about 50000 children (contract specific product items).
There are also other pages with suppliers and other data.
But main data are contracts and product items. I had interconnected children from contracts and product items and populated links for page reference field by script and very good advice from Ryan and Gebeer.
So this is very short explanation how now system is.
So I can not simply place specific contract product item children ("floors") and put them to specific contract children page( "house") now - I have already data in pages and children.
If I wanted to do it the way you wrote, it could take me a lifetime to change this structure...
For this reason I specified as simply as possible using that example with house and floors what now want to do.
It is mainly for product item s field which is number of item in context of contract - so for example one contract has 20 items and every item has its "number", but it is not ID or unique number but just number which was entered when that item was created. Now this numbers are in data as text field like "01", "02". Reason was that it was better for import.
Customer has access to admin backend to edit data, because I will not create new forms on frontend since in PW backend they are good.

What I want is numbering for new items which will customer create by using PW.
So for old data which are now in system it is not needed but for new I just prepare integer field and add it to template of product item children.
So when new children are created in context of referenced contract I need to auto increment and populate that number in each item.
It does not matter that there will be same number in field in another new items, because those items will be connected on another contract referenced children page..
Customer is using quick adding of items by entering only names on each row (Input Page List Select Multiple) and click on SAVE.
Here is screenshot (it is referenced field with input type Page List Select Multiple):

image.png.74468b4139845b69062d29df2c40829e.png

In that moment could be very nice that after click on save (Uložit) for each new item is populated that integer number field with auto generated numbers from 1.

Regarding conflict with existing pages it is problem, because every product item which customer create for new contract is unique - so there is always needed to create new and not use existing. So when new item is created it is always needed to be unique.

what do you think about it now ? Do you understand now ?
Will your hook work ?

 

Link to comment
Share on other sites

I have tried hook from you and it works - so thanks very much...
I have it in ready.php and it appears that it is doing what I needed.
What it does more is that it puts value 1 to current existing data, but it is OK, because this numbering is only for new data.
I will test it more and let you know

Link to comment
Share on other sites

Yes, I see, sorry ?

Quote

What it does more is that it puts value 1 to current existing data

It should only update pages that are new or don’t have a number yet. You can remove the condition “|| $floor->floor_number <= 0” to only handle new pages.

I’m still not sure what you need the numbers for. Will they be read-only? My hook will generate them by counting all items in the page reference field, but there is no guarantee someone isn’t going to change a number later and end up with duplicates even within the same page reference field. ProcessWire keeps its own number in the database to sort the selected pages. In the database it looks like this (using PhpMyAdmin):

image.png.2afd50176ae9c0dae4b01e4abbceca9e.png

This sort field has the advantage that there should never be any duplicates. However, when users manually sort the pages, they will of course change accordingly, so they’re not tied to their page.

Your main problem will still be that InputfieldPage does not just create pages as it explicitly says, but will choose existing pages if their title matches an entered line. In fact I haven’t found any indication for this behaviour anywhere but in the code itself. It’s clearly an intentional feature, but it feels like a bug when the inputfield itself only says “create new” and “they will be created”… You may be able to suppress this behavious with a hook but it’ll be ugly.

Have you considered some of the more powerful modules like PageTable?

Link to comment
Share on other sites

On 7/11/2024 at 9:24 PM, Jan Romero said:

Yes, I see, sorry ?

It should only update pages that are new or don’t have a number yet. You can remove the condition “|| $floor->floor_number <= 0” to only handle new pages.

I’m still not sure what you need the numbers for. Will they be read-only? My hook will generate them by counting all items in the page reference field, but there is no guarantee someone isn’t going to change a number later and end up with duplicates even within the same page reference field. ProcessWire keeps its own number in the database to sort the selected pages. In the database it looks like this (using PhpMyAdmin):

image.png.2afd50176ae9c0dae4b01e4abbceca9e.png

This sort field has the advantage that there should never be any duplicates. However, when users manually sort the pages, they will of course change accordingly, so they’re not tied to their page.

Your main problem will still be that InputfieldPage does not just create pages as it explicitly says, but will choose existing pages if their title matches an entered line. In fact I haven’t found any indication for this behaviour anywhere but in the code itself. It’s clearly an intentional feature, but it feels like a bug when the inputfield itself only says “create new” and “they will be created”… You may be able to suppress this behavious with a hook but it’ll be ugly.

Have you considered some of the more powerful modules like PageTable?

Hi.
I tested all and I now know that inputfieldPage after save is creating new children pages in referenced page. It is working nice also with your numbering. I have condition in page template when showing on frontend, that if item has already older field with text name of item position it will use it.
Otherwise will display new auto number with wireLen adjusted formatting (1 -> 01).
It works nice and I will just make changes to code for handling only new pages, but it is not needed.
For new chilren pages it nicely fill auto numbers.
There will be testing from customer so I will see after their editing how it goes...

Regarding PageTable - it is very nice - I am very considering it to integrate. Is needed to pay for whole ProFields from Ryan or is it working anyway ?
Also I am not so sure if I have data to integrate it with this (lots of imported already)...
 

 

Link to comment
Share on other sites

On 7/12/2024 at 12:19 AM, Jan Romero said:

Here’s a PR that would guarantee pages to be newly created from the create textarea (if so configured): https://github.com/processwire/processwire/pull/298

 

image.png

It is very nice from you. I think it is good to know that there is option to create new pages then use same already in system.
At least for my project is better to have every time new page, because every new page is unique for my customer even if it has same name.
He has business with Antiquities and every item from 1 contract is unique - so every time is new contract there are also new unique items on it.
For example item "Vase with decoration pictures" from one contract is not same as same named vase from another contract.
For this reason every item (child page) is new and unique.

Link to comment
Share on other sites

1 hour ago, PavelRadvan said:

Is needed to pay for whole ProFields from Ryan or is it working anyway ?
Also I am not so sure if I have data to integrate it with this (lots of imported already)...

PageTable is free because a gracious Finnish company sponsored it ? It’s just called "ProFields PageTable" for historical reasons. There are also modules like PageTableNext that extend it futher.

I would imagine you can switch between Page Reference and PageTable pretty easily. In the database, they look just the same: two IDs and a sort number.

Edited by Jan Romero
Link to comment
Share on other sites

2 hours ago, Jan Romero said:

PageTable is free because a gracious Finnish company sponsored it ? It’s just called "ProFields PageTable" for historical reasons. There are also modules like PageTableNext that extend it futher.

I would imagine you can switch between Page Reference and PageTable pretty easily. In the database, they look just the same: two IDs and a sort number.

OK. That is good. I am preparing another field for contract page which should contain some crucial and personal data for contracted customer - i.e personal identification number, address and other details. So I could use PageTable for this...also i could try to switch...need to know more details...

Link to comment
Share on other sites

  • Pavel Radvan changed the title to [SOLVED] Auto numbering and increment value of the field of new child pages in context of parent page reference field

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
 Share

×
×
  • Create New...