Koszyk i kasa w WooCommerce to dziś bloki - aplikacja Reacta, która rozmawia ze sklepem przez Store API. Stary szablon PHP nadal istnieje, ale w nowych instalacjach nie jest tym, co widzi klient.
Najgorsze w tej zmianie jest to, jak cicho przebiega. Kod, który dokładał pole do kasy, nie rzuca błędem i nie trafia do dziennika. Po prostu nie robi nic, a pole znika ze strony, na której ktoś płaci.
Co przestało działać
Trzy rzeczy spotykane w niemal każdym starszym poradniku:
woocommerce_checkout_fields- filtr nadal się wykonuje, ale blokowa kasa nie buduje z niego formularza. Pole nie pojawia się nigdzie.woocommerce_before_cart,woocommerce_after_cart_tablei cała rodzina haków szablonu koszyka - nie odpalają, bo szablon się nie renderuje.wc_fragment_refreshna stronie koszyka - nie działa, bo WooCommerce nie ładuje tam skryptu fragmentów. Na innych stronach działa, co jest najbardziej mylące: ten sam kod raz działa, raz nie.
Dochodzi do tego mniej oczywista zmiana: walidacja po stronie przeglądarki przestaje wystarczać. Store API przyjmuje żądania niezależnie od tego, co pokazał formularz.
Pole w kasie: zamiennik
Od WooCommerce 8.9 jest do tego osobne API. Rejestracja wygląda tak:
add_action( 'woocommerce_init', function () {
woocommerce_register_additional_checkout_field( [
'id' => 'mojsklep/nip',
'label' => 'NIP',
'location' => 'contact',
'type' => 'text',
'required' => false,
] );
}, 20 );
Dwie rzeczy warto zapamiętać od razu.
Pole wymagane sprawdza serwer
Przy 'required' => true zamówienie złożone bez zaznaczenia albo wypełnienia pola odpada po stronie serwera, z błędem rest_invalid_param. Nie trzeba do tego pisać własnej walidacji i - co ważniejsze - nie da się tego obejść, wysyłając żądanie prosto do Store API. Przy polach zgody to nie jest ozdoba, tylko cały sens.
Lokalizacja decyduje, kiedy poznasz wartość
Pole z grupy order WooCommerce zapisuje dopiero razem z zamówieniem. Jeśli potrzebujesz wartości w trakcie wypełniania kasy - bo na przykład budujesz coś wokół porzuconych koszyków - musi być w contact albo address. To jedna z tych różnic, które widać dopiero wtedy, gdy wszystko jest już napisane.
Wartości lądują w meta zamówienia z przedrostkiem _wc_other/, czyli w naszym przykładzie _wc_other/mojsklep/nip. Pełny przykład z polem NIP, razem z walidacją sumy kontrolnej, jest w osobnym wpisie.

Pułapka: motyw wczytuje się za późno
Akcja woocommerce_blocks_loaded odpala się, zanim WordPress wczyta motyw. Zwykłe add_action w functions.php nigdy się nie wykona - bo w chwili, gdy motyw jest czytany, akcja już przeleciała.
// W motywie trzeba sprawdzić, czy akcja już była, i w razie czego
// wywołać funkcję wprost. We wtyczce ten problem nie istnieje.
if ( did_action( 'woocommerce_blocks_loaded' ) ) {
moja_rejestracja_pol();
} else {
add_action( 'woocommerce_blocks_loaded', 'moja_rejestracja_pol' );
}
To ta sama pułapka, co przy wtyczkach montowanych na plugins_loaded: motyw startuje na after_setup_theme, czyli po wszystkim, co wtyczki zdążyły zrobić. Jeśli kod ma działać niezależnie od motywu, jego miejsce jest we wtyczce.
Układ i style
Blokowa kasa przełącza się między jedną a dwiema kolumnami przy szerokości kontenera, nie okna - przez container queries. Reguła @media (max-width: 700px) zadziała o kilkadziesiąt pikseli za późno albo za wcześnie, bo okno jest o padding szersze niż kontener. Przy poprawkach wyglądu mierz element, nie ekran.
Kiedy wrócić do klasycznej kasy
Da się - wystarczy podmienić blok na skrót . Bywa to sensowne, gdy sklep ma rozbudowane, działające rozszerzenia, których nikt nie przepisze w tydzień.
Warto jednak wiedzieć, że to ruch na czas określony. Kierunek rozwoju WooCommerce jest jeden i każdy kolejny miesiąc na klasycznej kasie to kolejny miesiąc kodu, który i tak trzeba będzie przenieść.
Nowa wtyczka? Dowiesz się pierwszy.
Premiery, poradniki i promocje - raz na jakiś czas, bez zasypywania skrzynki.