Audio file in structure field

Hi there!

I try to set up a “media” page where audio files, video files etc are collected.

In order to structure the audio files on the page, I use a structure field on the page like this:

title: Media
preset: page

pages:
    template: default

fields:
    intro:
        label: Intro-Text
        type: textarea
    audio:
        label: Audiobeispiele
        type: structure
        fields:
            titel:
                label: Titel
                type: text
                width: 1/3
            desc:
                label: Beschreibung
                type: text
                width: 1/3
            audio:
                label: Audio-Datei
                type: files
                query: page.audio
                multiple: false
                width: 1/3

As you can see I use the “page” preset for the page. The mp3 files are uploaded using the preset files section on the page.

When I try to select an audio file in the structure field, a broken document icon is shown.
The resulting content looks like this:

Title: Media

----

Intro: 

----

Audio: 

- 
  titel: Meine tolle Aufnahme
  desc: Tonstudioaufnahme 2018
  audio:
    - my-recording.mp3
- 
  titel: Eine weitere Aufnahme
  desc: Tonstudioaufnahme 2018
  audio:
    - my-recording.mp3

So far looking good, but in the front end the audio files are not referenced correctly, and the result is this:

<audio controls="">
  <source src="" type="">
</audio>

I’m using this code in my frontend template:

<?php foreach ($page->content()->audio()->toStructure() as $audio): ?>

<audio controls>
<source src="<?= $audio->url() ?>" type="<?= $audio->mime() ?>">
</audio>

<?php endforeach ?>

Any ideas?

Yes, first $audio is a structure item and you have to call the individual fields. Secondly, content from the files/pages/users fields is stored as yaml, so you have to use the toFile() method in this case to get the file from the content:

<?php foreach ($page->audio()->toStructure() as $audio): ?>
<?php if ($file = $audio->audio()->toFile()): ?>
<audio controls>
    <source src="<?= $file->url() ?>" type="<?= $file->mime() ?>">
</audio>
<?php endif ?>
<?php endforeach ?>

The if statement is necessary to make sure that the file exists before we call a method like url(). Otherwise, PHP would throw an error in case the file was renamed or deleted at a later point in time.

1 Like

You should first convert the filename to an actual file:

<?php foreach ($page->content()->audio()->toStructure() as $audio): ?>
<?php if($audioFile = $audio->audio()->toFile()): ?>
<audio controls>
<source src="<?= $audioFile->url() ?>" type="<?= $audioFile->mime() ?>">
</audio>
<?php endif ?>
<?php endforeach ?>

@texnixe: :racing_car:

1 Like

Also, I’d suggest you add a file template to limit the files that can be uploaded.

In your media page .yml

files:
  template: audio

In you file blueprint, use the accept option to limit the allowed mime types.

then in your /site/blueprints/files/audio.yml:

accept: audio/mp3

(or whatever audio files you want to allow)

1 Like

Wow, thank you guys for your quick responses! It is working now.

Yes, normally I use the toFile() method (i.e. with images) to get at the file object. In this case I totally forgot it, must be due to the heat here in Germany I guess :wink:

Good suggestion to use a template, I’ll try that next.

Since this is your first post here (hello! :slight_smile:), I’ll just assume you’re new to Kirby.
If you aren’t, you might already know this…

Otherwise, this might interest you:

You can also bind data to files.

Since the presence of a structure item in your page now completely depends on the file being there, you could consider to move the data regarding the file (titel, desc), into the metadata of each file.

You would need to setup a file blueprint and change your page blueprint.

page blueprint could be:

title: Media

columns: 
  - width: 3/4
    sections:
      fields:
        type: fields
        fields:
          intro:
            label: Intro-Text
            type: textarea
      audio:
        type: files
        template: audio
        text: "{{file.titel.or(file.filename)}}"
        info: "{{file.desc}}"
  - width: 1/4
    sections:
      pages:
        type: pages

file blueprint (put it into site/blueprints/files/audio.yml):

title: Audio
fields:
  titel: 
    type: text
  text:
    label: Beschreibung
    type: text

Then in your template you should be able to go with:

<?php foreach($page->audio() as $audioFile) : ?>
  titel: <?= $audioFile->titel()->html() ?><br>
  desc: <?= $audioFile->desc()->html() ?>
  
  <audio controls>
    <source src="<?= $audioFile->url() ?>" type="<?= $audioFile->mime() ?>">
  </audio>
<?php endforeach; ?>

(untested)

edit:
@texnixe: :racing_car: :racing_car:

1 Like

@rasteiner Good point. It wouldn’t even be necessary to change the blueprint, keeping the preset would be possible as well.

@Pat:

Meta data are a good way to store additional data for files. However, sometimes people don’t like the workflow for adding meta data too much, because you have to go to the file view first before you can enter the data. In that case, your structure field approach might work better. It really depends.

@rasteiner: Thanks! I read in the docs that this is possible, but I am not experienced enough (yet) to make the mental leap in order to apply it in practice. This is my first K3 project – have used K2 for projects in the past.

It’s a good idea, but for my particular project I tend to go with with texnixe’s advice – a structure field is more “immediate” and my client is not very computer literate. I also use a structure field on another page in the project, so there’s some sort of familiarity as far as the UX is concerned.

The question remains, what can be done about the “broken document” icons?
I tried to use the filename with “text: {{ file.filename }}” as a field option for this files field, but it doesn’t work. It is this some sort of internal referencing in the panel going wrong?

See the screenshot:

Screen%20Shot%202019-07-01%2012%2023%2028%20AM

What’s your Kirby version? I don’t get that icon but the image src uses the audio file’s url which doesn’t make sense. Strangely, setting image: false doesn’t work either. Might be a bug.

@texnixe: I use Kirby 3.1.4.

Yes, same here – the audio file’s url is in the src of the image in the cell of the field.
Then again, when I access a row containing audio to edit it, everything displays fine (truncated screenshot):

Screen%20Shot%202019-07-01%2001%2006%2005%20PM

Yes, that’s exactly the same then apart from the icon. I guess that could be solved with a custom preview for the files field in a structure field depending on mime type.

Unfortunately, setting image: false results in an error:

But maybe the issue is more the preview rather than the field itself.

Thanks for opening the issue!

As far as I’m concerned, it’s a minor, cosmetic thing. Everything else is working fine :slightly_smiling_face: thanks again for your help!