Jak stworzyć własne funkcje w functions.php

dowiedz się

Plik functions.php to serce modyfikacji motywu: tu dopiszesz własne akcje, filtry i skróty, zmienisz zachowanie front-endu oraz panelu administratora, a także dołączysz klasy pomocnicze. Poniższa instrukcja przeprowadzi Cię od przygotowania środowiska, przez stworzenie pierwszych funkcji, po integrację z mechanizmem hooków. Znajdziesz też praktyczne przykłady gotowe do wklejenia oraz wskazówki dotyczące organizacji, testów i kontroli jakości zmian, aby rozwijać motyw świadomie i bezpiecznie.

Przygotowanie środowiska i dobre praktyki

Czym jest plik functions.php

W motywie plik functions.php ładuje się automatycznie przy każdym żądaniu. To doskonałe miejsce na definicje narzędzi, rejestrację wsparcia motywu (miniatury, menu, style), dodanie filtrowania i akcji oraz szybkie poprawki. Pamiętaj jednak, że to nie zamiennik wtyczki: logika, która ma działać niezależnie od motywu, powinna znaleźć się w wtyczce.

W praktyce functions.php pełni rolę kleju motywu: łączy funkcje z odpowiednimi zdarzeniami, ładuje pliki z katalogu inc/, inicjuje ustawienia i w miarę potrzeb warunkowo uruchamia kod wyłącznie tam, gdzie to konieczne (np. tylko w panelu administracyjnym lub na konkretnych typach wpisów).

Motyw potomny (child theme)

Jeśli korzystasz z gotowego motywu, twórz własne modyfikacje w motywie potomnym. Dzięki temu aktualizacje motywu nadrzędnego nie nadpiszą Twoich zmian. Struktura: wp-content/themes/nazwa-child/ i wewnątrz własny style.css oraz functions.php. W functions.php motywu potomnego dodaj kolejność ładowania stylów i skryptów oraz własne funkcje z unikalnym prefiksem, by uniknąć konfliktów.

