fbpx

Formularz wiadomości WooCommerce – wysyłaj maile, zarządzaj zamówieniami i magazynem jak profesjonalista!

Kompleksowy formularz wiadomości WooCommerce – wszystko w jednym miejscu

Ten rozbudowany formularz wiadomości WooCommerce to coś więcej niż prosty formularz. To potężne narzędzie, które stworzyłem, by zautomatyzować kontakt z klientami i jednocześnie ułatwić zarządzanie zamówieniami oraz stanem magazynowym wariantów produktów. Całość działa jako shortcode, więc mogę go dodać w dowolnym miejscu na stronie – np. na stronie w panelu admina lub jako dedykowaną podstronę tylko dla mnie.

Shortcode, który należy wstawić to:
[customers_table_and_form]

Najlepszym miejscem na dodanie kodu nie jest plik functions.php, tylko wtyczka Code Snippets. Dlaczego? Bo dzięki niej mogę łatwo zarządzać fragmentami kodu, włączać lub wyłączać je bez ryzyka zepsucia całej strony.

Jak działa i co oferuje formularz

Po pierwsze – wyciągam listę klientów, którzy w danym miesiącu kupili konkretny produkt. Ich dane, cena zakupu, data oraz adres e-mail są prezentowane w tabeli. Id produktu, który ma być filtrowany, mogę łatwo zmienić w tej linii kodu:

$product_id = 6257;

Wystarczy podmienić 6257 na dowolne ID mojego produktu w WooCommerce.

Po drugie – mam formularz do masowej wysyłki wiadomości e-mail. Mogę wysłać wiadomość do wszystkich klientów lub tylko do wybranych. Co więcej – formularz umożliwia dołączanie wielu załączników (max 5 MB każdy), co pozwala np. na wysłanie materiałów PDF lub grafik promocyjnych.

Całość zawiera także opcję testowego e-maila, który mogę wysłać do siebie, zanim wyślę do klientów. To pozwala mi sprawdzić formatowanie, poprawność treści i załączniki.

To właśnie dlatego ten formularz wiadomości WooCommerce jest tak funkcjonalny – bo nie muszę korzystać z zewnętrznych wtyczek mailingowych, żeby mieć podstawowy kontakt z klientem.

Obsługa stanów magazynowych produktów z wariantami

Po prawej stronie formularza znajduje się narzędzie do edycji stanów magazynowych. Mogę wybrać konkretny wariant (w tym przykładzie ID 7762 i 7763), wpisać nowy stan i zapisać. Jeśli dany produkt nie zarządza stanem magazynowym, otrzymam komunikat z błędem.

Kod pozwala zatem nie tylko komunikować się z klientami, ale też dynamicznie zarządzać wariantami produktów, co jest ogromnym ułatwieniem. Warianty można zmienić w tej sekcji:

echo '<option value="7762">Pakiet podstawowy</option>';
echo '<option value="7763">Pakiet rozszerzony</option>';

Po prostu podmieniam ID i nazwę zgodnie z moimi produktami.

Podsumowanie możliwości – co mogę dzięki temu zrobić

Ten formularz wiadomości WooCommerce daje mi pełną kontrolę nad:

  • filtrowaniem zamówień z danego miesiąca,
  • listą klientów z ich danymi,
  • masową lub selektywną wysyłką maili,
  • dodawaniem załączników,
  • testowaniem wiadomości,
  • edytowaniem stanów magazynowych wariantów,
  • podglądem całkowitej wartości zamówień danego produktu.

Dzięki temu wszystko mam w jednym miejscu. Nie muszę przechodzić między różnymi zakładkami WooCommerce. Wszystko mogę obsłużyć z jednego shortcode’u – szybko i wygodnie.

Ten kod idealnie sprawdza się dla sprzedawców kursów, pakietów, konsultacji lub produktów sezonowych. Ułatwia kontakt z klientami i oszczędza mnóstwo czasu.

