Allow users to change their own data in the frontend

Hi,

I am currently attempting to get a user interface to work.
Users can already register and verify themselves.

But what I still need to implement is to allow these users to change their own data.
Is there a way to let users update or change their own data from the frontend?
I figured that a form could be used and with the help of a controller a $user->update() or $user->changeEmail() could be run.
However I can’t seem to get this to work.
I am probably missing something, but so far my search hasn’t been successful.

my userpage controller:

<?php

return function ($kirby, $page) {


  $error = false;

  
  if ($kirby->request()->is('POST') && get('user')) {

    try {
        
        $kirby->impersonate('kirby');
        if(get('editEmail') !== ''){
            $user = $user->changeEmail(get('editEmail'));
        }

    } catch (Exception $e) {
      $error = true;
    }

  }

  return [
    'error' => $error
  ];

};

$user is not defined. You have to fetch the current user.

So should it be $user = $kirby->user()->changeEmail(get(‘editEmail’))?
This also doesn’t seem to work for me.

What exactly doesn’t work? Any error messages? Instead of setting $error to true, it would make more sense to output the error message, at least for debugging.

I don’t get an error or anything.
Even with $error being a boolean I didn’t get my “something went wrong”.
After clicking on send the page refreshes but in the end nothing is changed.

I am not sure how to display the error message with PHP.
Here’s my userpage controller:

<?php

return function ($kirby, $page) {


  $error = "";

  
  if ($kirby->request()->is('POST') && get('user')) {

    try {
        
        $kirby->impersonate('kirby');
        if(get('editEmail') !== ''){
            $user = $kirby->user()->changeEmail(get('editEmail'));
        }

    } catch (Exception $e) {
      $error = error_message;
    }

  }

  return [
    'error' => $error
  ];

};

Maybe there’s something wrong with my template?
userpage template:

<?php snippet('header', array("default" => true)) ?>

	<article class="viewDefault">

    <?php 
    if($error): ?>
        <div class="alert"><?= $page->authAlert()->html() ?> <?= $error ?></div>
    <?php endif ?>

    <?php 
        if(!$kirby->user()){
            go('login');
        }
    ?>

     <?php dump(get('email')) ?>   

		<div class="viewUserData" id="userData">

            <div id="name"><?= $page->username() ?>: <?= $kirby->user()->username() ?></div>
            <div id="email"><?= $page->email() ?>: <?= $kirby->user()->email() ?></div>
            <?php if($kirby->user()->role()) ?><div id="beruf"><?= $page->occupation() ?>: <?= $kirby->user()->content()->occupation() ?></div>
            <div id="adresse" class="userAddress">
                <div id="street"><?= $page->street() ?>: <?= $kirby->user()->content()->street() ?> <?= $kirby->user()->content()->housenumber() ?></div>
                <div id="PLZ"><?= $page->city() ?>: <?= $kirby->user()->content()->PLZ() ?> <?= $kirby->user()->content()->city() ?></div>
                <div id="tel"><?= $page->tel() ?>: <?= $kirby->user()->content()->tel() ?></div>
                <div id="fax"><?= $page->fax() ?>: <?= $kirby->user()->content()->fax() ?></div>
            </div>
        </div> 



        <form id="editUserData" class="editUserForm" method="post" action="<?= $page->url() ?>">

            <div>
                <label for="editEmail"><?= $page->username()->html() ?></label>
                <input type="email" id="editEmail" name="editEmail" placeholder="<?= $kirby->user()->email() ?>" value="<?= get('editEmail') ? esc(get('editEmail'), 'attr') : '' ?>">
            </div>

            <div>
                <label for="editPassword"><?= $page->password()->html() ?></label>
                <input type="password" id="editPassword" name="editPassword" value="<?= get('editPassword') ? esc(get('editPassword'), 'attr') : '' ?>">
            </div>

            <?php if($kirby->user()->role()->id() == 'client'): ?>

                <div class="clientField">
                    <label for="editFirstname"><?= $page->name()->html() ?></label>
                    <input type="text" id="editFirstname" name="editFirstname" value="<?= get('editFirstname') ? esc(get('editFirstname'), 'attr') : '' ?>">
                </div>


                <div class="clientField">
                    <label for="editLastname"><?= $page->lastname()->html() ?></label>
                    <input type="text" id="editLastname" name="editLastname" value="<?= get('editLastname') ? esc(get('editLastname'), 'attr') : '' ?>">
                </div>

                <select id="editOccupation" name="occupation">
                    <?php foreach($page->occupation_list()->toStructure() as $job): ?>
                    <option value="<?= $job->name()->html() ?>"><?= $job->name()->html() ?></option>
                    <?php endforeach; ?>
                </select>

            <?php elseif($kirby->user()->role()->id() == 'client-company'): ?>

                <div class="companyField">
                    <label for="editCompany_name"><?= $page->company_name()->html() ?></label>
                    <input type="text" id="editCompany_name" name="editCompany_name" placeholder="<?= $kirby->user()->content()->company_name() ?>" value="<?= get('editCompany_name') ? esc(get('editCompany_name'), 'attr') : '' ?>">
                </div>

            <?php endif; ?>

            <div>
                <label for="editTel"><?= $page->tel()->html() ?></label>
                <input type="text" id="editTel" placeholder="<?= $kirby->user()->content()->tel() ?>" name="editTel" value="<?= get('editTel') ? esc(get('editTel'), 'attr') : '' ?>">
            </div>


            <div>
                <label for="editFax"><?= $page->fax()->html() ?></label>
                <input type="text" id="editFax" name="editFax" placeholder="<?= $kirby->user()->content()->fax() ?>" value="<?= get('editFax') ? esc(get('editFax'), 'attr') : '' ?>">
            </div>


            <div>
                <label for="editStreet"><?= $page->street()->html() ?></label>
                <input type="text" id="editStreet" placeholder="<?= $kirby->user()->content()->street() ?>" name="editStreet" value="<?= get('editStreet') ? esc(get('editStreet'), 'attr') : '' ?>">
            </div>


            <div>
                <label for="editHousenumber"><?= $page->housenumber()->html() ?></label>
                <input type="text" id="editHousenumber" name="editHousenumber" placeholder="<?= $kirby->user()->content()->housenumber() ?>" value="<?= get('editHousenumber') ? esc(get('editHousenumber'), 'attr') : '' ?>">
            </div>

            <div>
                <label for="editPlz"><?= $page->plz()->html() ?></label>
                <input type="text" id="editPlz" name="editPlz" placeholder="<?= $kirby->user()->content()->plz() ?>" value="<?= get('editPlz') ? esc(get('editPlz'), 'attr') : '' ?>">
            </div>

            <div>
                <label for="editCity"><?= $page->city()->html() ?></label>
                <input type="text" id="editCity" name="editCity" placeholder="<?= $kirby->user()->content()->city() ?>" value="<?= get('editCity') ? esc(get('editCity'), 'attr') : '' ?>">
            </div>

            <div>
                <input type="submit" name="editUserData" value="<?= $page->editmode()->html() ?>" onsubmit="">
            </div>

        </form>

    
        <button id="editButton" class="editButton" onclick="toggleEdit();"><?= $page->button()->html() ?></button>

        <?php dump($kirby->user()) ?>
	</article>

