Wtyczki to sposób na rozszerzanie WordPressa bez modyfikacji core'a. Nawet jeśli jesteś frontend developerem, umiejętność napisania prostej wtyczki przyda się częściej niż myślisz — integracje z API, czyli Application Programming Interface, definiuje sposób komunikacji między aplikacjami lub modułami., custom shortcodes, modyfikacje zachowania sklepu WooCommerce.
W tym artykule stworzymy działającą wtyczkę od zera. Bez frameworków, bez boilerplate'ów — czysty PHP i WordPress API.
Krótka odpowiedź: Wtyczka WordPress to folder w wp-content/plugins/ z plikiem PHP zawierającym specjalny nagłówek komentarza. Rozszerzasz funkcjonalność przez podpinanie się pod hooki (add_action, add_filter), panel ustawień budujesz przez Settings API, a dane wejściowe zawsze sanityzujesz przed zapisem i escapujesz przed wyświetleniem. Wszystkie funkcje i stałe powinny mieć unikalny prefiks, żeby uniknąć konfliktów z innymi wtyczkami.
Co zbudujemy?
Wtyczkę "Reading Time" która:
Oblicza czas czytania dla każdego posta
Wyświetla go automatycznie przed treścią
Ma panel ustawień w adminie
Obsługuje shortcode do ręcznego umieszczenia
Struktura wtyczki
Minimalna wtyczka to jeden plik PHP. Ale dla porządku:
Code
wp-content/plugins/
└── reading-time/
├── reading-time.php # Główny plik (wymagany)
├── includes/
│ ├── functions.php # Funkcje pomocnicze
│ └── admin.php # Panel admina
├── assets/
│ └── style.css # Style
└── readme.txt # Opis dla wordpress.org
Krok 1: Główny plik wtyczki
Code
<?php/** * Plugin Name: Reading Time * Plugin URI: https://example.com/reading-time * Description: Wyświetla szacowany czas czytania dla postów * Version: 1.0.0 * Requires at least: 6.0 * Requires PHP: 8.0 * Author: Maciej Sala * Author URI: https://example.com * License: GPL v2 or later * Text Domain: reading-time */// Zabezpieczenie przed bezpośrednim dostępemif (!defined('ABSPATH')) { exit;}// Stałedefine('RT_PLUGIN_DIR', plugin_dir_path(__FILE__));define('RT_PLUGIN_URL', plugin_dir_url(__FILE__));define('RT_VERSION', '1.0.0');// Ładowanie plikówrequire_once RT_PLUGIN_DIR . 'includes/functions.php';// Admin tylko w paneluif (is_admin()) { require_once RT_PLUGIN_DIR . 'includes/admin.php';}// Aktywacjaregister_activation_hook(__FILE__, 'rt_activate');function rt_activate() { // Domyślne ustawienia $defaults = [ 'words_per_minute' => 200, 'display_position' => 'before_content', 'post_types' => ['post'], ]; add_option('rt_settings', $defaults);}// Deaktywacjaregister_deactivation_hook(__FILE__, 'rt_deactivate');function rt_deactivate() { // Cleanup jeśli potrzebny}// Odinstalowanie (dla większych wtyczek zwykle lepszy jest osobny uninstall.php)register_uninstall_hook(__FILE__, 'rt_uninstall');function rt_uninstall() { delete_option('rt_settings');}
Nagłówek w komentarzu jest wymagany — WordPress rozpoznaje po nim wtyczkę.
// W głównym pliku, po stałychadd_action('init', 'rt_load_textdomain');function rt_load_textdomain() { load_plugin_textdomain( 'reading-time', false, dirname(plugin_basename(__FILE__)) . '/languages' );}// Użycie w kodzie$label = sprintf( _n('%d minuta czytania', '%d minut czytania', $minutes, 'reading-time'), $minutes);
Wszystkie funkcje i stałe zaczynaj od unikalnego prefixu (rt_ w naszym przypadku), aby uniknąć konfliktów.
2. Sanityzacja danych
Code
// Wejście od użytkownika$input = sanitize_text_field($_POST['field']);// Escape przy wyświetlaniuecho esc_html($variable);echo esc_attr($attribute);echo esc_url($url);
3. Nonces dla formularzy
Code
// W formularzuwp_nonce_field('rt_save_settings', 'rt_nonce');// Przy zapisieif ( !isset($_POST['rt_nonce']) || !wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['rt_nonce'])), 'rt_save_settings')) { die('Security check failed');}
4. Capability checks
Code
if (!current_user_can('manage_options')) { wp_die('Brak uprawnień');}
Utwórz folder w wp-content/plugins/nazwa-wtyczki/ i główny plik PHP z nagłówkiem komentarza zawierającym Plugin Name: — WordPress rozpoznaje wtyczkę po tym nagłówku. Dodaj zabezpieczenie przed bezpośrednim dostępem (if (!defined('ABSPATH')) exit;) i możesz zacząć podpinać własny kod przez add_action() i add_filter(). Minimalna wtyczka to dosłownie kilkanaście linii kodu.
Jak używać Settings API do panelu ustawień wtyczki?
Zarejestruj stronę menu przez add_options_page() wewnątrz hooka admin_menu. Następnie w hooku admin_init użyj register_setting(), add_settings_section() i add_settings_field() do zdefiniowania formularza. Dane zapisuje WordPress automatycznie przy wysłaniu formularza — musisz tylko podać sanitize_callback do walidacji i sanityzacji danych wejściowych. To solidniejsze podejście niż ręczna obsługa $_POST.
Jak bezpiecznie obsługiwać dane wejściowe w wtyczce WordPress?
Zasada jest prosta: sanityzuj na wejściu, escapuj na wyjściu. Na wejściu używaj sanitize_text_field(), absint(), sanitize_email() zależnie od typu danych. Na wyjściu w HTML używaj esc_html(), w atrybutach esc_attr(), w URLach esc_url(). Dla formularzy zapisujących dane do bazy zawsze weryfikuj nonce przez wp_verify_nonce().
Czym różnią się haki aktywacji, deaktywacji i odinstalowania?
Hook aktywacji (register_activation_hook) uruchamia się jednorazowo przy włączeniu wtyczki — dobry moment na tworzenie tabel w bazie lub zapisanie domyślnych ustawień. Hook deaktywacji uruchamia się przy wyłączeniu wtyczki, ale dane powinny zostać (użytkownik może wtyczkę reaktywować). Hook odinstalowania (lub plik uninstall.php) uruchamia się przy usunięciu wtyczki — tu czyścisz opcje i tabele, żeby nie zostawiać śmieci.
Jak dodać shortcode w wtyczce WordPress?
Zarejestruj shortcode przez add_shortcode('nazwa', 'funkcja_callback'). Callback otrzymuje tablicę $atts z atrybutami i opcjonalnie $content dla shortcode'ów z zawartością. Użyj shortcode_atts() do scalenia podanych atrybutów z domyślnymi wartościami. Shortcode powinien zwracać HTML (przez return, nie echo), żeby mógł być osadzony w dowolnym miejscu.
Jak załadować style i skrypty tylko tam, gdzie są potrzebne?
Używaj wp_enqueue_style() i wp_enqueue_script() wewnątrz hooka wp_enqueue_scripts. Dla zasobów panelu admina użyj hooka admin_enqueue_scripts. Żeby załadować zasoby tylko na konkretnych stronach, sprawdzaj warunki przez is_singular(), is_page() itp. lub parametr $hook dostępny w admin_enqueue_scripts. Nigdy nie dodawaj <link> ani <script> bezpośrednio przez echo.
Jak przetestować wtyczkę WordPress podczas developmentu?
Włącz tryb debug przez define('WP_DEBUG', true) i define('WP_DEBUG_LOG', true) w wp-config.php — błędy PHP trafią do wp-content/debug.log. Używaj error_log(print_r($zmienna, true)) do podglądu danych. Możesz też tymczasowo wyświetlać dane w stopce strony dla zalogowanych adminów przez hook wp_footer z zabezpieczeniem current_user_can('manage_options').
Podsumowanie
Tworzenie wtyczki WordPress to:
Nagłówek PHP z metadanymi wtyczki
Hooks do podpinania się w odpowiednich miejscach
Settings API dla konfiguracji w adminie
Sanityzacja każdego inputu od użytkownika
Prefixowanie wszystkich funkcji
Sensowny uninstall i brak śmieci po deaktywacji
Nasza wtyczka Reading Time to ~200 linii kodu, ale pokazuje wszystkie kluczowe koncepty. Od tego wzorca możesz rozbudować praktycznie dowolną funkcjonalność.
Jeśli chcesz dobrze poukładać WordPressa, WooCommerce albo headless setup jeszcze przed wdrożeniem, skontaktuj się ze mną. Pomagam ocenić trade-offy techniczne, redakcyjne i biznesowe, zanim projekt zacznie generować kosztowny chaos.
Maciej Sala — project manager i frontendowiec z doświadczeniem w marketingu internetowym. Na co dzień pracuję z Reactem, Next.js i TypeScriptem, łącząc perspektywę produktową z praktycznym podejściem do kodu. Przez kilka lat związany z branżą gier wideo jako project manager i game designer.
Absolwent historii na Uniwersytecie Jagiellońskim i studiów podyplomowych z marketingu internetowego na Akademii Górniczo-Hutniczej w Krakowie. Poza pracą trenuje na siłowni, maluje figurki i realizuje własne projekty.
Astro.js vs Next.js — które narzędzie wybrać w 2026 roku?
Fachowe porównanie Astro.js i Next.js z perspektywy developera pracującego na co dzień w Next.js. Architektura, wydajność, SEO, DX, koszty i konkretne use case — z benchmarkami i przykładami kodu.
WordPress → Next.js — migracja treści, redirecty 301 i zachowanie pozycji SEO
Jak przenieść stronę z WordPress na Next.js bez utraty pozycji w Google? Eksport treści, mapowanie URL, redirecty 301, migracja obrazów i weryfikacja indeksacji.
Google Search Console + Next.js — indeksacja, błędy, performance i co z nimi robić
Jak korzystać z Google Search Console dla strony Next.js? Weryfikacja, sitemap, indeksacja, Core Web Vitals, crawl budget i najczęstsze problemy — praktyczny poradnik.