Programmatically update select field with api options in a structure field

Hi everyone,
I need to update a structure field in a Kirby command, everything works fine, except a select field pulling data from api that is stripped from the update ::

$sessions = $page->sessions()->yaml();
$data = Yaml::encode($sessions);
dump($data);  // ---> show all my fields correctly 

$updated = $page->update([
    'sessions' => $data
]);
dump($updated->sessions->yaml()); // --> select field with api option (aka "session") is removed while "test" field is ok

My page blueprint


fields:
  sessions:
    label: Session(s)
    type: structure
    translate: false
    max: 6
    fields:

      full:
        type: toggle
        label: Session complète
        text:
          - "Non"
          - "Oui"

      session:
        label: Session
        type: select
        options: api
        api:
          url: "{{site.url}}/options/sessions"
          query: Sessions
          text: "{{item.text}}"
          value: "{{item.value.slug}}"

      test:
        type: select
        translate: false
        options:
          design: Design
          architecture: Architecture
          photography: Photography
          3d: 3D
          web: Web
      

And the json returned by api

{"Sessions":[{"value":"2020","text":"2020"},{"value":"2021","text":"2021"},{"value":"2022","text":"2022"},{"value":"2023","text":"2023"},{"value":"2024","text":"2024"}]}

Could you post your options api for testing?

And which Kirby version are you using?

I’m using Kirby 3.8.3.
And my “json” options look like this

{
    "Sessions": [
        {
            "value": "2020",
            "text": "2020"
        },
        {
            "value": "2021",
            "text": "2021"
        },
        {
            "value": "2022",
            "text": "2022"
        },
        {
            "value": "2023",
            "text": "2023"
        },
        {
            "value": "2024",
            "text": "2024"
        }
    ]
}

Api request is on a custom route of current domain:

$routes = [
    [
        'pattern' => 'options/sessions',
        'action' => function () {
            $now = intval(date("Y"));
            $start = $now - 2;
            $end = $now + 2;
            $dates = range($start, $end);
            $data['Sessions'] = [];
            foreach ($dates as $year) {
                $data['Sessions'][] = [
                    'value' =>  strval($year),
                    'text' => strval($year)
                ];
            }
            return $data;
        }
    ]
]

You are mixing the old and the new options syntax. Using the old syntax, it should be fetch instead of query, the new (3.8+) should look like this:

      session:
        label: Session
        type: select
        options:
          type: api
          url: "{{site.url}}/options/sessions"
          query: Sessions
          text: "{{item.text}}"
          value: "{{item.value.slug}}"

Thanks @texnixe , but the behavior is still the same, the session field is stripped when page updates from command.

It seems that the field is missing from $form->data()

Hm, I tested your example in a fresh Starterkit without issues.

From where are you running your update script?

I run the script from CLI using vendor/bin/kirby purge-sessions

I tested with the cli as well without issues. This is what I tested

return [
	'description' => 'Nice command',
	'args' => [],
	'command' => static function ($cli): void {
        kirby()->impersonate('kirby');

        $page = page('test');
        $sessions = $page->sessions()->yaml();
        $data = Yaml::encode($sessions);
        dump($data);  // ---> show all my fields correctly

        $updated = $page->update([
            'sessions' => $data
        ]);
		$cli->success('Nice command!');
	}
];

I’m facing the same issue with a fresh plainkit install.

Edit: i found this is tied to site.url since i’ using a docker container.

The problem is solved by using localhost instead of {{site.url}}:

              session:
                type: select
                options:
                  type: api
                  url: "http://localhost/options/sessions"
                  query: Sessions
                  text: "{{item.text}}"
                  value: "{{item.value.slug}}"

Edit 2: Found that i can bypass autodetection by setting $config[‘url’] = ‘http://locahost