<script>


    function toggleEdit(){

        const userData = document.getElementById('userData');
        const editUserDataForm = document.getElementById('editUserData');
        const editButton = document.getElementById('editButton');

        console.log('I am happening')

        if(userData.classList.contains('viewUserData')){
        userData.classList.remove("viewUserData");
        userData.classList.add("inEdit");
        editUserDataForm.style.display = "block";
        editButton.innerText = "<?= $page->editmodeoff()->html() ?>"
        }
        else if(userData.classList.contains('inEdit')){
        userData.classList.remove("inEdit");
        userData.classList.add("viewUserData");
        editUserDataForm.style.display = "none";
        editUserDataForm.reset();
        editButton.innerText = "<?= $page->button()->html() ?>"
        }
    }

</script>

<?php snippet('footer') ?>

Your submit button is called editUserData not user, so

This condition will never be true.

Haha, that was a bit of a dumb mistake on my part.
Did not see that.

Ok, so right now I get an error.
It is an issue with permissions, it seems.

Kirby\Exception\PermissionException: The Kirby user cannot be changed in /Applications/MAMP/htdocs/mywebsite/kirby/src/Cms/UserActions.php

The user role has the following permission settings:

permissions:
  access:
    panel: false
    settings: false
    users: false
    user: true
  users: false
  pages: false
  user: true

Maybe I have done something wrong here.
Or my controller is off…

Since only a logged-in user can make changes, the $kirby->impersonate() line should be removed in the controller.

Sending a non-logged-in user to the login page should happen in the controller, not in the template.

I wonder if it wouldn’t be easier to send users to their account page to make changes instead of recreating stuff in the frontend? Might not always make sense though.

Now changing the users info works!
I thank you from the bottom for your help and patience!

I am recreating it all on the frontend because these users (only the ones who can register on the frontend as well) aren’t supposed to get into the panel at any cost.
They’re clients who register on the site to get access to seminars and trainings which my customer offers.
So I figured it would be alright to display the logged in user’s info on the frontend and let them edit only their own info there if need be.

That’s totally fine, I only wanted to point out the option, because it is perfectly possible to only give users access to their account page in the Panel, while blocking access to the rest of the Panel.