Jak stworzyć własne pola ACF i używać ich w motywach - icomMedia

Jak stworzyć własne pola ACF i używać ich w motywach

Jak stworzyć własne pola ACF i używać ich w motywach

ACF bywa pierwszym narzędziem, po które sięga deweloper chcący nadać treściom w serwisie strukturalny kształt i kontrolę edycyjną. Pozwala projektować pola dopasowane do projektu, mapować je do elementów wizualnych i wdrażać spójny model danych, dzięki któremu redaktorzy wprowadzają treści szybko i bezpiecznie. W niniejszym poradniku znajdziesz praktyczne wskazówki: od planowania i tworzenia pól, przez ich implementację w szablonach, po zagadnienia wydajności, bezpieczeństwa i integracji z API. Będą fragmenty kodu, wzorce projektowe i porady, które ułatwią utrzymanie projektu na lata.

Planowanie struktury danych i wybór typów pól

Zanim stworzysz pierwszą grupę pól, poświęć chwilę na model danych. Ustal, jakie elementy w projekcie są stałe, a jakie powtarzalne; które będą edytowane globalnie (np. stopka, dane kontaktowe), a które w kontekście pojedynczego wpisu czy strony. Zdefiniuj słownik pojęć, aby cały zespół (designer, copywriter, programista) używał identycznych nazw. Dobre nazwy kluczy sprawiają, że kod pozostaje czytelny i łatwy do wyszukania.

ACF oferuje szerokie spektrum typów pól: tekst, textarea, liczba, e-mail, URL, obraz, galeria, plik, selekt, checkbox, radio, true/false, data i czas, kolor, Google Map, relacje do innych treści, pola grupujące (Group), powtarzalne (Repeater) i układy (Flexible Content). Wersja PRO dodaje potężne narzędzia, które umożliwiają budowę modularnych sekcji. Zastanów się, czy dla danej sekcji lepszy będzie Repeater (zestaw powtarzalny jednego typu), czy Flexible Content (różne layouty do wyboru). Warto też określić reguły lokalizacji: gdzie pola mają być widoczne — w typie wpisu, taksonomii, stronie opcji, widżecie, menu czy w edytorze blokowym.

Strategia nazewnictwa powinna obejmować prefiksy dla grup i spójny styl dla kluczy: np. hero_title, hero_cta_url, hero_background_image. Długofalowo ułatwia to wyszukiwanie w repozytorium i refaktoryzację. Pomyśl również o spójnych wartościach domyślnych i opisach pól, aby redaktorzy nie musieli zgadywać kontekstu użycia.

Jednym z częstych dylematów jest budowa relacji między treściami. Pola Relationship, Post Object czy Taxonomy to wygodny sposób, by łączyć wpisy, produkty, wydarzenia czy autorów. W takich przypadkach kluczowe jest zrozumienie, jak przechowywane są wartości w bazie (post meta, term meta), jak będą sortowane i filtrowane, oraz jak zadbać o ich relacyjne spójności w przyszłości.

Tworzenie pól w panelu i przez kod: Local JSON, reużywalność, wersjonowanie

Najprostsza droga to zdefiniowanie grupy pól w panelu administracyjnym ACF. Po zapisaniu, wtyczka może generować pliki JSON, które zezwalają na wersjonowanie ich w Gicie i automatyczną synchronizację między środowiskami. Aby włączyć Local JSON, ustaw katalog w motywie lub wtyczce i podłącz odpowiednie filtry:

<?php
add_filter(’acf/settings/save_json’, function($path) {
  return get_stylesheet_directory() . '/acf-json’;
});
add_filter(’acf/settings/load_json’, function($paths) {
  $paths[] = get_stylesheet_directory() . '/acf-json’;
  return $paths;
});

Dzięki Local JSON zmiany w panelu są zapisywane do plików, a na innym środowisku ACF zaproponuje ich synchronizację. To bardzo wygodne rozwiązanie dla zespołów i CI/CD. Alternatywą, preferowaną w niektórych organizacjach, jest deklaratywne rejestrowanie pól w PHP. Wówczas nie polegasz na panelu i JSON, tylko trzymasz definicję w kodzie motywu lub wtyczki:

