What's the best way to use mediaUrls in json output from kirby-builder?

I have json representations of various pages using kirby-builder and would like to replace with absolute urls in /media such as:

https://headless.test/media/pages/home/a7299b8331-1605314917/filename.jpg

Here’s the simple json encoding I’m using for a page like /home.json:

$data = [
  'title' => $page->title()->value(),
  'blocks' => $page->pagebuilder()->yaml(),
];

echo json_encode($data);

Which outputs a structure like:

{
  "url": "https://cms.website.com",
  "title": "Home",
  "blocks": [
    {
      "asset": ["filename.jpg"],
      "asset_mobile": ["filename_mb.jpg"],
      "_key": "hero",
      "_uid": "hero_1601455189122_93"
    },
    {
      "headline": "lorem ipsum",
      "items": [
        {
          "asset": ["filename2.jpg"],
          "asset_mobile": ["filename_mb2.jpg"],    
        }
      ]
      "_key": "secondary_block",
      "_uid": "hero_1601455189122_94"
    }
  ]
}

I’d love a solution to elegantly handle outputting full paths for all of the assets. I also hope there is something in the works for the blocks implementation that’s being developed so it’s easy to make and serve a headless kirby site.

The problem is that if you only send data instead of rendered HTML to the frontend, you have to do all the parsing yourself, especially if you use Kirbytext or want to make use of Kirby’s resizing and cropping features for files to create responsive images. So the easiest way to solve this would be to send the rendered data in your json response.

But if you only want the data, I guess that is what you want to do all this on the frontend.

The way files work in Kirby, they are copied to the media folder when you call the $file->url() method. So if you only replace your filename with the path to the media folder, then you would get the URL but not the image.

I think you can solve this with your example by looping through your blocks array recursively and replace each filename with the result of $file->url().

Don’t know if there is a more elegant way.

Thank you for the reply. I ended up doing exactly that.

$pagebuilder = $page->blocks()->yaml();

function rewriteAbsoluteUrls ($builder, $page) {
  array_walk($builder, function(&$block) use($page) {
    array_walk($block, function(&$item, $key) use($page) {
      if ($key==='asset' && !empty($item)) {
       $item = ($file = $page->file($item[0])) ? $file->url() : '';
      }
      if ($key==='asset_mobile' && !empty($item)) {
       $item = ($file = $page->file($item[0])) ? $file->url() : '';
      }
      if(is_array($item) && !empty($item)) {
        $item = rewriteAbsoluteUrls($item, $page);
      }
    }, $page);
  }, $page);
  return $builder;
}

$pagebuilder = rewriteAbsoluteUrls($pagebuilder, $page);

$data = [
  'url' => $page->url(),
  'title' => $page->title()->value(),
  'blocks' => $pagebuilder
];

echo json_encode($data);

I also found the API today and the Better Rest plugin which do this way more elegantly :man_facepalming:t2: I’m using Kirby as a headless CMS.