AJAX Endpoints
Overzicht
Section titled “Overzicht”| Action | Handler | Nonce | Auth | Bestand |
|---|---|---|---|---|
delete_job | beam_delete_job() | delete_job_nonce | ACF admin=true via beam_user_can_delete_jobs() | modal-jobs.php |
update_job_status | beam_update_job_status() | update_job_status_nonce | edit_post capability | modal-jobs.php |
myproject_address | myproject_ajax_address() | myproject_address_nonce | nopriv ook (publiek) | form-addresses.php |
delete_job
Section titled “delete_job”- Hook:
wp_ajax_delete_job(alleen ingelogde gebruikers) - Methode: POST
- Nonce:
check_ajax_referer('delete_job_nonce', 'nonce')
Permissiecheck: beam_user_can_delete_jobs()
Section titled “Permissiecheck: beam_user_can_delete_jobs()”De verwijder-knop verschijnt alleen als deze functie true retourneert. De implementatie:
function beam_user_can_delete_jobs(int $user_id = 0): bool { if ($user_id <= 0) { $user_id = get_current_user_id(); } if ($user_id <= 0) { return false; }
$val = null; if (function_exists('get_field')) { // ACF user field context key: user_{ID} $val = get_field('admin', 'user_' . $user_id); }
if ($val === null || $val === '') { // Fallback als ACF niet geladen is $val = get_user_meta($user_id, 'admin', true); }
return ($val === true || $val === 1 || $val === '1' || $val === 'true' || $val === 'yes');}De functie controleert het ACF user-veld admin op de gebruiker. Het is een eigen permissielaag, los van WordPress capabilities. Er is een fallback naar get_user_meta() voor het geval ACF niet geladen is.
Request
Section titled “Request”$.ajax({ url: ajaxUrl, method: 'POST', data: { action: 'delete_job', nonce: deleteNonce, post_id: jobId }});Handler (volledige code)
Section titled “Handler (volledige code)”function beam_delete_job() { check_ajax_referer('delete_job_nonce', 'nonce');
if ( ! is_user_logged_in() ) { wp_send_json_error(array('message' => 'Niet ingelogd.'), 401); } if ( ! beam_user_can_delete_jobs() ) { wp_send_json_error(array('message' => 'Geen rechten om te verwijderen.'), 403); }
$post_id = isset($_POST['post_id']) ? absint($_POST['post_id']) : 0; if ( ! $post_id ) { wp_send_json_error(array('message' => 'Ongeldig ID.'), 400); }
$post = get_post($post_id); if ( ! $post || $post->post_type !== 'job' ) { wp_send_json_error(array('message' => 'Melding niet gevonden.'), 404); }
// Soft delete: verplaats naar prullenbak $result = wp_trash_post($post_id);
if ( is_wp_error($result) ) { wp_send_json_error(array('message' => $result->get_error_message()), 500); } if ( ! $result ) { wp_send_json_error(array('message' => 'Verwijderen is mislukt.'), 500); }
wp_send_json_success(array('message' => 'Melding verwijderd (prullenbak).'));}Foutresponses
Section titled “Foutresponses”| HTTP | Conditie | Message |
|---|---|---|
| 401 | Niet ingelogd | Niet ingelogd. |
| 403 | ACF admin veld niet truthy | Geen rechten om te verwijderen. |
| 400 | post_id is 0 of ontbreekt | Ongeldig ID. |
| 404 | Post bestaat niet of post_type !== 'job' | Melding niet gevonden. |
| 500 | wp_trash_post() retourneert WP_Error of false | Foutmelding of Verwijderen is mislukt. |
Succesresponse
Section titled “Succesresponse”{ "success": true, "data": { "message": "Melding verwijderd (prullenbak)." }}Let op: de actie is een soft delete (wp_trash_post), geen hard delete. De melding kan via de prullenbak hersteld worden.
Client-side
Section titled “Client-side”melding-modal.js verwijdert de tabelrij uit de DOM en sluit de modal.
update_job_status
Section titled “update_job_status”- Hook:
wp_ajax_update_job_status(alleen ingelogde gebruikers) - Methode: POST
- Nonce:
check_ajax_referer('update_job_status_nonce', 'nonce') - Permissie:
current_user_can('edit_post', $post_id)
Request
Section titled “Request”$.ajax({ url: ajaxUrl, method: 'POST', data: { action: 'update_job_status', nonce: statusNonce, post_id: jobId, status: newStatus // '0', '1' of '2' }});Handler (volledige code)
Section titled “Handler (volledige code)”function beam_update_job_status() { check_ajax_referer('update_job_status_nonce', 'nonce');
$post_id = isset($_POST['post_id']) ? absint($_POST['post_id']) : 0; $status = isset($_POST['status']) ? sanitize_text_field($_POST['status']) : '';
if (!$post_id || !in_array($status, array('0','1','2'), true)) { wp_send_json_error(array('message' => 'Ongeldige input.'), 400); }
$post = get_post($post_id); if (!$post || $post->post_type !== 'job') { wp_send_json_error(array('message' => 'Melding niet gevonden.'), 404); }
if (!current_user_can('edit_post', $post_id)) { wp_send_json_error(array('message' => 'Je hebt geen rechten om dit aan te passen.'), 403); }
// ACF veld bijwerken (op field name) if (function_exists('update_field')) { update_field('job-status', $status, $post_id); } else { update_post_meta($post_id, 'job-status', $status); }
// Als job-date leeg is, vul automatisch de huidige datum in $current_job_date = get_post_meta($post_id, 'job-date', true); $new_job_date = null;
if (empty(trim((string) $current_job_date))) { $new_job_date = wp_date('Ymd'); // Ymd formaat zoals ACF verwacht
if (function_exists('update_field')) { update_field('job-date', $new_job_date, $post_id); } else { update_post_meta($post_id, 'job-date', $new_job_date); } }
$labels = array( '0' => 'Openstaand', '1' => 'In behandeling', '2' => 'Afgerond', );
$response = array( 'status' => $status, 'label' => $labels[$status] ?? '', );
if ($new_job_date) { $response['job_date'] = wp_date('d-m-Y', strtotime($new_job_date)); $response['job_date_ymd'] = $new_job_date; }
wp_send_json_success($response);}Statuswaarden
Section titled “Statuswaarden”| Waarde | Label | Betekenis |
|---|---|---|
'0' | Openstaand | Nieuwe melding, nog niet opgepakt |
'1' | In behandeling | Monteur is bezig |
'2' | Afgerond | Werkzaamheden voltooid |
Foutresponses
Section titled “Foutresponses”| HTTP | Conditie | Message |
|---|---|---|
| 400 | post_id is 0, of status niet in ['0','1','2'] | Ongeldige input. |
| 404 | Post bestaat niet of post_type !== 'job' | Melding niet gevonden. |
| 403 | Gebruiker heeft geen edit_post cap voor dit post ID | Je hebt geen rechten om dit aan te passen. |
Succesresponse velden
Section titled “Succesresponse velden”{ "success": true, "data": { "status": "2", "label": "Afgerond", "job_date": "05-04-2026", "job_date_ymd": "20260405" }}| Veld | Type | Altijd aanwezig | Beschrijving |
|---|---|---|---|
status | string | Ja | De nieuwe statuswaarde ('0', '1', '2') |
label | string | Ja | Leesbaar label (Openstaand, In behandeling, Afgerond) |
job_date | string | Nee | Datum in dd-mm-yyyy formaat, alleen als job-date leeg was en automatisch is ingevuld |
job_date_ymd | string | Nee | Datum in Ymd formaat (ACF-compatibel), alleen als job-date automatisch is ingevuld |
Edge cases
Section titled “Edge cases”- job-date auto-fill: Als het ACF-veld
job-dateleeg is op het moment van statuswijziging, wordt automatisch de huidige datum ingevuld. Dit is een vangnet voor meldingen die nog geen plandatum hebben. - Status al op
'2': Er is geen server-side check die voorkomt dat je een al afgeronde melding opnieuw op'2'zet. De status wordt gewoon opnieuw geschreven. Dejob_date/job_date_ymdvelden worden dan niet meegestuurd (wantjob-dateis al gevuld). - ACF fallback: Zowel
update_field()alsupdate_post_meta()worden ondersteund. Als ACF niet geladen is, wordt direct naarwp_postmetageschreven.
Client-side
Section titled “Client-side”- Modal: status label en kleur worden direct geupdate
- Tabelrij: status dot en plandatum worden geupdate
- Prefill-knop wordt verborgen als status =
'2'
myproject_address
Section titled “myproject_address”- Hooks:
wp_ajax_myproject_address+wp_ajax_nopriv_myproject_address - Methode: GET
- Nonce:
wp_verify_nonce()via$_GET['nonce'] - 6 modes via
$_GET['mode']
Volledige documentatie: zie Adressysteem.
Request
Section titled “Request”$.ajax({ url: ajaxUrl, data: { action: 'myproject_address', mode: 'streets', q: searchTerm, nonce: addrNonce }});Foutresponses
Section titled “Foutresponses”| HTTP | Conditie | Message |
|---|---|---|
| 403 | Ongeldige nonce | Invalid nonce |
| 500 | Database tabel niet beschikbaar (werkbon_addresses_table_ready() retourneert false) | Database niet beschikbaar |
Modal HTML structuur
Section titled “Modal HTML structuur”De modal wordt gerenderd via modal_jobs() in de wp_footer hook, maar alleen op de pagina meldingen.
Data-attributen op #melding-modal
Section titled “Data-attributen op #melding-modal”<div id="melding-modal" class="melding-modal" data-file-url="<?php echo esc_url( get_the_permalink(2) ); ?>" data-edit-url="<?php echo esc_url( get_the_permalink(3500) ); ?>" data-employee-img-base="<?php echo esc_url( get_stylesheet_directory_uri() . '/assets/img/employees/' ); ?>" data-ajax-url="<?php echo esc_url( admin_url('admin-ajax.php') ); ?>" data-delete-nonce="<?php echo esc_attr( wp_create_nonce('delete_job_nonce') ); ?>" data-status-nonce="<?php echo esc_attr( wp_create_nonce('update_job_status_nonce') ); ?>">| Attribuut | Waarde | Doel |
|---|---|---|
data-file-url | Permalink van post ID 2 | URL naar werkbon PDF/bestand pagina |
data-edit-url | Permalink van post ID 3500 | URL naar het bewerkformulier |
data-employee-img-base | /wp-content/themes/werkbon/assets/img/employees/ | Basis-URL voor monteur profielfoto’s |
data-ajax-url | /wp-admin/admin-ajax.php | WordPress AJAX endpoint |
data-delete-nonce | Nonce string | Nonce voor delete_job actie |
data-status-nonce | Nonce string | Nonce voor update_job_status actie |
Modal inhoud
Section titled “Modal inhoud”De modal bevat de volgende secties (als <dl> definition list):
| Sectie | Element ID | Inhoud |
|---|---|---|
| Datum melding | melding-modal-post-day, melding-modal-post-date | Dag + datum van aanmaak |
| Ingepland op | melding-modal-day, melding-modal-date | Geplande uitvoeringsdatum |
| Adres | melding-modal-address, melding-modal-zipcity | Straat + postcode/stad + Google Maps link |
| Monteur | melding-modal-employees | Toegewezen monteur(s) |
| Contact | melding-modal-contact-company, -name, -email, -phone | Contactgegevens |
| Notitie | melding-modal-note | Vrije tekst notitie |
| Acties | job-status-select, job-prefill-btn, job-edit-btn, job-delete-btn | Status dropdown + actieknoppen |
| Aangemaakt | melding-modal-created-date, -time, -user | Timestamp + aanmaker |
Status dropdown
Section titled “Status dropdown”<select id="job-status-select"> <option value="0">Openstaand</option> <option value="1">In behandeling</option> <option value="2">Afgerond</option></select>Verwijder-knop (conditioneel)
Section titled “Verwijder-knop (conditioneel)”De verwijder-knop wordt alleen gerenderd als beam_user_can_delete_jobs() true retourneert voor de huidige gebruiker:
<?php if ( beam_user_can_delete_jobs() ) : ?><button type="button" class="btn btn-secondary btn-danger" id="job-delete-btn"> Verwijderen</button><?php endif; ?>Bestandsoverzicht
Section titled “Bestandsoverzicht”| Bestand | Pad | Functies |
|---|---|---|
modal-jobs.php | functions/modal-jobs.php | beam_user_can_delete_jobs(), modal_jobs(), beam_delete_job(), beam_update_job_status() |
form-addresses.php | functions/form-addresses.php | myproject_norm_search(), myproject_parse_street_key(), myproject_get_city_for_street(), myproject_ajax_address() |