<?php
add_action(’acf/init’, function() {
  if (function_exists(’acf_add_local_field_group’)) {
    acf_add_local_field_group([
      'key’ => 'group_hero’,
      'title’ => 'Sekcja Hero’,
      'fields’ => [
        [
          'key’ => 'field_hero_title’,
          'label’ => 'Tytuł’,
          'name’ => 'hero_title’,
          'type’ => 'text’,
        ],
        [
          'key’ => 'field_hero_bg’,
          'label’ => 'Tło’,
          'name’ => 'hero_background’,
          'type’ => 'image’,
          'return_format’ => 'id’,
        ],
      ],
      'location’ => [
        [[ 'param’ => 'post_type’, 'operator’ => '==’, 'value’ => 'page’ ]],
      ],
    ]);
  }
});

Jeżeli chcesz dodawać ustawienia globalne (np. dane kontaktowe, logotypy, stopkę), utwórz stronę opcji:

<?php
add_action(’acf/init’, function() {
  if (function_exists(’acf_add_options_page’)) {
    acf_add_options_page([
      'page_title’ => 'Ustawienia motywu’,
      'menu_title’ => 'Ustawienia’,
      'menu_slug’ => 'theme-settings’,
      'capability’ => 'edit_theme_options’,
      'redirect’ => false,
    ]);
  }
});

W przypadku zespołowej pracy ważne są konwencje: czy definicje pól trzymamy w JSON, czy w PHP, jak nazywamy pliki, gdzie je ładujemy, jak podpisujemy commity przy zmianach w polach. Zadbaj o instrukcję dla redaktorów, jak postępować przy przenoszeniu pól między środowiskami i jak rozwiązywać konflikty JSON.

Użycie pól w szablonach i blokach edytora

Pola ACF najczęściej odczytuje się funkcjami get_field() i the_field(). W przypadku obrazów i plików kontroluj format zwracanej wartości (ID, URL lub tablica). Oto proste przykłady użycia w szablonie pojedynczej strony:

<?php
$title = get_field(’hero_title’);
$bg_id = get_field(’hero_background’);
if ($title) {
  echo '<h1>’ . esc_html($title) . '</h1>’;
}
if ($bg_id) {
  $bg_url = wp_get_attachment_image_url($bg_id, 'full’);
  echo '<div class=”hero” style=”background-image:url(’ . esc_url($bg_url) . ’)”></div>’;
}

Jeśli masz pola globalne na stronie opcji, dodaj drugi parametr 'option’:

<?php
$phone = get_field(’contact_phone’, 'option’);
if ($phone) {
  echo '<a href=”tel:’ . esc_attr(preg_replace(’/\s+/’, ”, $phone)) . '”>’ . esc_html($phone) . '</a>’;
}

Dla powtarzalnych struktur (Repeater) stosujesz pętlę:

<?php
if (have_rows(’faq_list’)):
  echo '<dl class=”faq”>’;
  while (have_rows(’faq_list’)): the_row();
    $q = get_sub_field(’question’);
    $a = get_sub_field(’answer’);
    echo '<dt>’ . esc_html($q) . '</dt><dd>’ . wp_kses_post($a) . '</dd>’;
  endwhile;
  echo '</dl>’;
endif;

W projektach używających edytora blokowego z ACF PRO możesz rejestrować własne bloki z polami. To świetny sposób, aby przenieść komponentową architekturę designu do edycji treści. Przykład rejestracji bloku i funkcji renderującej:

<?php
add_action(’acf/init’, function() {
  if (function_exists(’acf_register_block_type’)) {
    acf_register_block_type([
      'name’ => 'cta-box’,
      'title’ => __(’CTA Box’, 'your-textdomain’),
      'render_callback’ => 'render_cta_block’,
      'category’ => 'widgets’,
      'icon’ => 'megaphone’,
      'supports’ => [’align’ => true, 'anchor’ => true],
    ]);
  }
});
function render_cta_block($block) {
  $title = get_field(’title’) ?: 'Zapisz się’;
  $desc = get_field(’description’) ?: ”;
  $url = get_field(’url’) ?: '#’;
  echo '<section class=”cta” id=”’ . esc_attr($block[’id’]) . '”>’;
  echo '<h2>’ . esc_html($title) . '</h2><p>’ . esc_html($desc) . '</p>’;
  echo '<a class=”btn” href=”’ . esc_url($url) . '”>Działaj</a>’;
  echo '</section>’;
}

