Symptom – 500 error when saving in Gutenberg
You’re writing an ACF block, you add a helper function – everything runs smoothly on the frontend. You go to the Gutenberg editor, click “Update” and you get:
PHP Fatal error: Cannot redeclare authors_picker_split_bio()
(previously declared in .../authors-picker.php:44)
The page returns 500 Internal Server Error, the editor UI shows “Updating failed”. The frontend? Working fine. The code? Looks correct.
Why this happens
WordPress renders the same ACF block template multiple times in one request:
- Once – preview in Gutenberg editor (via REST API)
- Second time – server-side render on save
- Third time – if you use InnerBlocks or repeats
On the frontend, the template loads once so there’s no problem. But in Gutenberg the second include causes a fatal error, because PHP doesn’t allow declaring a function with the same name twice.
Fix – if(!function_exists) guard
Every helper function defined inside an ACF block file (typically lib/blocks/block-name.php) needs to be wrapped in a guard:
if (!function_exists('my_helper_function')) {
function my_helper_function($arg) {
// function logic
return $result;
}
}
The guard checks if the function already exists – if so, it simply skips the declaration. The second include of the same block doesn’t crash.
What you don’t need to wrap
The rule applies only to named global functions. You don’t need to wrap:
- Anonymous functions (closures) in
add_action/add_filter - Class methods (classes have their own guard via
class_exists) - Variables and constants
So this code is safe without a guard:
add_filter('the_content', function($content) {
return $content . '<p>appendix</p>';
});
Cleaner alternative – move functions outside the template
Instead of wrapping every function in a guard, you can extract them from the block file to a separate helper file, included once via functions.php:
// functions.php
require_once get_template_directory() . '/lib/helpers/blocks-helpers.php';
// lib/helpers/blocks-helpers.php
function my_helper_function($arg) {
// logic
}
Then the block template just calls my_helper_function() without declaring. This is cleaner if the function is used by more than one block. For functions tightly coupled to a single block – in-place guard is fine.
How to catch this before it hits production
The fatal error only appears when saving in Gutenberg, so it’s easy to miss. Test like this:
- Write a new block or add a helper function
- Go to the editor of a page where this block is used
- Click Update – if you get “Updating failed” and the network console shows 500, that’s it
- Check WordPress
debug.log– the specific function name will be there
Summary
One simple rule: every named function in an ACF block file goes into an if(!function_exists()) guard. It won’t hurt where it’s not needed, and it saves you where it is.
Alternatively – keep functions outside blocks, in separate helpers. But that requires discipline; in-place guard is defensive and more forgiving.



