Account

Additional Data

Since we use a regular user blueprint for the account, you can add fields to store any data you want. Let's assume you want to add two more fields: one to store the member's address and one to store a flag indicating badges earned by the member.

We can set an additional layer of permissions for user blueprint fields provided by the Klub plugin. This will allow us to secure update requests from your frontend since we want to allow the VIP field to be read but not written.

site/blueprints/users/member.yml
title: Member

permissions:
  access:
    panel: false

fields:

  stripe:
    extends: fields/stripe

  address:
    translate: false
    type: textarea
    # klub: true

  badges:
    translate: false
    type: tags
    klub:
      write: false

User Method: $user->updateKlub($data)

To utilise the protection from the klub property on fields in user blueprints, you need to update the user model with $user->updateKlub($data) instead of the core Kirby $user->update($data) method.

Endpoint: klub/account

The klub/account-endpoint allows you to easily create custom forms to update user data without worrying about some of the security implications when submitting forms.

If we provide an endpoint to write data, we must remove malicious attempts to set data, which we consider hidden or read-only. The Klub plugin provides a protected endpoint that honours the permissions set for each field.

Given the example below. Even if someone sends data for the badges the logic behind the klub/account-endpoint will not write that data to the user content file since the permission state it should not.

site/templates/account.php
<?php
if (kirby()->user() === null) {
    go(site()->homePage()->url().'#login');
}
$user = kirby()->user();
?>
<form method="POST" action="<?= site()->url() ?>/klub/account">
    <div>
        <label for="name">Name</label>
        <input name="name" required type="text" value="<?= $user->name()->value() ?>"/>
    </div>

    <div>
        <label for="email">E-Mail</label>
        <input name="email" required type="email" value="<?= $user->email() ?>"/>
    </div>

    <div>
        <label for="address">Address</label>
        <textarea name="address"><?= $user->address()->value() ?></textarea>
    </div>

    <div>
        <label for="badges">Badges</label>
        <ul>
            <?php foreach ($user->badges()->split() as $badge) { ?>
                <li><?= $badge ?></li>
            <?php } ?>
        </ul>
       <?php // assume someone added this to their DOM before submitting the form ?>
       <!-- HACK START-->
       <input name="badges" type="text" value="hackers,rule"/>
       <!-- HACK END -->
    </div>
    
    <div>
        <input type="hidden" name="redirect" value="<?= $page->url() ?>">
        <input type="hidden" name="token" value="<?= csrf() ?>">
        <button type="submit">Save changes</button>
    </div>
</form>

Email, Name & Password

To prevent the user from modifying their email, name, or password, you can set the respective permissions using Kirby user blueprint permissions.

Unless you explicitly disable them in the permissions, the klub/account-endpoint will update them if they are provided in the POST-request.

site/templates/account.php
title: Member

permissions:
  access:
    panel: false
  user:
    changeEmail: false
    changeName: false
    changePassword: false

Encryption

You can use the config to enable encryption for the data stored by Stripe or enforce encryption of the full content file (in case you plan to store personal information). Read more about encryption here.

Storing Data at Stripe

Instead of storing data in the CMS it might be a viable idea to store data worth of protection at Stripe. The only drawback is a slight decrease in performance but with enough planning you might be able to limited that issue to the account view.

Delete Account

You can use the following code to create a form for account deletion.

site/snippets/account-delete.php
<form method="POST" action="<?= site()->url() ?>/klub/account/delete"
      onSubmit="return confirm('Seriously?');">
    <input type="hidden" name="token" value="<?= csrf() ?>">
    <button type="submit">Delete Account</button>
</form>

If you need to perform additional tasks when the user deletes their account consider registering the the user.delete:before or user.delete:after-hooks.

site/config/config.php
<?php

return [
    'hooks' => [
        'user.delete:before' => function (User $user) {
            // - send an email
            // - flag account in stripe or whatever
        },
    ],
    // other options
];
Kirby Klub is not affiliated with the developers of Kirby CMS. We are merely standing on the shoulder of giants.
© 2025 Bruno Meilick All rights reserved.