WordPress Plugin Saving Data to Database

Własna wtyczka WordPress zapisująca dane, wprowadzone przez odwiedzającego stronę, do bazy danych cz.1

W poprzednim wpisie utworzyliśmy wtyczkę WordPress, która dodawała do strony aplikację JavaScript. Nasza aplikacja mogła działać jako integralna część strony WordPress. Dziś pójdziemy o krok dalej — napiszemy wtyczkę, która będzie zapisywała dane wprowadzone przez użytkownika do bazy danych WordPressa.

Oczywiście w repozytorium wtyczek znajdziemy wiele gotowych rozwiązań tego typu, takich jak bardzo popularny Contact Form 7 czy nieco bardziej rozbudowany Forminator. Tym razem chcę jednak pokazać sam mechanizm działania formularza na stronie WordPress. Przedstawiony przykład będzie bardzo prosty, ale ten sam schemat można rozwinąć do znacznie bardziej złożonych aplikacji. Bez większego problemu, na podobnej zasadzie, można zbudować system rezerwacyjny lub inny system operujący na danych wprowadzanych przez użytkowników.

Tyle tytułem wstępu — teraz zabierzmy się do pisania.

Wyobraźmy sobie, że potrzebujemy prostego formularza, dzięki któremu użytkownik będzie mógł zapisać się na organizowane przez nas wydarzenie. Tak jak poprzednio, tworzymy katalog, którego nazwa odpowiada nazwie naszej wtyczki. W tym przypadku będzie to event-list-plugin. W katalogu umieszczamy plik PHP, którego nazwa (co ważne) jest identyczna z nazwą katalogu. Tworzymy zatem plik event-list-plugin.php.

Minimalna zawartość tego pliku to:

<?php
/*
Plugin Name: Event List Plugin
*/

Jak widać, są to podstawowe informacje dotyczące naszej wtyczki. Zgodnie z dokumentacją WordPressa informacje te mogą mieć bardziej rozbudowaną formę. Na potrzeby tego poradnika przyjmiemy jednak następującą postać nagłówka naszej wtyczki:

<?php
/*
Plugin Name: Event List Plugin
Description: A custom form for event submission
Version: 1.0
Author: Your Name
*/

Teoretycznie cały kod wtyczki WordPressa można zawrzeć w jednym pliku i taka wtyczka będzie działać poprawnie. Głównym problemem tego rozwiązania jest jednak to, że wraz ze wzrostem liczby funkcjonalności kod zacznie się szybko rozrastać. W efekcie stanie się on coraz mniej czytelny i trudny do utrzymania.

Dlatego przyjmijmy pewną strukturę katalogów i plików, która pomoże nam choć częściowo zapanować nad kodem. Organizacja plików wtyczek WordPressa to temat dość obszerny i różni developerzy mogą podchodzić do niego na wiele sposobów. Na potrzeby naszego przykładu przyjmiemy jednak bardzo prostą strukturę katalogów i plików:

>includes
>templates
event-list-plugin.php

W katalogu /includes umieścimy logikę odpowiedzialną za tworzenie nowej tabeli w bazie danych. Natomiast w katalogu /templates znajdą się szablony formularza dla użytkownika, lista zapisanych użytkowników wyświetlana w panelu administracyjnym WordPressa oraz plik arkusza stylów CSS.

Na chwilę wróćmy teraz do naszego pliku event-list-plugin.php:

<?php
/*
Plugin Name: Event List Plugin
Description: A custom form for event submission
Version: 1.0
Author: Your Name
*/

register_activation_hook(__FILE__, 'elp_activate');

function elp_activate()
{
    // Tutaj umieścimy kod tworzący nowe tabele bazy danych
    
}

register_activation_hook( string $file, callable $callback ) to funkcja WordPressa, która jest wykonywana w momencie aktywacji wtyczki. Przyjmuje ona dwa argumenty:

  • ciąg znaków (string) zawierający nazwę pliku wtyczki wraz ze ścieżką dostępu,
  • funkcję zwrotną (callback), która zostanie uruchomiona podczas aktywacji.

Użyta przez nas stała __FILE__ zwraca nazwę pliku wtyczki wraz z pełną ścieżką dostępu. Funkcja epl_activate() będzie odpowiedzialna za utworzenie nowej tabeli w bazie danych.

