Add/remove structure items from front with routes

Hi there!

I would like to manage the content of a structure field from the front, but I cannot find a way to add new items to it and remove existing ones from it by clicking on simple links. Could someone take a few minutes to see what I’m doing wrong please? :woozy_face:

The structure field is in a user blueprint called contributors.yml and its only purpose is to store schedules like ‘2021-07-14-16’ (where the last two digits are hours):

contributions:
 type: structure
 fields:
   schedule:
     type: date
     display: DD/MM/YYYY
     format: Y-m-d-H
     time: true

In a page (accessible only by the logged in contributors) I have calendar that includes maaaaany links ending with schedules formated the same way:

<a href="<?= url('calendar') ?>/2021-07-14-16">14 July 2021 at 16:00</a>
<a href="<?= url('calendar') ?>/2021-07-14-18">14 July 2021 at 18:00</a>
<a href="<?= url('calendar') ?>/2021-07-15-14">15 July 2021 at 14:00</a>
…

In the config.php file I have created this route:

[  
'pattern' => 'calendar/([0-9]+(-[0-9]+)+)',
  'action'  => function($schedule) {
    $kirby = kirby();
    if ($user = $kirby->user()) {
      $contributions = $user->contributions()->toStructure();
      if($contributions->findBy('schedule', $schedule) !== null) {
        // The following line doesn't work
        $contributions->add($schedule);
      } else {
        // Same for this one
        $contributions->remove($schedule);
      }
    } else {
      go('login');
    }
  }
],

I’ve been stuck on this for hours now, trying the addToStructure function seen on another post, playing with yaml instead of toStructure, etc… but this drives me crazy and I cannot find a solution. So I beg for the help of a kind soul here :crossed_fingers:

My brain thanks you!

You cannot add and remove elements to a field like this, you have to update the page with the newly created structure.

Here is an example function to add an item to a structure field.

function addToStructure($page, $field, $data = array()){
      $fieldData = page($page)->$field()->yaml();
      $fieldData[] = $data;
      $fieldData = yaml::encode($fieldData);
      try {
        page($page)->update(array($field => $fieldData));
        //return true;
      } catch(Exception $e) {
        return $e->getMessage();
      }
    }

In the same way, you can unset items from the array, and also update the page with the updated array.

Keep in mind that you have to authenticate (using impersonate()) to be able to perform the update method.

Thanks Sonja for your prompt reply. I’ll try at dawn with this function as I’m in my bed right now :sleepy:

When you say I can unset items from the array the same way however, I feel a bit lost. I would have expect to replace somewhere “add” by “unset”… but there is no “add” in this function. Could you please tell me what I should change so it can remove existing items?

Thank you.

This line adds an element to the array.

You remove an element from an array with unset

unset($fieldData[$key]);

where $key is the index of the array item which you want to remove (you of course have to find that index first, if you only know the value).

Thanks Sonja!!! Everything works fine now :smiling_face_with_three_hearts: