SMS z WooCommerce o statusie zamówienia: gotowy kod PHP

Sprawdzone z dokumentacją:

W WooCommerce podpinasz funkcję pod hook woocommerce_order_status_processing lub woocommerce_order_status_completed i wysyłasz wp_remote_post na https://smsportal.app/api/v1/gateway/send-sms z nagłówkiem x-api-key. Kod bierze numer z danych rozliczeniowych, dopisuje +48, zapisuje wynik w notatce zamówienia i nie wysyła tego samego SMS-a dwa razy.

Czego potrzebujesz

  • WooCommerce na WordPressie z dostępem do wp-config.php (FTP, panel hostingu).
  • Miejsce na kod: wtyczka Code Snippets albo functions.php motywu potomnego.
  • Konto smsportal z podłączonym telefonem z Androidem i kartą SIM.
  • Klucz API z panelu smsportal (Klucze API → Wygeneruj klucz API).

Jak wysyłać SMS o zamówieniu z WooCommerce

  1. Zapisz klucz w wp-config.php

    Dodaj nad linią /* That's all, stop editing! */ wiersz define( 'SMSPORTAL_API_KEY', 'twoj_klucz_api' );. Klucz nie trafi do bazy, eksportu fragmentów ani repozytorium motywu.

  2. Wklej kod

    W Code Snippets dodaj nowy fragment PHP i ustaw uruchamianie wszędzie. Bez wtyczki wklej kod na końcu functions.php motywu potomnego (plik ma już na początku <?php). Treści szablonów są bez polskich liter, żeby zmieścić się w 160 znakach jednej części.

    Fragment PHP: SMS przy statusach processing i completed
    // SMS o zmianie statusu zamówienia przez smsportal.
    // Klucz API trzymaj w wp-config.php, nie tutaj:
    // define( 'SMSPORTAL_API_KEY', 'twoj_klucz_api' );
    
    add_action( 'woocommerce_order_status_processing', function ( $order_id, $order ) {
    	smsportal_order_sms( $order, 'processing', 'Zamowienie #{number} przyjete. Dziekujemy, {name}! Sklep Kowalski' );
    }, 10, 2 );
    
    add_action( 'woocommerce_order_status_completed', function ( $order_id, $order ) {
    	smsportal_order_sms( $order, 'completed', 'Zamowienie #{number} wyslane. Sklep Kowalski' );
    }, 10, 2 );
    
    function smsportal_order_sms( $order, $status, $template ) {
    	if ( ! defined( 'SMSPORTAL_API_KEY' ) ) {
    		return;
    	}
    	$flag = '_smsportal_sms_' . $status;
    	if ( $order->get_meta( $flag ) ) {
    		return; // ten SMS już wyszedł, nie wysyłaj drugi raz
    	}
    	$phone = smsportal_normalize_phone( $order->get_billing_phone(), '48' );
    	if ( '' === $phone ) {
    		$order->add_order_note( 'SMS nie wysłany: brak poprawnego numeru telefonu.' );
    		return;
    	}
    	$message = strtr( $template, array(
    		'{number}' => $order->get_order_number(),
    		'{name}'   => $order->get_billing_first_name(),
    	) );
    
    	$response = wp_remote_post( 'https://smsportal.app/api/v1/gateway/send-sms', array(
    		'timeout' => 5,
    		'headers' => array(
    			'x-api-key'    => SMSPORTAL_API_KEY,
    			'Content-Type' => 'application/json',
    		),
    		'body'    => wp_json_encode( array(
    			'recipients' => array( $phone ),
    			'message'    => $message,
    		) ),
    	) );
    
    	if ( is_wp_error( $response ) ) {
    		$order->add_order_note( 'SMS nie wysłany: ' . $response->get_error_message() );
    		return;
    	}
    	$code = (int) wp_remote_retrieve_response_code( $response );
    	$body = wp_remote_retrieve_body( $response );
    	if ( $code < 200 || $code >= 300 ) {
    		$order->add_order_note( sprintf( 'SMS odrzucony (HTTP %d): %s', $code, substr( $body, 0, 200 ) ) );
    		return;
    	}
    
    	$order->update_meta_data( $flag, current_time( 'mysql' ) );
    	$order->save_meta_data();
    	$json  = json_decode( $body, true );
    	$batch = isset( $json['data']['smsBatchId'] ) ? ' (partia ' . $json['data']['smsBatchId'] . ')' : '';
    	$order->add_order_note( 'SMS w kolejce do ' . $phone . $batch . ': ' . $message );
    }
    
    // 600 100 200 -> +48600100200. Numery z + albo 00 zostają bez zmian.
    function smsportal_normalize_phone( $raw, $country_code ) {
    	$raw    = trim( (string) $raw );
    	$digits = preg_replace( '/\D+/', '', $raw );
    	if ( '' === $digits ) {
    		return '';
    	}
    	if ( 0 === strpos( $raw, '+' ) ) {
    		// już w formacie międzynarodowym
    	} elseif ( 0 === strpos( $digits, '00' ) ) {
    		$digits = substr( $digits, 2 );
    	} elseif ( ! ( 0 === strpos( $digits, $country_code ) && strlen( $digits ) > 9 ) ) {
    		$digits = $country_code . ltrim( $digits, '0' );
    	}
    	$length = strlen( $digits );
    	return ( $length >= 8 && $length <= 15 ) ? '+' . $digits : '';
    }
  3. Dopasuj statusy i treści

    Każdy status to osobny hook woocommerce_order_status_<status> (nazwa bez prefiksu wc-). Dostępne zmienne: {number} i {name}. Sklep spoza Polski zmienia '48' w wywołaniu smsportal_normalize_phone na swój kierunkowy.

  4. Przetestuj na własnym numerze

    Złóż zamówienie z własnym telefonem wpisanym bez +48 i zmień status w panelu. W notatkach zamówienia zobaczysz „SMS w kolejce” albo powód błędu. Ponowna zmiana na ten sam status nie wyśle drugiego SMS-a.

