Kirby + Vue.js starterkit w/ Kirby Builder

Hi all,

I’m using this amazing and powerful Kirby + Vue.js Starterkit in combination with Kirby Builder.

I’m trying to adapt @timoetting’s foreach loop for the Kirby Builder blocks into the json.php templates that the starterkit uses.

Here’s the standard PHP foreach loop:

foreach($page->projectBlocks()->toBuilderBlocks() as $block):
  snippet('blocks/' . $block->_key(), array('data' => $block));
endforeach;

In my project.json.php file, here’s what is working, without the builder loop:

<?php
$data = [
  'url' => $page->url(),
  'title' => $page->title()->value(),
  'heroImage' => $page->heroImage()->toFile()->url(),
  'overview' => $page->overview()->value()
];
echo json_encode($data);

Yeah! I can render all of the above in my Vue.js files on the frontend, but now the issue comes in when I attempt to use the builder loop…

Please note, I suck with PHP haha, I’m a frontend dev, zero PHP experience, I’m just trying by example here. So here’s two things I tried:

<?php
$data = [
  'url' => $page->url(),
  'title' => $page->title()->value(),
  'heroImage' => $page->heroImage()->toFile()->url(),
  'overview' => $page->overview()->value(),
  'builderBlocks' => array_values($page->projectBlocks()->toBuilderBlocks()->map(function ($block) {
    $block = snippet('blocks/' . $block->_key(), array('data' => $block));
    return [
      'block' => $block
    ];
  })->data())
];
echo json_encode($data);

Note: The above breaks, I just get a 404 Error page. Since the Vue.js starterkit is running with npm run dev it appears to be running its own PHP server on 127.0.0.1:8000 but the API is running on localhost:3000 so I’m completely lost in how to show/log PHP errors (this isn’t your typical php -S localhost:8000 running with MAMP or whatever) and yes, I turned debugging on/off in Kirby config, no luck though…

The above forloop of array_vlaues was copied from how the Starterkit was doing things from the site/templates/home.json.php example here.

Now here’s the other thing I tried:

 <?php
$data = [
  'url' => $page->url(),
  'title' => $page->title()->value(),
  'heroImage' => $page->heroImage()->toFile()->url(),
  'overview' => $page->overview()->value(),
  'builderBlocks' => array_values($page->projectBlocks()->toBuilderBlocks()->map(function ($block) {
    return $block->_key()->value();
  })->data())
];
echo json_encode($data);

If I just return the block key value, this doesn’t break, and my frontend code just outputs the value as a string. I’m using two builder blocks, so it renders each out by the key:

single_video_loop

split_text_block

The above values are also in my blueprint, and the name of the templates builder block file just like Tim’s documentation said to do (and I used that back in Kirby 2 which totally worked as well, so the naming convention I have is all set up correctly as far as I know).

Happy to provide more details / examples if need be (like my blueprint setup, etc).

Thank you all for reading through this and helping out in advance! :zap:

The issue seems to really come down to the snippet function:
snippet('blocks/' . $block->_key(), array('data' => $block));

In my loop, I can’t even hard-code a file to get this to output anything:

‘builderBlocks’ => array_values($page->projectBlocks()->toBuilderBlocks()->map(function ($block) {
return snippet(‘blocks/split_text_block’, array());
})->data())

I tried to pass an empty array and just reference the one file specifically, and in the split_text_block.php snippet, I removed any dynamic data, just some hard-coded html to see if anything would come back, and it doesn’t :frowning:

Since in the standard $data array you only return data, wouldn’t it make more sense to only return the builder block data and render the stuff client side with your vue templates?

Thanks for the quick reply Sonja! That would be amazing, haha, but I don’t know how to get that dynamic data. The data builder (i.e. site/templates/project.json.php) I’m using works perfectly until I tried adding in the builder blocks loop, how else can I pass the builder blocks in to each project?

I mean, I am already rendering with vue templates - the data is being passed in already through some middleware routing stuff the Starterkit set up out of the box.