Moglibyśmy umieścić kod tworzący tabelę bezpośrednio wewnątrz tej funkcji, jednak mając na uwadze przyjętą wcześniej strukturę wtyczki, wydzielimy tę logikę do osobnego pliku. Umieścimy go w katalogu /includes i nazwiemy elp-database-setup.php.

Wewnątrz tego pliku umieśćmy następujący kod:

<?php
function elp_create_table()
{
    global $wpdb;
    $table_name = $wpdb->prefix . 'event_list';
    $charset_collate = $wpdb->get_charset_collate();

    $sql = "CREATE TABLE $table_name (
        id mediumint(9) NOT NULL AUTO_INCREMENT,
        user_name tinytext NOT NULL,
        user_email varchar(100) NOT NULL,
        status varchar(20) DEFAULT 'pending' NOT NULL,
        PRIMARY KEY (id)
    ) $charset_collate;";

    require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
    dbDelta($sql);
}

Przyjrzyjmy się tej funkcji PHP. Instrukcja global $wpdb udostępnia instancję obiektu wpdb, który odpowiada za komunikację z bazą danych w WordPressie.

Linia
$table_name = $wpdb->prefix . 'event_list'
służy do zdefiniowania nazwy naszej tabeli w bazie danych, z uwzględnieniem prefiksu WordPressa.

Z kolei
$charset_collate = $wpdb->get_charset_collate()
odpowiada (w pewnym uproszczeniu) za poprawne i spójne przechowywanie znaków tekstowych w bazie danych, zgodnie z konfiguracją WordPressa.

Następnie tworzymy zapytanie SQL, które dodaje do bazy danych następujące kolumny:

  • id – klucz główny,
  • user_name – nazwa użytkownika,
  • user_email – adres e-mail użytkownika,
  • status – kolumna przyjmująca domyślną wartość "pending".

Funkcja dbDelta( $sql ) wykonuje przygotowane zapytanie SQL i tworzy nową tabelę, w której będziemy przechowywać dane użytkowników zapisanych na nasze wydarzenie.

Na koniec wystarczy wywołać tę funkcję w głównym pliku wtyczki event-list-plugin.php. Po wprowadzonych zmianach plik wygląda następująco:

<?php
/*
Plugin Name: Event List Plugin
Description: A custom form for event submission
Version: 1.0
Author: Your Name
*/

register_activation_hook(__FILE__, 'elp_activate');

function elp_activate()
{
    require_once plugin_dir_path(__FILE__) . 'includes/elp-database-setup.php';
    elp_create_table();
}

Jeżeli włączyliście wtyczkę zaraz po jej utworzeniu, możecie się zdziwić, że powyższa zmiana nie spowodowała utworzenia nowej tabeli w bazie danych. Może się wydawać, że nasz kod nie działa. Aby tabela została utworzona, należy dezaktywować, a następnie ponownie aktywować wtyczkę.

Funkcja register_activation_hook() jest wywoływana wyłącznie w momencie aktywacji wtyczki, dlatego funkcja elp_create_table() zostanie uruchomiona właśnie wtedy. Po ponownej aktywacji wtyczki w bazie danych powinna pojawić się nowa tabela o nazwie prefix_event_list (domyślnie wp_event_list).

Pora na kolejny etap. Utwórzmy teraz szablon formularza, z którego użytkownik będzie mógł skorzystać, aby zapisać się na listę uczestników wydarzenia. W katalogu /templates tworzymy plik sign-form1.php:

<?php
if (! defined('ABSPATH')) {
    exit; // Exit if accessed directly
}
?>

<div class="mrp-reservation-form-container">
    <h2>Event registration</h2>
    <form action="<?php echo esc_url(admin_url('admin-post.php')); ?>" method="POST" class="mrp-form">
        <!-- Security Nonce Field -->
        <?php wp_nonce_field('elp_submit_reservation_action', 'elp_reservation_nonce'); ?>

        <!-- Hidden field to tell admin-post.php which action to fire -->
        <input type="hidden" name="action" value="elp_submit_reservation">

        <div class="mrp-form-group">
            <label for="user_name">Full Name:</label>
            <input type="text" id="user_name" name="user_name" required>
        </div>

        <div class="mrp-form-group">
            <label for="user_email">Email Address:</label>
            <input type="email" id="user_email" name="user_email" required>
        </div>
        <button type="submit" class="mrp-submit-btn">Register</button>
    </form>
</div>