Warto pamiętać o dwóch praktykach: po pierwsze, rozbijaj widoki na małe szablony częściowe i przekazuj do nich tylko to, co potrzebne (np. get_template_part z tablicą args). Po drugie, nie mieszaj logiki pobierania danych z HTML — z czasem docenisz czystość kodu i łatwość testowania.

W dojrzałych projektach rozważ mapowanie surowych wartości ACF do obiektów PHP/DTO, co ułatwia walidację typów, testy jednostkowe i późniejsze refaktoryzacje. Dzięki temu warstwa widoku przestaje zależeć od szczegółów implementacyjnych w ACF.

Zaawansowane typy pól, konwencje i praktyczne wzorce

Przy polach obrazów zdecyduj, czy przechowujesz ID (rekomendowane), czy URL. ID daje dostęp do rozdzielczości, metadanych i automatycznych atrybutów. Dla Linku ustaw return_format na array, by otrzymać tytuł, URL i target w jednym. W przypadku Relationship i Post Object określ, czy chcesz pojedynczą wartość, czy tablicę. Pamiętaj, że Relationship może być kosztowny przy dużych bazach — filtruj dostępne typy wpisów, taksonomie i stosuj lazy-loading w UI, aby panel działał płynnie.

Group porządkuje pola w logiczne sekcje; Repeater pozwala budować listy; Flexible Content umożliwia mieszanie layoutów. Typ Taxonomy w trybie „Load & Save Terms” może automatycznie synchronizować przypisania kategorii/tagów przy zapisie. Z kolei pola klikalne typu True/False świetnie włączają warianty szablonów („pokaż/ukryj”).

Częstą potrzebą jest niestandardowa walidacja. ACF udostępnia filtr acf/validate_value, np. aby wymagać formatu numeru identyfikacyjnego:

<?php
add_filter(’acf/validate_value/name=company_nip’, function($valid, $value, $field, $input) {
  if (!$valid) return $valid;
  if (!preg_match(’/^[0-9]{10}$/’, $value)) {
    return 'NIP musi mieć 10 cyfr’;
  }
  return $valid;
}, 10, 4);

Możesz też modyfikować dane przy zapisie (acf/update_value) — np. normalizować numer telefonu lub usuwać zbędne spacje.

W przypadku treści modułowej z Flexible Content dobrym wzorcem jest mapowanie układów na oddzielne pliki szablonów. Każdy layout ma swój partial, a kontroler wybiera właściwy plik po nazwie układu. Zyskujesz izolację komponentów i porządek w repozytorium.

Jeśli edytor ma mieć presetowane opcje, skorzystaj z filtrów acf/load_field, aby dynamicznie załadować np. listę miast, ceny, czy stany zamówień. Dla złożonych wyborów rozważ tworzenie własnych typów pól (custom field types), gdzie frontend kontrolki budujesz w JS/React, a backend w PHP, zgodnie z API ACF dla deweloperów rozszerzeń.

Optymalizacja: wydajność, cache, bezpieczeństwo, dostępność

