Add single structureObject to structure collection

Hi there!

Sorry, AGAIN a question from me about handling and updating structure objects…

I have a a structure that holds credits (role and name) for a project.
Now I want to add a single row that is generated programmatically to this within my controller.

I thought I could use the StructureObject constructor, as documented here, but if I use that in my controller I get an error Class 'StructureObject' not found?

What is an easy way to add an extra row to the structure field? I don’t want to update the pages field permanently, I just want to add an extra row virtually within my page’s controller.

Thanks!

Code?

Well I did not get much further than

$so = new StructureObject();

and that already raises the error. Or do I not need a structureObject at all? Is there a built-in structure method to use instead?

Edit: And yes, I also tried to pass a key/value array in the structureObject constructor, same error.

The $props array is required and as a minimum need the id. Call it with the full class name*:

$so = new Kirby\Cms\StructureObject(['id' => 'whatever']);

If you dump that, you get something this:

Kirby\Cms\StructureObject Object
(
    [content:protected] => 
    [id:protected] => abc
    [parent:protected] => 
    [structure:protected] => 
    [site:protected] => 
    [propertyData:protected] => Array
        (
            [content] => 
            [id] => abc
            [parent] => 
            [structure] => 
            [site] => 
        )

)

So you see what other props there are.

* Why? Because there is no alias defined for the StructureObject class, see /kirby/config/aliases.php.

Let’s use the Starterkit as an example:

$structure = page('about')->social()->toStructure();
$count = $structure->count();
$so = new Kirby\Cms\StructureObject(['id' => $count, 'parent' => page('about'), 'content' => [
  'platform' => 'Facebookshit',
  'url' => 'https://facebookshit.com'
]]);

foreach ($structure as $item) {
  dump($item->platform());
}

Gave this a try, the new row does not appear in the structure field when I loop over it. Even tried your specific code on the about page of the starterkit and the dump returns only the fields that were already there:

20200320-171627_Screenshot_GoogleChrome

Oops, sorry, I forgot to copy this line before looping though the result:

$structure->add($so);

Ah, now it works. Also, $count = $structure->count()-1; should be $count = $structure->count() instead if the item needs to be added to the end, else the last item will be overwritten.

Thanks!

Why is structureObject missing from the aliases? Should I prepare a PR to add it or is it omitted on purpose?

Because there are only aliases for the most important classes. I don’t think it would make sense to have aliases for all classes.

You can find the full names for all classes in the docs and also a list of aliases.

If you need an object more often within a file, you can use a use statement with the namespace and then use the short form.

use Kirby\Cms\StructureObject;

$so = new StructureObject(['id' => $count, 'something', 'parent' => page('about'), 'content' => [
  'platform' => 'Facebook',
  'url' => 'https://facebook.com'
]]);

Ok, but then should the constructor not be documented differently?

new Kirby\Cms\StructureObject(array $props)

And maybe a hint that the id field is required.

(Sorry that I keep pointing out stuff in the docs, but I think having stuff complete and consistent will help all users in the long term. I am very willing to prepare a PR as well)

No, you can’t change this, because this is generated automatically from the source code. The full class name is given below the headline. We would have to generally change this then.

I have trouble adding items to the structure field. My page being $e, I’m trying:

$structure = $e->links()->toStructure();
$count = $structure->count();
$i = 0;
foreach ($urls as $u) {
  $so = new Kirby\Cms\StructureObject([
    'id' => $count + $i, 
    'parent' => $e, 
    'content' => [
      'linkUrl'   => $u["url"],
      'linkText'  => $u["type"]
    ]
  ]);
  $structure->add($so);
  $i++;
}

What am I missing?

What is the problem, the code seems to be ok.

The new data doesn’t show up in the panel. (I’m running locally)

If you want to store this stuff rather than just output in on the frontend, you have to store it first, $page->update().

In that case, using yml is the better option, see the famous addToStructure() method here

Oh, right! Thanks a lot :partying_face: