How can I link complex iframes through the panel into my site?

Hey there!

I am planning to use Kirby for some sort of blog style website, so in the panel I plan on using something like the editor or the new blocks feature. This will work fine for regular content like text, images or even tables.

However, on the site in question, every once in a while, I need to include some sort of custom coded interactive things that require a more complex coding setup (probably some dedicated HTML / CSS / JS files, including some dedicated media files). A good example for that would be some sort of interactive map, maybe like in this example here. However, these could be very different examples, so they don’t always follow the same structure.

Now I wonder: How can I include things like that into a blog article via the panel? Is there maybe any way to point Kirby to a folder and then let it load this folder into an iframe or something like that? Looking for ideas!

Thanks!

Edit: Replaced all the "backend"s with "panel"s, because that’s what I actually meant.

The easiest would probably be to reference snippets that contain the code needed for your interactive stuff.

Sorry, I realize I was not quite clear enough on the backend part, my mistake:

I would like to be able to somehow tie in these “blocks” with the panel (that’s what I meant by backend in my original post). As far as I know, snippets are not really connected to the panel, so they would probably not help me much in this case, right?

Well, of course you would need a block that lets you select these snippets, which could be provided through a route.

Could you elaborate? Is this something that needs to be custom written? Or can this be done with Kirby’s onboard tools?

Maybe to elaborate a bit more: I will need this in the panel, because I will need the editors to be able to somehow pick one of these blocks and have them decide where to place that within the article. If there are any other mechanisms for that that come to mine, I’m open for ideas.

With the new Kirby block, it should be possible to define a select field that is fed with options through a route. This route could return possible snippets from a specific folder that are then retrieved within the block snippet.

So this means writing a new custom select field for snippets, right?
I am afraid this is way above my skill level.

Are there any other ways/ideas? Would there maybe be a way to define a simple field that contains a simple link to some subfolder (outside the content folder) that would allow me to pull in this subfolder’s contents?

No, in the new blocks field, you can add a fieldset with a select field. Within this select field, you can use all queries (from other field, from API etc.) that you can use in a select field as set out in the documentation. So you would probably use an API query and your API would be a route that returns a list of snippets in a folder.

Woah, ok, I had no idea that select fields can be used in that way. This sounds like a good option. I will give this a try and see if I can get this to work. Thanks!

Ok, I am just trying to make sense of this, but I don’t know what I have to do.
In the blueprint, for the select field, I guess I have to use the api option:

myselector:
  type: select
  name: Snippet Selector
  options: api
  api:
    url: "???"

But what do I have to put into the URL property? How do I actually connect this to the snippets? Do I have to create some API endpoint for the snippets first? If so, how can I do this? Sorry, first time I try to use the Kirby API feature and I am lost.

API URL: The url to a route: https://getkirby.com/docs/reference/panel/fields/select#options-via-api__dynamic-api-urls

so for example

url: "{{ site.url }}/my-api/snippets.json"

Then you create a route with the desired route pattern: https://getkirby.com/docs/guide/routing

pattern: 'my-api/snippets.json'

Inside that route, you read the files in the folder with your snippets, and return an array.

1 Like

Hm, I think I understand the setup of the select field, as I was able to create a test setup with an external API and managed to load a JSON as a list into this field.

However, I am still having trouble to set up the routing. If my pattern parameter is

pattern: 'my-api/snippets.json'

how do I set up the return statement so that it points at my snippets folder (or any other non-content folder for that matter)? Could anyone give me a brief example?

Thanks!

[
  'pattern'  => 'my-api/snippets.json',
  'action' => function () {
	 $data   = Dir::read(kirby()->root('snippets') . '/path-to-filder');
     $result = [];
	 foreach ($data as $key => $item) {
		$result[$key]['name'] = basename($item, '.php');
	 }

	 return $result;
   },
],
1 Like

Thank you @pixelijn, this works great! While I understand your code now, I could have never come up with that myself.

I am now trying to make this snippet select field usable in my template by placing the url of the selected snippet to the src attribute of an iframe:

<iframe src="<?= kirby()->root('snippets') . '/interactive/' . $block->snippet() ?>">
</iframe>

While this does work, the page that appears in the iframe gets overwritten by Kirby’s default template. So I don’t actually get the html page that I want in my iframe, but the default page. Is there a way to skip the applying of this default template?

I don’t quite understand how Kirby handles the applying of templates to iframe-embedded pages, but I would like it to apply no template whatsoever in this case.

Thanks!

A snippet doesn’t have a URL,only a path. But for an iframe, you need a URL. I would have expected that you render the snippet directly in your template, not inside an iframe. Or if it is an iframe, that the iframe is in the snippet.

Ah, that makes sense. Now I also understand why it should be handled via snippets and not any other arbitrary folder.

However, I am trying to get this to work, when I include the iframe in the snippet itself (or wrap it around the snippet() method in my template) it kind of pulls it into the document, but it seems to handle the html code as some sort of string instead of html? Any idea how to avoid this and make it render as actual html within the iframe?

This is my snippet:

<iframe>

  <html>
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>Hello World</title>
    <link rel="stylesheet" href="">
  </head>
  <body>
    <h1>Hello World</h1>
    <p>This is a test</p>
  </body>
  </html>

</iframe>

and here is what it looks like in the Chrome dev tools:

20201108-135350_Screenshot_GoogleChrome

I did a quick test and this works:

Template:

<iframe src="<?php echo url('getsnippet/test') ?>" frameborder="0"></iframe>

Snippet:

<html>
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>Hello World</title>
    <link rel="stylesheet" href="">
  </head>
  <body>
    <h1>Hello World</h1>
    <p>This is a test</p>
  </body>
</html>

Config:

  'routes' => [
      [
        'pattern' => 'getsnippet/(:any)',
        'action' => function($snippet) {
          $html = snippet($snippet, [], true);
          return $html;
        }
      ]
  ],

Downside: The URLs are directly accessible, unless you lock them when they are not called from a script.

Just now I found time to give your solution a test and it works great! Thank you so much!

Not sure how to do that, but for my use case it is not issue whatsoever to have the URLs accessible, so I’ll leave it as you suggested. Thanks again!

This may be irrelevant now, but I had to do something similar and was able to paste some complex iframe code into the blocks > markdown field, that then rendered as an iframe in the frontend.