Define images for multiselect values

Hi all!

I have a collection of Icons. On each project of the website a different selection of them is displayed. When using multiselect I get a nice list of a selection as words. Would it be possible to define an image for each value that will be displayed when the value ist selected in the panel?

Would be so so fantastic if anybody has an idea.

Thanks!
Lukas

Any reason you are not using a files field?

I imagine it for the client to be way more smooth to use a multiselect than uploading different icons for every page.

What does your multiselect actually query? Just some strings? If the icons are in fact images, they could be stored in a central location, so they wouldn’t have to be uploaded to each page.

Could you please post the yaml for your field?

Sorry, i may have explained it a bit badly. There are 50 projects. For each project a selection of icons (approx. 2-10) from a pool of 40 icons applies. Instead of uploading the icons (svg) individually in each project i thought they could be stored centrally and you can select the applicable ones in the panel via multiselect or checkboxes.

  services:
    label: Service
    type: multiselect
    options:
      information: Information
      parkplatz: Parkplatz
      garderobe: Garderobe
      bushaltestelle: Bushaltestelle
      gastronomie: Gastronomie

Does this make sense? Thanks a lot!

Ok, so you are in fact just using strings in your options and on top of that, these are hardcoded instead of provided via a query. I don’t really see how you could connect these to your images.

Let’s assume your icons were stored in the $site object, i.e. directly in the content folder. Then you use a files field instead of a multiselect field.

I somehow doubt that having an image in the multiselect dropdown would be a great idea, it would be have to be so small that nobody would recognize what it is supposed to be? Additionally, you could make it appear in the dropdown, but to actually show it with the selected option, it would require a custom solution similar to this plugin: Awesome Picker | Kirby CMS (which only works for a single icon)

Edit: just remembered this one: GitHub - sylvainjule/kirby-imageboxes: Add illustrations to Kirby's checkboxes. Kirby 2 and 3.

But with 40 icons, you’d probably need a separate tab.

I don’t need the icons to be visible in the panel, they’re just for the frontend. So maybe using a multiselect isn’t a good idea in the first place. What I am trying is to display a selection of SVGs from a bigger pool of SVGs without uploading each SVG for each project individually. So in the panel I could select for Project 1 the SVGs A, E, F, G and for Project 2 the SVGs A, B, E and so on.

Even if I’m repeating myself: I still don’t understand why you don’t want to use a files field. It’s the easiest solution. The files don’t have to be uploaded to each page separately for this solution

Or shouldn’t they be in the content folder at all?

Alright, yeah I think you’re right. How can I upload the icons once and not for each page separately?

You can upload them to the $site object (i.e. via the site.yml blueprint). In your site blueprint, create a files section for the icons, e.g.

sections:
  icons:
    type: files
    template: icon

Then you can query them like this in your projects:

fields:
  services:
    type: files
    query: site.images.template('icon')

Alternatively, if you really want to keep the icons out of the content folder, you can do the following:

services:
  type: multiselect
  options: query
  query: site.services

Where site.services is a custom site method defined in a plugin:

/site/plugins/a-plugin/index.php

<?php

use Kirby\Cms\App as Kirby;
use Kirby\Filesystem\Dir;

Kirby::plugin('cookbook/a-plugin', [
    'siteMethods' => [
        'services' => function() {
            $icons = Dir::read(kirby()->root('assets') . '/icons');
            return $icons;
        }
    ]
]);

So nice, thanks so much! Sadly I still don’t get it to work, this is my code to display the icons:

<ul>
<?php foreach ($page->services()->split() as $service): ?>
<li><img src="<?= $service->url() ?>"></li>
<?php endforeach ?>
</ul>

Which appproach have you used now? Files field or the multiselect with the site method?

For the second approach, your code would have to look like this:

<?php 
$services = $page->services()->split(',');
// only show the list if there are any services selected
if (count($services)): ?>
  <ul>
    <?php foreach ($services as $service): ?>
      <!-- try to create a new asset from the file in the assets/icons folder -->
      <?php if ($asset = new Asset('assets/icons/' . $service)): ?>
        <li><img src="<?= $asset->url() ?>"></li>
      <?php endif ?>
    <?php endforeach ?>
  </ul>
<?php endif ?>

Note that $services is just an array of strings. So you have to get the actual image from the assets folder based on the name of the icon file.

1 Like

Wow, this is soooo good! Perfect, thank you so so much! It works like a charm. I really appreciate your great support, thanks!!!

Just as a last comment: Would it be possible to clean up the file name? Right now in the panel in the multiselect area its IconAB.svg — would be really chic without the .svg :blush:

Sure:

<?php

use Kirby\Cms\App as Kirby;
use Kirby\Filesystem\Dir;
use Kirby\Toolkit\Str;

Kirby::plugin('cookbook/a-plugin', [
    'siteMethods' => [
        'services' => function() {
            $icons = Dir::read(kirby()->root('assets') . '/icons');
            return array_map(fn ($item) => Str::before($item, '.'), $icons);
        }
    ]
]);

Note that you have to append .svg when outputting the file in this case.

1 Like

Thanks!!! :slightly_smiling_face::upside_down_face: