GT ACF Blocks 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        Background external-image download queue
    license-manager.php        License activation and update checks
    block-migrator.php         Block Migrator & Repair (admin card + WP-CLI)
    block-recovery.php         Self-healing InnerBlocks recovery + WP-CLI repair
    performance-manager.php    Block Manager, usage inventory, diagnostics
    generated-block-manifest.php  Generated block/field-group manifest
  assets/
    js/
      block-transforms.js      Editor-side block transforms
    css/
      editor-blocks.css        Consolidated editor style bundle
  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

Diagram of the GT ACF Blocks boot sequence with context gates: operational modules load only in admin, cron, WP-CLI, or REST requests, and a public frontend request carries only registration and rendering code

The plugin loads in this order:

The ACF Blocks architecture is deliberately flat: one main file, an includes directory for registration and compatibility, and a blocks directory where every block is a self-contained folder. Understanding this layout is most of what you need to extend or debug the plugin.

  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 the star rating endpoint file. Operational modules load contextually: image-localizer.php, block-migrator.php, and performance-manager.php only in admin, cron, or WP-CLI requests, and block-recovery.php in WP-CLI and REST contexts. Public frontend requests carry only registration and rendering code. If ACF is missing, the plugin 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() reads block definitions from the generated manifest (includes/generated-block-manifest.php), an OPcache-friendly PHP array that replaces request-time directory scans and JSON decoding. For each block it calls register_block_type(), loads the ACF field groups, and includes extra.php if present. A filesystem scan of blocks/ remains as a fallback when the manifest is missing, and blocks disabled through the Block Manager are skipped.

  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 load as one consolidated bundle (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

Since 2.9.0, all block CSS is consolidated into one cacheable editor bundle (assets/css/editor-blocks.css), enqueued on enqueue_block_assets (priority 999999, admin only). The per-block style handles that block.json registers are dequeued in the editor so nothing loads twice. When you disable blocks through the Block Manager, the plugin builds a site-specific bundle that excludes their CSS.

One stylesheet request instead of dozens makes the editor iframe both faster and more predictable across WordPress versions and themes.

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.

Quick answers to common questions:

Where does each block live in the plugin?

Under blocks/{block-name}/ with its block.json, field group JSON, and render template together. Nothing is scattered: deleting a block folder removes that block cleanly, and copying one is the starting point for a custom block.

Can I override a block’s template from my theme?

Yes, the render pipeline checks your theme for an override before falling back to the plugin’s template, so customizations survive plugin updates. The render templates lesson covers the exact lookup order.