Dodaję go przez Code Snippets, włączam, wstawiam shortcode na stronie i gotowe. Tak właśnie działa dobry formularz wiadomości WooCommerce.

function woocommerce_customers_table_and_form_shortcode() {
    ob_start();

    $message = ''; // Zmienna na komunikaty

    // ID produktu do sprawdzenia (główny produkt)
    $product_id = 6257;
    $current_month_start = date('Y-m-01 00:00:00');
    $current_month_end = date('Y-m-t 23:59:59');

    // Pobieranie zamówień z bieżącego miesiąca dla produktu o ID 6257
    $args = array(
        'limit'           => -1,
        'status'          => 'completed',
        'date_completed'  => $current_month_start . '...' . $current_month_end,
    );
    
    $orders = wc_get_orders($args);
    $customers = [];
    $total_value = 0;
    $lp = 1; // Zmienna do numeracji LP
    
    foreach ($orders as $order) {
        foreach ($order->get_items() as $item) {
            if ($item->get_product_id() == $product_id) {
                $customer = $order->get_billing_first_name() . ' ' . $order->get_billing_last_name();
                $date = $order->get_date_completed()->date('Y-m-d');
                $price = $item->get_total();
                $total_value += $price;
                $customers[] = [
                    'lp'       => $lp,
                    'name'     => $customer,
                    'date'     => $date,
                    'price'    => number_format($price, 2, ',', ' ') . ' zł',
                    'email'    => $order->get_billing_email(),
                    'order_id' => $order->get_id() // ID zamówienia do identyfikacji
                ];
                $lp++;
            }
        }
    }

    // Obsługa wysyłania formularza wiadomości (bez zmian)
    if (isset($_POST['submit_message'])) {
        $subject = sanitize_text_field($_POST['message_subject']);
        $content = wp_kses_post($_POST['message_content']);
        
        $send_option = $_POST['send_option'];
        $emails = [];

        if ($send_option === 'all') {
            foreach ($customers as $customer) {
                $emails[] = $customer['email'];
            }
            $message = '<div class="message-success"><span>Wiadomość została wysłana do wszystkich klientów!</span></div>';
        } elseif ($send_option === 'specific') {
            $send_to = isset($_POST['send_to']) ? $_POST['send_to'] : [];
            foreach ($customers as $customer) {
                if (in_array($customer['order_id'], $send_to)) {
                    $emails[] = $customer['email'];
                }
            }
            $email_count = count($emails);
            if ($email_count > 0) {
                $message = '<div class="message-success"><span>Wiadomość została wysłana do ' . $email_count . ' klientów!</span></div>';
            } else {
                $message = '<div class="message-error"><span>Brak wybranych klientów do wysłania wiadomości.</span></div>';
            }
        }
        
        if (!empty($emails)) {
            $attachments = [];
            if (!empty($_FILES['message_attachments'])) {
                foreach ($_FILES['message_attachments']['tmp_name'] as $key => $tmp_name) {
                    if ($_FILES['message_attachments']['size'][$key] <= 5242880) { // Max 5MB
                        $uploaded = wp_upload_bits($_FILES['message_attachments']['name'][$key], null, file_get_contents($tmp_name));
                        if (!$uploaded['error']) {
                            $attachments[] = $uploaded['file'];
                        }
                    }
                }
            }
            $headers = array('Content-Type: text/html; charset=UTF-8');
            foreach ($emails as $email) {
                wp_mail($email, $subject, $content, $headers, $attachments);
            }
        }
    }

    // Wyświetlanie komunikatu nad formularzem i tabelą klientów
    echo $message;

    echo '<div class="caly-formularz" style="display: flex; justify-content: space-between;">';

    // Formularz po lewej stronie (bez zmian)
    echo '<div class="lewa-strona" style="flex: 1; padding-right: 20px;">';
    echo '<div class="wiadomosc-testowa">';
    echo '<div class="tytulik"><span class="tu-jest-naglowek">Test wysyłania wiadomości</span></div>';
    echo '<form id="test-email-form">';
    echo '<div class="do-testowania"><label class="do-testu" for="test_email">Adres email do testu:</label><br></div>';
    echo '<input type="email" id="test_email" name="test_email" required><br>';
    echo '<button type="button" id="send-test-email">Wyślij test</button>';
    echo '</form>';
    echo '</div>';
    echo '<hr>';

    ?>
    <div class="formularz">
        <div class="naglowek-formularza">
            <span class="tu-jest-naglowek">Formularz dla GLOW UP</span>
        </div>
        <form id="send-message-form" method="post" enctype="multipart/form-data">
            <div class="do-testowania">
                <label class="do-testu" for="test_email">Temat wiadomości:</label><br>
            </div>
            <input type="text" id="message_subject" name="message_subject" required><br><br>
            <div class="linia-oddzielajaca">
                <hr class="linijka" style="border: 0; height: 1px; background-color: #ddd; width: 450px; margin: 0 auto;"><br>
            </div>
            <div class="do-testowania">
                <label for="message_content">Treść wiadomości:</label><br>
            </div>
            <div class="tresc-wysylanej-wiadomosci">
                <?php
                $content = '';
                wp_editor($content, 'message_content', array('textarea_rows' => 6));
                ?>
                <br>
            </div>
            <div class="linia-oddzielajaca">
                <hr class="linijka" style="border: 0; height: 1px; background-color: #ddd; width: 450px; margin: 0 auto;"><br>
            </div>
            <div class="do-testowania">
                <label for="send_option">Wyślij do:</label><br>
                <select id="send_option" name="send_option">
                    <option value="all">Wyślij do wszystkich</option>
                    <option value="specific">Wyślij do pojedynczych klientów</option>
                </select><br><br>
            </div>
            <div id="customer_list" style="display:none;">
                <div class="prawa-strona">
                    <div class="tabela-z-klientami">
                        <table border="1" cellpadding="10">
                            <?php if (!empty($customers)) : ?>
                                <?php foreach ($customers as $customer) : ?>
                                    <tr class="zawartosc-komorek">
                                        <td><?php echo esc_html($customer['lp']); ?></td>
                                        <td><?php echo esc_html($customer['name']); ?></td>
                                        <td><input type="checkbox" class="customer-checkbox" name="send_to[]" value="<?php echo esc_html($customer['order_id']); ?>"></td>
                                    </tr>
                                <?php endforeach; ?>
                            <?php else : ?>
                                <tr>
                                    <td colspan="5">Aktualnie brak klientów do wyświetlenia.</td>
                                </tr>
                            <?php endif; ?>
                        </table>
                    </div>
                </div>
            </div>
            <div class="linia-oddzielajaca">
                <hr class="linijka" style="border: 0; height: 1px; background-color: #ddd; width: 450px; margin: 0 auto;"><br>
            </div>
            <div class="do-testowania">
                <label for="message_attachments">Załączniki (maksymalnie 5, max 5MB każdy):</label>
            </div>
            <input type="file" name="message_attachments[]" multiple accept=".jpg,.jpeg,.png,.pdf,.docx,.xlsx,.txt,.zip,.rar"><br><br>
            <ul id="attachment-list"></ul>
            <input class="guziczek-formularza" type="submit" name="submit_message" value="Wyślij wiadomość">
        </form>
    </div>
    <script>
    // Obsługa załączników - wyświetlanie nazw plików
    document.querySelector('input[type="file"]').addEventListener('change', function() {
        const fileList = this.files;
        const attachmentList = document.getElementById('attachment-list');
        attachmentList.innerHTML = '';
        for (let i = 0; i < fileList.length; i++) {
            const fileItem = document.createElement('li');
            fileItem.textContent = fileList[i].name;
            attachmentList.appendChild(fileItem);
        }
    });
    // Pokazywanie/ukrywanie listy klientów w zależności od wyboru w polu select
    document.getElementById('send_option').addEventListener('change', function() {
        const customerList = document.getElementById('customer_list');
        customerList.style.display = (this.value === 'specific') ? 'block' : 'none';
    });
    // AJAX do testowego wysyłania wiadomości
    document.getElementById('send-test-email').addEventListener('click', function() {
        const email = document.getElementById('test_email').value;
        const subject = document.getElementById('message_subject').value;
        const content = tinyMCE.get('message_content').getContent();
        const formData = new FormData();
        formData.append('action', 'send_test_email');
        formData.append('email', email);
        formData.append('subject', subject);
        formData.append('content', content);
        const files = document.querySelector('input[name="message_attachments[]"]').files;
        for (let i = 0; i < files.length; i++) {
            formData.append('attachments[]', files[i]);
        }
        fetch('<?php echo admin_url('admin-ajax.php'); ?>', {
            method: 'POST',
            body: formData
        })
        .then(response => response.text())
        .then(data => {
            alert('Wiadomość testowa została wysłana prawidłowo!');
        })
        .catch(error => {
            alert('Błąd przy wysyłaniu wiadomości testowej.');
        });
    });
    </script>
    <?php
    echo '</div>'; // Koniec lewego kontenera

    // Ustawienie lokalizacji na polski
    setlocale(LC_TIME, 'pl_PL.UTF-8');

    // Prawa strona – obsługa zmiany stanu magazynowego dla wariantów
    echo '<div class="prawa-strona" style="flex: 1;">';
    $message = '';

    // Obsługa formularza zmiany stanu magazynowego
    if (isset($_POST['new_stock']) && is_numeric($_POST['new_stock'])) {
        $new_stock = intval($_POST['new_stock']);
        if (isset($_POST['selected_variant']) && !empty($_POST['selected_variant'])) {
            $selected_variant_id = intval($_POST['selected_variant']);
            $variation = wc_get_product($selected_variant_id);
            if ($variation && $variation->managing_stock()) {
                $variation->set_stock_quantity($new_stock);
                $variation->save();
                $message = '<div class="message-success"><span>Stan magazynowy dla wariantu ' . esc_html(get_the_title($selected_variant_id)) . ' został zaktualizowany!</span></div>';
            } else {
                $message = '<div class="message-error"><span>Nie znaleziono wariantu lub nie zarządza on stanem magazynowym.</span></div>';
            }
        } else {
            $message = '<div class="message-error"><span>Proszę wybrać wariant.</span></div>';
        }
    }

    echo $message;

    // Formularz aktualizacji stanu magazynowego z wyborem wariantu
    echo '<div class="zmiana-stanu-magazynowego">';
    echo '<form method="post">';
	echo '<div class="wybierz-wariant">';
    echo '<label for="selected_variant">Wybierz wariant:</label><br>';
    echo '<select id="selected_variant" name="selected_variant">';
	echo '</div>';
    echo '<option value="">-- Wybierz wariant --</option>';
   echo '<option value="7762">Pakiet podstawowy</option>';
echo '<option value="7763">Pakiet rozszerzony</option>';
    echo '</select><br><br>';

    // Pole do wpisania nowej wartości – ukryte do momentu wyboru wariantu
    echo '<div id="variant_update_fields" style="display:none;">';
    echo '<label class="stany-magazynowe" for="new_stock">Wpisz nowy stan magazynowy:</label><br>';
    echo '<input type="number" id="new_stock" name="new_stock" min="0" required><br>';
    echo '<button class="guzik-do-stanow" type="submit">Zmień stan</button>';
    echo '</div>';
    echo '</form>';

    // Skrypt JS pokazujący pole aktualizacji po wybraniu wariantu
    echo '<script>
        document.getElementById("selected_variant").addEventListener("change", function() {
            var fields = document.getElementById("variant_update_fields");
            if (this.value !== "") {
                fields.style.display = "block";
            } else {
                fields.style.display = "none";
            }
        });
    </script>';

    // Wyświetlanie aktualnych stanów magazynowych dla obu wariantów
    $variant1 = wc_get_product(7762);
    $variant2 = wc_get_product(7763);
    $stock1 = $variant1 ? $variant1->get_stock_quantity() : 'N/A';
    $stock2 = $variant2 ? $variant2->get_stock_quantity() : 'N/A';

    echo '<p class="aktualny-stan-magazynowy">Aktualny stan magazynowy:</p>';
    echo '<ul>';
    echo 'Pakiet podstawowy: ' . esc_html($stock1) . ' miejsc<br>';
echo 'Pakiet rozszerzony: ' . esc_html($stock2) . ' miejsc';

    echo '</ul>';

    echo '</div>'; // Koniec prawego kontenera

    echo '<div class="informacja-o-miesiacu">';
    echo '<span class="lista-klientow-tytul">Lista klientów, którzy kupili produkt w miesiącu:</span><b><span class="miesiac"> ' . strftime('%B') . '</b></span>';
    echo '</div>';

    if (!empty($customers)) {
        echo '<div class="tabela-z-klientami">';
        echo '<table border="1" cellpadding="10">';
        echo '<tr class="nazwy-komorek"><th>LP</th><th>Imię i Nazwisko</th><th>Data Zakupu</th><th>Cena</th></tr>';
        foreach ($customers as $customer) {
            echo '<tr class="zawartosc-komorek">';
            echo '<td>' . esc_html($customer['lp']) . '</td>';
            echo '<td>' . esc_html($customer['name']) . '</td>';
            echo '<td>' . esc_html($customer['date']) . '</td>';
            echo '<td>' . esc_html($customer['price']) . '</td>';
            echo '</tr>';
        }
        echo '<tr class="podsumowanie">';
        echo '<td colspan="3"><strong>Łączna wartość zamówień:</strong></td>';
        echo '<td><strong>' . number_format($total_value, 2, ',', ' ') . ' zł</strong></td>';
        echo '</tr>';
        echo '</table>';
    } else {
        echo '<p>Aktualnie brak sprzedaży.</p>';
    }
    echo '</div>';

    echo '</div>'; // Koniec kontenera flex

    return ob_get_clean();
}

