Architecture

  • JNext lesson
  • KPrevious lesson
  • FSearch lessons
  • EscClear search

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:

  1. acf-blocks.php runs immediately. It defines constants and instantiates the license manager (which hooks into admin_menu, admin_init, and the update system).

  2. On plugins_loaded, acf_blocks_init() checks whether ACF is available. If yes, it loads functions.php, compat.php, and image-localizer.php. If ACF is missing, it registers an admin notice and stops.

  3. On init (priority 5), acf_blocks_register_styles() pre-registers all block stylesheets with wp_register_style(). This allows WordPress to conditionally enqueue them only when a block appears on the page.

  4. On acf/init (priority 5), acf_blocks_load_blocks() scans the blocks/ directory. For each subdirectory containing a block.json, it calls register_block_type(), loads ACF field groups from any *.json files (excluding block.json), and includes extra.php if present.

  5. On block_categories_all, a custom “ACF Blocks” category is inserted at the top of the block inserter.

  6. On enqueue_block_editor_assets, the block transforms script is enqueued.

  7. 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 an acf key 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" in block.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:

  1. add_editor_style() via after_setup_theme (priority 999) – Registers all block CSS files as editor styles.

  2. wp_enqueue_style() via enqueue_block_assets (priority 999999, admin only) – Directly enqueues all block stylesheets in the editor.

  3. 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.