Skip to content

AJAX Endpoints

ActionHandlerNonceAuthBestand
delete_jobbeam_delete_job()delete_job_nonceACF admin=true via beam_user_can_delete_jobs()modal-jobs.php
update_job_statusbeam_update_job_status()update_job_status_nonceedit_post capabilitymodal-jobs.php
myproject_addressmyproject_ajax_address()myproject_address_noncenopriv ook (publiek)form-addresses.php
  • 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.

$.ajax({
url: ajaxUrl,
method: 'POST',
data: {
action: 'delete_job',
nonce: deleteNonce,
post_id: jobId
}
});
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).'));
}
HTTPConditieMessage
401Niet ingelogdNiet ingelogd.
403ACF admin veld niet truthyGeen rechten om te verwijderen.
400post_id is 0 of ontbreektOngeldig ID.
404Post bestaat niet of post_type !== 'job'Melding niet gevonden.
500wp_trash_post() retourneert WP_Error of falseFoutmelding of Verwijderen is mislukt.
{
"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.

melding-modal.js verwijdert de tabelrij uit de DOM en sluit de modal.

  • 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)
$.ajax({
url: ajaxUrl,
method: 'POST',
data: {
action: 'update_job_status',
nonce: statusNonce,
post_id: jobId,
status: newStatus // '0', '1' of '2'
}
});
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);
}
WaardeLabelBetekenis
'0'OpenstaandNieuwe melding, nog niet opgepakt
'1'In behandelingMonteur is bezig
'2'AfgerondWerkzaamheden voltooid
HTTPConditieMessage
400post_id is 0, of status niet in ['0','1','2']Ongeldige input.
404Post bestaat niet of post_type !== 'job'Melding niet gevonden.
403Gebruiker heeft geen edit_post cap voor dit post IDJe hebt geen rechten om dit aan te passen.
{
"success": true,
"data": {
"status": "2",
"label": "Afgerond",
"job_date": "05-04-2026",
"job_date_ymd": "20260405"
}
}
VeldTypeAltijd aanwezigBeschrijving
statusstringJaDe nieuwe statuswaarde ('0', '1', '2')
labelstringJaLeesbaar label (Openstaand, In behandeling, Afgerond)
job_datestringNeeDatum in dd-mm-yyyy formaat, alleen als job-date leeg was en automatisch is ingevuld
job_date_ymdstringNeeDatum in Ymd formaat (ACF-compatibel), alleen als job-date automatisch is ingevuld
  • job-date auto-fill: Als het ACF-veld job-date leeg 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. De job_date/job_date_ymd velden worden dan niet meegestuurd (want job-date is al gevuld).
  • ACF fallback: Zowel update_field() als update_post_meta() worden ondersteund. Als ACF niet geladen is, wordt direct naar wp_postmeta geschreven.
  • Modal: status label en kleur worden direct geupdate
  • Tabelrij: status dot en plandatum worden geupdate
  • Prefill-knop wordt verborgen als status = '2'
  • 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.

$.ajax({
url: ajaxUrl,
data: {
action: 'myproject_address',
mode: 'streets',
q: searchTerm,
nonce: addrNonce
}
});
HTTPConditieMessage
403Ongeldige nonceInvalid nonce
500Database tabel niet beschikbaar (werkbon_addresses_table_ready() retourneert false)Database niet beschikbaar

De modal wordt gerenderd via modal_jobs() in de wp_footer hook, maar alleen op de pagina meldingen.

<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') ); ?>"
>
AttribuutWaardeDoel
data-file-urlPermalink van post ID 2URL naar werkbon PDF/bestand pagina
data-edit-urlPermalink van post ID 3500URL 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.phpWordPress AJAX endpoint
data-delete-nonceNonce stringNonce voor delete_job actie
data-status-nonceNonce stringNonce voor update_job_status actie

De modal bevat de volgende secties (als <dl> definition list):

SectieElement IDInhoud
Datum meldingmelding-modal-post-day, melding-modal-post-dateDag + datum van aanmaak
Ingepland opmelding-modal-day, melding-modal-dateGeplande uitvoeringsdatum
Adresmelding-modal-address, melding-modal-zipcityStraat + postcode/stad + Google Maps link
Monteurmelding-modal-employeesToegewezen monteur(s)
Contactmelding-modal-contact-company, -name, -email, -phoneContactgegevens
Notitiemelding-modal-noteVrije tekst notitie
Actiesjob-status-select, job-prefill-btn, job-edit-btn, job-delete-btnStatus dropdown + actieknoppen
Aangemaaktmelding-modal-created-date, -time, -userTimestamp + aanmaker
<select id="job-status-select">
<option value="0">Openstaand</option>
<option value="1">In behandeling</option>
<option value="2">Afgerond</option>
</select>

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; ?>
BestandPadFuncties
modal-jobs.phpfunctions/modal-jobs.phpbeam_user_can_delete_jobs(), modal_jobs(), beam_delete_job(), beam_update_job_status()
form-addresses.phpfunctions/form-addresses.phpmyproject_norm_search(), myproject_parse_street_key(), myproject_get_city_for_street(), myproject_ajax_address()