Building custom WordPress themes is one of those skills that is easy to do badly. ACF Pro plus a strict folder convention makes it dramatically easier to do well. Here is the setup I have used on roughly 40 client builds at Swivt and Growthzilla.
01Why ACF Pro is still the answer in 2026
Gutenberg has come a long way. Full Site Editing is real. So why am I still paying for ACF Pro?
- Authoring experience. ACF builds editor UIs that match how clients think about their content.
- Custom blocks in PHP. Skip the React build pipeline for blocks. Write a template, register a field group, done.
- Repeaters, flexible content, relationships. Native Gutenberg can do most of this — clumsily. ACF makes it pleasant.
- It has been stable for a decade. Clients can hand the site to the next dev and it will just work.
02Folder structure
Every WP theme I ship looks like this:
theme/
├── style.css // required header, mostly empty
├── functions.php // thin — just include()s
├── header.php
├── footer.php
├── index.php
├── front-page.php
├── page.php
├── single.php
├── archive.php
├── 404.php
│
├── inc/ // PHP includes
│ ├── setup.php
│ ├── assets.php
│ ├── acf.php
│ ├── blocks.php
│ └── helpers.php
│
├── partials/ // reusable template pieces
│ ├── nav.php
│ ├── footer.php
│ ├── hero.php
│ └── card.php
│
├── blocks/ // ACF block templates
│ ├── hero/
│ │ ├── block.json
│ │ └── render.php
│ └── feature-grid/
│ ├── block.json
│ └── render.php
│
├── acf-json/ // version-controlled field groups
└── assets/
├── css/
├── js/
└── img/
acf-json/. Toggling “Local JSON” in ACF means field groups version-control like normal code — no more “the staging site has different fields than prod.”03Field groups by template, not by post type
Beginners attach field groups to a post type. Better: attach them to the template. That way, switching a page from “Default” to “Landing” swaps the fields automatically.
04ACF Blocks for Gutenberg
Modern WP, page builder ergonomics, no React build step:
// blocks/hero/block.json
{
"name": "acf/hero",
"title": "Hero",
"category": "theme",
"icon": "star-filled",
"acf": {
"mode": "preview",
"renderTemplate": "render.php"
}
}
05Partial templates and get_template_part
Anything that appears in more than one place lives in partials/ and is included via get_template_part() — the WordPress equivalent of a React component.
06Gotchas to avoid
- Always escape output.
esc_html(),esc_url(),esc_attr(). - Set a fallback for empty fields. Editors will leave things blank. Default gracefully.
- Do not query inside loops.
get_field()does not hit the DB but child queries do. Batch. - Version-control your
acf-json/. Commit those files. The whole point. - Use ACF block previews. Editors should see roughly what visitors see. Set
"mode": "preview"inblock.json.
This setup has handled marketing sites, ecommerce, and editorial publications. If you are still building WP themes that look like 2018, give this structure a weekend.