Jump to Navigation Jump to Main Content Jump to Footer
Home » Docs » Features » Native and ACF block support with auto‑registration

Native and ACF block support with auto‑registration

Chisel lets you build faster with blocks. Our theme auto‑discovers and registers both native and ACF blocks on boot, so you ship features – not boilerplate. Drop your block assets and Twig templates in place and the system handles the rest: assets enqueued, categories organized, templates wired, and smart defaults applied. Editors get a polished block library under a branded category, while developers enjoy a zero‑friction workflow.

Under the hood, a lightweight factory in inc/WP/Blocks.php does the heavy lifting—collecting definitions, registering blocks on init, and exposing their Twig locations to Timber for consistent rendering. The result is clean, predictable markup across the board, powered by Twig and aligned with your design system.

Performance is baked in. Only the styles for blocks actually used on a page are kept; the rest are dequeued, with optional critical CSS inlined for instant paint. Whether your blocks compile to build/blocks/ or ACF counterparts in build/blocks-acf/, the experience is seamless: one convention, one rendering path, and a faster site – out of the box.

Overview

  • Native and ACF blocks are compiled to build/blocks/ and build/blocks-acf/.
  • At runtime, both are auto‑discovered and registered via a factory: Chisel\Factory\RegisterBlocks.
  • Twig templates for blocks are resolved from their source folders in src/, so you can keep PHP/Twig close to the block code.

Key classes and paths:

  • inc/WP/Blocks.php — native blocks lifecycle
  • inc/WP/AcfBlocks.php — ACF blocks lifecycle
  • inc/Factory/RegisterBlocks.php — discovery + registration for both types
  • src/blocks/ — native blocks (e.g., src/blocks/accordion/)
  • src/blocks-acf/ — ACF blocks (e.g., src/blocks-acf/slider/)
  • build/blocks/ and build/blocks-acf/ — compiled block assets with block.json

Native blocks lifecycle

  • Bootstrap: Chisel\WP\Blocks hooks
    • init → register_blocks() calls the factory to register all native blocks
    • Adds a custom block category at the top of the inserter
      • block_categories_all → block_categories() using theme name
    • Adds custom block pattern categories
      • register_block_patterns_categories()
    • Extends Twig lookup paths for block templates
      • timber/locations → tiwg_files_locations() adds src/blocks/{block}/
    • Post‑render content tweaks
      • render_block() removes layout classes and adds custom classes via Chisel\Helper\BlocksHelpers::get_block_object_classnames()
    • Performance helpers (covered later)
      • Dequeues unused block styles on a page and adds “critical” inline CSS if available

File: inc/WP/Blocks.php


ACF blocks lifecycle

  • Bootstrap: Chisel\WP\AcfBlocks hooks
    • acf/init → register_blocks() calls the factory to register all ACF blocks
    • Extends Twig lookup paths for block templates
      • timber/locations → tiwg_files_locations() adds src/blocks-acf/{block}/
    • ACF JSON integration for per‑block field groups
      • acf/settings/load_json → each block’s acf-json folder is added as a load path
      • acf/settings/save_json → when saving a field group assigned to a block, it writes to that block’s acf-json folder
    • Performance helper parallel to native blocks (dequeue unused, inline “critical” CSS when present)

File: inc/WP/AcfBlocks.php


block.json expectations

  • The factory supports file references in block.json like:
    • "style": "file:./style.css"
    • "editorScript": ["file:./editor.js", "file:./extra.js"]
  • For each referenced file:
    • Styles → wp_register_style( handle, url, [], version )
    • Scripts → wp_register_script( handle, url, dependencies, version, args )
      • Dependencies loaded from accompanying .asset.php if present

See: inc/Factory/RegisterBlocks.php::register_custom_blocks()


Twig templates

  • Both Chisel\WP\Blocks and Chisel\WP\AcfBlocks add block source directories to Timber’s locations:
    • src/blocks/{block-name}/
    • src/blocks-acf/{block-name}/
  • This allows Twig files shipped in src/**/ to be discovered at runtime, while assets come from build/**/.

