Updating User field in Structure via hook

I’m trying to add users to a specific structure depending on their role via a hook. My structure looks like this:

Codes:

- 
  code: ATEST
  user:
    - 40oDx6nv
- 
  code: BTEST
  user: [ ]
- 
  code: CTEST
  user: [ ]

Codes are manually added to the Structure and the User field left empty so when a new user is created they are assigned a code by being added to the next empty user field in the structure. Here’s my hook (in update:after to make testing easier, will be changed to create:after and adjusted later):

'user.update:after' => function ($newUser,$oldUser) {
      if($newUser->role() == 'customer'){
        $site = $this->site();        
        $yaml = $site->content()->codes()->yaml();
        foreach($yaml as $y) {
          if(!isset($y['user'])) {
            $y['user'] = $newUser;
            break;
          }
        }
      }
    },

This doesn’t do anything though. I’ve never updated a structure before, only ever added to one, so I’m pretty sure that’s where I’m going wrong here. Any ideas?

Inside the structure field, does the user field only ever have one user or can there be multiple ones? What is the condition for adding a user to a particular code? Please describe in a bit more details what exactly you want to achieve.

Your hook doesn’t contain any code that updates anything…

It should be one user per field.

I’m trying to assign a pre-defined promotion code to users when their account is created. The accounts are being created from the frontend (successfully) after a payment from Stripe is made. So my client enters promotion codes in the structure field and leaves the user field blank. A user then signs up, and in a user.creater:after hook I check for the next code in the structure field that has an empty user field and write that user to the structure field. I was trying to repurpose this code to do that: Update specific structure field - #2 by texnixe

So first problem, you need a user.create:after hook instead of user.update:after hook.

Secondly, you need to find the key of the array item with an empty users field.

  'hooks' => [
    'user.create:after' => function ($user) {
      if ($user->role()->name() === 'customer') {
        $site       = site();
        $codes      = $site->codes()->yaml();
        $emptyItems = array_filter($codes, function ($item) {
          return empty($item['user']);
        });
        if (!empty($emptyItems)) {
          $key = array_key_first($emptyItems);
          $codes[$key]['user'] = [$user->id()];
        }

        $site->update(['codes' => Data::encode($codes, 'yaml')]);
      }
    },
  ]
1 Like

Works great, thank you! I was using user.update just to make testing easier. I definitely need to brush up on my PHP, I didn’t know array_key_first existed!