Compare commits

..

6 Commits

Author SHA1 Message Date
Remo Zaros
76ca74e1a6 clear shopping card when modal is shown 2026-06-29 13:35:30 +02:00
Remo Zaros
4f8de2e1f4 Make chechout work in Safari 2026-06-29 11:39:43 +02:00
Remo Zaros
159f96c9c2 Trim values 2026-06-29 09:42:10 +02:00
Remo Zaros
72bfb88bfb Make address fields populate dynamic. 2026-06-27 13:43:48 +02:00
Remo Zaros
0b467752fb remove 'winkel' from code 2026-06-26 18:28:41 +02:00
Remo Zaros
ab97611783 change cookie to work with cache plugin 2026-06-26 18:27:21 +02:00
3 changed files with 192 additions and 127 deletions

View File

@@ -40,13 +40,14 @@ function set_pppr_cookie($is_local, $street_name, $house_number, $postcode, $cit
$signature = hash_hmac('sha256', $data_string, WP_PPPR_SALT); $signature = hash_hmac('sha256', $data_string, WP_PPPR_SALT);
$cookie_value = $data_string . "|" . $signature; $cookie_value = $data_string . "|" . $signature;
$is_secure = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off'); $cookie_domain = $_SERVER['SERVER_NAME'];
$is_secure = is_ssl();
setcookie("PPPR", $cookie_value, [ setcookie("PPPR", $cookie_value, [
'expires' => time() + 7200, 'expires' => time() + 7200,
'path' => '/', 'path' => '/',
'domain' => $_SERVER['SERVER_NAME'], 'domain' => $cookie_domain,
'secure' => $is_secure, // Only send over HTTPS 'secure' => $is_secure,
'httponly' => true, // Prevent JavaScript access 'httponly' => true, // Prevent JavaScript access
'samesite' => 'Lax' // Protect against CSRF 'samesite' => 'Lax' // Protect against CSRF
]); ]);
@@ -55,11 +56,38 @@ function set_pppr_cookie($is_local, $street_name, $house_number, $postcode, $cit
function unset_pppr_cookie( $path = '/') { function unset_pppr_cookie( $path = '/') {
unset($_COOKIE["PPPR"]); unset($_COOKIE["PPPR"]);
if (empty($domain)) { $domain = $_SERVER['SERVER_NAME'];
setcookie("PPPR", '', time() - 3600, '/'); $is_secure = is_ssl();
} else {
setcookie("PPPR", '', time() - 3600, '/' , $_SERVER['SERVER_NAME']); // 3. Send the delete command with ALL matching parameters
setcookie(
"PPPR",
'',
time() - 3600,
'/',
$domain,
$is_secure, // Critical: Must match the 'secure' flag used when setting
true
);
} }
function update_expire_pppr_cookie() {
if (!isset($_COOKIE['PPPR'])) {
return false;
}
$cookie_value = $_COOKIE['PPPR'];
$cookie_domain = $_SERVER['SERVER_NAME'];
$is_secure = is_ssl();
setcookie("PPPR", $cookie_value, [
'expires' => time() + 7200,
'path' => '/',
'domain' => $cookie_domain,
'secure' => $is_secure,
'httponly' => true, // Prevent JavaScript access
'samesite' => 'Lax' // Protect against CSRF
]);
} }
function verify_pppr_cookie_string() { function verify_pppr_cookie_string() {

View File

@@ -4,7 +4,7 @@
* Plugin Name: Prijzen per poscodeereeks. * Plugin Name: Prijzen per poscodeereeks.
* Description: Producten worden gefiltered aan de hand van opgegegeven postcodereeksen.Gebruikers met een postcode die in een opgegegeven postcodereeks valt zal een lokale prijs zien. Waar elke gebruiker met een postcode die buiten eem opgegeven reeks valt zal de reguliere prijs te zien krijgen. * Description: Producten worden gefiltered aan de hand van opgegegeven postcodereeksen.Gebruikers met een postcode die in een opgegegeven postcodereeks valt zal een lokale prijs zien. Waar elke gebruiker met een postcode die buiten eem opgegeven reeks valt zal de reguliere prijs te zien krijgen.
* Author: Remo Zaros * Author: Remo Zaros
* Version: 0.9.8 * Version: 0.9.82
* Text Domeain: prijs-per-postcode * Text Domeain: prijs-per-postcode
*/ */
@@ -159,8 +159,13 @@ class PrijsPerPostcode
!is_shop() !is_shop()
) { ) {
if (!verify_pppr_cookie_string()) { if (!verify_pppr_cookie_string()) {
wp_redirect(home_url("/winkel/")); if (!WC()->cart->is_empty()) {
WC()->cart->empty_cart();
}
wp_safe_redirect($this->get_shop_url());
exit(); exit();
}else{
update_expire_pppr_cookie();
} }
} }
} }
@@ -227,6 +232,12 @@ class PrijsPerPostcode
} }
return $translated_text; return $translated_text;
} }
public function get_shop_url () {
return (function_exists('wcml_get_store_url'))
? wcml_get_store_url() // WPML WooCommerce Multilingual
: get_permalink(wc_get_page_id('shop')); // Fallback
}
} }
new PrijsPerPostcode(); new PrijsPerPostcode();

