├── .github ├── FUNDING.yml └── workflows │ └── update-kirby-submodule.yml ├── .gitmodules ├── site ├── templates │ ├── emails │ │ ├── account-activation.text.php │ │ └── account-activation.html.php │ ├── user.json.php │ ├── user.csv.php │ ├── login.php │ ├── register.php │ └── user.php ├── snippets │ ├── notification.php │ └── header.php ├── blueprints │ ├── users │ │ └── user.yml │ └── pages │ │ ├── login.yml │ │ └── register.yml ├── controllers │ ├── login.php │ ├── register.php │ └── user.php └── config │ └── config.php ├── content ├── site.txt ├── login │ └── login.txt ├── register │ └── register.txt └── user │ └── user.txt ├── ISSUE_TEMPLATE.md ├── .editorconfig ├── LICENSE ├── .gitignore └── README.md /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: kreativ-anders 2 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "kirby"] 2 | path = kirby 3 | url = https://github.com/getkirby/kirby.git 4 | -------------------------------------------------------------------------------- /site/templates/emails/account-activation.text.php: -------------------------------------------------------------------------------- 1 | Welcome, 2 | 3 | Please click the link to activate your Account: -------------------------------------------------------------------------------- /site/templates/emails/account-activation.html.php: -------------------------------------------------------------------------------- 1 |

Welcome

2 |

Please click the link to activate your Account:

-------------------------------------------------------------------------------- /site/snippets/notification.php: -------------------------------------------------------------------------------- 1 |
2 |

alert()->html() : '' ?>

3 |

