How to call custom blocks in template

Hello everyone :slight_smile:

I have this custom block fields:

I would want to show all the image blocks and video blocks in the page template. I’m struggling with how to write it in the template:

<div class='exhibit-images'>
       <?php foreach ($exhibit->media()->image()->toBlocks() as $imgBlock): ?>
              <img src="<?= $imgBlock->url() ?>" >
      <?php endforeach ?>
</div>

Thanks in advance!

Not sure what you are trying to do. To render the complete blocks field, you would call toBlocks() on the media field:

<div class='exhibit-images'>
       <?php echo $exhibit->media()->toBlocks()  ?>
</div>

To filter the blocks by block type:

<div class='exhibit-images'>
   <?php 
        $blocks =  $exhibit->media()->toBlocks()->filterBy('type', 'image'); 
        echo $blocks;
    ?>
</div>

This assumes that you have a snippet for your image block type.

Otherwise, you would indeed have to loop through the blocks and output the html for them:

<div class='exhibit-images'>
   <?php foreach ($exhibit->media()->toBlocks()->filterBy('type', 'image') as $block):?>
    <img src="<?= $block->url() ?>" alt="">
  <?php endforeach ?>
</div>

Thanks for the reply!
I try to show the images from the image block in it’s page template.

I don’t have a snippet for them so I loop through the blocks as you suggested. For some reason now the image src is undefined, any idea why? Maybe it’s because that the image block is a field that I’ve created and it’s not the default image/file block?
When I use filterBy(‘type’, ‘image’) - does it recognize this custom image block? or should I call it differently.

Here is the full yml file:

and this is the template:

        <?php foreach ($page->children()->listed() as $exhibit): ?>
            <div class='exhibit'>
                <div class='exhibit-images'>
                    <?php foreach ($exhibit->media()->toBlocks()->filterBy('type', 'image') as $block):?>
                        <img src="<?= $block->url() ?>" alt="">
                    <?php endforeach ?>
                </div>
            </div>
        <?php endforeach ?>

Thank you!

I forgot the field, should be

<?php foreach ($page->children()->listed() as $exhibit) : ?>
    <div class='exhibit'>
        <div class='exhibit-images'>
            <?php foreach ($exhibit->media()->toBlocks()->filterBy('type', 'image') as $block) : ?>
                <?php if ($image = $block->image()->toFile()) : ?>
                    <img src="<?= $image->url() ?>" alt="">
                <?php endif; ?>
            <?php endforeach ?>
        </div>
    </div>
<?php endforeach ?>

This is the variant for a single file. If you have more than one file in the image field, then you have to use toFiles() instead and then loop through the files.

For one file, I would limit the number of files that can be selected in the blueprint to 1.

Thanks! I used toFile() and it works!

I have another question - since I have another field: video, I would want it to show images and videos together. so I would want it to say that if it’s a video field show a video (vimeo). if it’s an image field show an image (as you suggested).
Any idea how should I write the php markdown?
Thank you!

You probably mean a video block, not a video field?
If I were you, I would create the snippet for your custom block and then just call

<?php echo $exhibit->media()->toBlocks(); ?>

This will then output all blocks in the order they appear in the blocks field and with the correct markup.

For me, your current markup doesn’t make sense if you want to output the blocks in the order they appear, i.e. if you first filter by image blocks, unless that is what you want?

Otherwise, loop through the blocks and output the manual code for the image block and the default snippet for the video block.

<?php foreach ($page->children()->listed() as $exhibit) : ?>
    <div class='exhibit'>
        <?php foreach ($exhibit->media()->toBlocks() as $block) : ?>
            <?php if ($block->type() === 'image') : ?>
                <?php if ($image = $block->image()->toFile()) : ?>
                  <img src="<?= $image->url() ?>" alt="">
                <?php endif; ?>
            <?php elseif ($block->type() === 'video') : ?>
                <?php snippet('blocks/' . $block->type(), [
                    'block' => $block,
                ]) ?>
            <?php endif ?>
        <?php endforeach ?>
    </div>
    </div>
<?php endforeach ?>

Ok I understand - so I need to create a snippet for my custom block.

I have created a snippet file called ‘image.php’ in the blocks folder inside the snippets folder.
How does the snippet should be? according to this I wrote the snippet like that:

<img src='<?= $block->url() ?>' alt=''>

and in the template I wrote this (as you suggested earlier):

 <div class='exhibit'>
       <?php echo $exhibit->media()->toBlocks(); ?>
</div>

in the inspect I can see it shows all the images but again giving me undefined src. any idea why?
and do I need to create a snippet for the video block too?

Thanks again! I’m new to Kirby - I really appreciate your help! :slight_smile:

You are using the default video block, right? Then there is already a snippet for the video block and you don’t have to create it (unless you want to make changes to it).

You image block, however, should look like this:

<?php if ($image = $block->image()->toFile()) : ?>
  <img src="<?= $image->url() ?>" alt="">
<?php endif; ?>

My bad, I copied the wrong code into my code snippet above, sorry.

You might want to enhance this image snippet with a srcset attribute to make your image responsive, and if your image is not purely decorative but conveys meaning, don’t forget the alt text.

Thanks! the images work perfectly now :pray:

About the video, I used the default video block and it worked as well. but I would want to make some changes with the video so I thought I will make a custom field only for the link and then I will create a snippet for it too. I tried this one but it didn’t work:

<?php if ($vid = $block->video()->toLink()) : ?>
  <div style="padding:56.4% 0 0 0;position:relative;">
    <iframe proj-vid src="<?= $vid->url() ?> ?background=1&quality=1080p" style="position:absolute;top:0;left:0;width:100%;height:100%;" frameborder="0" allowfullscreen></iframe>
  </div>
<?php endif; ?>

Last question for today :slight_smile:
Thanks a lot!

this is the yml now:

  gallery: 
    type: fields
    fields: 
      media: 
        type: blocks
        fieldsets:
            video:
              name: video
              icon: video
              fields:
                url:
                  type: url
            image:
              name: image
              icon: images
              fields:
                image:
                  type: files

This is the original snippet and I’d recommend that you base your snippet on it. You can use the $attr parameter to add additional parameters.

The field inside your block is called url not video in your example and since it is a url field, you shouldn’t call toLink on it.

Thanks a lot again!
I used the video block as you suggested and Ive added attributes through JS.
I really appreciate your help :pray: