cart->empty_cart(); } add_action("wp_footer", "show_modal"); render_dialog_html(); } } add_action("wp_ajax_unset_my_session", "handle_unset_session_fetch"); add_action("wp_ajax_nopriv_unset_my_session", "handle_unset_session_fetch"); add_action("wp_footer", "modify_checkout_with_js"); add_action("wp_enqueue_scripts", "load_assets_reset_postcode_on_checkout"); } function modal_styles() { wp_enqueue_style( "prijs-per-postcode", plugins_url("/assets/postcode_modal.css", __FILE__), [], // Voeg een lege dependencies array toe (verplicht) filemtime(plugin_dir_path(__FILE__) . "assets/postcode_modal.css"), // Voeg versie toe ); } function show_modal() { echo <<<'HTML' HTML; } function send_postcode_data() { $URL = get_rest_url(null, "postcode-modal/v1/submit"); $nonce = wp_create_nonce("wp_rest"); echo << const postcodeModal = document.querySelector("#postcode_modal"); const modalForm = document.querySelector("#postcode_modal_form"); const sndBtn = document.querySelector("#postcode_modal_submit"); const sndBtnLdr = sndBtn.querySelector(".btn_loader"); const sndBtnTxt = sndBtn.querySelector(".btn_text"); const errorMsg = document.querySelector("#error_message_modal_postcode"); // 1. Validatie bij blur (client-side checks) modalForm.querySelectorAll("input").forEach(input => { input.addEventListener("blur", ev => { errorMsg.innerHTML = ""; if (!ev.target.validity.valid && ev.target.value !== "") { errorMsg.innerHTML = ev.target.title; } }); }); // 2. Submit Handler modalForm.addEventListener('submit', async (e) => { e.preventDefault(); errorMsg.innerHTML = ""; // UI: Laadstatus sndBtn.disabled = true; sndBtnLdr.style.opacity = "1"; sndBtnTxt.style.opacity = "0"; const formData = new FormData(e.target); const payload = Object.fromEntries(formData.entries()); try { const resp = await fetch('{$URL}', { method: 'POST', credentials: 'same-origin', headers: { 'Content-Type': 'application/json', 'X-WP-Nonce': '{$nonce}' }, body: JSON.stringify(payload) }); const data = await resp.json(); sndBtn.disabled = false; sndBtnLdr.style.opacity = "0"; sndBtnTxt.style.opacity = "1"; if (data.status === "error") { const errorCode = data.code; // Komt nu correct door vanuit PHP const apiMessage = data.message; let userErrorMessage = "Gegevens zijn niet correct."; // Specifieke foutafhandeling if (errorCode === "HUISNUMMER_NOT_FOUND" || apiMessage.includes("not found")) { userErrorMessage = "Adres is niet gevonden."; } else if (errorCode === "HUISNUMMER_AMBIGUOUS") { const suggestions = data.suggestions || []; if (suggestions.length > 0) { userErrorMessage = `Meerdere opties: \${suggestions.join(", ")}. Voeg een toevoeging toe.`; } else { userErrorMessage = "Huisnummertoevoeging is verplicht."; } } else if (errorCode === "CURL_ERROR" || errorCode === "JSON_ERROR") { userErrorMessage = "Serverfout. Probeer het later opnieuw."; } errorMsg.innerHTML = userErrorMessage; } if (data.status === "success") { // Succes: Modal sluiten en eventueel reload of update postcodeModal.close(); // Optioneel: location.reload(); of update de pagina content } } catch (err) { sndBtn.disabled = false; sndBtnLdr.style.opacity = "0"; sndBtnTxt.style.opacity = "1"; errorMsg.innerHTML = "Er ging iets mis bij het verbinden."; } }); HTML; } function render_dialog_html() { echo <<<'HTML'

Vul je postcode en huisnummer in.

Onze prijzen zijn afhankelijk van de regio. Vul daarom de postcode en het huisnummer in om de exacte prijzen te bekijken.

HTML; } function handle_postcode_modal($data) { $params = $data->get_params(); $nonce = $data->get_header("X-WP-Nonce"); // 1. Security if (!wp_verify_nonce($nonce, "wp_rest")) { echo json_encode(["status" => "error", "message" => "nononce"]); exit(); } // 2. Basis Validatie if (!verify_postcode($params["postcode"])) { echo json_encode(["status" => "error", "message" => "postcode"]); exit(); } if (!verify_huisnummer($params["huisnummer"])) { echo json_encode(["status" => "error", "message" => "huisnummer"]); exit(); } // 3. API Call (Ruwe data) $result = getStraatnaam($params["postcode"], $params["huisnummer"]); // 4. Validatie & Logic $hasError = isset($result["error"]); $errorCode = null; $errorMessage = null; $candidates = []; $straatnaam = null; $woonplaats = null; if ($hasError) { $errorCode = $result["error"]["code"] ?? "UNKNOWN_ERROR"; $errorMessage = $result["error"]["message"] ?? "Onbekende fout"; $candidates = $result["error"]["details"]["candidates"] ?? []; // SPECIAL CASE: HUISNUMMER_AMBIGUOUS if ($errorCode === "HUISNUMMER_AMBIGUOUS" && !empty($candidates)) { $plainMatch = null; // Zoek naar candidate ZONDER toevoeging foreach ($candidates as $candidate) { if ( empty($candidate["huisletter"]) && empty($candidate["huisnummertoevoeging"]) ) { $plainMatch = $candidate; break; } } // Als we een 'platte' match hebben (bijv. 15), dan is het SUCCES if ($plainMatch) { $hasError = false; // Negeer de error $straatnaam = $plainMatch["straat"]; $woonplaats = $plainMatch["woonplaats"]; } } } else { // Normaal succes (geen error in response) if (!empty($result["results"])) { $straatnaam = $result["results"][0]["straat"]; $woonplaats = $result["results"][0]["woonplaats"]; } else { // Edge case: geen error veld, maar ook geen results $hasError = true; $errorCode = "NO_RESULTS"; $errorMessage = "Adres niet gevonden"; } } // 5. Response sturen if ($hasError) { return new WP_REST_Response([ "status" => "error", "code" => $errorCode, "message" => $errorMessage, "suggestions" => $result["error"]["details"]["suggestions"] ?? [], "apirequest" => "openpostcode.nl", ], 400); } set_pppr_cookie( postcode_in_range($params["postcode"]), trim($straatnaam), trim($params["huisnummer"]), trim($params["postcode"]), trim($woonplaats) ); return new WP_REST_Response([ "status" => "success", "message" => "all good", ], 200); } function register_modal_api() { register_rest_route("postcode-modal/v1", "submit", [ "methods" => "POST", "callback" => "handle_postcode_modal", "permission_callback" => "__return_true", ]); } function verify_postcode($postcode) { if (!preg_match('/^[0-9]{4}\s?[A-Za-z]{2}$/', $postcode) === 1) { return false; } return true; } function verify_huisnummer($huisnummer) { if (!preg_match('/^[0-9]{4}\s?[A-Za-z]{2}$/', $huisnummer) === 1) { return false; } return true; } function getStraatnaam($postcode, $huisnummer) { $url = "https://openpostcode.nl/api/v2/address?postcode=" . urlencode($postcode) . "&huisnummer=" . urlencode($huisnummer); $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_TIMEOUT, 10); curl_setopt($ch, CURLOPT_USERAGENT, "PHP/OpenPostcodeClient"); $response = curl_exec($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); if (curl_error($ch)) { curl_close($ch); return [ "error" => ["code" => "CURL_ERROR", "message" => curl_error($ch)], ]; } curl_close($ch); // Decodeer als associatieve array (true) $data = json_decode($response, true); // Als JSON decode faalt if (json_last_error() !== JSON_ERROR_NONE) { return [ "error" => [ "code" => "JSON_ERROR", "message" => "Invalid JSON response", ], ]; } // Geef de RUWE response terug (inclusief meta, error, results, etc.) return $data; } function postcode_in_range($postcode) { $vals = get_option("local_postcodes_values", ""); $rows = preg_split("/\R/", $vals, -1, PREG_SPLIT_NO_EMPTY); $pc_arr = []; foreach ($rows as $row) { $row = trim($row); $postcode_range = explode("-", $row); $pc_arr[] = [(int) $postcode_range[0], (int) $postcode_range[1]]; } $cleanPostcode = strtoupper(preg_replace("/\s+/", "", $postcode)); if (!preg_match('/^\d{4}[A-Z]{2}$/', $cleanPostcode)) { return false; } $numberPart = (int) substr($cleanPostcode, 0, 4); foreach ($pc_arr as $pc_to_check) { if ($numberPart >= $pc_to_check[0] && $numberPart <= $pc_to_check[1]) { return true; } } return false; } function modify_checkout_with_js() { if ( !is_checkout() || (is_wc_endpoint_url() && !is_wc_endpoint_url("order-received")) ) { return; } $data = get_PPPR_data(); $city = esc_js($data["city"]); $postcode = esc_js( preg_replace( "/(\d+)([A-Z]+)/", '$1 $2', strtoupper($data["postcode"]) )); $address = esc_js($data["street"] . " " . strtoupper($data["house_number"])); echo << jQuery(document).ready(function($) { function lockCheckoutFields() { if (typeof wp !== 'undefined' && wp.data && wp.data.dispatch) { const store = 'wc/store/cart'; wp.data.dispatch(store).setShippingAddress({ first_name: '', last_name: '', address_1: '{$address}', address_2: '', city: '{$city}', state: '', postcode: '{$postcode}', country: 'NL', phone: '', email: '' }); setTimeout(() => { const targets = '#shipping-postcode, #shipping-city, #shipping-address_1'; $(targets).each(function() { // Voeg readonly attribuut toe (voor toegankelijkheid) $(this).prop('readonly', true); $(this).css({ 'background-color': '#f9f9f9', 'cursor': 'not-allowed', 'pointer-events': 'none' // Blokkeert alle muisklikken in het veld }); }); if ($('.postcode-reset').length === 0) { const div = document.createElement("div"); div.setAttribute("class", "postcode-reset"); div.innerHTML = ` Reset postcode. `; div.style.width = "100%"; document.querySelector(".wc-block-components-address-form__city")?.after(div); $('.reset-postcode-show-comfirm').on('click', function(e) { e.preventDefault(); $(this).hide(); $(this).next('.bevestiging').show(); }); $('.decline').on('click', function(e) { e.preventDefault(); $(this).closest('.bevestiging').hide(); $('.reset-postcode-show-comfirm').show(); }); $('.accept').on('click', function(e) { e.preventDefault(); $.ajax({ url: ajax_object.ajax_url, type: 'POST', data: { action: 'unset_my_session', // Matches wp_ajax_ hook nonce: ajax_object.nonce // Matches wp_create_nonce action }, success: function(response) { if (response.success) { location.reload(); } else { console.error('Server returned error:', response.data); alert('Failed to reset session: ' + (response.data || 'Unknown error')); } }, error: function(xhr, status, error) { console.error('AJAX request failed:', status, error); console.log('Response Text:', xhr.responseText); // Check for PHP fatal errors } }); }); } jQuery(document.body).trigger('update_checkout'); }, 800); // Iets langere delay voor React rendering } else { console.error('WooCommerce Blocks API is niet beschikbaar'); } } lockCheckoutFields(); let updateTimeout; $(document.body).on('updated_checkout', function() { clearTimeout(updateTimeout); updateTimeout = setTimeout(lockCheckoutFields, 500); }); }); HTML; } function load_assets_reset_postcode_on_checkout() { if (is_checkout() && !is_wc_endpoint_url()) { wp_enqueue_style( "reset-postcode-style", plugin_dir_url(__FILE__) . "assets/reset-postcode.css", [], "1.0.0", ); wp_enqueue_script( "reset-postcode-script", plugin_dir_url(__FILE__) . "assets/reset-postcode.js", [], "1.0.0", true, ); // Pass PHP variables to JavaScript wp_localize_script("reset-postcode-script", "ajax_object", [ "ajax_url" => admin_url("admin-ajax.php"), "nonce" => wp_create_nonce("reset_postcode_nonce"), // Creates a secure token ]); } } function handle_unset_session_fetch() { // Verify the nonce for security if (!wp_verify_nonce($_POST["nonce"], "reset_postcode_nonce")) { wp_die("Security check failed."); } unset_pppr_cookie(); // Send a JSON response wp_send_json_success(); }