4 |
5 | -------------------------------------------------------------------------------- /content/site.txt: -------------------------------------------------------------------------------- 1 | Title: Mægazine 2 | 3 | ---- 4 | 5 | Login: Login 6 | 7 | ---- 8 | 9 | Logout: Logout 10 | 11 | ---- 12 | 13 | Register: Register 14 | 15 | ---- 16 | 17 | User: User Settings 18 | -------------------------------------------------------------------------------- /content/login/login.txt: -------------------------------------------------------------------------------- 1 | Title: Login 2 | 3 | ---- 4 | 5 | Alert: Invalid email or password 6 | 7 | ---- 8 | 9 | Email: Email 10 | 11 | ---- 12 | 13 | Password: Password 14 | 15 | ---- 16 | 17 | Button: Login -------------------------------------------------------------------------------- /ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## Expected Behavior 2 | 3 | 4 | ## Actual Behavior 5 | 6 | 7 | ## Steps to Reproduce the Problem 8 | 9 | 1. 10 | 1. 11 | 1. 12 | 13 | ## Idea 14 | 15 | Any ideas already how to solve it? 16 | -------------------------------------------------------------------------------- /content/register/register.txt: -------------------------------------------------------------------------------- 1 | Title: Register 2 | 3 | ---- 4 | 5 | Alert: Invalid email or password 6 | 7 | ---- 8 | 9 | Honeypot: Username 10 | 11 | ---- 12 | 13 | Email: Email 14 | 15 | ---- 16 | 17 | Password: Password 18 | 19 | ---- 20 | 21 | Button: Register 22 | -------------------------------------------------------------------------------- /site/blueprints/users/user.yml: -------------------------------------------------------------------------------- 1 | title: User 2 | 3 | permissions: 4 | access: 5 | panel: false 6 | 7 | fields: 8 | info: 9 | label: Info 10 | type: info 11 | theme: passive 12 | text: "User was last modified on {{ user.modified('l, d. M Y — g:i a') }}" -------------------------------------------------------------------------------- /site/templates/user.json.php: -------------------------------------------------------------------------------- 1 | user()) { 6 | 7 | $bookmarks = $kirby->user()->bookmarks()->yaml(); 8 | 9 | $json = [ 10 | 'User' => $kirby->user()->email() 11 | ]; 12 | 13 | } 14 | else { 15 | $json = []; 16 | } 17 | 18 | echo json_encode($json); -------------------------------------------------------------------------------- /site/blueprints/pages/login.yml: -------------------------------------------------------------------------------- 1 | title: Login 2 | icon: 🔐 3 | 4 | fields: 5 | alert: 6 | label: Alert text 7 | type: text 8 | email: 9 | label: Label for email 10 | type: email 11 | password: 12 | label: Label for password 13 | type: text 14 | button: 15 | label: Button text 16 | type: text -------------------------------------------------------------------------------- /site/templates/user.csv.php: -------------------------------------------------------------------------------- 1 | user()) { 8 | 9 | $csv .= "Email;Langauge\n"; 10 | $csv .= $kirby->user()->email().";".$kirby->user()->language()."\n"; 11 | 12 | 13 | } 14 | else { 15 | $csv = []; 16 | } 17 | 18 | echo $csv; -------------------------------------------------------------------------------- /site/blueprints/pages/register.yml: -------------------------------------------------------------------------------- 1 | title: Register 2 | icon: 🔐 3 | 4 | fields: 5 | alert: 6 | label: Alert text 7 | type: text 8 | email: 9 | label: Label for email 10 | type: email 11 | email_info: 12 | label: GDPR info for email 13 | type: text 14 | password: 15 | label: Label for password 16 | type: text 17 | password_info: 18 | label: GDPR info for password 19 | type: text 20 | button: 21 | label: Button text 22 | type: text -------------------------------------------------------------------------------- /content/user/user.txt: -------------------------------------------------------------------------------- 1 | Title: User Settings 2 | 3 | ---- 4 | 5 | Alert: Invalid email or password 6 | 7 | ---- 8 | 9 | Email: New Email 10 | 11 | ---- 12 | 13 | Password: New Password 14 | 15 | ---- 16 | 17 | Button: Update User 18 | 19 | ---- 20 | 21 | Export: Export and download YOUR data: 22 | 23 | ---- 24 | 25 | Danger: Danger Zone 26 | 27 | ---- 28 | 29 | Delete_Button: Delete Account 30 | 31 | ---- 32 | 33 | Delete_Warning: Are you sure? This action cannot be reversed! 34 | 35 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | [*.{css,scss,less,js,json,ts,sass,html,hbs,mustache,phtml,html.twig,md,yml}] 2 | charset = utf-8 3 | indent_style = space 4 | indent_size = 2 5 | end_of_line = lf 6 | trim_trailing_whitespace = true 7 | insert_final_newline = true 8 | 9 | [*.md] 10 | indent_size = 4 11 | trim_trailing_whitespace = false 12 | 13 | [site/templates/**.php] 14 | indent_size = 2 15 | 16 | [site/snippets/**.php] 17 | indent_size = 2 18 | 19 | [package.json,.{babelrc,editorconfig,eslintrc,lintstagedrc,stylelintrc}] 20 | indent_style = space 21 | indent_size = 2 22 | -------------------------------------------------------------------------------- /site/templates/login.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |
6 | 7 | 8 | 9 |
10 | title()->html() ?> 11 | 12 |
13 | 14 | 15 | 16 |
17 | 18 |
19 | 20 | 21 | 22 |
23 | 24 |
25 | 26 |
27 | 28 |
29 |
30 | 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 kreativ-anders | Manuel Steinberg 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /site/templates/register.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |
6 | 7 | 8 | 9 |
10 | title()->html() ?> 11 | 12 | 13 |
14 | 15 | 16 |
17 | 18 |
19 | 20 | 21 | 22 |
23 | 24 |
25 | 26 | 27 | 28 |
29 | 30 |
31 | 32 |
33 | 34 |
35 |
36 | 37 | -------------------------------------------------------------------------------- /site/controllers/login.php: -------------------------------------------------------------------------------- 1 | user()) { 6 | go('/'); 7 | } 8 | 9 | $error = null; 10 | $alert = null; 11 | 12 | if ($kirby->request()->is('POST') && get('login')) { 13 | 14 | // VALIDATE CSRF TOKEN 15 | if (csrf(get('csrf')) === true) { 16 | 17 | // GET FORM DATA 18 | $data = [ 19 | 'email' => get('email'), 20 | 'password' => get('password') 21 | ]; 22 | 23 | $rules = [ 24 | 'email' => ['required', 'email'], 25 | 'password' => ['required'] 26 | ]; 27 | 28 | $messages = [ 29 | 'email' => 'Please enter a valid email adress', 30 | 'password' => 'Please enter a password' 31 | ]; 32 | 33 | // VALIDATE FORM DATA 34 | if($invalid = invalid($data, $rules, $messages)) { 35 | 36 | $alert = $invalid; 37 | $error = true; 38 | 39 | // VALID DATA 40 | } else { 41 | 42 | // LOGIN USER 43 | try { 44 | 45 | $kirby->auth()->login($data['email'], $data['password']); 46 | 47 | } catch (Exception $e) { 48 | 49 | if(option('debug')) { 50 | 51 | $alert['error'] = 'Invalid email or password: ' . $e->getMessage(); 52 | } 53 | else { 54 | 55 | $alert['error'] = 'Invalid email or password!'; 56 | } 57 | } 58 | 59 | // SUCCESSFUL 60 | if (empty($alert) === true) { 61 | 62 | $data = []; 63 | go(); 64 | } 65 | } 66 | // INVALID CSRF TOKEN 67 | } else { 68 | 69 | $alert['error'] = 'Invalid CSRF token!'; 70 | } 71 | } 72 | 73 | return [ 74 | 'error' => $error, 75 | 'alert' => $alert, 76 | 'data' => $data ?? false 77 | ]; 78 | }; -------------------------------------------------------------------------------- /site/templates/user.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 |
9 | 10 | 11 | 12 | user()->email() ?> 13 | 14 |
15 | 16 | 17 | 18 |
19 | 20 |
21 | 22 | 23 | 24 |
25 | 26 |
27 | 28 |
29 | 30 |
31 |
32 | 33 |

34 | export()->html() ?> ( JSON | CSV ) 35 |

36 | 37 |
38 | 39 | 40 | 41 |
42 | danger()->html() ?> 43 | 44 |
45 | 46 |
47 | 48 |
49 |
50 | 51 | -------------------------------------------------------------------------------- /site/config/config.php: -------------------------------------------------------------------------------- 1 | true, 12 | 'panel' =>[ 13 | 'install' => true 14 | ], 15 | 'user.email.activation' => false, 16 | 'user.email.activation.sender' => '...', 17 | 'user.email.activation.subject' => 'Account Activation Link', 18 | 'routes' => [ 19 | [ 20 | 'pattern' => 'logout', 21 | 'action' => function() { 22 | 23 | if ($user = kirby()->user()) { 24 | $user->logout(); 25 | } 26 | 27 | go('login'); 28 | 29 | } 30 | ], 31 | [ 32 | 'pattern' => 'user/activate/(:alphanum)', 33 | 'action' => function($token) { 34 | 35 | if (option('user.email.activation', false) === false) { 36 | go(); 37 | } 38 | 39 | $kirby = kirby(); 40 | $kirby->impersonate('kirby'); 41 | 42 | if ($user = $kirby->users()->findBy('emailActivationToken', $token)) { 43 | 44 | if ($user->emailActivationToken()->toString() === Str::toType($token, 'string')) { 45 | 46 | $user->update([ 47 | 'emailActivation' => true 48 | ]); 49 | 50 | $kirby->impersonate(); 51 | go(); 52 | //go('CUSTOM_SUCCESSFUL_ACTIVATION_PAGE'); 53 | 54 | } 55 | else { 56 | $kirby->impersonate(); 57 | return false; 58 | //go('CUSTOM_ERROR_ACTIVATION_PAGE'); 59 | //return page('CUSTOM_ERROR_ACTIVATION_PAGE'); 60 | } 61 | 62 | } 63 | 64 | $kirby->impersonate(); 65 | } 66 | ] 67 | ], 68 | 'email' => [ 69 | 'transport' => [ 70 | 'type' => 'smtp', 71 | 'host' => '...', 72 | 'port' => 587, 73 | 'security' => 'tls', 74 | 'auth' => true, 75 | 'username' => '...', 76 | 'password' => '..' 77 | ] 78 | ] 79 | ]; 80 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # This is a Kirby User Management Add-On! 2 | # (Based on Kirby´s Starterkit) 3 | # ------------ 4 | 5 | index.php 6 | favicon.ico 7 | .htaccess 8 | composer.json 9 | 10 | assets 11 | 12 | content/home 13 | content/1_photography 14 | content/2_notes 15 | content/3_about 16 | content/error 17 | content/sandbox 18 | 19 | site/blueprints/site.yml 20 | 21 | site/blueprints/fields 22 | site/blueprints/files 23 | site/blueprints/users/default.yml 24 | 25 | site/blueprints/pages/about.yml 26 | site/blueprints/pages/album.yml 27 | site/blueprints/pages/default.yml 28 | site/blueprints/pages/error.yml 29 | site/blueprints/pages/home.yml 30 | site/blueprints/pages/note.yml 31 | site/blueprints/pages/notes.yml 32 | site/blueprints/pages/photography.yml 33 | site/blueprints/pages/albums.yml 34 | 35 | site/blueprints/sections/albums.yml 36 | site/blueprints/sections/notes.yml 37 | 38 | site/collections 39 | 40 | site/controllers/album.php 41 | site/controllers/note.php 42 | site/controllers/notes.php 43 | 44 | site/models 45 | 46 | site/snippets/footer.php 47 | site/snippets/gallery.php 48 | site/snippets/intro.php 49 | site/snippets/layout.php 50 | site/snippets/layouts.php 51 | site/snippets/note.php 52 | site/snippets/pagination.php 53 | site/snippets/prevnext.php 54 | site/snippets/social.php 55 | site/snippets/image.php 56 | site/snippets/blocks 57 | 58 | site/templates/about.php 59 | site/templates/album.php 60 | site/templates/default.php 61 | site/templates/home.php 62 | site/templates/note.php 63 | site/templates/notes.php 64 | site/templates/photography.php 65 | 66 | # System files 67 | # ------------ 68 | 69 | Icon 70 | .DS_Store 71 | 72 | # Temporary files 73 | # --------------- 74 | 75 | /media/* 76 | !/media/index.html 77 | 78 | # Lock files 79 | # --------------- 80 | .lock 81 | 82 | # -------------SECURITY------------- 83 | # NEVER publish these files via Git! 84 | # -------------SECURITY------------- 85 | 86 | # Cache Files 87 | # --------------- 88 | 89 | /site/cache 90 | 91 | # Accounts 92 | # --------------- 93 | 94 | /site/accounts/* 95 | !/site/accounts/index.html 96 | 97 | # Sessions 98 | # --------------- 99 | 100 | /site/sessions/* 101 | !/site/sessions/index.html 102 | 103 | # License 104 | # --------------- 105 | /site/config/.license -------------------------------------------------------------------------------- /.github/workflows/update-kirby-submodule.yml: -------------------------------------------------------------------------------- 1 | name: Update Kirby Submodule 2 | 3 | on: 4 | schedule: 5 | - cron: '0 6 1 * *' # Monthly on 1st at 06:00 UTC 6 | workflow_dispatch: 7 | 8 | jobs: 9 | update-kirby: 10 | runs-on: ubuntu-latest 11 | 12 | steps: 13 | - name: Checkout repository 14 | uses: actions/checkout@v4 15 | with: 16 | submodules: recursive 17 | fetch-depth: 0 18 | 19 | - name: Configure Git (main + submodule) 20 | run: | 21 | git config user.name "github-actions" 22 | git config user.email "github-actions@github.com" 23 | cd kirby 24 | git config user.name "github-actions" 25 | git config user.email "github-actions@github.com" 26 | cd - 27 | 28 | - name: Get previous kirby tag 29 | id: previous 30 | run: | 31 | cd kirby 32 | git fetch --tags 33 | prev_tag=$(git describe --tags --abbrev=0 2>/dev/null || echo "") 34 | echo "prev_tag=$prev_tag" >> $GITHUB_OUTPUT 35 | 36 | - name: Update kirby submodule 37 | run: | 38 | git submodule update --remote --checkout kirby 39 | 40 | - name: Get latest kirby tag after update 41 | id: latest 42 | run: | 43 | cd kirby 44 | git fetch --tags 45 | latest_tag=$(git describe --tags --abbrev=0 2>/dev/null || echo "") 46 | echo "latest_tag=$latest_tag" >> $GITHUB_OUTPUT 47 | 48 | - name: Skip if no tag or no change 49 | if: steps.latest.outputs.latest_tag == '' || steps.latest.outputs.latest_tag == steps.previous.outputs.prev_tag 50 | run: | 51 | echo "No new tag or tag unchanged — skipping PR creation." 52 | exit 0 53 | 54 | - name: Create Pull Request 55 | uses: peter-evans/create-pull-request@v6 56 | with: 57 | commit-message: "chore: update kirby to ${{ steps.latest.outputs.latest_tag }}" 58 | title: "Update kirby submodule to ${{ steps.latest.outputs.latest_tag }}" 59 | body: | 60 | This PR updates the `kirby` submodule from **${{ steps.previous.outputs.prev_tag }}** to **${{ steps.latest.outputs.latest_tag }}**. 61 | 62 | 🔍 [View changes on GitHub](https://github.com/getkirby/kirby/compare/${{ steps.previous.outputs.prev_tag }}...${{ steps.latest.outputs.latest_tag }}) 63 | 64 | branch: "update-kirby-submodule" 65 | delete-branch: true 66 | -------------------------------------------------------------------------------- /site/snippets/header.php: -------------------------------------------------------------------------------- 1 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 27 | <?= $site->title() ?> | <?= $page->title() ?> 28 | 29 | 36 | 42 | 43 | 50 | 51 | 52 | 53 | 54 | 55 | 56 |
57 | url()` to create a link back to the homepage 60 | for the logo and `$site->title()` as a temporary logo. You 61 | probably want to replace this with an SVG. 62 | */ 63 | ?> 64 | 67 | 68 | 94 |
95 | 96 |
97 | -------------------------------------------------------------------------------- /site/controllers/register.php: -------------------------------------------------------------------------------- 1 | user()) { 6 | go('/'); 7 | } 8 | 9 | $error = null; 10 | $alert = null; 11 | 12 | // TOKEN FOR ACCOUNT ACTIVATION 13 | $token = Str::random(16); 14 | 15 | if($kirby->request()->is('POST') && get('register')) { 16 | 17 | // CHECK HONEYPOT 18 | if(empty(get('username')) === false) { 19 | go('//localhost'); 20 | exit; 21 | } 22 | 23 | // VALIDATE CSRF TOKEN 24 | if (csrf(get('csrf')) === true) { 25 | 26 | // GET FORM DATA 27 | $data = [ 28 | 'email' => get('email'), 29 | 'password' => get('password') 30 | ]; 31 | 32 | $rules = [ 33 | 'email' => ['required', 'email'], 34 | 'password' => ['required', 'minLength' => 8] 35 | ]; 36 | 37 | $messages = [ 38 | 'email' => 'Please enter a valid email adress', 39 | 'password' => 'Please enter a valid password' 40 | ]; 41 | 42 | // VALIDATE FORM DATA 43 | if($invalid = invalid($data, $rules, $messages)) { 44 | 45 | $alert = $invalid; 46 | $error = true; 47 | 48 | } else { 49 | 50 | $kirby = kirby(); 51 | $kirby->impersonate('kirby'); 52 | 53 | try { 54 | 55 | // CREATE USER 56 | $user = $kirby->users()->create([ 57 | 'email' => $data['email'], 58 | 'role' => 'user', 59 | 'language' => 'en', 60 | 'password' => $data['password'] 61 | ]); 62 | 63 | // CHECK EMAIL ACTIVATION 64 | if (option('user.email.activation', false) === true) { 65 | 66 | $user->update([ 67 | 'emailActivation' => false, 68 | 'emailActivationToken' => $token 69 | ]); 70 | } 71 | 72 | } catch(Exception $e) { 73 | 74 | if(option('debug')) { 75 | 76 | $alert['error'] = 'The user could not be created: ' . $e->getMessage(); 77 | } 78 | else { 79 | 80 | $alert['error'] = 'The user could not be created!'; 81 | } 82 | } 83 | 84 | $kirby->impersonate(); 85 | 86 | // SUCCESSFUL 87 | if (empty($alert) === true && $user) { 88 | 89 | // ACTIVATE ACCOUNT BY EMAIL IF ENABLED 90 | if (option('user.email.activation', false) === true) { 91 | 92 | $link = $kirby->site()->url() . "/user/activate/" . $token; 93 | 94 | $email = $kirby->email([ 95 | 'to' => $data['email'], 96 | 'from' => option('user.email.activation.sender'), 97 | 'subject' => option('user.email.activation.subject', 'Account Activation Link'), 98 | 'template' => 'account-activation', 99 | 'data' => [ 100 | 'link' => $link, 101 | ] 102 | ]); 103 | } 104 | 105 | // LOGIN USER 106 | if($user->login($data['password'])) { 107 | go(); 108 | } 109 | 110 | $data = []; 111 | } 112 | } 113 | // INVALID CSRF TOKEN 114 | } else { 115 | 116 | $alert['error'] = 'Invalid CSRF token!'; 117 | } 118 | }; 119 | 120 | return [ 121 | 'error' => $error, 122 | 'alert' => $alert, 123 | 'data' => $data ?? false 124 | ]; 125 | }; -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Kirby Userkit Add-On (Template) 2 | 3 | * [What do you get?](#what-do-you-get) 4 | * [Why an Add-On?](#why-an-add-on) 5 | * [Installation](#installation) 6 | * [Notes](#notes) 7 | * [Kirby CMS Licence](#kirby-cms-licence) 8 | * [Support](#support) 9 | * [Contribute](#contribute) 10 | 11 | 12 | ## What do you get? 13 | A functional, lean, and unstyled Kirby User Management Add-On (Template) for Kirby CMS. 14 | 15 | **Functionality** | **Comment** 16 | --------------------------- | --------------------------- 17 | Register / Login | Yes 18 | Activation by Email | Yes (Disabled by dafault) 19 | Logout | Virtual 20 | Change Email | Yep 21 | Change Password | Sure 22 | Export Data | CSV & JSON 23 | Dedicated Role | Of course 24 | CSS | Nope 25 | Data Validation | Yes 26 | Success Messages | Partly (Best is to do it manually to adapt to **YOUR** way of working.) 27 | Messages | Mix of hardcoded and page content 28 | 29 | ## Why not use login with Google/Facebook/etc.? 30 | Short answer: **Simplicity and Privacy**. An individual solution like this keeps it simple and create a stronger bond between you and your visitors. No dependency on third parties like Firebase, Okta, OAuth2, etc. 31 | 32 | ## Why an Add-On? 33 | IMHO a Plug-in does not make sense due to interoperability. Also this kind of Add-On adapts way more easy to **YOUR** project and way of working. 34 | 35 | ## Installation: 36 | 1. Download the repository 37 | 2. Unzip the files. 38 | 3. Paste (overwrite) the folder *content* and *site* on top of the root folder of your Kirby installation. 39 | 4. Done! 40 | 41 | ### Configuration 42 | - Set `email` config (see [Kirby email options](https://getkirby.com/docs/reference/system/options/email)) 43 | - Set `user.email.activation` config to true (default false). 44 | - Set `user.email.activation.sender` config email sender (mandatory when email activation is enabled). 45 | - Set `user.email.activation.subject` config email subject (mandatory when email activation is enabled). 46 | - Change activation token length in `register.php` controller (default 16). 47 | 48 | ## Notes: 49 | This Add-On is built for Kirby CMS based on **Kirby´s Starterkit Version 4.0.2**. 50 | 51 | In case you are using Kirby´s Plainkit ensure to add the pages/links for the following pages somewhere in your snippets or templates! 52 | 53 | - Register 54 | - Login 55 | - Logout 56 | - User 57 | 58 | > :warning: Last Login have been removed since hooks make life more difficult. 59 | 60 | The user will be logged in even the account is not activated by email yet! 61 | You can check `$kirby->user()->emailActivation()` for disabling certain features, pages etc. 62 | 63 | To change the email template go to `templates\email\account-activation.*.php`. 64 | 65 | In case the user changes the email address the activation status is set to `false`and another email will be sent. 66 | 67 | ### Kirby CMS Licence 68 | **Kirby CMS requires a dedicated licence:** 69 | 70 | *Go to https://getkirby.com/buy* 71 | 72 | ## Disclaimer 73 | The source code is provided "as is" with no guarantee. Use it at your own risk and always test it yourself before using it in a production environment. If you find any issues, please create a new issue. 74 | 75 | ## Support 76 | 77 | In case this Add-On saved you some time and energy consider supporting kreativ-anders by donating via [PayPal](https://paypal.me/kreativanders) or becoming a **GitHub Sponsor**. 78 | 79 | ## Contribute 80 | 81 | Feel free to fork the repository and participate. 82 | -------------------------------------------------------------------------------- /site/controllers/user.php: -------------------------------------------------------------------------------- 1 | user()) { 6 | go('/'); 7 | } 8 | 9 | $error = null; 10 | $alert = null; 11 | 12 | // CHECK ACCOUNT ACTIVATION 13 | if(option('user.email.activation', false) === true && $kirby->user()->emailActivation()->toString() === '' || $kirby->user()->emailActivation() != true) { 14 | 15 | $alert['error'] = 'Please check your emails to activate the account.'; 16 | } 17 | 18 | // UPDATE USER 19 | if($kirby->request()->is('post') && get('update')) { 20 | 21 | // VALIDATE CSRF TOKEN 22 | if (csrf(get('csrf')) === true) { 23 | 24 | // GET FORM DATA 25 | $data = [ 26 | 'email' => get('email'), 27 | 'password' => get('password') 28 | ]; 29 | 30 | $rules = [ 31 | 'email' => ['email'], 32 | 'password' => ['minLength' => 8] 33 | ]; 34 | 35 | $messages = [ 36 | 'email' => 'Please enter a valid email adress', 37 | 'password' => 'Please enter an eight character password' 38 | ]; 39 | 40 | // VALIDATE FORM DATA 41 | if($invalid = invalid($data, $rules, $messages)) { 42 | 43 | $alert = $invalid; 44 | $error = true; 45 | 46 | // VALID DATA 47 | } else { 48 | 49 | // EMAIL 50 | if (V::email($data['email']) && !get('password')) { 51 | 52 | try { 53 | 54 | $kirby->user()->changeEmail($data['email']); 55 | $success = 'Your email has been changed!'; 56 | 57 | // TOKEN FOR ACCOUNT RE-ACTIVATION 58 | $token = Str::random(16); 59 | 60 | $kirby->user()->update([ 61 | 'emailActivation' => false, 62 | 'emailActivationToken' => $token 63 | ]); 64 | 65 | // ACTIVATE ACCOUNT BY EMAIL IF ENABLED 66 | if (option('user.email.activation', false) === true) { 67 | 68 | $link = $kirby->site()->url() . "/user/activate/" . $token; 69 | 70 | $email = $kirby->email([ 71 | 'to' => $data['email'], 72 | 'from' => option('user.email.activation.sender'), 73 | 'subject' => option('user.email.activation.subject', 'Account Activation Link'), 74 | 'template' => 'account-activation', 75 | 'data' => [ 76 | 'link' => $link, 77 | ] 78 | ]); 79 | } 80 | 81 | } catch(Exception $e) { 82 | 83 | if(option('debug')) { 84 | 85 | $alert['error'] = 'The user email could not be changed: ' . $e->getMessage(); 86 | } 87 | else { 88 | 89 | $alert['error'] = 'The user email could not be changed!'; 90 | } 91 | } 92 | } 93 | 94 | // PASSWORD 95 | if ($data['password']) { 96 | 97 | try { 98 | 99 | $kirby->user()->changePassword($data['password']); 100 | $success = 'Your password has been changed!'; 101 | 102 | } catch(Exception $e) { 103 | 104 | if(option('debug')) { 105 | 106 | $alert['error'] = 'The user password could not be changed: ' . $e->getMessage(); 107 | } 108 | else { 109 | 110 | $alert['error'] = 'The user password could not be changed!'; 111 | } 112 | } 113 | } 114 | 115 | // SUCCESSFUL 116 | if (empty($alert) === true) { 117 | 118 | $error = null; 119 | } 120 | } 121 | // INVALID CSRF TOKEN 122 | } else { 123 | 124 | $alert['error'] = 'Invalid CSRF token!'; 125 | } 126 | } 127 | 128 | // DELETE USER 129 | if($kirby->request()->is('post') && get('delete')) { 130 | 131 | try { 132 | 133 | $kirby->user()->delete(); 134 | go('/'); 135 | 136 | } catch(Exception $e) { 137 | 138 | if(option('debug')) { 139 | 140 | $alert['error'] = 'The user could not be deleted: ' . $e->getMessage(); 141 | } 142 | else { 143 | 144 | $alert['error'] = 'The user could not be deleted!'; 145 | } 146 | } 147 | } 148 | 149 | return [ 150 | 'error' => $error, 151 | 'alert' => $alert, 152 | 'data' => $data ?? false, 153 | 'success' => $success ?? false 154 | ]; 155 | }; --------------------------------------------------------------------------------