Converting Structure to JSON and resolving internal Links

Hello,

at the moment I am trying to convert the data of a structure to a json string.
Is there an easy way to do this, while also replacing all the strings in file/link fields into actual urls that I can link?

<?php
/** @var \Kirby\Cms\Block $block */

// Assuming $blocks is your Kirby blocks variable
$data = [];


foreach ($block->elements() as $elements) {

    foreach($elements as $element) {
        $element["portrait"] = page()->file($element["portrait"][0])->url();
        
        array_push($data, $element);
    }
}
?>

This is what I got so far. I do not understand why I have to double loop, but so be it.

What I am stuck with now is that for link fields, where I link to internal pages, which gives me a string like page://sO3r3W56B16Juh0S . So far, there is no way to make this to the actual url to put this into a href.

Is there any easy way to achieve this?

Regards, Stephan

Is elements the structure field in question? If so, please see the structure field documentation how to convert a structure field to a structure object: Structure | Kirby CMS

Your assumption is correct, elements is the structure field in question.

This is the definition of the whole block:

fields:
   elements:
    label: Testimonials
    type: structure
    fields:
      name:
        label: Name
        type: text
      company:
        label: Firma
        type: text
      quote:
        label: Zitat
        type: text
      portrait:
        label: Portrait
        type: files
      link:
        label: Link
        type: link
   time:
    label: Intervall (in ms)
    type: number
    default: 5000

I have tried to work with the toStructure() method that you linked and ended up with this code for a small tester (which is very close the the example provided):

$data = [];
$items = $page->elements()->toStructure();

foreach ($items as $item){
    array_push($data, "foobar");
}

This always leaves me with an empty array, even though the structure is definitely populated with data. I am using Kirby 4.3.0

Furthermore, my question was also, how can I convert an internal page id (or whatever this string is) like page://sO3r3W56B16Juh0S into a url or uri, so I can use it in an href. I couldnt find any method in the documentation for this yet.

Regards, Stephan

Here, $item is a “row” in your structure, from here you have to access the individual fields with $item->fieldName(), e.g. $item->name();

If a field contains a reference to a page or file, you use the field converter methods intended for this purpose, so for a files field with a single file reference:

$fileUrl = $item->portrait()->toFile()?->url();

(all within the loop…)

You find example of using/converting field values in the documentation for each field (there’s almost always a section “How to use in your templates”, particularly for fields that need to be converted. And an overview of all available field methods here: Field methods | Kirby CMS.

This is no different whether these fields are used directly on the page level, or if fields are nested without an object field, a structure field or block types.

Here, $item is a “row” in your structure, from here you have to access the individual fields with $item->fieldName(), e.g. $item->name();

I understand that this is what is supposed to be the case, but in actuality it is not. I end up with an empty array.

This is the whole block

<?php
/** @var \Kirby\Cms\Block $block */
/** @var \Kirby\Cms\Page $page */

// Assuming $blocks is your Kirby blocks variable
$data = [];

$items = $page->elements()->toStructure();

foreach ($items as $item){
    array_push($data, $item->portrait()->toFile()?->url());
    array_push($data, 'foobar');
}


?>

<?php if ($block->elements()->isNotEmpty()): ?>
    <?= var_dump($data) ?>
<?php endif ?>

The output on the website is array(0) { }

The element is definitely populated with data as I can see with this code

foreach ($block->elements() as $elements) {

    foreach($elements as $element) {
        $element["portrait"] = page()->file($element["portrait"][0])->url();

        array_push($data, $element);
    }
}

This way yields the following $data variable

array(1) { [0]=> array(5) { ["name"]=> string(8) "sadfasdf" ["company"]=> string(8) "asdfasdf" ["quote"]=> string(12) "asdfasdfasdf" ["portrait"]=> string(91) "http://www.personeco.test:8080/media/pages/home/ac1841c9b3-1704314201/rand_name.jpg" ["link"]=> string(23) "page://k1f4eWaGEc6LuDYc" } }

How come the suggested solution this is not working?

You are calling $page->elements() here while this is supposed to be inside the block, so $block->elements()->toStructure()

Alright, that works. I guess I was confused because the example in the documentation used $page.

Anyways, thank you very much for your help :slight_smile: