Konfiguracja wooCommerce pozwala określić dla jakich metod wysyłki możemy wybrać opcję za pobraniem, ale nie ma możliwości zablokowania wtedy innych kanałów płatności. Może to wywołać u klienta konsternację lub spowodować błąd, taki że klient wybierze droższą opcję za pobraniem a i tak zapłaci z góry.
Gotowe wtyczki
Znalazłem wtyczkę, która w darmowej wersji robi różne cuda w koszyku. Disable payment method / COD fees / Advance COD or Partial payment for Order for WooCommerce potrafi wyłączyć metody płatności dla wybranego towaru, dla kodu pocztowego, ale mimo iż wpisywałem nazwę metody płatności na wszystkie sposoby, to tego nie umiał. Nie było też w dokumentacji opisu tego filtru, więc odpuściłem sobie…
Własne rozwiązanie
Misha Rudrastyh na swoim blogu pokazał rozwiązanie usuwające możliwość wyboru metody za pobraniem jeżeli wskażemy odpowiedni sposób wysyłki. Realizuje się to za pomocą filtru 'woocommerce_available_payment_gateways' To odwrotna logika, do moich potrzeb, więc trzeba ją odwrócić. Na początek kod autorstwa Mishy:
add_filter( 'woocommerce_available_payment_gateways', 'rudr_payment_method_by_shipping' ); function rudr_payment_method_by_shipping( $gateways ) { if( is_admin() ) { // do nothing in /wp-admin return $gateways; } if( is_wc_endpoint_url( 'order-pay' ) ) { // "Pay for order" page $order = wc_get_order( wc_get_order_id_by_order_key( $_GET[ 'key' ] ) ); if( $order->has_shipping_method( 'local_pickup' ) ) { if( isset( $gateways[ 'cod' ] ) ) { unset( $gateways[ 'cod' ] ); // unset cash on delivery if exists } } } else { // Cart/Checkout page // get a shipping method selected by a customer $chosen_shipping_method = WC()->session->get( 'chosen_shipping_methods' )[0]; // check the shipping method if ( 'local_pickup:4' === $chosen_shipping_method ) { if( isset( $gateways[ 'cod' ] ) ) { unset( $gateways[ 'cod' ] ); } } } return $gateways; }
Interesuje nas opcja else warunku od linii 18. Do zmiennej $chosen_shipping_method przypisany jest wybór metody wysyłki. Potem jest sprawdzenie, czy to ten dla którego nie występuje pobranie. Jeżeli tak, to ta metoda wysyłki znika w linii 26. Po zmianie parametrów zamówienia wooCommerce sprawdza wszystko jeszcze raz, więc jeżeli zmienimy wysyłkę na inną, to za pobraniem wróci.
Plusy ujemne
Po pierwsze mi zależało na tym, by po wyborze metody wysyłki z opcją za pobraniem znikały inne metody płatności. Tutaj znika za pobraniem. Po drugie, autor podał nazwę metody na sztywno i to w specyficzny sposób: 'local_pickup:4'. Czyli jest to nazwa z id metody. Skąd to wziąć? Trzeba zajrzeć do konsoli i przekopiować. Czyli zakładamy, że właściciel sklepu zna się na kodowaniu? Nie możemy! Znalazłem rozwiązanie bardziej uniwersalne i intuicyjne.
add_filter('woocommerce_available_payment_gateways', 'wdax_payment_method_by_shipping'); if (!function_exists('wdax_payment_method_by_shipping')) { function wdax_payment_method_by_shipping($gateways) { if (is_admin()) { // do nothing in /wp-admin return $gateways; } if (is_wc_endpoint_url('order-pay')) { // "Pay for order" page $order = wc_get_order(wc_get_order_id_by_order_key($_GET['key'])); if ($order->has_shipping_method('local_pickup')) { if (isset($gateways['cod'])) { unset($gateways['cod']); // unset cash on delivery if exists } } } else { // Cart/Checkout page // get a shipping method selected by a customer $chosen_shipping_method = WC()->session->get('chosen_shipping_methods')[0]; // get a shipping method for order $shipping = WC()->session->get('shipping_for_package_0'); foreach ($shipping["rates"] as $shipping_id => $shipping_method) { // check the shipping method if ($shipping_id === $chosen_shipping_method && (stristr($shipping_method->meta_data["_fs_method"]["method_description"], '(cod)') !== false)) { foreach ($gateways as $gateway => $val) { if ($gateway !== 'cod') unset($gateways[$gateway]); } } } } return $gateways; } }
Interesuje nas kod między liniami 22 a 35. Przede wszystkim musimy znać metody wysyłki. Pobieramy je w linii 25 do zmiennej $shipping. Przypisywana jest tablica, której kluczami są poszukiwane wcześniej ręcznie nazwy metod wysyłki. Teraz należy w pętli sprawdzić czy mamy do czynienia z wybranym wariantem czy nie.
Za pobraniem – Cash on delivery
Woocommerce nie daje nam możliwości określenie metody wysyłki jako 'za pobraniem'. Ja korzystam z systemu Apaczka.pl, a ich wtyczka wymaga instalacji dodatku Flexible Shipping. Jest tam pole na opis metody, np. "InPost za pobraniem". Jeżeli dodamy gdzieś hasło "(cod)", to można w ten sposób oznaczyć metodę i łatwo ją rozpoznać, tak jak w linii 29. Zastosowałem funkcję stristr by nie robić problemu z wielkością znaków. Jeżeli listowana metoda jest metodą wskazaną przez klienta sklepu i opisaną jako 'za pobraniem' przez właściciela, to następuje kolejna pętla w linii 30. Listowane są bramki płatności i jeżeli id bramki nie równa się 'cod', to metoda jest usuwana. Na końcu zostaje tylko opcja za pobraniem. I tak samo jak poprzednio, jakakolwiek zmiana parametrów powoduje reset i ponowne sprawdzanie wymogów.
Nie jest to może idealna metoda, bo wymaga odpowiedniej wtyczki, ale Flexible Shipping jest bardzo popularnym, wręcz powszechnym rozwiązaniem. Jeżeli ktoś chciałby rozbudować moje rozwiązanie o inne warianty, to wystarczy sprawdzić parametry zapisane w zmiennej $shipping i poprawić warunek z linii 29.
Gdzie to umieścić?
Ja swoje rozwiązanie załączyłem do folderu mu-plugins. Można też zrobić sobie osobną wtyczkę albo wkleić kod do function.php szablonu, ale pierwsze rozwiązanie jest chyba strzałem z armaty do wróbli, a drugie, o ile nie korzystamy z szablonu dziecka, może zniknąć przy następnej aktualizacji.