Gotowe scenariusze

  • Paczka nadana, z numerem przesyłki

    Hook woocommerce_order_status_completed wysyła „Zamówienie wysłane”. Numer przesyłki nie jest polem WooCommerce: odczytaj go przez $order->get_meta() z pola, które zapisuje Twoja wtyczka do śledzenia, i dopisz do strtr jako {tracking}.

  • Nieudana płatność

    Dodaj trzeci hook woocommerce_order_status_failed z treścią typu „Płatność za #{number} nie przeszła, dokończ ją w sklepie”. Link z $order->get_checkout_payment_url() jest długi, więc SMS zajmie kilka części.

  • Zamówienie gotowe do odbioru

    Status „Gotowe do odbioru” dodany wtyczką ma własny slug, np. ready-pickup. Hook to wtedy woocommerce_order_status_ready-pickup, a treść podaje godziny otwarcia punktu.

Błędy i rozwiązania

Notatka „SMS odrzucony (HTTP 401)”
Przyczyna: Zły klucz albo nagłówek Authorization zamiast x-api-key.
Co zrobić: Sprawdź stałą SMSPORTAL_API_KEY w wp-config.php i wygeneruj nowy klucz, jeśli stary usunięto.
Notatka „SMS odrzucony (HTTP 400)”
Przyczyna: Brak włączonego telefonu na koncie albo niezweryfikowany e-mail.
Co zrobić: W panelu sprawdź, czy telefon jest podłączony i włączony, oraz potwierdź adres e-mail.
Notatka „SMS odrzucony (HTTP 429)”
Przyczyna: Wyczerpany limit SMS-ów w pakiecie.
Co zrobić: Treść odpowiedzi w notatce mówi, który limit się skończył. Zmień pakiet albo poczekaj na odnowienie.
Brak jakiejkolwiek notatki o SMS-ie
Przyczyna: Brak stałej SMSPORTAL_API_KEY, nieaktywny fragment kodu albo status, który nie ma hooka.
Co zrobić: Sprawdź, czy fragment jest włączony i czy stała jest zdefiniowana przed require_once ABSPATH . 'wp-settings.php'.
Notatka „SMS w kolejce”, ale SMS nie dociera
Przyczyna: Telefon jest offline albo Android usypia aplikację.
Co zrobić: Sprawdź zasięg, internet i stan telefonu w panelu. Wiadomość czeka do 72 godzin, potem wygasa.

Najczęstsze pytania

Czy ten kod działa z HPOS (nowym magazynem zamówień)?

Tak. Hooki statusu odpala sam obiekt zamówienia niezależnie od magazynu, a znacznik wysyłki zapisuje `update_meta_data` i `save_meta_data`, czyli metody, które WooCommerce zaleca dla HPOS zamiast `update_post_meta`.

Czy wysyłka spowalnia składanie zamówienia?

Żądanie czeka na odpowiedź najwyżej 5 sekund, zwykle znacznie krócej. Opcja `'blocking' => false` skraca to do zera, ale wtedy kod nie zna wyniku, więc nie zapisze notatki ani znacznika przeciw duplikatom.

Czy mogę użyć webhooków WooCommerce zamiast kodu?

Tak, ale webhook z WooCommerce → Ustawienia → Zaawansowane → Webhooki wysyła własny format zamówienia, którego smsportal nie przyjmie. Potrzebny jest krok pośredni, np. n8n albo Make, który wyciągnie telefon i zbuduje treść SMS-a.

Co z odpowiedziami klientów na SMS?

Trafiają do panelu smsportal, bo klient odpisuje na Twój numer. Żeby przekazać je dalej, np. na Slacka, ustaw webhook ze zdarzeniem `MESSAGE_RECEIVED` w n8n lub Make.

Czy na SMS o zamówieniu potrzebuję zgody klienta?

Wiadomość o realizacji konkretnego zamówienia jest transakcyjna. Reklama, kupon czy promocja w SMS-ie wymaga osobnej zgody marketingowej zgodnie z Prawem komunikacji elektronicznej. Do kampanii lepszy jest dostawca z nazwą nadawcy.

Źródła

  1. WooCommerce: kod klasy WC_Order (hooki statusów)
  2. WooCommerce: HPOS recipe book (metadane zamówień)
  3. WooCommerce: Webhooks
  4. WordPress: WP_Http::request (timeout, blocking)
  5. Code Snippets w katalogu wtyczek WordPress
  6. smsportal: dokumentacja API

Więcej w poradnikach

Wyślij pierwszego SMS-a jeszcze dziś

Załóż darmowe konto, podłącz telefon i sprawdź, jak klienci reagują na wiadomości z Twojego numeru.