Sorting of different file types

Hello,

I have images, videos, audio files as well as documents. Each file type has its own blueprint and sortable upload area. In my page template, each file type has its own area: images appear first, followed by videos and audio files. This works well.

Now, I want to enable the user to mix and sort different file types, for example, he can put a video in the first place, a picture in the second and a video again in the third by using the panel. I am facing several problems here:

  • Images, videos and audio files should appear here only.
  • Images, videos and audio files need different HTML tags such as img, video and audio.

So far, I created one upload area for specific suffixes in my page blueprint:

  media:
    type: files
    template: media

as well as a file blueprint:

title:  Media

    accept:
      extension: jpg, png, gif, mp4, mp3
    fields:
      alt:
        label: Alt
        type: text
      caption:
        type: text

My page template outputs all files roughly at the moment:

<?php if ($page->files()->isNotEmpty()): ?>
<?php foreach ($page->files() as $file): ?>
	<figure>
		<?= $file ?>
		<?php if ($file->caption()->isNotEmpty()): ?>
		<figcaption>
			<?= $file->caption()->kirbytext()  ?>
		</figcaption>
		<?php endif ?>
    </figure>
<?php endforeach ?>
<?php endif ?>

but I aim to output files type-specifically:

<?php if ($page->images()->isNotEmpty()): ?>
<?php foreach ($page->images() as $image): ?>
	<figure>
		<?= $image->resize(1200, 1200, 90) ?>
		<?php if ($image->caption()->isNotEmpty()): ?>
		<figcaption>
			<?= $image->caption()->kirbytext()  ?>
    	</figcaption>
        <?php endif ?>
    </figure>
<?php endforeach ?>
<?php endif ?>
  
<?php if ($page->videos()->isNotEmpty()): ?>
<?php foreach ($page->videos() as $video): ?>
	<figure>
		<video autoplay controls loop>
			<source src="<?= $video->url() ?>" type="video/mp4">
		</video>
		<?php if ($video->caption()->isNotEmpty()): ?>
		<figcaption>
			<?= $video->caption()->kirbytext() ?>
		</figcaption>
		<?php endif ?>
	</figure>
<?php endforeach ?>
<?php endif ?>
 
<?php if ($page->audio()->isNotEmpty()): ?>
<?php foreach ($page->audio() as $audio): ?>
	<figure>
		<audio autoplay controls loop>
			<source src="<?= $audio->url() ?>" type="audio/mpeg">
		</audio>
		<?php if ($audio->caption()->isNotEmpty()): ?>
		<figcaption>
			<?= $audio->caption()->kirbytext() ?>
		</figcaption>
		<?php endif ?>
	</figure>
<?php endforeach ?>
<?php endif ?>

How do I determine and appropriately output different file types in my template now? All files should be displayed as sorted in the panel and with the correct HTML tag.

Check the file type while looping through each file, then output the html for the file type. I’d store a snippet for each file type which you can then call according to file type.

Thank you @pixelijn. Yes, that’s what I thought. My problem is that I don’t know how to check the file type while looping through each file and how to output the HTML for each file type then at once.

Support you create three snippets image.php, video.php and audio.php.

$files = $page->files();
foreach ( $files as $file ) {
  snippet($file->type()); // type should output either image, video or audio
}
1 Like

Thank you very much!

I created the snippets, for instance: snippets/image.php

<?php if ($page->images()->isNotEmpty()): ?>
<?php foreach ($page->images() as $image): ?>
<figure>
	<?= $image->resize(1200, 1200, 90) ?>
	<?php if ($image->caption()->isNotEmpty()): ?>
	<figcaption>
		<?= $image->caption()->kirbytext()  ?>
  </figcaption>
  <?php endif ?>
</figure>
<?php endforeach ?>
<?php endif ?>

My template calls the files as sorted in the panel but images appear two times. Can you tell me why?

<?php if ($page->files()->isNotEmpty()): ?>
<?php foreach ($page->files()->sortBy('sort', 'asc') as $file): ?>
  <figure>
  <?= snippet($file->type()) ?>
  <?php if ($file->caption()->isNotEmpty()): ?>
  <figcaption>
    <?= $file->caption()->kirbytext()  ?>
  </figcaption>
  <?php endif ?>
</figure>
<?php endforeach ?><?php endif ?>

Your snippet is not supposed to have the foreach loop but just the html for a single file

1 Like

Dear @pixelijn,

my three snippets are now:

<?= $file()->resize(1200, 1200, 90) ?>
 
<video autoplay controls loop>
	<source src="<?= $file->url() ?>" type="video/mp4">
</video>
 
<audio autoplay controls loop>
	<source src="<?= $file->url() ?>" type="audio/mpeg">
</audio>

Unfortunately, I receive error messages such as:

Call to a member function resize() on string

or

Call to a member function url() on string

Can you tell me what’s wrong?

Could you please post the code that remains in the template now?

1 Like

Here it is:

    <?php if ($page->files()->isNotEmpty()): ?>
    <?php foreach ($page->files()->sortBy('sort', 'asc') as $file): ?>
    <figure>
      <?= snippet($file->type()) ?>
      <?php if ($file->caption()->isNotEmpty()): ?>
      <figcaption>
        <?= $file->caption()->kirbytext()  ?>
      </figcaption>
      <?php endif ?>
    </figure>
    <?php endforeach ?>
    <?php endif ?>

The issue is the parentheses after $file…

FYI: You can get the mime type from the file as well

type="<?= $file->mime() ?>"

I changed it to:

<?= $file->resize(1200, 1200, 90) ?>

I still receive the same error:

Call to a member function resize() on string

All snippets cause the same problem.

If you comment out the snippet and dump($file), what do you get?

If I replace <?= snippet($file->type()) ?> in my template with <?= $file->dump() ?>, I get a long information page for each uploaded file.

If I replace <?= $file()->resize(1200, 1200, 90) ?> in my snippet with it, I get the error again.

It feels like the snippets are not connected to the $file variable.

My first thought was that you have to pass the file object to the snippet:

<?= snippet($file->type(), ['file' => $file]) ?>

But if the variable was undefined, the error message should be that the variable is undefined and not that the variable is a string.

But I actually wanted you to write

<?php dump($file) ?>

in the loop.

1 Like

Yes, if I write <?php dump($file) ?> in the loop, I get a long info list for each file.

If I type <?= $file->type() ?>, I get the type of each file only.

Danke, danke, danke! :pray:

Passing the file object to the snippets works!

The working page template:

<?php if ($page->files()->isNotEmpty()): ?>
<?php foreach ($page->files()->sortBy('sort', 'asc') as $file): ?>
<figure>
  <?= snippet($file->type(), ['file' => $file]) ?>
  <?php if ($file->caption()->isNotEmpty()): ?>
  <figcaption>
    <?= $file->caption()->kirbytext()  ?>
  </figcaption>
  <?php endif ?>
</figure>
<?php endforeach ?>
<?php endif ?>

A working snippet example:

<?= $file->resize(1200, 1200, 90) ?>

Schönen Feierabend, liebe @pixelijn

:smiling_face_with_three_hearts:

P.S. If I upload a PDF, it doesn’t show up. That’s fine. Anyways, do you recommend to explicitly exclude files I don’t want to show up? Or are image, video and audio files already exclusive due to the snippets?

Since you don’t have a snippet for other files than image, video or audio, they will not be rendered. But I’d nevertheless filter them out first.

$files = $page->files()->filterBy('type', 'in', ['image', 'video', 'audio']);

No need to loop through files you don’t want.

1 Like