Please choose your EasyBox Locker!

Eroarea din titlu am primit-o lucrând la un magazin virtual peste WooCommerce, având instalat modulul de livrare prin SameDay (problemă pe care au mai întâlnit-o și alții). Ei, cu toate că este selectat locker-ul la care să fie livrată comanda, modulul emite acest mesaj. Pentru început, am aruncat un ochi în codul sursă al modulului:

Sursa erorii

Sursa erorii

Cu alte cuvinte, se purta ca și cum datele nu ar fi fost trimise deloc. Să consultam și globul de cristal, adică Developer Tools – Network. Șoc sau nu, o să-ți vină sau n-o să-ți vină să crezi așa ceva, dar datele nu erau acolo deloc. Voilà, precum zăpezile anului trecut, precum bunul simț la ecologiști, imposibil de găsit:

Datele trimise

Datele trimise

Punct în care am trecut la studierea (cu atenție și-ngrijorare) a structurii HTML a paginii de checkout. În cazul meu, câmpurile pe care se bazează modulul erau adăugate în afara formularului (form.woocommerce-checkout), chiar înaintea deschiderii tag-ului său.

La prima vedere, o scăpare impardonabilă a celui care a creat modulul, însă de ce nu se-ntâmplă tuturor, ci doar unora? Ei bine, aceste câmpuri ascunse care transportă ce date ar trebui ele să transporte sunt adăugate folosind hook-ul woocommerce_review_order_after_shipping, care, la rândul său este apelat în review-order.php.

Pe de altă parte, formularul de checkout este definit în form-checkout.php și cuprinde tot conțiunutul, chiar și partea care invocă indirect review-order.php. Ambele sunt fișiere din tema standard a WooCommerce și ambele pot fi suprascrise de terți prin temele lor. Nu spune nimeni că cine face asta trebuie să definească formularul în același mod, la fel cum nu spune nimeni că trebuie să apeleze aceleași hook-uri. Unele pot fi, din varii rațiuni, pur și simplu sărite.

Așadar, nu consider că este un bug din modul, nu consider că este musai un bug din temă, deși anumite argumente pot fi aduse de ambele părți. Dar este, părerea mea, ceva ce dezvoltatorul ar fi trebuit să prevadă și să compenseze.

Până atunci, ce pot face oamenii năpăstuiți ca mine e să adauge o secvență de javascript în pagina de checkout care să mute câmpurile discordiei dintr-o parte într-alta (practic, să creeze o nouă copie, așa cum am preferat eu, pentru a nu crea și alte potențiale probleme).

Minim, se poate folosi pe post de declanșator evenimentul checkout_place_order, generat de javascript-ul folosit de WooCommerce în acea pagină atunci când utilizatorul apasă butonul de plasare comandă. Bănuiesc că pot fi folosite și alte evenimente, cum ar fi document ready.

function _syncHiddenField($ckForm, $addBeforeElement, name, value) {
	var $formField = $ckForm.find('input[name="' + name + '"]');
	if (!$formField.size()) {
		jQuery('<input type="hidden" id="wmyc_' + name 
				+ '" name="' + name 
				+ '" value="" />')
			.insertBefore($addBeforeElement);
	}
	   
   $formField.val(value);
}

jQuery(function() {
	jQuery('form.woocommerce-checkout').on('checkout_place_order', 
		function() {
		var $ckForm = jQuery('form.woocommerce-checkout');
		var $lockerField = jQuery('#locker');
		var $lockerNameField = jQuery('#locker_name');
		var $lockerAddressField = jQuery('#locker_address');
		var $placeOrderBtn = $ckForm.find('#place_order');
	   
		if ($lockerField.size()) {
			_syncHiddenField($ckForm, 
				$placeOrderBtn, 
				'locker', 
				$lockerField.val());
		}
	   
		if ($lockerNameField.size()) {
			_syncHiddenField($ckForm, 
				$placeOrderBtn, 
				'locker_name', 
				$lockerNameField.val()); 
		}
	   
		if ($lockerAddressField.size()) {
			_syncHiddenField($ckForm, 
				$placeOrderBtn, 
				'locker_address', 
				$lockerAddressField.val()); 
		}
	   
		return true;
	});
});

Pentru plasarea secvenței în pagină am folosit tot hook-ul woocommerce_review_order_after_shipping, cu funcția atașată hăt la coadă. După câteva comenzi plasate aparent cu succes, am verificat suplimentar că-n tabela wp_post_meta se salvează corect informațiile locker-ului și, într-adevar, așa îmi pare.

În principiu ceva similar ar trebui să facă și dezvoltatorul și, de va face vreodată, acest script poate fi înlăturat. Dacă-l puneți într-un modul complet separat, cum l-am pus eu, vă va fi cu atât mai ușor.