WordPress hook

WooCommerce rendelés utáni item meta adatok mentése, hook különbségek

WooCommerce rendelés utáni item meta adatok mentése, hook különbségek 1440 960 bacsoa

Ma futottam bele egy érdekes problémába, gondoltam megosztom másokkal is, mert szerintem elég nagy a zavar a fejekben – legalábbis az internet népét és a Stackoverflow felhasználóit tekintve.

Adott egy WooCommerce (4.8, de amúgy szerintem majdnem mindegy). A feladat, hogy a WooCommerce-ben leadott rendelés után hajtsunk végre valamit.

Erre több lehetőségünk is van. Mivel a WooCommerce rendelés gyakorlatilag egy egyedi WordPress bejegyzés (shop_order), ezért van neki post_status mezője. Ezeknek a szabványos WordPress bejegyzésekhez hasonlóan többféle státusza van, sőt lehet neki egyedit is adni. Általában alapértelmezetten a wc-processing (feldolgozás alatti) státuszt kapja meg. Egy SQL lekérdezéssel ellenőrizhetjük, hogy egy adott WooCommerce webáruházunkban hány fajta státuszú rendelés létezik:

SELECT post_status
FROM `wp_posts` 
WHERE `post_type` = 'shop_order' 
GROUP BY post_status

A Woocommerce rendelés státuszokról és magáról a Order objektumról itt olvashatsz bővebben.

Azért kellett ez a rövid bevezető, mert nem mindegy, hogy a rendelések mely státuszánál, mi fusson le. A Woocommerce erre többféle beépített hook-ot kínál. Mi az a hook? Ez gyakorlatilag egy callback. Mi az a callback? Na igen, ez az amikor 15 dolgot el kell magyarázni, hogy a végén egy szót megérts 🙂 A Callback-ről magyarul itt olvashatsz bővebben. A WordPress hook-okról pedig itt.

A rendelés leadása utáni tranzakciókezelésre a Woocommerce többféle hook megoldást is nyújt, például ezeket:

  1. woocommerce_checkout_order_processed
  2. woocommerce_payment_complete
  3. woocommerce_thankyou

A teljes listát itt találod.

Több, eltérő leírás van erről a neten, sőt a Woocommerce verziók között is vannak eltérések. Arra is kell vigyázni és ezt sokan elrontják, hogy minden hook-nak eltérő mennyiségű paramétere van. Ha többet adsz át az nem gond, de ha kevesebbet, akkor le sem fut. Sajnos vannak olyan hook-ok, amik nem dobnak hibát, csak egyszerűen nem működnek. Az alábbi példában például a 10, 3 a végén azt jelenti, hogy 3 paramétert vár és 10 prioritással fusson le. Mivel többet is egymásba ágyazhatsz, és az egyik felülírhatja a másikat, hogy ne legyen olyan egyszerű az élet. Főleg akkor jó ez, ha egy másik plugin már használja valami unintelligens 99999 prioritással és te meg nem jössz rá, hogy a tiéd miért nem működik… 😀

Amibe ma belefutottam, az egy elég egyszerűnek tűnő probléma. Én általában a woocommerce_checkout_order_processed hook-ot használom. Ez három paramétert vár. Az 1. a Woocommerce rendelés azonosító (wc_order_id), a 2. az elküldött személyes adatok (posted_data), a 3. pedig maga a rendelés objektum (order class):


add_action( 'woocommerce_checkout_order_processed', 'exibio_woocommerce_order_processed', 10, 3 );
function exibio_woocommerce_order_processed( $wc_order_id, $posted_data, $order ) {
    // ez fut le a rendelés leadása után
}

Ez a hook akkor fut le, ha a rendelés a processing státuszára már átváltott (tehát a wc-processed után). Sajnos vannak olyan bővítmények, amelyek rosszul használják a rendeléshez tartozó és elmentett item meta data, azaz a rendelés tétel meta adatok (ezek általában a rendeléshez tartozó egyedi mezők, paraméterek, akár a felhasználók által átadott változók, stb.) elmentését és nem a woocommerce_checkout_order_processed hook-ot használják, hanem a woocommerce_thankyou hook-ot. Nem ugyanarra való, de sajnos sokan összekeverik vagy helytelenül használják.

 

Emiatt hiába vártam egy plugin által összegyűjtött mezőit a rendelés meta adatait között, az csak a rendelés leadása utáni pillanatban vált elérhetővé. Ez azért volt, mert a plugin nem a processed utáni pillanatban mentette el a meta adatokat, hanem a thank you endpoint utáni pillanatban. Ez azt okozta, hogy a hook utáni iterálásnál on-the-fly hiába kérdeztem le az order_itemmeta táblát, nyoma sem volt a plugin által elmentett adatoknak.

Először a woocommerce_checkout_order_processed hook után egy sima SQL lekérdezést használtam (az item_id egyébként az order objektumon belüli változó). Az $items objektum iterálása SQL lekérdezéssel:

global $wpdb;
$items = $order->get_items();
foreach ($items as $item_id => $item) {
$sql = "
	SELECT meta_value
	FROM wp_woocommerce_order_itemmeta
	WHERE `order_item_id` = {$item_id}
	AND (meta_key = '_sumo_pp_payment_id')
";

$result = $wpdb->get_results($sql, ARRAY_A);
if ( !empty($result) ) {
	$sumo_pp_payment_obj = $result[0];
	$sumo_pp_payment_id = (int) $sumo_pp_payment_obj['meta_value'];
}

}

Ugyanez, dedikált Woocommerce függvénnyel lényegesen egyszerűbb, de egyik sem adott vissza találatot.

$items = $order->get_items();
foreach ($items as $item_id => $item) {
	$sumo_pp_payment_id = (int) wc_get_order_item_meta( $item_id, '_sumo_pp_payment_id', true );
}

Sehol semmi. Aztán amikor már lezajlott a rendelésleadás (és lefutott a woocommerce_thankyou hook filtere is, ami kb 1 mp múlva már megtörtént), akkor már ott volt a _sumo_pp_payment_id nevű rekord tartalma. Tanulság: ha legközelebb belefutsz egy ilyenbe és nem találod az adott meta mezőt, próbáld ki mindhárom hook-ot, hátha az adott megoldásban az lesz a nyerő.

Ajánlott irodalom:

  1. Egy WooCommerce hiba, amikor a woocommerce_checkout_order_processed hook előbb lefut, mint kéne: https://github.com/woocommerce/woocommerce/issues/28113
  2. A woocommerce-checkout-order-processed miért nem működik? https://stackoverflow.com/questions/45997729/any-idea-why-woocommerce-checkout-order-processed-not-firing-when-user-is-not-lo
  3. A woocommerce_thankyou hook használata https://stackoverflow.com/questions/43301940/woocommerce-thankyou-hook-not-working
  4. A woocommerce_payment_complete értelme, vagyis amikor az a fontos, hogy mikor van kifizetve egy rendelés: https://stackoverflow.com/questions/46686075/woocommerce-checkout-order-processed-hook-executing-function-twice