Working with files from structure fields

Hi,
I’m trying to correctly display files that are attached to specific entries of a structure blueprint field.

The text file has the following structure:

Events:

- 
  date: 2020-02-21
  title: Workshop 1
  description: 'Lorem sit amet - Stet clita dasd gubergren'
  link:
    - projects/topic-one
  external-link: ""
  files:
    - Test.pdf
  publish: 'true'
- 
  date: 2020-02-12
  title: Workshop 2
  description: 'Sit amet - Stet clita dasd gubergren, Lorem ipsum dolor'
  link: [ ]
  external-link: ""
  files: [ ]
  publish: 'true'
- 

I’d like to embed “Test.pdf” as a download link in the rendered html.

My code already iterates through the individual events and displays their title and description:

  <div>
    <?php 
    $x = 0;
    foreach ($page->events()->yaml() as $event): ?>
      
      <?php
      $today = date("d-m-Y");

      if ($event['publish'] == 'true') {
      
        if (strtotime($event['date']) < strtotime($today)) { ?>
           
          <h1 class="date">
            <?= str_replace("-", "/", $event['date']) ?>
          </h1>
          <div class="description">
            <?= $event['description'] ?>
          </div>

          <?php
        }
      }
      ?>
    <?php endforeach ?>
  </div>

But I cant really get my head around on how to do the same thing for the files. Adding the following ends up in an error message “Call to a member function file() on array”.

<?php if($file = $event->file()): ?>
  <?= $file->filename() ?>
<?php endif ?>
<?php if($file = $event->files()->toFile()): ?>

Your field is called files not file, and you have to convert it to a File object.

But that syntax only works with the toStructure() method, you are using yaml(). If you want to stick with yaml:

<?php if($file = $page->file($event['files'])): ?>

Thanks for the reply!
Unfortunately I still can’t make it work.

When using the yaml code you’ve posted, I’m prompted with the following error:

Argument 1 passed to Kirby\Cms\Page::file() must be of the type string or null, array given, called in /Applications/MAMP/htdocs/cmlab-kirby/site/templates/event_simple.php on line 76

I think you have to pass a parameter to $page->file(). E.g. $page->file("my-file-name.jpg"); or $page->file(null).

Ah, ok, that is because

$event['files'])

doesn’t return a simple string. I think you are better off with using toStructure() here:

<div>
    <?php 
    $x = 0;
    foreach ($page->events()->toStructure() as $event) :  ?>
      
      <?php
      $today = date("d-m-Y");

      if ($event->publish()->bool()) :
      
        if ($event->date()->toDate() < strtotime($today)) : ?>
           
          <h1 class="date">
            <?=  $event->date()->toDate('Y/m/d') ?>
          </h1>
          <div class="description">
            <?= $event->description() ?>
          </div>

          <?php endif ?>

       <?php endif  ?>
    <?php endforeach ?>
  </div>

Then you should be able to use

<?php if($file = $event->files()->toFile()): ?>

Thanks,
this renders a file URL. But only shows the same URL from the first field for each of the following fields.

Hm, weird. Using your code and switching to toStructure() resolves the error message but doesn’t show any file links. It seems like the if statement simply never executes.

Please post your complete resulting code.

Here you go

<div>
  <?php 
  $x = 0;
  foreach ($page->events()->toStructure() as $event) :  ?>
      
    <?php
    $today = date("d-m-Y");

    if ($event->publish()->bool()) :
      
      if ($event->date()->toDate() < strtotime($today)) : ?>
           
        <h1 class="date">
          <?=  $event->date()->toDate('Y/m/d') ?>
        </h1>
        <div class="description">
          <?= $event->description() ?>

          <?php if($file = $event->files()->toFile()): ?>
            <?= $file->filename() ?>
            <p>Test</p>
          <?php endif ?>

        </div>

       <?php endif ?>

     <?php endif  ?>
  <?php endforeach ?>
</div>

I can’t see why the code should not do what it is supposed to to. Unless you have more than one file per files field, in which case we would have to change from toFile() to toFiles() and use another loop. But from what I understood, there is only one file per structure item?

Do you get any output at all?

Ouch, my bad. I only added a file name to the field in the content file but didn’t add the actual file in the folder. That’s why nothing was showing up.

It works now. Thanks so much for your help!