Blog · usługi programistyczne

ACF Blocks – fatal error „Cannot redeclare” przy zapisie w Gutenbergu

2026-07-23

Symptom – 500 przy zapisie w Gutenbergu

Piszesz sobie ACF blok, dodajesz funkcję pomocniczą – wszystko śmiga na frontendzie. Wchodzisz do edytora Gutenberga, klikasz „Aktualizuj” i dostajesz:

PHP Fatal error: Cannot redeclare authors_picker_split_bio()
(previously declared in .../authors-picker.php:44)

Strona wraca 500 Internal Server Error, w interfejsie edytora widzisz komunikat „Nie powiodła się aktualizacja”. Frontend? Działa bez zarzutu. Kod? Wygląda poprawnie.

Komunikat błędu Gutenberg 'Nie powiodła się aktualizacja' - fatal error PHP Cannot redeclare przy zapisie bloku ACF
Klasyczny widok „Nie powiodła się aktualizacja” w Gutenbergu.

Dlaczego to się dzieje

WordPress renderuje ten sam template bloku ACF wielokrotnie w jednym request:

  • Raz – preview w edytorze Gutenberga (przez REST API)
  • Drugi raz – server-side render przy zapisie
  • Trzeci raz – jeśli używasz InnerBlocks albo powtórzeń

Na frontendzie template ładuje się raz więc nie ma problemu. Ale w Gutenbergu drugi include daje fatal error, bo PHP nie pozwala zadeklarować funkcji o tej samej nazwie dwa razy.

Fix – guard if(!function_exists)

Każdą funkcję pomocniczą definiowaną wewnątrz pliku bloku ACF (typowo lib/blocks/nazwa-bloku.php) trzeba owinąć w guard:

if (!function_exists('my_helper_function')) {
    function my_helper_function($arg) {
        // logika funkcji
        return $result;
    }
}

Guard sprawdza czy funkcja już istnieje – jeśli tak, po prostu pomija deklarację. Drugi include tego samego bloku nie wywala się.

Czego nie trzeba tak owijać

Reguła dotyczy tylko nazwanych funkcji globalnych. Nie musisz obwijać:

  • Anonymous functions (closures) w add_action / add_filter
  • Metod klas (klasy same z siebie mają guard przez class_exists)
  • Zmiennych i stałych

Więc taki kod jest bezpieczny bez guarda:

add_filter('the_content', function($content) {
    return $content . '<p>dopisek</p>';
});

Prostsza alternatywa – przenieś funkcje poza template

Zamiast obwijać każdą funkcję w guard, można je wyciągnąć z pliku bloku do osobnego pliku helper’a, dołączanego raz przez functions.php:

// functions.php
require_once get_template_directory() . '/lib/helpers/blocks-helpers.php';

// lib/helpers/blocks-helpers.php
function my_helper_function($arg) {
    // logika
}

Wtedy template bloku po prostu wywołuje my_helper_function() bez deklarowania. To czystsze rozwiązanie jeśli funkcja jest używana przez więcej niż jeden blok. Dla funkcji ściśle związanych z jednym blokiem – guard w miejscu jest OK.

Jak to złapać zanim wyjdzie na produkcję

Fatal error pojawia się tylko przy zapisie w Gutenbergu, więc łatwo go przeoczyć. Testuj tak:

  1. Napisz nowy blok albo dodaj funkcję pomocniczą
  2. Wejdź w edytor strony, na której ten blok jest używany
  3. Kliknij Aktualizuj – jeśli dostajesz „Nie powiodła się aktualizacja” i w konsoli sieci widać 500, to jest to
  4. Sprawdź debug.log WordPressa – tam będzie konkretna nazwa funkcji

Podsumowanie

Jedna prosta reguła: każda nazwana funkcja w pliku bloku ACF idzie w guard if(!function_exists()). Nie zaszkodzi tam gdzie nie trzeba, uratuje tam gdzie trzeba.

Alternatywnie – trzymaj funkcje poza blokami, w osobnych helperach. Ale to wymaga dyscypliny, guard w miejscu jest defensywny i wybacza więcej.

Wróć do wszystkich wpisów

Masz projekt do omówienia?

Napisz, o co chodzi - nie musi być technicznie, od tego jestem ja. Odezwę się i powiem wprost, czy i jak mogę pomóc.