Skip to content

Architectuur

Het Werkbon thema is een traditioneel WordPress thema (geen block theme) met procedurele PHP, SCSS voor styling, en jQuery-gebaseerd JavaScript. Er zijn geen namespaces, geen classes, en geen autoloader — alle functionaliteit wordt geladen via een glob-include in functions.php.

werkbon/
├── functions.php # Glob loader (9 regels)
├── header.php # HTML head, nav partial
├── footer.php # wp_footer, closing tags
├── index.php # Default template
├── 404.php # Error pagina
├── page-dashboard.php # Template: Dashboard
├── page-jobs.php # Template: Jobs (meldingen lijst)
├── page-jobs-form.php # Template: Jobs form (create/edit)
├── page-login.php # Template: Login
├── page-reports.php # Template: Reports
├── style.css # Gecompileerde CSS (87KB)
├── main-min.js # Gebundelde JS (87KB, NIET geminificeerd)
├── package.json # Node dependencies
├── functions/ # 34 PHP bestanden
│ ├── admin.php # Admin configuratie, menu's, login logo
│ ├── login.php # Auth redirects, cookie expiration
│ ├── roles.php # Role management (2 rollen)
│ ├── scripts.php # Script/style enqueue
│ ├── posttypes.php # CPT registratie (file, job, contact)
│ ├── api-job.php # REST: POST /jobs/create (20.6KB)
│ ├── api-contact.php # REST: GET/POST /contacts (23.9KB)
│ ├── api-file.php # REST: GET /files + webhook (12.8KB)
│ ├── form-addresses.php # AJAX address chain (37.9KB)
│ ├── form-prefill.php # Form prefill logic (35.7KB)
│ ├── form-work.php # Werkzaamheden modal+tabel (30.3KB)
│ ├── form-material.php # Materiaal tabel (14.2KB)
│ ├── form-search-contact.php # Contact zoek modal
│ ├── form-overview.php # Overview paneel
│ ├── wpforms.php # Core WPForms hooks
│ ├── wpforms-field-mappings.php # Field ID ↔ ACF key mapping (18.7KB)
│ ├── wpforms-add-or-update-contact.php # Contact upsert (12.6KB)
│ ├── wpforms-create-file-post.php # Form 40 → FILE CPT
│ ├── wpforms-update-job-post-submission.php # Form 3493 → JOB CPT
│ ├── wpforms-edit-job.php # Edit mode detectie
│ ├── wpforms-confirmation-overview.php # Smart tags
│ ├── wpforms-normalize-phone.php # Telefoon E.164
│ ├── wpforms-custom-date-field.php # Flatpickr integratie
│ ├── wpforms-custom-select-field.php # Select2 integratie
│ ├── wpforms-drag-and-drop.php # jQuery UI sortable
│ ├── change-job-status-on-file-complete.php # Auto status update
│ ├── update-employers-after-submit.php # Employer array parsing
│ ├── add-prefill-body-class.php # Body class voor prefill
│ ├── author.php # User/employer helpers
│ ├── db-addresses.php # Address tabel management (15.6KB)
│ ├── db-optimize.php # Postmeta indexes (8.8KB)
│ ├── contact-admin-columns.php # Admin kolommen
│ ├── modal-jobs.php # Melding modal + AJAX (9.2KB)
│ └── modal-reports.php # Reports modal (3.5KB)
├── partials/ # 5 template partials
│ ├── navigation.php # Navigatie + user dropdown (95 regels)
│ ├── show-login.php # Login weergave (16 regels)
│ ├── show-dashboard.php # Dashboard content (58 regels)
│ ├── show-jobs.php # Meldingen lijst + filters (583 regels)
│ └── show-reports.php # Rapporten lijst + filters (748 regels)
├── acf-json/ # 4 ACF field groups (JSON sync)
│ ├── group_5c7027cd8e1d8.json # Werkbonnen velden
│ ├── group_5e14d7eb790f3.json # Gebruiker velden
│ ├── group_693b783dd764b.json # Meldingen velden
│ └── group_694e8176243b2.json # Contact velden
├── assets/
│ ├── fonts/ # Ginto Nord + Mercury (WOFF2/WOFF/OTF)
│ ├── img/ # logo-tina.svg, logo-login.png, favicon
│ ├── csv/ # Maasdelta adresbestanden
│ ├── js/
│ │ ├── main.js # CodeKit bundle manifest
│ │ ├── nav.js # Navigatie (2.4KB)
│ │ ├── modal-search-contact.js # Contact zoek modal (29.8KB)
│ │ ├── file-conditional-logic.js # Conditional fields (2.2KB)
│ │ └── modules/
│ │ ├── prefill-manager.js # MutationObserver utilities
│ │ ├── wpforms-werkbon.js # Form sync, type detectie
│ │ ├── melding-modal.js # Modal AJAX (26.8KB)
│ │ ├── form-field-locks.js # Field locking (14.4KB)
│ │ ├── file-overview-sync.js # Overview panel (8.1KB)
│ │ ├── form-prefill-helpers.js # Prefill utilities (5.9KB)
│ │ └── submit-validation.js # Verify checkbox (8.3KB)
│ └── scss/
│ ├── style.scss # Entry point
│ ├── variables.scss # Kleuren, breakpoints, mixins
│ ├── elements.scss # Base elements
│ ├── nav.scss # Navigatie
│ ├── form-new.scss # Formulier styling (16.4KB)
│ ├── form-work.scss # Werkzaamheden styling
│ └── components/ # 18 SCSS partials
│ ├── _wpforms-base.scss
│ ├── _wpforms-verify.scss
│ ├── _wpforms-streetname.scss
│ ├── _wpforms-team.scss
│ ├── _wpforms-material.scss
│ ├── _meldingen.scss
│ ├── _meldingen-filters.scss
│ ├── _meldingen-pagination.scss
│ ├── _cards.scss
│ ├── _sections.scss
│ ├── _pages.scss
│ ├── _misc.scss
│ ├── _modal.scss
│ ├── _status.scss
│ ├── _tooltip.scss
│ └── _select2.scss
└── node_modules/ # jQuery, Flatpickr, Select2, Reset
// functions.php — 9 regels
add_action('init', function () {
error_log('LOADED FUNCTIONS: ' . __FILE__); // DEBUG — verwijderen!
});
foreach (glob(__DIR__ . '/functions/*') as $filename):
require_once($filename);
endforeach;