W projektach o dużym ruchu i wielu polach nie zapominaj o skali. Zacznij od profilowania: Query Monitor, Xdebug, Blackfire — zobacz, co naprawdę boli. Kluczowe zasady:

  • Batchuj odczyty meta: funkcje WordPressa cache’ują meta, gdy pobierasz posty przez WP_Query; nie rób osobnych zapytań dla każdego wpisu, jeśli możesz zwrócić je jednym zapytaniem i potem czytać get_field() per obiekt.
  • Ostrożnie z Relationship/Repeater wewnątrz pętli — mogą generować kaskady zapytań; stosuj transients lub wp_cache_set/wp_cache_get dla bloków/sekcji, które rzadko się zmieniają.
  • Unikaj sortowań po meta_value bez indeksów; gdy potrzebujesz sortowania po liczbie/dacie, trzymaj w polu metadanych wartość znormalizowaną (np. UNIX timestamp, int), ustaw meta_type i meta_key w WP_Query.
  • ACF Local JSON skraca czasy ładowania panelu, bo unika deserializacji z bazy przy każdej konfiguracji pól.

Przykład cache dla sekcji hero z unieważnianiem po zapisie wpisu:

<?php
function render_cached_hero($post_id) {
  $key = 'hero_’ . $post_id;
  $html = wp_cache_get($key, 'theme’);
  if ($html !== false) return $html;
  ob_start();
  $title = get_field(’hero_title’, $post_id);
  $bg_id = get_field(’hero_background’, $post_id);
  if ($title) echo '<h1>’ . esc_html($title) . '</h1>’;
  if ($bg_id) echo '<div class=”hero”>’ . wp_get_attachment_image($bg_id, 'full’) . '</div>’;
  $html = ob_get_clean();
  wp_cache_set($key, $html, 'theme’, 3600);
  return $html;
}
add_action(’save_post’, function($post_id) {
  wp_cache_delete(’hero_’ . $post_id, 'theme’);
});

W kontekście bezpieczeństwa pamiętaj o podstawach: escapuj output (esc_html, esc_attr, esc_url, wp_kses_post), waliduj input, sprawdzaj uprawnienia. ACF w panelu sam dba o nonce’y, ale jeśli tworzysz formularze na froncie (acf_form), weryfikuj capabilities i filtruj pola, których użytkownik nie powinien zmieniać. Zadbaj też o politykę mediów: odpowiednie rozmiary generowanych obrazów, atrybuty alt, lazy-loading i aria-labels poprawiają performance i dostępność.

Jeśli przechowujesz dane wrażliwe, rozważ szyfrowanie części wartości albo przynajmniej separację dostępu do grup pól przez role. Upewnij się, że backupy i logi nie wypisują prywatnych danych. Błędy szablonu nie powinny ujawniać struktury bazy — pokrywaj dane domyślne sensownymi fallbackami.

Ostatecznie, testuj komponenty wizualne w przeglądarkach i na urządzeniach mobilnych, sprawdzaj wpływ na TTFB, LCP i CLS. ACF to nie tylko dane, ale i astrożne renderowanie, aby zachować elastyczność bez kompromisów w UX.

Integracje i API: REST, GraphQL, wielojęzyczność, importy

Jeśli tworzysz architekturę headless lub hybrydową, dane z ACF warto wystawić w API. W rdzeniu dostępne jest REST API; wiele motywów korzysta też z WPGraphQL. Dla REST API możesz zarejestrować pola własnoręcznie:

<?php
add_action(’rest_api_init’, function() {
  register_rest_field(’page’, 'acf’, [
    'get_callback’ => function($obj) {
      return get_fields($obj[’id’]);
    },
    'schema’ => null,
  ]);
});

Takie rozwiązanie umożliwia frontom SPA/SSR pobieranie kompletnego pakietu danych w jednym żądaniu. Jeśli używasz WPGraphQL, zainstaluj rozszerzenie WPGraphQL for ACF, które automatycznie mapuje pola do schematu i zapewnia typowanie. Uważaj na prywatne pola (np. klucze API) — nie publikuj ich w publicznym API bez autoryzacji.

W projektach wielojęzycznych (Polylang, WPML) ustal strategię dla pól: czy mają być tłumaczone per język, czy współdzielone. ACF posiada opcje „Translatable” w integracjach, a edytorzy często potrzebują oddzielnych mediów i linków per język. Projektując strukturę, przewiduj tę złożoność już dziś, by uniknąć migracji jutro.

