Use hook to update structure for all users

I am trying to use a hook, to update a specific structure on every user with a specific role. This is the structure on the page:

projectDeliveryTeamStructure:
  label: Test Structure
  type: structure
  fields:
    task:
      label: Task
      type: text

This is the structure on the user

projectDeliveryTeamStructure:
  label: Test Structure
  type: structure
  columns:
    task:
      width: 2/3
    progress:
      width: 1/3
  fields:
    task:
      label: Task
      type: text
    progress:
      label: Progress
      type: select
      default: incomplete
      options:
        incomplete: Incomplete
        pending: Pending
        complete: Complete

I need my hook to make the text columns match up, across all users. This is what I have so far:

'page.update:after' => function ($newPage, $oldPage) {
      if ($newPage->template() == 'building-block') {

        // Now I am sure it is a building block page being updated

        $blockName = $newPage->slug();
        function toUpper($matches) {
          return strtoupper($matches[1]);
        }
        $blockName = preg_replace_callback('/[-_](.)/', 'toUpper', $blockName);
        $structure = $blockName . 'Structure';

        // Now I have the name of the structure, which is the same as on the user.

        $kirby = kirby();
        $users = $kirby->users()->role('participant');

        // Now I have all the users that need their structure field updating.

        foreach ($users as $user) {
          $user->update([

          ]);
        }
      }
    },

I am not sure what to do in the loop to apply the update. If anyone has any thoughts that would be great

With update you mean, you want to add this information as a new item to the structure field? Not update an existing task field?

I would like to totally mirror it. So for instance if on save the structure on the page looked like this:

Projectdeliveryteamstructure:

- 
  task: I am the first entry
- 
  task: I am the second one

The structure for the users would look like this:

Projectdeliveryteamstructure:

- 
  task: I am the first entry
  progress: pending
- 
  task: I am the second one
  progress: pending

The progress shouldn’t be changed, and if new lines are added these should be set to incomplete

This would only make sense if the structure items were not sortable, so that you can always be sure that the first entry on the page matches the first entry on the user. Or your items would need to have an id by which they would be identifiable.

Hi,
From the user panel the client will just be editing the progress section, which is a select box. The text would not be editable, and the rows should not be sortable from the user panel.
I get your point about the unique IDs, these would be really useful so the progress was attached to the task. Is that possible?

I have implemented AutoID now on the user and on the page, so that should help with linking up the values. On the page I now have:

Projectdeliveryteamstructure:

-
  autoid: t35wmkbg
  task: I am the first one
-
  autoid: 85q4bcmy
  task: I am the second one
-
  autoid: cwg2yc5q
  task: I am the third one

Any pointers on what I need to do with my hook to get this to update for the user?

Hi,
I finally got this working! Thanks everyone who took the time to take a look.

@mikeharrison Would you like to share your solution? It might actually help other who want to do the same… :slightly_smiling_face:

Sure - it’s pretty messy / embarrasing but it does work! Here it is:

'page.update:after' => function ($newPage, $oldPage) {
      if ($newPage->template() == 'building-block') {

        // Now I am sure it is a building block page being updated

        $blockName = $newPage->slug();
        function toUpper($matches) {
          return strtoupper($matches[1]);
        }
        $blockName = preg_replace_callback('/[-_](.)/', 'toUpper', $blockName);

        // This generates the structure names that match those on the user template
        $leadershipAndCommunicationKeyTasks = $blockName . 'LeadershipAndCommunicationKeyTasks';

        //This gets the structures off the page
        $updatedleadershipAndCommunicationKeyTasks = $newPage->leadershipAndCommunicationKeyTasks()->yaml();

        // Get all participant users
        $kirby = kirby();
        $users = $kirby->users()->role('participant');

        // Loop through and make the changes
        foreach ($users as $user) {

          $currentUserLeadershipAndCommunicationKeyTasks = $user->$leadershipAndCommunicationKeyTasks()->yaml();

          foreach ($currentUserLeadershipAndCommunicationKeyTasks as $a) {
            $one[$a['autoid']] = $a;
          }

          foreach ($updatedleadershipAndCommunicationKeyTasks as $a){
            if ( isset($one[$a['autoid']])){
              $a['progress'] = $one[$a['autoid']]['progress'];
          }

          $updatedleadershipAndCommunicationKeyTasks2[] = $a;

          }

          $user->save([
            $leadershipAndCommunicationKeyTasks => Data::encode($updatedleadershipAndCommunicationKeyTasks2, "yaml"),
          ]);
        }
      }
    },