// AJAX do wysyłania testowego emaila (bez zmian)
function send_test_email_ajax() {
    $email = sanitize_email($_POST['email']);
    $subject = sanitize_text_field($_POST['subject']);
    $content = wp_kses_post($_POST['content']);
    $attachments = [];

    if (!empty($_FILES['attachments'])) {
        foreach ($_FILES['attachments']['tmp_name'] as $key => $tmp_name) {
            if ($_FILES['attachments']['size'][$key] <= 5242880) { // Max 5MB
                $uploaded = wp_upload_bits($_FILES['attachments']['name'][$key], null, file_get_contents($tmp_name));
                if (!$uploaded['error']) {
                    $attachments[] = $uploaded['file'];
                }
            }
        }
    }
    $headers = array('Content-Type: text/html; charset=UTF-8');
    wp_mail($email, $subject, $content, $headers, $attachments);
    echo 'success';
    wp_die();
}
add_action('wp_ajax_send_test_email', 'send_test_email_ajax');
add_action('wp_ajax_nopriv_send_test_email', 'send_test_email_ajax');

add_shortcode('customers_table_and_form', 'woocommerce_customers_table_and_form_shortcode');

WAŻNE: Formularz wymaga stylizacji CSS od strony front-endu. Bez stylizacji kod będzie działał prawidłowo ale nie będzie wyglądał dobrze.

Zdjęcie profilowe autora

Bartosz Świnicki

Jeśli podobają Ci się moje treści i chcesz docenić moją pracę, możesz mnie symbolicznie wesprzeć.

Imię:


Nazwisko:


Adres email:


Nazwa Twojej firmy:


NIP Twojej firmy

REGON Twojej firmy



Adres Twojej firmy

Ulica

Kod pocztowy

Miasto

Wybierz bramkę płatniczą na Twojej stronie