Multiple structure fields, categories and urls

Hi there,

so I’m building a school site that has different school systems as part of it (“Berufsschulzentrum” - " occupational education center") and I’m working on a calendar for said school.
I have two tabs on the site level (categories and dates). There’s a structure field for categories with category name, abbreviation and page.
There are (for now) two structure fields on the dates page, because they want to keep different sorts of dates separate from each other (like exam dates and events for example).

category structure field:

Kategorien:
  label: Kategorien
  icon: tag
  fields:
    categories:
      help: Hier können Sie Kategorien für News und Termine anlegen.
      label: Kategorien
      type: structure
      disabled: false
      fields:
        category:
          label: Kategoriename
          type: text
        categorycode:
          label: Kategorieabkürzung
          type: text
        categoryurl:
          label: Link zur Schulseite
          type: pages
          multiple: false

date structure field (one of them, the other one is the same)

  calendar:
    label: Termine
    icon: calendar
    fields:
      pruefungstermine:
        label: Prüfungstermine
        type: structure
        fields:
          dateStart:
            label: Datum Start
            type: date
            width: 1/2
          dateEnd:
            label: Datum Ende
            type: date
            width: 1/2
          timeStart:
            label: Zeit Start
            type: time
            width: 1/2
          timeEnd:
            label: Zeit Ende
            type: time
            width: 1/2
          title:
            label: Terminname
            type: text
          place:
            label: Ort der Veranstaltung
            type: text
            width: 1/2
          impdate:
            label: Wichtiger Termin
            type: toggle
            help: Wenn ausgewählt wird Terminname rot angezeigt
            text:
              - "nein"
              - "ja"
              width: 1/2
            description:
              label: Beschreibung
              type: textarea
              maxlength: 300
            categories:
              label: Kategorien
              help: Mehrfachauswahl möglich.
              type: checkboxes
              columns: 3
              options: query
              query: 
                fetch: site.categories.toStructure
                text: "{{ structureItem.category }} {{ structureItem.categorycode }}"
                value: "{{ structureItem.categorycode }}"
              links:
                label: Weiterführender Link
                type: pages
                multiple: false

and the php of the dates page is probably a mess… because I tried way too many things:

<?php
        $dates = site()->pruefungstermine()->toStructure();
        $veranstaltungen = site()->veranstaltungen()->toStructure();
        $dates = $dates->add($veranstaltungen);
        $months = array();
        foreach ($dates as $date) :
            $months[] = strftime('%B %Y', strtotime($date->datestart()));
        endforeach;
        $filteredmonths = array_unique($months); ?>
    
        <div role="region" aria-labelledby="Caption01" tabindex="0" class="dates">
        <table>
            <caption id="Caption01">Terminkalender in scrollbarem Container</caption>
            <thead>
                <tr>
                    <th scope="col">Datum/Uhrzeit</th>
                    <th scope="col">Schule</th>
                    <th scope="col">Terminname</th>
                    <th scope="col">Ort</th>
                    <th scope="col">Beschreibung</th>
                    <th scope="col">Link</th>
                </tr>
            </thead>
        <?php foreach($filteredmonths as $month): ?>
            <tbody>
            <tr class="tablemonth">
                <td><h2><?= $month ?></h2></td>
            </tr>    

        <?php 
            $monthevents= $dates->filter(function ($child) use($month) {
                return strftime('%B %Y', strtotime($child->datestart())) == $month;
            });
            foreach($monthevents as $event): ?>

                <tr>
                    <td>
                        <?php if($event->dateStart()->toDate('d.m.') == $event->dateEnd()->toDate('d.m.') or $event->dateEnd()->isEmpty()): ?>
                            <?= $event->dateStart()->toDate('d.m.') ?><br />
                        <?php else: ?>
                            <?= $event->dateStart()->toDate('d.m.') ?> bis <?= $event->dateEnd()->toDate('d.m.') ?><br />
                        <?php endif ?>
                        <?php if($event->timeStart()->isEmpty() and $event->timeEnd()->isEmpty()): ?>
                        <?php else: ?>
                            <?php if($event->timeStart()->isNotEmpty() and $event->timeEnd()->isEmpty()): ?>
                                <?= $event->timeStart()->toDate('H:i') ?> Uhr
                            <?php else: ?>
                                <?= $event->timeStart()->toDate('H:i') ?> Uhr bis <?= $event->timeEnd()->toDate('H:i') ?> Uhr
                            <?php endif ?>
                        <?php endif ?>
                    </td>
                    <td><?php foreach($categories = $event->categories()->split() as $category): ?>
                    <?php 
                        $eventcategories = $site->categories();
                        $categoryurl = $eventcategories->filterBy('categorycode', 'in', $category);
                        dump($categoryurl);                            
                    ?>
                                <a href="<?= $categoryurl->categorycode()->url() ?>">
                                    <div class="datecategory">
                                        <?= $category ?>
                                    </div>
                                </a>
                        <?php endforeach ?>
                    </td>
                    <td><?= $event->title() ?></td>
                    <td><?= $event->place() ?></td>
                    <td><?= $event->description() ?></td>
                    <td><?php if($link = $event->links()->toPage()): ?><a class="linkbtn" href="<?= $link->url() ?>"><!--<?= $link->title() ?>-->Mehr<?php endif ?></a></td>
                </tr>
                <?php endforeach ?>
      <?php endforeach ?>
    </tbody>
        </table>
    </div>

So categories and dates are separate tabs on the site level, the code further down is a page called “dates” that takes the data of the two tabs and shows it. What I want to achieve: get all the data of the categories to the dates page so I can link to the school page. Or another way how to get the schoolspages-url to the dates page.

I really hope someone can help me or point me into the right direction

Cheers,
Daniel

// get all categories
$categories = $page->categories()->toStructure();
// find the one matching the current category code:
$category = $categories->findBy('categorycode', $category);
if ( $category ) {
  echo $category->categoryurl(); // etc.
}

Hey pixelijn,

thank you for your quick reply!
When I use it like that and put the “echo $category->categoryurl()” in href of the link I get a “Call to a member function categoryurl() on null” Error. Did I miss something?

Cheers,
Daniel

Sorry, should be $site->categories()->toStructure(), of course.

Now I get another error:
Method Kirby\Cms\Field::__toString() must not throw an exception, caught Whoops\Exception\ErrorException: Array to string conversion

Is there a stack trace?

I’m sorry, but I do not know what that means. How can I get a stack trace?

What I mean if there is any more information regarding this error, i.e. in which code line it is caused etc.

It shows only the dates.php, without showing a line:

Is that what you meant?

Edit: I looked through some more pages on the forum and changed the PHP Version of MAMP to 7.4.2.
Now I get an “array to string conversion”-error on that line:

 <a href="<?= $category->categoryurl() ?>">

Ah, sorry, I missed that your categoryurl is not a URL field but a pages field. So you have to convert the value to a page first, then get the url from that page:

if ( $category && ( $p = $category->categoryurl()->toPage() ) ) {
  echo $p->url();
}
1 Like

No problem, that did it! Thank you so much pixelijn! I was looking and trying for hours.