View File

@@ -88,10 +88,8 @@ function send_postcode_data()
body: JSON.stringify(payload) body: JSON.stringify(payload)
}); });
// Parse altijd eerst de JSON, zelfs bij HTTP fouten
const data = await resp.json(); const data = await resp.json();
// UI: Reset knop
sndBtn.disabled = false; sndBtn.disabled = false;
sndBtnLdr.style.opacity = "0"; sndBtnLdr.style.opacity = "0";
sndBtnTxt.style.opacity = "1"; sndBtnTxt.style.opacity = "1";
@@ -269,10 +267,10 @@ function handle_postcode_modal($data)
} }
set_pppr_cookie( set_pppr_cookie(
postcode_in_range($params["postcode"]), postcode_in_range($params["postcode"]),
$straatnaam, trim($straatnaam),
$params["huisnummer"], trim($params["huisnummer"]),
$params["postcode"], trim($params["postcode"]),
$woonplaats trim($woonplaats)
); );
return new WP_REST_Response([ return new WP_REST_Response([
@@ -345,7 +343,7 @@ function getStraatnaam($postcode, $huisnummer)
]; ];
} }
// Geef de RUWE response terug (inclusief meta, error, results, etc.) // Give me back RUWE data (inclusive meta, error, results, etc.)
return $data; return $data;
} }
@@ -376,126 +374,154 @@ function postcode_in_range($postcode)
return false; return false;
} }
function modify_checkout_with_js() function modify_checkout_with_js() {
{ if ( ! is_checkout() || ( is_wc_endpoint_url() && ! is_wc_endpoint_url( 'order-received' ) ) ) {
if (
!is_checkout() ||
(is_wc_endpoint_url() && !is_wc_endpoint_url("order-received"))
) {
return; return;
} }
$data = get_PPPR_data();
$city = $data["city"]; $data = get_PPPR_data();
$postcode = $formatted_postcode = preg_replace( if ( empty( $data ) ) {
"/(\d+)([A-Z]+)/", return;
'$1 $2', }
strtoupper($data["postcode"]),
); $city = trim(esc_js( $data['city'] ));
$address = $postcode = trim(esc_js( preg_replace( '/(\d+)([A-Z]+)/', '$1 $2', strtoupper( $data['postcode']))));
$data["street"] . " " . strtoupper($data["house_number"]); $address = trim(esc_js( $data['street'] . ' ' . strtoupper( $data['house_number'])));
// Enqueue script properly to handle dependencies and nonces
wp_enqueue_script( 'jquery' );
wp_localize_script( 'jquery', 'ajax_object', array(
'ajax_url' => admin_url( 'admin-ajax.php' ),
'nonce' => wp_create_nonce( 'unset_my_session_nonce' )
) );
echo <<<HTML echo <<<HTML
<script type="text/javascript" id="set_pppr_fields"> <script type="text/javascript" id="set_pppr_fields">
jQuery(document).ready(function($) { document.addEventListener('DOMContentLoaded', function() {
function lockCheckoutFields() { // Safari Fix: Handle back/forward cache (bfcache)
if (typeof wp !== 'undefined' && wp.data && wp.data.dispatch) { window.addEventListener('pageshow', function(event) {
const store = 'wc/store/cart'; if (event.persisted || (typeof wp !== 'undefined' && wp.data)) {
initPPPRFields();
wp.data.dispatch(store).setShippingAddress({ }
first_name: '',
last_name: '',
address_1: 'Tjeuke Timmermansstraat 43',
address_2: '',
city: 'Tilburg',
state: '',
postcode: '5041 EK',
country: 'NL',
phone: '',
email: ''
}); });
function initPPPRFields() {
// Wait for React/WC Blocks to mount
setTimeout(() => { setTimeout(() => {
const targets = '#shipping-postcode, #shipping-city, #shipping-address_1'; const addressVal = '{$address}';
const cityVal = '{$city}';
const postcodeVal = '{$postcode}';
$(targets).each(function() { // Map WC Blocks field selectors
// Voeg readonly attribuut toe (voor toegankelijkheid) const fields = [
$(this).prop('readonly', true); { id: 'shipping-address_1', val: addressVal },
{ id: 'shipping-city', val: cityVal },
{ id: 'shipping-postcode', val: postcodeVal }
];
$(this).css({ fields.forEach(field => {
'background-color': '#f9f9f9', // 1. Try Redux Dispatch (Standard)
'cursor': 'not-allowed', if (typeof wp !== 'undefined' && wp.data && wp.data.dispatch) {
'pointer-events': 'none' // Blokkeert alle muisklikken in het veld try {
wp.data.dispatch('wc/store/cart').setShippingAddress({ [field.id.replace('shipping-', '')]: field.val });
} catch(e) { console.warn('Redux update skipped', e); }
}
// 2. Force DOM Update (Safari Fallback)
// Select both legacy and Blocks inputs
const inputs = document.querySelectorAll('#' + field.id + ', input[name="' + field.id.replace('shipping-', '') + '"]');
inputs.forEach(input => {
if (input.value !== field.val) {
input.value = field.val;
// CRITICAL FOR SAFARI: Manually trigger events so React notices
['input', 'change'].forEach(evtType => {
input.dispatchEvent(new Event(evtType, { bubbles: true, cancelable: true }));
});
}
// 3. Apply Visual Lock
input.setAttribute('data-pppr-locked', 'true');
input.readOnly = true;
}); });
}); });
if ($('.postcode-reset').length === 0) { // Inject Reset Button once
const div = document.createElement("div"); if (!document.querySelector('.postcode-reset')) {
div.setAttribute("class", "postcode-reset"); const cityContainer = document.querySelector('.wc-block-components-address-form__city');
if (cityContainer) {
const div = document.createElement('div');
div.className = 'postcode-reset';
div.style.display = 'block';
div.style.width = '100%';
div.style.marginTop = '10px';
div.innerHTML = ` div.innerHTML = `
<a href="#" class="reset-postcode-show-comfirm" style="font-size:12px; text-decoration:underline;">Reset postcode.</a> <a href="#" class="reset-postcode-show-comfirm" style="font-size:12px; text-decoration:underline; display:block; margin-top:5px;">Reset postcode.</a>
<span class="bevestiging" style="display:none; font-size:12px;"> <span class="bevestiging" style="display:none; font-size:12px; margin-top:5px;">
Deze handeling leegt ook de winkelwagen. Weet je het zeker? Deze handeling leegt ook de winkelwagen. Weet je het zeker?
<a href="#" class="accept" style="color:red; font-weight:bold;">&nbsp;&nbsp;JA&nbsp;</a>/ <a href="#" class="accept" style="color:red; font-weight:bold;">&nbsp;&nbsp;JA&nbsp;</a>/
<a href="#" class="decline">&nbsp;nee&nbsp;&nbsp;</a> <a href="#" class="decline">&nbsp;nee&nbsp;&nbsp;</a>
</span>`; </span>`;
cityContainer.parentNode.insertBefore(div, cityContainer.nextSibling);
div.style.width = "100%"; // Event Listeners (using delegation for safety)
document.querySelector(".wc-block-components-address-form__city")?.after(div); div.addEventListener('click', function(e) {
$('.reset-postcode-show-comfirm').on('click', function(e) {
e.preventDefault(); e.preventDefault();
$(this).hide(); if (e.target.classList.contains('reset-postcode-show-comfirm')) {
$(this).next('.bevestiging').show(); e.target.style.display = 'none';
}); div.querySelector('.bevestiging').style.display = 'block';
$('.decline').on('click', function(e) { } else if (e.target.classList.contains('decline')) {
e.preventDefault(); div.querySelector('.bevestiging').style.display = 'none';
$(this).closest('.bevestiging').hide(); div.querySelector('.reset-postcode-show-comfirm').style.display = 'block';
$('.reset-postcode-show-comfirm').show(); } else if (e.target.classList.contains('accept')) {
}); fetch(ajax_object.ajax_url, {
method: 'POST',
headers: {
$('.accept').on('click', function(e) { 'Content-Type': 'application/x-www-form-urlencoded',
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) { body: new URLSearchParams({
if (response.success) { action: 'unset_my_session',
location.reload(); nonce: ajax_object.nonce
} else { })
console.error('Server returned error:', response.data); })
alert('Failed to reset session: ' + (response.data || 'Unknown error')); .then(res => res.json())
} .then(res => {
}, if (res.success) location.reload();
error: function(xhr, status, error) { else alert('Failed to reset: ' + (res.data || 'Unknown error'));
console.error('AJAX request failed:', status, error); })
console.log('Response Text:', xhr.responseText); // Check for PHP fatal errors .catch(err => console.error('AJAX error:', err));
} }
}); });
});
}
jQuery(document.body).trigger('update_checkout');
}, 800); // Iets langere delay voor React rendering
} else {
console.error('WooCommerce Blocks API is niet beschikbaar');
} }
} }
lockCheckoutFields(); // Add CSS for locked state dynamically
if (!document.getElementById('pppr-styles')) {
const style = document.createElement('style');
style.id = 'pppr-styles';
style.textContent = `
input[data-pppr-locked="true"] {
background-color: #f9f9f9 !important;
cursor: not-allowed !important;
pointer-events: none !important;
opacity: 0.7;
}
`;
document.head.appendChild(style);
}
let updateTimeout; }, 600); // Delay for WC Blocks hydration
$(document.body).on('updated_checkout', function() { }
clearTimeout(updateTimeout);
updateTimeout = setTimeout(lockCheckoutFields, 500); // Initialize on load
initPPPRFields();
// Re-apply if checkout updates (e.g. shipping method change)
document.body.addEventListener('updated_checkout', function() {
setTimeout(initPPPRFields, 400);
}); });
}); });
</script> </script>