Jeśli łączysz serwis z systemami zewnętrznymi (CRM, DAM, ERP), rozważ trzymanie w ACF jedynie kluczy/ID i pobieranie danych na żądanie, albo synchronizację wsadową cronem do znormalizowanych pól. Wówczas łatwiej testować i skalować, a dostawców można zmieniać bez przepisywania frontu.

Migracje, eksporty, testy i długa perspektywa utrzymania

ACF wspiera eksport/import do JSON i PHP. W praktyce sprawdza się podejście: definicje w JSON (edycja w panelu), ale stałe fundamenty kluczowe dla działania motywu w PHP (immutable). Dzięki temu nowe sekcje można szybko klikać w panelu, a core pól krytycznych dla działania pozostaje nienaruszalny.

W migracjach treści pamiętaj o różnicach ID mediów między środowiskami. Gdy pola zwracają ID, na importach odtwarzaj biblioteki mediów albo stosuj mapy ID. Dla linków względnych buduj helpery, które przemapują domeny. Przy przenoszeniu Flexible Content testuj układy na seedowanych treściach, aby wychwycić brakujące partiale lub niekompletne style.

Testy: jednostkowe (mapowanie wartości ACF do DTO), integracyjne (render wybranych sekcji) i e2e (Cypress/Playwright) dla krytycznych ścieżek. Zautomatyzuj statyczną analizę PHP (PHPStan/Psalm) i kontrolę jakości kodu. W pipeline CI buduj też zrzut ACF JSON i sprawdzaj, czy nie powstały niesynchronizowane pliki w repo.

Monitoring jakości danych jest równie ważny, co sama konfiguracja. Włącz raporty o pustych polach wymaganych (required), ostrzeżenia o niewykorzystanych layoutach, a także sprawdzanie poprawności linków i obrazów. Dzięki temu utrzymasz porządek w rosnących projektach.

Najczęstsze pułapki i sprawdzona checklista wdrożeniowa

Najczęstsze błędy pojawiają się, gdy szybkie prototypowanie zamienia się w legacy. Oto typowe pułapki:

  • Brak strategii wersjonowania pól: mieszanka JSON i panelu bez synchronizacji, co prowadzi do nadpisywania definicji.
  • Niewłaściwe formaty zwrotu (np. obraz jako URL, gdy w szablonie oczekujesz ID) — skutkuje błędami i trudnym refaktorem.
  • Flexible Content bez konwencji nazewniczej layoutów i bez dedykowanych partiali — chaos w renderowaniu.
  • Duże Relationship bez ograniczeń zapytań i filtrów — spowolniony panel.
  • Brak escapingu i walidacji — potencjalne luki w XSS i niespójne dane.
  • Trzymanie danych globalnych w wielu miejscach (strony opcji, różne posty) — niespójność i błędy edytorskie.
  • Brak testów regresji wizualnej i brak seedów danych — kruchy front po drobnych zmianach pola.

Przed wdrożeniem na produkcję skorzystaj z checklisty:

  • Czy wszystkie grupy pól mają sensowne nazwy, opisy i wymagane flagi?
  • Czy return_format jest spójny z oczekiwaniami szablonów?
  • Czy ważne wartości mają domyślne fallbacki i czy front nie psuje layoutu przy pustych polach?
  • Czy zastosowano esc_html/esc_url/wp_kses_post w odpowiednich miejscach?
  • Czy cache’ujesz najdroższe sekcje i czy czyszczenie cache działa po zapisie?
  • Czy Local JSON jest w repo i czy synchronizacja działa na wszystkich środowiskach?
  • Czy pola globalne są na stronie opcji, a nie porozrzucane po pojedynczych stronach?
  • Czy pola wykorzystywane w API są bezpieczne i nie ujawniają kluczy prywatnych?
  • Czy role i capabilities ograniczają dostęp do edycji wrażliwych pól?
  • Czy edytor wie, jak używać layoutów i które pola są obowiązkowe?

