Directory Structure
acf-blocks-plugin/
acf-blocks.php Main plugin file
includes/
functions.php Block registration, styles, editor assets
compat.php ACF 6.7+ compatibility layer
image-localizer.php External image download on save
license-manager.php License activation and update checks
assets/
js/
block-transforms.js Editor-side block transforms
blocks/
accordion-block/ One directory per block
block.json Block metadata (ACF v3)
block-data.json ACF field group definition
accordion-block.php PHP render template
accordion.css Block stylesheet
extra.php Optional: additional hooks
callout/
...
(27 more block directories)
llm/
(29 markdown files for AI/LLM reference)
.github/
workflows/
release.yml CI: tag push creates zip release
Boot Sequence
The plugin loads in this order:
-
acf-blocks.phpruns immediately. It defines constants and instantiates the license manager (which hooks intoadmin_menu,admin_init, and the update system). -
On
plugins_loaded,acf_blocks_init()checks whether ACF is available. If yes, it loadsfunctions.php,compat.php, andimage-localizer.php. If ACF is missing, it registers an admin notice and stops. -
On
init(priority 5),acf_blocks_register_styles()pre-registers all block stylesheets withwp_register_style(). This allows WordPress to conditionally enqueue them only when a block appears on the page. -
On
acf/init(priority 5),acf_blocks_load_blocks()scans theblocks/directory. For each subdirectory containing ablock.json, it callsregister_block_type(), loads ACF field groups from any*.jsonfiles (excludingblock.json), and includesextra.phpif present. -
On
block_categories_all, a custom “ACF Blocks” category is inserted at the top of the block inserter. -
On
enqueue_block_editor_assets, the block transforms script is enqueued. -
Editor styles are loaded through three overlapping mechanisms (see below).
Block Category
All blocks are registered under the acf-blocks category, which appears first in the block inserter. The category is added via the block_categories_all filter.
Per-Block Structure
Every block lives in its own directory under blocks/ and contains at minimum:
block.json– Standard WordPress block metadata with anacfkey specifying the render template and block version.block-data.json– An ACF field group definition (JSON). This is loaded automatically. No manual import through the ACF admin is needed.{block-name}.php– The PHP render template that receives$block,$content,$is_preview, and$post_id.{block-name}.css– Block styles, referenced via"style": "file:./filename.css"inblock.json.
Some blocks also include:
extra.php– Additional hooks, AJAX handlers, or scripts. Loaded automatically if present.{block-name}.js– Frontend JavaScript (e.g. star rating submission, section block editor component).
No Build Step
The plugin has no build system, no package.json, no webpack or bundler. All JavaScript is vanilla ES5-compatible (IIFE pattern). Assets are committed as source files and deployed as-is.
Editor Style Loading
Getting block styles into the Gutenberg editor iframe is notoriously unreliable across WordPress versions and themes. The plugin uses three overlapping mechanisms to ensure styles always appear:
-
add_editor_style()viaafter_setup_theme(priority 999) – Registers all block CSS files as editor styles. -
wp_enqueue_style()viaenqueue_block_assets(priority 999999, admin only) – Directly enqueues all block stylesheets in the editor. -
Inline CSS injection via
block_editor_settings_all(priority 999999) – Reads all CSS files and injects them as inline styles into the editor settings object.
On the frontend, styles are loaded conditionally. WordPress only enqueues a block’s stylesheet when that block appears on the page, because the styles are pre-registered (not enqueued) during init.
CSS Class Naming
All blocks use the acf- prefix for CSS classes: .acf-accordion, .acf-hero-block, .acf-product-review, etc. This prevents conflicts with theme and plugin styles.