Adding a new native block

  1. Create folder: src/blocks/{block-name}/
  2. Add your block code:
    • JS/CSS built to build/blocks/{block-name}/
    • block.json in build/blocks/{block-name}/ (generated by your build step)
  3. Reference files in block.json using file:./... (style/script/editorScript/viewScript, etc.)
  4. Run build: npm run build (or npm run dev during development)
  5. The block will be auto‑discovered on next init.

Adding a new ACF block

  1. Create folder: src/blocks-acf/{your-block}/
  2. Add your block source; build produces build/blocks-acf/{your-block}/block.json
  3. Create ACF field group and assign it to the block:
    • The theme routes acf-json save/load to src/blocks-acf/{your-block}/acf-json automatically.
  4. Run build; the block is auto‑discovered/registered on acf/init.

Tip: Keep Twig templates in the corresponding /{block-name}/{block-name}.twig folder so Timber can locate them automatically.


Editor UX enhancements

  • Custom block category named after the theme (slug: chisel-blocks)
  • Optional block pattern categories (under chisel-patterns/*)
  • Default alignment for certain blocks can be injected to the editor data
    • Example: Chisel\WP\Blocks::blocks_alignment_data() sets chisel/slider default to full

Block scripts/styles in block.json (with concrete mapping)

This explains each scripts/styles field in a block’s block.json and how source filenames in src

produce the files you reference in build:

  • assets/example-blocks/blocks/example/ (source reference)
  • Actual theme blocks live under src/blocks/{block}/ and compile to build/blocks/{block}/ or for ACF blocks live under src/blocks-acf/{block}/ and compile to build/blocks-acf/{block}/

Key reference files:

  • block.json
  • index.js (imports ./style.scss)
  • edit.js (imports ./editor.scss)
  • script.js (imports ./style.scss)
  • view.js (imports ./view.scss)

block.json fields (what they do)

In block.json:

{
  "ignoreScripts": ["script"],
  "editorScript": "file:./index.js",
  "editorStyle": "file:./index.css",
  "style": ["file:./style-index.css", "file:./style-script.css"],
  "script": "file:./script.js",
  "viewScript": "file:./view.js",
  "viewStyle": "file:./view.css"
}
JSON
  • editorScript
    • JS loaded in the editor only.
    • Example points to file:./index.js.
    • Source: index.js is your editor entry file.
    • Build outputs: index.js (+ index.asset.php for dependencies/version).
  • editorStyle
    • CSS loaded in the editor only.
    • Example points to file:./index.css.
    • Source: index.js imports editor.scss.
    • Build outputs index.css.
  • style
    • CSS loaded in both editor and frontend (the “shared” styles).
    • The example shows an array:
      • file:./style-index.css — produced because index.js imports ./style.scss.
      • file:./style-script.css — produced because script.js imports ./style.scss.
    • Why two files: each entry that imports style.scss emits its own “style-{entry}.css” file. If you import the same SCSS from multiple entries, you’ll get multiple output CSS files.
  • script
    • JS loaded in both editor and frontend.
    • Example points to file:./script.js.
    • Source: script.js
    • Build outputs script.js
  • viewScript
    • JS loaded on the frontend only (not in the editor).
    • Example points to file:./view.js.
    • Source: view.js.
    • Build outputs view.js
  • viewStyle
    • CSS loaded on the frontend only.
    • Example points to file:./view.css.
    • Source: view.scss
    • Build outputs view.css.
  • ignoreScripts
    • Array of script keys you want to build but NOT enqueue as scripts (useful when a JS file exists purely to import SCSS).
    • Example: ["script"] prevents enqueuing the script handle for script.js, but CSS from script.js (i.e., style-script.css) still builds and can be referenced under “style”.
    • From inc/Factory/RegisterBlocks.php: scripts in ignoreScripts are not registered in production; during dev, they may still be registered to support live reload.

Where to place files in your theme

  • Put block source under src/blocks/{block-name}/ or under src/blocks-acf/{block-name}/ ****for ACF blocks
    • index.js (editor entry; imports style.scss)
    • edit.js (imports editor.scss)
    • script.js (shared entry; can import style.scss)
    • view.js (frontend entry; can import view.scss)
    • style.scss, editor.scss, view.scss
  • After build (npm run build), you’ll get in build/blocks/{block-name}/ or in /build/blocks-acf/{block-name}/ for ACF block
    • block.json
    • index.js, index.asset.php, index.css
    • script.js, script.asset.php, style-script.css
    • style-index.css
    • view.js, view.asset.php, view.css

Use file:./{built-filename} in

block.json to reference these outputs.


Arrays vs strings in block.json

  • All script/style fields accept either a string or an array.
  • Use arrays when multiple outputs need to be enqueued for the same key (e.g., "style": ["file:./style-index.css", "file:./style-script.css"]).

Handles and dependencies (implementation detail)

  • The factory (inc/Factory/RegisterBlocks.php) generates handles like:
    • block-{type}-{blockName}-{key}Examples:
      • block-wp-example-style
      • block-wp-example-editorScript
  • For JS entries, WordPress dependencies and versions come from .asset.php files generated by the build (e.g., index.asset.php).

Tip: If a JS file exists just to import SCSS, add its key to ignoreScripts to avoid loading an empty script tag.


Critical CSS for blocks: critical.scss

What it is

  • You can co-locate a critical.scss with your block and import it from script.js.
  • It compiles to a special CSS file named script.css in the block’s build folder.
  • On the frontend, when the block is present on the page, the theme will inline the contents of that script.css into the main stylesheet handle. This optimizes above-the-fold rendering.

How to use it in your block

  • In your block source (native or ACF), in src/blocks/{block}/script.js or src/blocks-acf/{block}/script.js:
    • Import shared styles (optional): import './style.scss' → builds style-script.css
    • Import critical styles: import './critical.scss' → builds script.css (the critical bundle)

When it is inlined

  • Only on the frontend (not in wp-admin).
  • Only if the block is used on the current page:
    • get_content_blocks_names() is used to detect block usage.
  • The theme then:
    • Dequeues unused block styles for blocks not present.
    • If script.css exists for a used block, it fetches it and inlines it:
      • BlocksHelpers::get_block_inline_css($blocks_url, $block_name) → reads .../{block}/script.css
      • wp_add_inline_style( AssetsHelpers::get_final_handle('main'), $css )
  • Inline size limit:
    • Filtered via chisel_styles_inline_size_limit (default set to 10000) in Blocks::styles_inline_size_limit().

Practical guidance

  • Keep critical.scss minimal: above‑the‑fold essentials only (fonts, layout primitives, key colors).
  • Scope strictly to your block to avoid bleed:
    • Example: .b-your-block { ... }
  • Do not import critical.scss from editor-only entries; import it from script.js so it builds to script.css.
  • If script.js exists only to import SCSS and has no runtime JS, add "script" to "ignoreScripts" in block.json to avoid enqueuing the JS:
    • You still get:
      • style-script.css → add it under "style" in block.json
      • script.css → inlined automatically when the block is present

Notes and troubleshooting

  • If a block does not appear:
    • Ensure build/blocks/{block}/block.json (or build/blocks-acf/...) exists.
    • Confirm file:./... references point to files actually present after build.
  • During dev, scripts may be registered even when “ignored” in metadata to enable live reload:
    • See ThemeHelpers::is_fast_refresh() logic in the factory.
  • If Twig is not rendering:
    • Check that the Twig template lives under the source path the class adds to Timber (src/blocks/..., src/blocks-acf/...).

Do you like Chisel?

Give it a star on GitHub!