I have no problem rendering my data with vue, everything is passed through except the Builder blocks back in to project.json.php file… something weird going on with the snippet / foreachloop.

Hey @texnixe, the following example isn’t working (I’m not too savvy with PHP), but maybe this is a better approach? Ideally, I just want to render each snippet block and drop it’s full html into my data:

<?php
$builderBlocks = '';
foreach($page->projectBlocks()->toBuilderBlocks() as $block):
  $builderBlocks .= snippet('blocks/' . $block->_key(), array('data' => $block));
endforeach;

$data = [
  'url' => $page->url(),
  'title' => $page->title()->value(),
  'heroImage' => $page->heroImage()->toFile()->url(),
  'overview' => $page->overview()->value(),
  'builderBlocks' => $builderBlocks
];
echo json_encode($data);

Then, in my vue.js, I’d just render something like this:

<template>
  <main>
    <h1>{{ page.title }}</h1>
    <p>{{ page.overview }}</p>
    <div class="builder-blocks">
      {{ page.builderBlocks }}
    </div>
  </main>
</template>

Again, the above works without the builder blocks - this in fact renders the page title and overview no problem.

If all you want in the builderblock variable is a string with all the builder block html:

$builderBlockHtml = '';
foreach($page->projectBlocks()->toBuilderBlocks() as $block):
  $builderBlockHtml .= snippet('blocks/' . $block->_key(), array('data' => $block, true);
endforeach;


$data = [
  'url' => $page->url(),
  'title' => $page->title()->value(),
  'heroImage' => $page->heroImage()->toFile()->url(),
  'overview' => $page->overview()->value(),
  'builderBlocks' => $builderBlockHtml
];

Then in template:

<div class="builder-blocks">
      {{ page.builderBlocks }}
</div>

So, in the loop you add each snippet to your $builderBlockHtml variable and pass that to your $data array.

Thanks for the suggestion, I tried that but still no luck. (I think all you changed) was adding the true parameter?
array('data' => $block, true);

This still gives an Error 404 (breaks the API) and I can’t see the PHP errors. :confused:

Ah, sorry, there was a closing parenthesis missing:

$builderBlockHtml = '';
foreach($page->projectBlocks()->toBuilderBlocks() as $block):
  $builderBlockHtml .= snippet('blocks/' . $block->_key(), array('data' => $block), true);
endforeach;

Heck yeah! Now I just had to do the v-html thing for vue to render as html:

<div v-html="page.builderBlocks"></div> and problem solved!! :sunglasses::sunglasses::sunglasses:

Looks like your answer here did the trick (in combo with using v-html for vue to render as html)

But, of course, one more challenge to present itself…

Please don’t totally hate me for this, but of course, one of my builder blocks is a slideshow - I was planning to wrap this as a <Flickity /> component in my _.vue file and do all the fun stuff over there in vue land.

However, since the above solution renders everything in one html chunk, this would get ugly using JS to rewrite the entire snippet of html. So the above was a perfect solution for simpler builder blocks…

Is there another way to pass in the builder block data where I have the data values and I can use a switch case or if else conditional to render these as separate blocks in vue? For example:

<section v-for="(block, index) in page.builderBlocks" class="builder-block">
  <SplitTextBlock v-if="block.id === 'split-text-block'" :data="block.data" />
</section>

Haven’t tested the above, just a quick thought…?

That was my first idea that you just pass the data of the blocks and do the templating client-side.

So, you could return the builder block data as array

$data = [
  'url' => $page->url(),
  'title' => $page->title()->value(),
  'heroImage' => $page->heroImage()->toFile()->url(),
  'overview' => $page->overview()->value(),
  'builderBlocks' => $page->projectBlocks()->yaml(),
];
echo json_encode($data);
1 Like

Wow! Just tested this out, exactly what I needed, thanks a million!

I apologize, I misread what you suggested way back at your first reply in this thread. I was under the impression that I had to use that forloop based on Tim’s example - learn something new every day!

Kirby makes things too easy! :sweat_smile:

HUGE thanks to @texnixe and @timoetting for all of your amazing work and support!