Hi all!
What is the easiest, most straight-forward way of programatically adding entries to a structure field? Do I have to parse and rewrite the contents of the entire page every time I want to add a new item, or is there an easier way to do it?
Hi all!
What is the easiest, most straight-forward way of programatically adding entries to a structure field? Do I have to parse and rewrite the contents of the entire page every time I want to add a new item, or is there an easier way to do it?
Since you can only update a field, not parts of a field, there is no change compared to how we did that in Kirby 2, I think. I.e. get the contents of the field as an array, add new item, store again.
This is what I do in cases like this:
$states = $page->states()->yaml();
$states[] = [
'abbr' => 'SP',
'name' => 'São Paulo',
'capital' => 'São Paulo'
];
$page->update([
'states' => Yaml::encode($states)
]);
It would be cool to have a field method to simplify this process:
$page->states()->addToStructure([
'abbr' => 'SP',
'name' => 'São Paulo',
'capital' => 'São Paulo'
]);
EDIT: Since I need this one for myself a lot, here you go:
<?php // site/plugins/site/index.php
use Kirby\Cms\Field;
Kirby::plugin('site/methods', [
'fieldMethods' => [
'addToStructure' => function (Field $field, array $entry): void {
$value = $field->yaml();
if (isset($entry[0]) && is_array($entry[0])) {
array_push($value, ...$entry);
} else {
array_push($value, $entry);
}
$field->parent()->update([
$field->key() => Yaml::encode($value)
]);
}
]
]);
EDIT 2: Just updated the method to allow adding multiple entries at once:
$page->states()->addToStructure([
[ 'name' => 'Goiás' ],
[ 'name' => 'São Paulo' ],
]);
Thank you both - that’s what I was thinking. Like @pedroborges, I was hoping for an addToStructure()
method - I think I’m getting lazier and lazier…
@pedroborges beat me to it.
Note that you need to be authenticated (either logged in or as almighty) to be able to update the page.
I’d also wrap the update method in a try-catch block and emit an error message.
@texnixe, how do we impersonate the superuser, so we can do things like updating the page via code?
EDIT: I think I found it in another forum post:
kirby()->impersonate('kirby')
@luxlogica Yep, that’s it. We now call this “authenticate as almighty”
I tried to use this, got a peculiar error, I may be making a silly mistake and can’t see it.
This is the exception I am getting:
TypeError
Argument 1 passed to Kirby\Cms\App::{closure}() must be an instance of Field, instance of Kirby\Cms\Field given, called in /home/jaume/public_html/dev/dietz/kirby/src/Cms/Field.php on line 79
plugins/field-methods/index.php :
<?php
Kirby::plugin('jaume/field-methods', [
'fieldMethods' => [
'addToStructure' => function (Field $field, array $entry): void {
$value = $field->yaml();
if (isset($entry[0]) && is_array($entry[0])) {
array_push($value, ...$entry);
} else {
array_push($value, $entry);
}
$field->parent()->update([
$field->key() => Yaml::encode($value)
]);
}
]
]);
I am testing it on a template, like this:
if (count($giftCards) > 0) {
echo 'go!';
try {
// Auth
kirby()->impersonate('kirby');
$data;
foreach ($giftCards as $gift) {
$data = [
'code' => createCode(),
'order' => $page->id(),
'price' => $gift['sum'],
'spent' => 00.00,
'total' => $gift['sum'],
'status' => true,
];
}
$site->giftcardhistory()->addToStructure($data);
} catch (Exception $e) {
echo $e->getMessage();
}
}
This is the relevant structure field’s yaml:
giftcards:
label: Gift Cards
icon: box
sections:
giftcardhistory:
type: fields
fields:
giftcardhistory:
label: Gift Cards History
type: structure
fields:
code:
type: text
order:
type: pages
price:
type: number
spent:
type: number
total:
type: number
status:
type: toggle
What’s wrong?
Thank you
Remove the Field
type hint or change to Kirby\Cms\Field or add a use statement at the top of the file.
Thank you, it works. What would the use statement include here?
What is the difference between Field and Kirby\Cms\Field ?
Thanks
There is no class Field
, or rather the full namespace is Kirby\Cms\Field
.
use Kirby\Cms\Field;
Ah I see, the namespace is use
d then it is possible to use the Field class like that, otherwise it is not found anywhere, just like @pedroborges was actually doing.
Understood, thank you