Jeżeli integrujesz z wyszukiwarką (np. Elastic, Algolia), przemyśl indeksowanie wartości ACF. Czasem lepiej zdenormalizować część danych do własnych tabel lub do indeksu, niż generować skomplikowane meta_query. W obszarze SEO atomizuj dane: osobne pola dla meta title, opisu, Open Graph i danych strukturalnych; generuj je deterministycznie, ale daj możliwość nadpisania przez redaktora.

Praktyczne przykłady i gotowe fragmenty dla codziennej pracy

Szybki helper do pobierania obrazów z fallbackiem alt/title:

<?php
function theme_image($id, $size = 'large’, $attrs = []) {
  if (!$id) return ”;
  $defaults = [’class’ => 'img’];
  $attrs = array_merge($defaults, $attrs);
  $attr_html = ”;
  foreach ($attrs as $k => $v) {
    $attr_html .= ’ ’ . esc_attr($k) . '=”’ . esc_attr($v) . '”’;
  }
  return wp_get_attachment_image($id, $size, false, $attrs);
}

Automatyczne dopełnienie danych przy zapisie pola (np. generowanie slugów dla kart FAQ):

<?php
add_filter(’acf/update_value/name=faq_list’, function($value, $post_id, $field) {
  if (!is_array($value)) return $value;
  foreach ($value as &$row) {
    if (!empty($row[’question’]) && empty($row[’slug’])) {
      $row[’slug’] = sanitize_title($row[’question’]);
    }
  }
  return $value;
}, 10, 3);

Filtrowanie opcji select z zewnętrznego źródła przy ładowaniu pola:

<?php
add_filter(’acf/load_field/name=city’, function($field) {
  $cities = [’Warszawa’, 'Kraków’, 'Gdańsk’];
  $field[’choices’] = array_combine($cities, $cities);
  return $field;
});

W projektach opartych na edytorze blokowym miksuj natywne bloki z ACF Blocks. Tam, gdzie potrzebujesz pełnej kontroli nad strukturą danych i UX edytora, blok ACF pozwoli połączyć kreatywność z przewidywalnością. Tam, gdzie natywne bloki wystarczają, nie nadbudowuj — prostota jest zaletą. W rezultacie redaktorzy czują moc narzędzia, a Ty zachowujesz stabilność i klarowną kontrolę nad kodem.

Na koniec pamiętaj, że ACF to tylko narzędzie. To od architektury projektu, dyscypliny w repozytorium, recenzji kodu i komunikacji zależy, jak efektywnie przełożysz pomysły na działający produkt. Kiedy łączysz przemyślane wzorce, rygor jakości i odpowiedzialne korzystanie z API, otrzymujesz środowisko pracy, w którym treść i komponenty współgrają, a utrzymanie i rozwój są przewidywalne.

Całość spina dojrzały proces: projekt struktury danych, definicje pól w JSON/PHP, implementacja w szablonach i blokach, pomiary i optymalizacja, testy, integracje i dbałość o bezpieczeństwo. To cykl, który naturalnie wpisuje się w styl pracy z WordPress i pozwala w pełni wykorzystać potencjał ACF w motywach, niezależnie od skali projektu i zespołu.

Gdy będziesz gotowy wejść poziom wyżej, spróbuj generować schematy danych i dokumentację pól automatycznie na podstawie definicji (np. komendy CLI). W dłuższej perspektywie takie narzędzia minimalizują rot, a onboarding nowych osób staje się błyskawiczny. I pamiętaj: inwestycja w jakość modeli danych procentuje, bo każdy kolejny feature budujesz szybciej, bez nieustannego dłubania w fundamentach.

Chcesz mieć dobrą stronę internetową?

Zadzwoń do nas. Porozmawiamy o stronie dopasowanej
do Twoich potrzeb.

601 162 666

Poprzedni wpis
Tworzenie sklepów internetowych Bełżyce
Następny wpis
Strona wizytówkowa a SEO – co jest kluczowe
Zadzwoń Konsultacja