Authenticatie & Rollen
Login Flow
Section titled “Login Flow”De volledige authenticatie wordt afgehandeld via een template_redirect hook in functions/login.php.
Flow diagram
Section titled “Flow diagram”Bezoeker request |template_redirect hook |is_admin()? ---- Ja ----> Doorlaten (wp-admin eigen auth) |wp-login.php? -- Ja ----> Doorlaten (veiligheidsnet) |AJAX/REST? ----- Ja ----> Doorlaten |Ingelogd? |--- Ja --> Is /login/? -- Ja --> Redirect naar / | -- Nee --> Toon pagina | |--- Nee -> Is /login/? -- Ja --> Toon login pagina -- Nee --> Redirect naar /login/Volledige handler code
Section titled “Volledige handler code”add_action('template_redirect', function () {
if ( is_admin() ) return;
$login_slug = 'login';
// Sta wp-login.php toe (veiligheidsnet) if ( strpos($_SERVER['REQUEST_URI'] ?? '', 'wp-login.php') !== false ) return;
// Sta AJAX/REST toe if ( (defined('DOING_AJAX') && DOING_AJAX) || (defined('REST_REQUEST') && REST_REQUEST) ) return;
// Wel ingelogd: /login -> / if ( is_user_logged_in() ) { if ( is_page($login_slug) ) { wp_safe_redirect( home_url('/') , 302 ); exit; } return; // verder alles toegestaan }
// Niet ingelogd: alleen /login toegestaan if ( is_page($login_slug) ) return;
wp_safe_redirect( home_url('/' . $login_slug . '/') , 302 ); exit;});Uitzonderingen (geen redirect)
Section titled “Uitzonderingen (geen redirect)”| Type request | Check | Reden |
|---|---|---|
Admin requests (/wp-admin/) | is_admin() | WordPress eigen login-check handelt dit af |
wp-login.php | strpos(REQUEST_URI) | Veiligheidsnet voor directe wp-login toegang |
| AJAX requests | DOING_AJAX constant | AJAX endpoints moeten altijd bereikbaar zijn |
| REST API requests | REST_REQUEST constant | /wp-json/ endpoints moeten functioneren |
Edge cases
Section titled “Edge cases”- REST API: Wordt expliciet doorgelaten via
REST_REQUESTconstant. REST endpoints hebben hun eigen authenticatie viarest_authentication_errors. - AJAX: Wordt doorgelaten via
DOING_AJAX. Elke AJAX handler doet zijn eigen nonce + capability check. - WP Cron: Wordt niet expliciet afgevangen, maar WP Cron draait via
wp-cron.phpdat niet doortemplate_redirectgaat (het laadtwp-load.phpdirect). - Monteur naar /wp-admin/: De
is_admin()check laat dit door. WordPress zelf toont dan het dashboard. Monteurs (subscribers) zien een beperkt dashboard zonder menu-items diemanage_optionsvereisen.
Logout redirect
Section titled “Logout redirect”add_filter('logout_redirect', function ($redirect_to, $requested_redirect_to, $user) { return home_url('/');}, 10, 3);Na uitloggen wordt altijd geredirect naar de homepage. Omdat de gebruiker dan niet meer is ingelogd, vangt template_redirect dit op en stuurt door naar /login/.
Sessie Management
Section titled “Sessie Management”add_filter('auth_cookie_expiration', function ($expiration, $user_id, $remember) { return 30 * DAY_IN_SECONDS; // 30 dagen}, 10, 3);- Cookie duur: 30 dagen (2.592.000 seconden)
- De
$rememberparameter wordt genegeerd — ook zonder “Onthoud mij” duurt de sessie 30 dagen - Risico op gedeelde apparaten — zie Security Audit
Rollen
Section titled “Rollen”Slechts 2 rollen. Alle andere worden permanent verwijderd bij init (prioriteit 20).
Role setup code
Section titled “Role setup code”add_action('init', function () {
// 1) Hernoem rollen in de UI if ( wp_roles() ) { $wp_roles = wp_roles();
if ( isset($wp_roles->roles['administrator']) ) { $wp_roles->roles['administrator']['name'] = 'Beheerder'; $wp_roles->role_names['administrator'] = 'Beheerder'; }
if ( isset($wp_roles->roles['subscriber']) ) { $wp_roles->roles['subscriber']['name'] = 'Monteur'; $wp_roles->role_names['subscriber'] = 'Monteur'; } }
// 2) Verwijder standaard rollen foreach (['editor', 'author', 'contributor'] as $role) { if ( get_role($role) ) { remove_role($role); } }
// 3) Geef Monteur (subscriber) delete capabilities $role = get_role('subscriber'); if ( $role ) { $role->add_cap('delete_posts'); $role->add_cap('delete_published_posts'); $role->add_cap('delete_private_posts'); $role->add_cap('delete_others_posts'); $role->add_cap('delete_pages'); $role->add_cap('delete_published_pages'); $role->add_cap('delete_private_pages'); $role->add_cap('delete_others_pages'); $role->add_cap('delete_attachments'); }
}, 20);Roltabel
Section titled “Roltabel”| WP Rol | UI Label | Beschrijving |
|---|---|---|
administrator | Beheerder | Volledige toegang |
subscriber | Monteur | Standaard subscriber + uitgebreide delete rechten |
Verwijderde rollen: editor, author, contributor — permanent via remove_role().
Rechtenmatrix
Section titled “Rechtenmatrix”| Capability | Beheerder | Monteur |
|---|---|---|
read | Ja | Ja |
edit_posts | Ja | Ja |
delete_posts | Ja | Ja (toegevoegd) |
delete_published_posts | Ja | Ja (toegevoegd) |
delete_private_posts | Ja | Ja (toegevoegd) |
delete_others_posts | Ja | Ja (toegevoegd) |
delete_pages | Ja | Ja (toegevoegd) |
delete_published_pages | Ja | Ja (toegevoegd) |
delete_private_pages | Ja | Ja (toegevoegd) |
delete_others_pages | Ja | Ja (toegevoegd) |
delete_attachments | Ja | Ja (toegevoegd) |
upload_files | Ja | Ja |
manage_options | Ja | Nee |
editable_roles filter
Section titled “editable_roles filter”Voorkomt dat andere rollen (ook door plugins aangemaakt) zichtbaar zijn in de user editor:
add_filter('editable_roles', function ($roles) { $allowed = ['administrator', 'subscriber'];
foreach ($roles as $key => $role) { if ( ! in_array($key, $allowed, true) ) { unset($roles[$key]); } }
return $roles;});pre_user_role filter
Section titled “pre_user_role filter”Forceert dat alleen administrator of subscriber als rol kan worden opgeslagen. Onbekende rollen worden teruggezet naar subscriber:
add_filter('pre_user_role', function ($new_role) { $allowed = ['administrator', 'subscriber']; return in_array($new_role, $allowed, true) ? $new_role : 'subscriber';});ACF Admin veld
Section titled “ACF Admin veld”- Veldnaam:
admin(true/false) op user profiel - Vereist voor: melding verwijderen via
beam_user_can_delete_jobs() - Dit is een eigen permissielaag, los van WordPress capabilities
- Zie AJAX Endpoints voor de volledige
beam_user_can_delete_jobs()implementatie
ACF Employer veld
Section titled “ACF Employer veld”- Veldnaam:
employer(true/false) op user profiel - Markeert gebruiker als monteur/technician
acs_get_employers_all_index()bouwt een gecachte index (12 uur transient)
Admin Bar
Section titled “Admin Bar”Verborgen voor alle gebruikers (inclusief administrators):
add_filter('show_admin_bar', '__return_false');De CSS “bump” die WordPress toevoegt voor de admin bar wordt ook verwijderd:
add_action('get_header', 'my_filter_head');function my_filter_head() { remove_action('wp_head', '_admin_bar_bump_cb');}Custom Login Pagina
Section titled “Custom Login Pagina”De login pagina is een WordPress Page met slug login. De styling wordt aangepast via hooks in functions/admin.php.
Login logo
Section titled “Login logo”function my_custom_login_logo() { echo '<style type="text/css"> h1 a { background-image:url('.get_bloginfo('template_directory').'/assets/img/logo-login.png) !important; background-size:auto !important; height:100px !important; width:300px !important; } </style>';}add_action('login_head', 'my_custom_login_logo');- Logo:
/assets/img/logo-login.png(300x100px, centered) - Injectie via CSS in de
login_headhook
Admin footer
Section titled “Admin footer”add_filter('admin_footer_text', 'remove_footer_admin');function remove_footer_admin() { echo 'Made by <a href="http://www.angelovaudo.com" target="_blank">Angelo Vaudo</a>';}Admin menu z-index fix
Section titled “Admin menu z-index fix”function admin_menu_fix() { echo '<style>#adminmenu { transform: translateZ(0); }</style>';}add_action('admin_head', 'admin_menu_fix');Voorkomt z-index rendering problemen in het WordPress admin menu.
Menu Registratie
Section titled “Menu Registratie”add_action('init', 'register_menus');function register_menus() { register_nav_menus( array( 'menu' => __( 'Main menu' ), 'mobile' => __( 'Mobile menu' ) ) );}| Location | Beschrijving |
|---|---|
menu | Desktop horizontaal menu, gerenderd in partials/navigation.php |
mobile | Mobiel menu, gerenderd als onderdeel van de account dropdown |
Navigatie
Section titled “Navigatie”Bestand: partials/navigation.php
De navigatie is alleen zichtbaar voor ingelogde gebruikers (is_user_logged_in()).
Gebruikersnaam logica
Section titled “Gebruikersnaam logica”$current_user = wp_get_current_user();$first_name = trim( (string) get_user_meta($current_user->ID, 'first_name', true) );$user_name = $first_name;if ( $user_name === '' ) { $user_name = $current_user->display_name ?: $current_user->user_login;}Prioriteit: voornaam > display_name > user_login.
Profielfoto logica
Section titled “Profielfoto logica”De profielfoto komt uit het ACF user-veld img-profile. Drie formaten worden ondersteund:
$avatar_url = '';if ( function_exists('get_field') ) { $acf_profile_img = get_field('img-profile', 'user_' . $user_id);
if ( is_array($acf_profile_img) ) { // ACF image array: gebruik medium size, fallback naar full URL $avatar_url = !empty($acf_profile_img['sizes']['medium']) ? $acf_profile_img['sizes']['medium'] : ($acf_profile_img['url'] ?? ''); } elseif ( is_numeric($acf_profile_img) ) { // Attachment ID: haal medium src op $src = wp_get_attachment_image_src((int) $acf_profile_img, 'medium'); $avatar_url = $src ? $src[0] : ''; } elseif ( is_string($acf_profile_img) ) { // Directe URL string $avatar_url = $acf_profile_img; }}| Return type van ACF | Afhandeling |
|---|---|
| Array (image object) | $img['sizes']['medium'] of $img['url'] |
| Numeric (attachment ID) | wp_get_attachment_image_src($id, 'medium') |
| String (URL) | Directe URL |
| Geen/leeg | Geen profielfoto getoond |
Er is geen Gravatar fallback. Als img-profile niet ingesteld is, wordt geen afbeelding getoond.
Navigatie structuur
Section titled “Navigatie structuur”<nav class="site-nav" aria-label="Hoofdnavigatie"> <div class="container nav-inner">
<!-- Logo kolom --> <div class="nav-column nav-column-logo"> <a href="/" class="site-logo"> <!-- SVG inline via file_get_contents() --> </a> </div>
<!-- Desktop menu --> <div class="nav-column nav-column-menu show-desktop" id="primary-menu"> <!-- wp_nav_menu('menu') --> </div>
<!-- Account dropdown --> <div class="nav-column nav-column-account"> <div class="account-dropdown" data-account-dropdown> <button class="account-trigger" aria-expanded="false" aria-controls="account-menu"> <img class="img-profile" src="..." /> <!-- conditioneel --> <span class="account-name">Voornaam</span> <span class="account-caret">▾</span> </button>
<ul class="account-menu" id="account-menu" role="menu"> <!-- Mobiel menu (hide-desktop) --> <!-- wp_nav_menu('mobile') als <li> wrapper -->
<li> <a class="logout" href="...">Uitloggen</a> </li> </ul> </div> </div>
</div></nav>Desktop vs. mobiel
Section titled “Desktop vs. mobiel”| Element | Desktop | Mobiel |
|---|---|---|
nav-column-menu | Zichtbaar (show-desktop) | Verborgen |
| Mobile menu in dropdown | Verborgen (hide-desktop) | Zichtbaar als onderdeel van account dropdown |
| Account dropdown | Profielfoto + naam + caret | Profielfoto + naam + caret |
| Uitlogknop | Altijd in dropdown | Altijd in dropdown |
Het logo (/assets/img/logo-tina.svg) wordt inline gerenderd via file_get_contents(). Dit voorkomt een extra HTTP request en maakt CSS styling mogelijk.
Logout URL
Section titled “Logout URL”$logout_url = wp_logout_url( home_url('/') );De redirect na logout gaat naar /, maar het logout_redirect filter overschrijft dit ook naar home_url('/'). Vervolgens vangt template_redirect de niet-ingelogde gebruiker op en stuurt door naar /login/.
ACF Options Page
Section titled “ACF Options Page”if( function_exists('acf_add_options_page') ) { acf_add_options_page();}Standaard ACF options page zonder parameters. Beschikbaar onder Settings > Options in wp-admin.
Bestandsoverzicht
Section titled “Bestandsoverzicht”| Bestand | Pad | Hooks | Functies |
|---|---|---|---|
login.php | functions/login.php | template_redirect, logout_redirect, auth_cookie_expiration | Login redirect logica, sessie duur |
roles.php | functions/roles.php | init (prio 20), editable_roles, pre_user_role | Rol setup, capability toewijzing, rol lockdown |
admin.php | functions/admin.php | show_admin_bar, login_head, admin_footer_text, get_header, admin_head, init | Admin bar, login styling, menu registratie, ACF options |
navigation.php | partials/navigation.php | (partial, geen hooks) | Navigatie HTML met profielfoto, menu’s, account dropdown |