Change field after page creation

Hi,

I want to set the Month number in a field on page creation.
At first I tried with the page.create:after hook but all sorts of weird things where happening when I did…

Now I’m trying with a page model but no luck either, I don’t see what I’m doing wrong though. Probably something stupid :sweat_smile:

I have a contract.yml and my page model is /site/models/contract.php

class ContractPage extends Page {

    public static function create(array $props): Page
    {
        $props['content']['renewalMonth'] = date('m');

        return parent::create($props);
    }

}

What exactly does not work? Does the field remain empty in a newly created page? For it to show up in the Panel, you have to define this field in the corresponding blueprint.

The field indeed doesn’t get filled in although it is defined in the contract.yml blueprint.

Could you post your blueprint?

The model should actually work without issues, unless there is something in the blueprint that prevents it.

Yeah sure, nothing really special there (I think) :thinking:

title: Contract

status:
  draft:
    label: Inactive
  unlisted: false
  listed:
    label: Active

columns:
  main:
    width: 2/3
    fields:
      items:
        type: structure
        label: Contract items
        columns:
          name:
            width: 1/3
          service:
            width: 1/4
          renewalMonth:
            width: 1/6
          company:
            width: 1/3
        fields:
          amount:
            type: number
            label: Amount
            default: 1
          name:
            type: text
            label: name
          service:
            type: pages
            query: site.find('services')
            multiple: true
          customPurchasePrice:
            type: number
            label: Custom purchase price
          customSalesPrice:
            type: number
            label: Custom Sales price
          parentItem:
            type: pages
            label: Parent contract
            query: site.find('contracts')
            subpages: false
            multiple: false
      notes:
        type: textarea
        buttons: false
        label: Notes

  sidebar:
    width: 1/3
    fields:
      customer:
        label: Customer
        type: pages
        query: site.find('customers').children
        subpages: true
        multiple: true
      isInternal:
        type: toggle
        label: Internal
      renewalMonth:
        type: text
        label: Renewal month
      renewalDate:
        type: date
        label: Renewal date
        default: now
        required: true

That looks ok, it’s just a standard text field without any validation. And in my quick test in a Starterkit it works as expected.

What is your Kirby version?

3.4.4

I was just reading about the page models and I’m wondering if I’m using it wrong. ( I do believe so actually ) – I don’t have a template, i just have the blueprint. My idea was to use as a create page hook -ish kinda thing but maybe that’s not what it’s supposed for … :sweat_smile:

If my suspection is right … is there a way to populate a page field in the page.create:after hook or something? :thinking: (that was I was trying at first but no luck…)

Cheers,
Sam

The model should work even if there is no template, no idea why it doesn’t work for you.

A hook is also possible. Could you please provide your hook code that didn’t work?

If I do the following I get 2 pages on save, 1 listed, 1 unlisted (with the same content) and no filled in renewal date.

<?php
return [
'hooks' => [
    'page.create:after' => function ($page) {

        $page->changeStatus('listed');

        if($page->intendedTemplate() == 'contract')
        {
            $page->update([
                'renewalMonth' => date('m'),
            ]);
        }

    }
]
];

many classes in kirby are sort of immutable. By that I mean that methods create and return a copy of the object and don’t necessarily “change” the object.

Therefore, maybe try this:

$page = $page->changeStatus('listed');

if($page->intendedTemplate() == 'contract')
{
    $page->update([
        'renewalMonth' => date('m'),
    ]);
}
1 Like

Using a model or a hook is not even necessary, because you can set a default in your blueprint, which is certainly the best option:

      renewalMonth:
        type: text
        default: date('m')

But @rasteiner is right about the immutability of objects in Kirby, you always need to store the result of a method like update etc. in a variable in order to continue to work with that object.

That’s what I tried at first @texnixe but he just puts date('m') in the renewalMonth field instead of the computed number. :man_shrugging:

Ah sorry, yes, I forgot to disable the model, that’s why I thought it worked :see_no_evil: Wishful thinking, because query language for defaults is what I would like to happen.