Aandachtspunten:

  • Laadvolgorde is onvoorspelbaar — afhankelijk van het bestandssysteem
  • Elk bestand in /functions/ wordt automatisch geladen — ook niet-PHP bestanden of test/temp bestanden
  • Geen namespace of class-based structuur — alle functies in global scope
  • Debug logging actieferror_log() bij elke pageload
Browser Request
WordPress Template Resolution
page-{slug}.php (page-jobs.php, page-dashboard.php, etc.)
├── get_header()
│ ├── HTML head, meta, favicon
│ ├── wp_head() → CSS + JS enqueue
│ └── get_template_part('partials/navigation')
├── get_template_part('partials/show-{naam}')
│ └── show-jobs.php / show-dashboard.php / etc.
└── get_footer()
├── wp_footer() → modals, inline scripts
└── Closing tags

Niet aanwezige templates (niet nodig — CPTs zijn niet publiek queryable):

  • single.php, archive.php, search.php, category.php
PrefixHerkomstVoorbeelden
acs_Legacy “ACS” project naamacs_job_api_create, acs_contacts_list, acs_get_employers_all_index
beam_Nieuwere conventiebeam_delete_job, beam_user_can_delete_jobs, beam_get_form40_field_map
werkbon_Theme-specifiekwerkbon_enqueue_scripts, werkbon_addresses_lookup, werkbon_create_meta_index
myproject_Legacy adres systeemmyproject_ajax_address
hra_Contact upserthra_upsert_contact_from_wpforms, hra_set_relationship_field, hra_norm_email
thra_Werkzaamheden formthra_add_werkzaamheden_modal, thra_add_werkzaamheden_button
my_Telefoon normalisatiemy_normalize_phone_nl_to_e164, my_get_area_code_by_city
wpf_dev_WPForms dev hookswpf_dev_filter_placeholder_values, wpf_dev_process_filter_choices_values

Config: config.codekit3 (84KB configuratiebestand)

SCSS pipeline:

  • Entry: assets/scss/style.scss
  • Imports: variables, elements, nav, form-new, form-work + 18 component partials
  • Output: style.css (87KB, niet geminificeerd)

JS bundeling via @codekit-prepend directives in main.js:

// @codekit-prepend "nav.js"
// @codekit-prepend "modules/prefill-manager.js"
// @codekit-prepend "modules/wpforms-werkbon.js"
// @codekit-prepend "modules/melding-modal.js"
// @codekit-prepend "modules/form-field-locks.js"
// @codekit-prepend "modules/file-overview-sync.js"
// @codekit-prepend "modules/form-prefill-helpers.js"
// @codekit-prepend "modules/submit-validation.js"

Output: main-min.js (87KB — NIET daadwerkelijk geminificeerd ondanks de naam)

Losse scripts (niet in bundle):

  • modal-search-contact.js (29.8KB) — apart geladen via wp_enqueue_scripts
  • file-conditional-logic.js (2.2KB)
scripts.php
wp_deregister_script('jquery');
wp_register_script('jquery', get_template_directory_uri() . '/node_modules/jquery/dist/jquery.min.js', [], '3.7.1', false);
// false = HEADER loading (niet footer) — vereist voor WPForms compatibiliteit
wp_enqueue_script('werkbon-main', get_template_directory_uri() . '/main-min.js', ['jquery'], $version, true);
// defer attribuut toegevoegd via filter

jQuery wordt in de header geladen (render-blocking) vanwege WPForms compatibiliteit.

8 modules communiceren via 12+ globale variabelen. Dit is het meest fragiele deel van de applicatie.

