List image in two different sections with different templates

I have a project page in my panel, where the user should be able to fill an image gallery as well as pick a cover image for the project.

I made two file sections, cover and gallery:

cover:
  type: files
  label: Cover
  layout: cards
  max: 1
  template: cover
gallery:
  headline: Bilder & Videos
  type: files
  layout: cards
  size: tiny
  template: media

Now I want the cover image as soon as it is added to also appear in the gallery section, as the cover image will also be part of the gallery and should as such appear like that for the user, so they can manually sort it in the gallery. However, when I add a cover image it is not listed in the gallery and if I try to add the same image to the gallery it (rightfully) complains that the image already exists. How can I solve this, so I can list an image in both file sections and have it sortable in one of them?

Thank you!

If you use a files field instead of a files section for the cover image, you don’t run into this problem. The user would then select one of the uploaded files as cover image. The cover image would be in section and sortable together with the rest.

BTW: You use the label property for the cover “section” but label is a field property, not a section property.

Ok, I don’t know if I can change it so easily to a field, as it currently is together in a column with another file section. I have tried to change it, but did not manage to. Is it possible to mix a file field and a file section in one column?

I think it is necessary to post the entire setup, to understand what I am after:

// some full width column above here

sidebar:
  width: 1/3
  sections:
    cover:
      headline: Cover
      type: files
      layout: cards
      max: 1
      template: cover
    sounds:
      headline: Sound
      type: files
      template: sound

main:
  width: 2/3
  sections:
    gallery:
      headline: Bilder & Videos
      type: files
      layout: cards
      size: tiny
      template: media

// yet another full width column below here

In the end it should look like this (while still allowing the cover to appear in the gallery and be sortable there):

Yes, you have to define two sections, a file section and a fields section. In the fields section, you can then define your field.

sidebar:
  width: 1/3
  sections:
    fields:
      type: fields
      fields:
        cover:
          label: Cover
          type: files
          layout: cards
          max: 1
          query: page.images.template('sound')
    sounds:
      headline: Sound
      type: files
      template: sound
1 Like

Thanks, the layout works now.

However, I wonder, is there any way to make the Cover/Gallery connection work both ways? So, if I upload an image in the Cover file field to automatically assign the media template to it as well and therefore have it automatically appear in the gallery as well. Or is that out of the question?

Yes, that’s possible. I totally missed the gallery section and used the sound template, but anyway.

fields:
  cover:
    label: Cover
    type: files
    layout: cards
    max: 1
    query: page.images.template('media')
    uploads: media

I haven’t tested if the section is automatically updated without reloading the page.

Absolutely amazing, it works like a charm! Thank you so much @texnixe! I am really impressed how flexible the Kirby 3 panel is. I am only now really beginning to understand how it works.

And yes, the section is updated automatically in the moment when I upload an image to the cover field.

Good to know!

Yes, it takes a while to understand if you are new to it but I think this price is worth what you get in exchange.

Actually, I realize now, I tricked myself. Because with the setup now, I don’t have two different templates anymore … For the cover image I actually wanted to have the template cover. I guess that would break the setup again.

Anyways, the reason why I wanted the template cover was simply because I did not want the user to be allowed to upload a video (which would be possible with the media template). Sooo, one more question: Is there a way to restrict the upload both to a template (media) and additionally also to images (while at the same time the media template would allow for both videos and image uploads usually).

Sorry, I know this is really going into annoying tiny details now, but it would be great if I could get it to work exactly the way I originally planned … :pensive:

Hm, the only way to prevent that would probably be a hook that checks if the field contains an image or not and then not save the page. Don’t know if this can be achieved with a file.upload hook in combination with the field name or only with a page.update hook.

Or you prevent uploading through the field and let the user only select from what was already uploaded. Not so nice. from a workflow point-of-view…

Yes, but then they could also select a video that was uploaded to the gallery section, so that wouldn’t work either. Also the hook option would not be very user friendly, as it first suggests you could upload a video and then after you have done it, it “kicks it out of the field again”.

What would solve this issue altogether would be, if file sections allowed to hold several types of templates, not just one. That would also additionally solve the other issue, I had a few days ago.

Would this (sections with more than one template) be a reasonable feature request? If so, I would write one up on GitHub. Would make some scenarios easier for me at least.

That is possible, but usually it makes sense to prevent uploads in this case, although I guess it would be possible to allow updates with only one template while displaying multiple. I created a plugin recently that allows querying files from anywhere but has the upload function disabled. It would be possible to extend this to only allow uploads with a single template, though, I guess. So it would work in the same way as the field. does.

Yes, feel free to create an ideas issue on GitHub.

Another option could be to upload to the field with the cover template but then use a hook to secretly change the template after upload.

To clarify, because I am not 100% sure that you understand my requirements or that I understand your suggested solution: Ideally I would need the following:

Have one section gallery, that allows and displays files from two different templates, let’s call them image and video. And ideally this section would also allow for the upload of both these template types.

(Then I could easily in my cover field just allow/upload the template image and all would be good).

Is such a setup possible, especially the part with uploading two different types of templates?

No, that’s not possible. It would in fact require that you create a custom section with an upload dialog where the user could choose a template (similar to the page create dialog). But that would then be open to errors, because the user could easily choose the wrong template …

I don’t think there is an easy solution.

I would limit this to letting the user upload only via the gallery section and then let them choose a cover from the uploaded images while disabling the upload function of the files field. Everything else is just a mess.

That leaves the problem that you could load a video into the cover file field, which I want to prevent. But I think considering that an upload of two templates per section is not possible, I like the hook idea that after uploading an image to the cover field, I secretly change its template via a hook. While that is probably not the cleanest version of doing it, this should work for my specific case, I think.

Thanks for your help and for bearing with me.

No, not if you limit the selection to images

query: page.images

But the file hook version works as well:

    'hooks' => [
      'file.create:after' => function($file) {
        if ($file->template() == 'cover') {
          $file->update([
            'template' => 'media'
          ]);
         }
      }
    ],
1 Like

Ah. Didn’t know that. Well in that case I guess this is indeed the cleaner and especially easier solution. Thanks.

Edit: Wow and you also hosted the hook solution, you are just too quick for me. I will give this some thought and then decide for one. Thanks again.

Hm, this does not work somehow, I just tested it. While it seems to enter the if statement, the media template does not get applied. The image does not appear in the media section and the meta file still lists the template as Template: cover. Any idea, why the template does not get reassigned?

No, I tested before I posted. Multi-language?

Where did you put the hook?

No, no multi-language setup. The hook is in the config file, I expanded the file.create.after hook that I had already in place.

My entire hook is here, but I think the other parts should not have any influence on the part that I copied from you:

  'hooks' => [
    'file.create:after' => function ($file) {
      // change cover template to media, so images are also listed in the gallery
      if ($file->template() == 'cover') {
        $file->update([
          'template' => 'media'
        ]);
      }

      $filetype = $file->type();

      if($filetype === 'video') {
        try {
          exec('ffmpeg -y -i ' . $file->root() . ' -ss 3 -t 1 ' . $file->parent()->root() . '/' . F::name($file->filename()) . '.jpg');

        } catch(Exception $e) {
          echo 'Video thumbnail could not be extracted.';
          echo $e->getMessage();

        }

      }

      $file->update(['filetype' => $filetype]);
    }
  ]