Przykład dołączenia stylu motywu nadrzędnego: function mychild_enqueue_styles() { wp_enqueue_style(’parent-style’, get_template_directory_uri() . '/style.css’); } add_action(’wp_enqueue_scripts’, 'mychild_enqueue_styles’);

Bezpieczeństwo i kopie zapasowe

Przed edycją utwórz kopię pliku i upewnij się, że masz dostęp do SFTP lub menedżera plików na hostingu. Aktywuj tryb debug: w wp-config.php ustaw define(’WP_DEBUG’, true);, a błędy loguj do pliku przez define(’WP_DEBUG_LOG’, true);. Wrażliwe operacje zabezpieczaj uprawnieniami (current_user_can) i nonce’ami (wp_create_nonce, wp_verify_nonce). W danych wejściowych stosuj sanetyzację (sanitize_text_field, esc_url_raw) i eskapowanie na wyjściu (esc_html, esc_attr).

Struktura i organizacja kodu

Gdy kod rośnie, przenieś część logiki do katalogu inc/ i ładuj pliki przez require_once get_stylesheet_directory() . '/inc/custom-post-types.php’;. Grupy funkcji rozdziel tematycznie: inc/hooks.php, inc/admin.php, inc/frontend.php. Stosuj prefiksy, np. mytheme_, aby uniknąć kolizji nazw. Funkcje warunkuj: jeśli dana biblioteka jest dostępna, jeśli panel to is_admin(), jeśli strona to warunki typu is_singular(’product’).

Podstawy tworzenia funkcji i ich ładowanie

Tworzenie pierwszej funkcji

Funkcję zapisujesz w stylu: function mytheme_register_support() { add_theme_support(’post-thumbnails’); add_theme_support(’title-tag’); register_nav_menus([’primary’ => 'Menu główne’]); } add_action(’after_setup_theme’, 'mytheme_register_support’);. Zwróć uwagę na odroczenie działania: definicja funkcji jest w pliku, ale uruchomienie następuje dopiero na odpowiedniej akcji.

Drobne narzędzie do pobrania skróconego opisu: function mytheme_get_short_text($text, $limit = 140) { $text = wp_strip_all_tags($text); if (mb_strlen($text) <= $limit) { return $text; } return mb_substr($text, 0, $limit) . '…'; }. To pomocnicza funkcja, którą wywołasz w szablonach bezpośrednio: echo mytheme_get_short_text(get_the_content(), 180);

Zasięg, kolizje i prefiksowanie

Functions.php jest ładowany globalnie, więc nazwy bez prefiksu łatwo zderzą się z innymi. Przyjmij konwencję: prefiks z nazwą motywu lub projektu, np. mytheme_. Dodatkowo w kluczowych miejscach użyj if (!function_exists(’mytheme_function_name’)) { function mytheme_function_name() { /*…*/ } } aby umożliwić nadpisanie w motywie potomnym.

Warunkowe ładowanie i sprawdzanie środowiska

Unikaj pracy w ciemno. Przykłady: jeśli jakiś fragment ma dotyczyć tylko frontu, opakuj go w if (!is_admin()) { add_action(’wp_enqueue_scripts’, 'mytheme_enqueue’); }. Do panelu: if (is_admin()) { add_action(’admin_init’, 'mytheme_admin_boot’); }. Dla konkretnych szablonów: if (is_page_template(’templates/landing.php’)) { /* landing-only */ } — i najlepiej umieścić to wewnątrz hooków szablonów, by nie sprawdzać tego na każdej stronie bez potrzeby.

Stałe, konfiguracja i pliki pomocnicze

Zdefiniuj stałe ułatwiające ścieżki: if (!defined(’MYTHEME_PATH’)) { define(’MYTHEME_PATH’, get_stylesheet_directory()); } if (!defined(’MYTHEME_URI’)) { define(’MYTHEME_URI’, get_stylesheet_directory_uri()); }. Dzięki temu w enqueue lub przy require będzie krócej i czytelniej. Dla czytelności duże fragmenty (np. rejestracja CPT, taksonomii, shortcode’ów) przenieś do inc/ i dołączaj tylko raz przez require_once.

Integracja z WordPress: akcje i filtry

Hooki akcji (add_action)

Akcje to punkty w cyklu ładowania, w których możesz „zrobić coś”. Przykłady: after_setup_theme (włączasz wsparcie motywu), init (rejestrujesz CPT), wp_enqueue_scripts (ładujesz skrypty), admin_menu (dodajesz strony w panelu). Składnia: add_action(’nazwa_akcji’, 'twoja_funkcja’, $priorytet = 10, $liczba_argumentów = 1). Funkcja callback przyjmuje argumenty, jeśli dany hook je przekazuje.

Przykład: function mytheme_enqueue_assets() { wp_enqueue_style(’mytheme-style’, MYTHEME_URI . '/assets/css/style.css’, [], '1.0.0′); wp_enqueue_script(’mytheme-app’, MYTHEME_URI . '/assets/js/app.js’, [’jquery’], '1.0.0′, true); } add_action(’wp_enqueue_scripts’, 'mytheme_enqueue_assets’);

Hooki filtrów (add_filter)

Filtry pozwalają modyfikować wartość przed jej użyciem. Składnia: add_filter(’nazwa_filtra’, 'twoja_funkcja’, 10, 1). Przykład zmiany długości zajawki: function mytheme_excerpt_length($length) { return 24; } add_filter(’excerpt_length’, 'mytheme_excerpt_length’);. Przykład modyfikacji tytułu: function mytheme_title_prefix($title) { if (is_singular()) { return '★ ’ . $title; } return $title; } add_filter(’the_title’, 'mytheme_title_prefix’);

Priorytety, liczba argumentów i kolejność

Priorytet steruje kolejnością: niższy numer = wcześniej. Gdy wiele wtyczek i motyw próbują modyfikować tę samą rzecz, odpowiedni priorytet rozwiąże konflikt. Jeśli filtr/akcja podaje więcej argumentów (np. the_content z dodatkowymi danymi), ustaw czwarty parametr add_filter, a w samej funkcji zadeklaruj odpowiednią liczbę parametrów.

Usuwanie i nadpisywanie hooków

Aby usunąć wcześniejszy callback, użyj remove_action lub remove_filter, podając identyczną nazwę funkcji i priorytet. Przykład: remove_action(’wp_head’, 'print_emoji_detection_script’, 7); remove_action(’wp_print_styles’, 'print_emoji_styles’);. Nadpisywanie bywa możliwe przez wyższy priorytet albo wcześniejsze odpięcie oryginalnego callbacka.

Praktyczne przykłady i gotowe fragmenty

Rejestracja shortcode’u

Prosty shortcode do wstawienia przycisku: function mytheme_btn_shortcode($atts, $content = ”) { $atts = shortcode_atts([’url’ => '#’, 'style’ => 'primary’], $atts, 'btn’); $url = esc_url($atts[’url’]); $style = sanitize_html_class($atts[’style’]); $label = esc_html($content ?: 'Zobacz’); return ’’ . $label . ’’; } add_shortcode(’btn’, 'mytheme_btn_shortcode’);. Użycie w treści: [btn url=”https://example.com” style=”secondary”]Czytaj więcej[/btn]

Modyfikacje treści i nawigacji

Własny excerpt z wielokropkiem i linkiem: function mytheme_excerpt_more($more) { if (is_admin()) return $more; return ’ … czytaj dalej’; } add_filter(’excerpt_more’, 'mytheme_excerpt_more’);. Nawigacja okruszkowa: function mytheme_breadcrumbs() { $out = ’

’; echo $out; }

Optymalizacja ładowania skryptów i stylów

Odłącz zbędne skrypty na stronach, które ich nie potrzebują: function mytheme_optimize_assets() { if (!is_page(’kreator’)) { wp_dequeue_script(’contact-form-7′); wp_dequeue_style(’contact-form-7′); } } add_action(’wp_enqueue_scripts’, 'mytheme_optimize_assets’, 100);. Dla zewnętrznych skryptów rozważ defer/async: add_filter(’script_loader_tag’, function($tag, $handle, $src) { if (’mytheme-app’ === $handle) { return ’’; } return $tag; }, 10, 3);

Cache aplikacyjny i dane tymczasowe

Gdy generujesz ciężkie zapytania, zapamiętaj wynik: function mytheme_top_posts() { $cached = get_transient(’mytheme_top_posts’); if (false !== $cached) return $cached; $q = new WP_Query([’posts_per_page’ => 5, 'orderby’ => 'comment_count’]); $posts = wp_list_pluck($q->posts, 'post_title’); set_transient(’mytheme_top_posts’, $posts, HOUR_IN_SECONDS); return $posts; }. Inwaliduj cache po publikacji: add_action(’save_post’, function() { delete_transient(’mytheme_top_posts’); });

Zmiany w panelu administracyjnym

Ukryj niepotrzebne widżety kokpitu: function mytheme_cleanup_dashboard() { remove_meta_box(’dashboard_quick_press’, 'dashboard’, 'side’); remove_meta_box(’dashboard_primary’, 'dashboard’, 'side’); } add_action(’wp_dashboard_setup’, 'mytheme_cleanup_dashboard’);. Własna strona ustawień: function mytheme_admin_menu() { add_menu_page(’Ustawienia motywu’, 'Motyw’, 'manage_options’, 'mytheme’, 'mytheme_settings_page’, 'dashicons-admin-generic’); } add_action(’admin_menu’, 'mytheme_admin_menu’); function mytheme_settings_page() { echo ’

Ustawienia Motywu

Tu zbuduj formularz opcji.

’; }

Formularze, walidacja, nonce

Obsługa akcji z formularza: add_action(’admin_post_mytheme_save’, 'mytheme_handle_save’); function mytheme_handle_save() { if (!current_user_can(’manage_options’)) wp_die(’Brak uprawnień’); check_admin_referer(’mytheme_save_nonce’); $title = sanitize_text_field($_POST[’mytheme_title’] ?? ”); update_option(’mytheme_title’, $title); wp_redirect(add_query_arg(’saved’, '1′, wp_get_referer())); exit; }. W formularzu dodaj: wp_nonce_field(’mytheme_save_nonce’); i action=”admin-post.php” z inputem name=”action” value=”mytheme_save”.

REST API: własny endpoint

Wystaw dane do integracji: add_action(’rest_api_init’, function() { register_rest_route(’mytheme/v1′, '/latest’, [’methods’ => 'GET’, 'callback’ => 'mytheme_rest_latest’]); }); function mytheme_rest_latest(WP_REST_Request $req) { $q = new WP_Query([’posts_per_page’ => 3]); $data = array_map(function($p) { return [’id’ => $p->ID, 'title’ => get_the_title($p), 'link’ => get_permalink($p)]; }, $q->posts); return rest_ensure_response($data); }. Pamiętaj o uprawnieniach i buforowaniu wyników.

Filtrowanie uploadów i typów MIME

Dodaj SVG z ostrożnością: function mytheme_mime_types($mimes) { $mimes[’svg’] = 'image/svg+xml’; return $mimes; } add_filter(’upload_mimes’, 'mytheme_mime_types’);. Rozsądnie: waliduj pliki (np. skan zawartości) i ogranicz uprawnienia do roli edytora/administratora.

Własne typy wpisów i taksonomie

Rejestracja CPT: add_action(’init’, function() { register_post_type(’portfolio’, [’label’ => 'Portfolio’, 'public’ => true, 'supports’ => [’title’, 'editor’, 'thumbnail’], 'show_in_rest’ => true, 'has_archive’ => true]); });. Taksonomia: register_taxonomy(’tech’, 'portfolio’, [’label’ => 'Technologie’, 'hierarchical’ => false, 'show_in_rest’ => true]);. Pamiętaj o przepisywaniu URL: po rejestracji wejdź w Ustawienia › Bezpośrednie odnośniki lub wywołaj flush_rewrite_rules() raz po aktywacji.

Międzynarodowienie (i18n) i tłumaczenia

Oznacz teksty funkcją tłumaczeń: __(’Tekst’, 'mytheme’) lub esc_html__(’Tekst’, 'mytheme’). Załaduj domenę w after_setup_theme: load_theme_textdomain(’mytheme’, MYTHEME_PATH . '/languages’);. Twórz pliki .po/.mo i dbaj o zgodność kontekstu, aby tłumaczenia były poprawne.

Kontrola jakości i standardy kodu

Stosuj PSR-ish dla PHP i WordPress Coding Standards. Automatyzuj sprawdzanie: użyj PHP_CodeSniffer i rulesetów WPCS, uruchamiaj w CI. Dodaj statyczną analizę (Psalm/PHPStan) oraz testy jednostkowe dla funkcji bez efektów ubocznych. To zmniejsza ryzyko regresji i ułatwia utrzymanie.

Diagnostyka problemów i logowanie

Do szybkiej inspekcji: error_log(print_r($zmienna, true));, w przeglądarce tymczasowo var_dump z die() wyłącznie lokalnie. W WordPress dostępne są helpery typu doing_it_wrong_log, a także WP-CLI do zadań inspekcyjnych. Mierz wpływ na wydajność: microtime(true) przed/po oraz Query Monitor do przeglądu zapytań SQL i hooków.

  • Włącz WP_DEBUG i WP_DEBUG_LOG na środowiskach deweloperskich.
  • Oznaczaj kosztowne fragmenty komentarzami i rozważ ich cache.
  • Wprowadzaj zmiany iteracyjnie, commitami w systemie kontroli wersji.

Checklist przed wdrożeniem

  • Czy każda funkcja ma prefiks i opis celu?
  • Czy hook jest poprawny, a priorytet uzasadniony?
  • Czy dane są sanetyzowane przy wejściu i eskapowane przy wyjściu?
  • Czy wyłączono debug na produkcji i włączono cache?
  • Czy wprowadzono ewentualny mechanizm wycofania (feature flag) dla ryzykownych zmian?

Aby zamknąć całość w spójnej praktyce: edytuj w motywie potomnym, trzymaj porządek w inc/, przypinaj funkcje do właściwych hooków z właściwym priorytetem, wykorzystuj cache i mierz efekty. Bilans między elastycznością a kontrolą osiągniesz, gdy konsekwentnie stosujesz prefiksy, dokumentację w komentarzach i testy lokalne przed publikacją.

Dla ułatwienia orientacji, poniżej wyróżniam słowa-klucze, do których warto często wracać podczas pracy: WordPress, functions.php, funkcje, hooki, filtry, bezpieczeństwo, wydajność, child theme, debugowanie, transienty.

< Powrót

Zapisz się do newslettera


Zadzwoń Napisz