VariabeleGezet doorGelezen doorDoel
BEAM_FIELD_IDSPHP (wp_localize_script)Alle modulesCentrale field ID mapping
BEAM_WPF40_CONFIGPHP (wp_localize_script)wpforms-werkbonForm 40 configuratie
BEAM_CONTACT_PREFILL_BUSYmodal-search-contactform-field-locksPauzeert lock cycle tijdens prefill
BEAM_ADDR_DISPLAY_MODE[formId]modal-search-contactform-field-locksAdres in readonly display
BEAM_ADDR_LOCK[formId]modal-search-contactform-addresses (PHP inline)Voorkomt resets tijdens resolution
BEAM_ADDR_INIT_SELECT2[formId]PHP (form-addresses)form-field-locks, modal-searchLazy Select2 init callback
BEAM_ADDR_PREFILL[formId]modal-search-contactform-addressesOpgeslagen resolved address
BEAM_ADDR_UNLOCKED[formId]modal-search-contactform-field-locksAdres ontgrendeld
BEAM_WPF40_UNLOCKEDform-field-locksform-field-locksForm 40 unlock state
BEAM_WPF3493_UNLOCKEDform-field-locksform-field-locksForm 3493 unlock state
BEAM_CREATE_CONTACT_SUMMARY[formId]PHPmodal-search-contactSummary render callback
BEAM_CONTACT_LAYOUT[formId]PHPmodal-search-contactField layout configuratie
MYPROJECT_ADDR_READY[formId]form-addressesmodal-search-contactAddress script ready flag
PrefillManagerprefill-managerAlle modulesUtility object
MechanismeIntervalModuleDoel
Lock cycle polling250msform-field-locksCheck of velden vergrendeld moeten zijn
Overview sync polling300msfile-overview-syncVang programmatische value changes
Address resolution lock350-700msmodal-search-contactVoorkom interferentie tijdens CSV lookup
Contact prefill busy~300msmodal-search-contactPauzeer lock cycle tijdens velden vullen
Select2 AJAX debounce200msform-addressesVoorkom overmatige API calls
MutationObserverEvent-basedform-field-locks, prefill-managerDetecteer dynamische DOM wijzigingen
FontGewichtenFormatenGebruik
Ginto Nord500 (Medium), 700 (Bold), 800 (Black)WOFF2, WOFF, OTFHeadings, UI elementen
Mercury300 (Light), 400 (Regular), 500 (Medium), 700 (Bold)WOFF2, WOFF, OTFBody tekst
// CSS Custom Properties
--ui-btn-primary: #...;
--ui-btn-secondary: #...;
--color-*: ...;
// SCSS Variables (variables.scss)
$breakpoint-tablet: 768px; // Enige breakpoint
$font-heading: 'Ginto Nord', sans-serif;
$font-body: 'Mercury', serif;
  • Een breakpoint: 768px
  • Niet mobile-first — desktop stijlen als basis, media query voor mobile
  • Component-specifieke responsive regels in SCSS partials
ComponentDoel
_wpforms-baseWPForms basis styling
_wpforms-verifyVerify checkbox styling
_wpforms-streetnameStraatnaam veld styling
_wpforms-teamTeam/monteur selectie
_wpforms-materialMateriaal tabel
_meldingenMeldingen lijst
_meldingen-filtersFilter knoppen
_meldingen-paginationPaginatie
_cardsCard componenten
_sectionsPagina secties
_pagesPagina-specifieke stijlen
_miscOverige stijlen
_modalModal dialogen
_statusStatus indicators
_tooltipTooltips
_select2Select2 overrides
PackageVersieDoelGeladen
jQuery3.7.1DOM manipulatie, AJAX, Select2/Flatpickr basisHeader (blocking)
Flatpickr4.6.13Datum picker in formulierenVia WPForms
Select24.1.0-rc.0Enhanced select dropdowns (adres, contact)Via form-addresses
Eric Meyer Reset2.0.0CSS resetIn SCSS import

Alle packages worden geïnstalleerd via npm install en geladen vanuit node_modules/.

OptimalisatieImplementatieBestand
Postmeta indexes6 composite indexes op contact meta keysdb-optimize.php
Custom address tabelGeïndexeerde lookups i.p.v. CSV scanningdb-addresses.php
Bulk meta cacheupdate_postmeta_cache() voorkomt N+1 queriesshow-jobs.php, show-reports.php, contact-admin-columns.php
OptimalisatieTTLBestand
Employer user index12 uur (transient)author.php
Webhook debounce3 seconden (transient)api-contact.php
Contact upsert cacheRequest-scoped (static)wpforms-add-or-update-contact.php
  • Direct array iteration: foreach ($posts as $post) i.p.v. while (have_posts()) + the_post()
  • Meta-aware ordering: orderby => ['meta_value_num' => 'DESC', 'date' => 'DESC']
  • Whitelisted per_page: Alleen 25, 50, 100 toegestaan (voorkomt misbruik)