Nasz szablon musimy teraz zarejestrować w głównym pliku wtyczki event-list-plugin.php. Do dodania go na stronę posłużymy się znanym nam już z poprzedniego wpisu mechanizmem shortcode’ów WordPressa.

<?php
/*
Plugin Name: Event List Plugin
Description: A custom form for event submission
Version: 1.0
Author: Your Name
*/

register_activation_hook(__FILE__, 'elp_activate');

function elp_activate()
{
    require_once plugin_dir_path(__FILE__) . 'includes/elp-database-setup.php';
    elp_create_table();
}

function elp_render_reservation_form()
{
    ob_start(); // Start output buffering

    // Include the form template
    include plugin_dir_path(__FILE__) . 'templates/sign-form1.php';

    return ob_get_clean(); // Return the form HTML
}

add_shortcode('sign_form_1', 'elp_render_reservation_form');

Nasz shortcode, którego użyjemy do dodania formularza na stronę, będzie miał postać [sign_form_1]. Funkcja ob_start() uruchamia buforowanie wyjścia HTML, natomiast ob_get_clean() zwraca zawartość tego bufora.

Jeśli dodaliśmy shortcode do jednej ze stron, formularz powinien być już widoczny. Wciśnięcie przycisku „Register” nie wywołuje jednak jeszcze żadnej akcji. Zajmijmy się teraz obsługą formularza.

Zależy nam na tym, aby dane wprowadzone w formularzu, po kliknięciu przycisku „Register”, zostały zapisane w bazie danych. W tym celu utworzymy funkcję, która będzie odpowiedzialna za zapis tych danych.

Mała uwaga: wielu programistów wydzieliłoby taką funkcję do osobnego pliku. Na potrzeby tego tutorialu pozwolę sobie jednak umieścić ją w głównym pliku wtyczki, ponieważ uważam, że będzie to bardziej czytelne dla osób początkujących.

Po dodaniu funkcji elp_handle_reservation_submission() plik event-list-plugin.php wygląda następująco:

<?php
/*
Plugin Name: Event List Plugin
Description: A custom form for event submission
Version: 1.0
Author: Your Name
*/

register_activation_hook(__FILE__, 'elp_activate');

function elp_activate()
{
    require_once plugin_dir_path(__FILE__) . 'includes/elp-database-setup.php';
    elp_create_table();
}

function elp_render_reservation_form()
{
    ob_start(); // Start output buffering

    // Include the form template
    include plugin_dir_path(__FILE__) . 'templates/sign-form1.php';

    return ob_get_clean(); // Return the form HTML
}

add_shortcode('sign_form_1', 'elp_render_reservation_form');

function elp_handle_reservation_submission()
{
    // Verify nonce for security
    if (! isset($_POST['elp_reservation_nonce']) || ! wp_verify_nonce($_POST['elp_reservation_nonce'], 'elp_submit_reservation_action')) {
        wp_die('Security check failed');
    }

    // Sanitize and validate form data
    $user_name = sanitize_text_field($_POST['user_name']);
    $user_email = sanitize_email($_POST['user_email']);

    // Save to database
    global $wpdb;
    $table_name = $wpdb->prefix . 'event_list';

    $wpdb->insert(
        $table_name,
        array(
            'user_name' => $user_name,
            'user_email' => $user_email,
        )
    );
    // Redirect user after submission
    wp_redirect(home_url('/thank-you-page/')); // Create a thank you page first
    exit;
}

add_action('admin_post_elp_submit_reservation', 'elp_handle_reservation_submission');

W uproszczeniu funkcja ta pobiera zawartość pól formularza i — po ich walidacji oraz oczyszczeniu danych za pomocą funkcji sanitize_text_field() i sanitize_email() — korzystając z metody $wpdb->insert(), zapisuje wartości user_name oraz user_email w utworzonej wcześniej tabeli bazy danych.

Wartość id jest dodawana automatycznie (zdefiniowaliśmy ją jako AUTO_INCREMENT), natomiast pole status domyślnie ustawiane jest na wartość "pending".

Funkcja add_action() poprzez pierwszy parametr admin_post_elp_submit_reservation łączy akcję wysłania formularza (pole action w formularzu) z funkcją odpowiedzialną za zapis danych do bazy danych.

Mamy już nasze dane w bazie danych, teraz przydałoby się dodać możliwość odczytywania ich w panelu admina w WordPressie. Zajmiemy się tym w kolejnej części tutorialu.