Advanced Custom Fields
Lumbermill uses Advanced Custom Fields for all WordPress admin field definitions. Fields are written in PHP using the ACF Builder library and live in the acf-php/ directory.
Creating Fields
Section titled “Creating Fields”All ACF field groups are located in acf-php/. Each subdirectory maps to a part of WordPress — pages, templates, post types, and so on.
Creating a Field Group
Section titled “Creating a Field Group”Start by creating the file structure for your field group. For a header group on a news-overview template:
Directorylumbermill
Directoryacf-php
Directorytemplates
Directorynews-overview
- index.php
- header.php
Open header.php and define the field group:
<?php
return createFieldGroup('News Overview - Header', function ($fieldGroup) { // fields go here});Adding Fields
Section titled “Adding Fields”Add fields to the group by calling addField() with the appropriate field type:
<?php
use App\Lib\ACF\Field\AdvancedLink;use JorenRothman\ACFBuilder\Fields\Basic\Text;use JorenRothman\ACFBuilder\Fields\Content\Image;use JorenRothman\ACFBuilder\Fields\Content\Wysiwyg;
return createFieldGroup('News Overview - Header', function ($fieldGroup) { $image = Image::make('Image'); $title = Text::make('Title'); $text = Wysiwyg::make('Text'); $link = AdvancedLink::make('Link'); $fieldGroup->addField($image); $fieldGroup->addField($title); $fieldGroup->addField($text); $fieldGroup->addField($link);});Registering the Field Group
Section titled “Registering the Field Group”Open news-overview/index.php and register the group with a location rule:
<?php
use JorenRothman\ACFBuilder\FieldGroupLocations;
$header = loadFieldGroup(__DIR__ . '/header.php');
$location = new FieldGroupLocations;$location->and('page_template', '==', 'templates/news-overview.php');
$header->register($location, 10);That’s it — no wiring step. acf-php/index.php autoloads every nested index.php with a glob, so a new templates/news-overview/index.php is picked up automatically:
foreach (glob(__DIR__ . '/*/*/index.php') as $fieldGroup) { include_once $fieldGroup;}Fetching Meta Fields
Section titled “Fetching Meta Fields”There are three ways to fetch ACF fields: via a Timber object in PHP, from an option page, or directly in a Twig template.
Timber Object (recommended)
Section titled “Timber Object (recommended)”Get the post object and call meta() to fetch fields. Group related fields under a single context key to keep templates clean and avoid naming conflicts:
$post = Timber::get_post();
$context['header'] = [ 'title' => $post->meta('header_title'), 'text' => $post->meta('header_text'), 'image' => $post->meta('header_image'),];Access the values in Twig using dot notation:
{# views/templates/single.twig #}
<div class="header"> <h1>{{ header.title }}</h1> <p>{{ header.text }}</p> <img src="{{ header.image.src }}" alt="{{ header.image.alt }}" /></div>Timber automatically transforms certain ACF field types — relationship fields become Timber\Post objects, image fields become Timber\Image objects, and so on. See Getting data from ACF for the full list.
Option Pages
Section titled “Option Pages”Option page fields hold global site settings. Always fetch them via ACFFieldsUtil::getOptions() — it calls get_fields('options') once per request and caches the result, so multiple callers share a single DB query.
The preferred place to expose option values globally is config/timber.php — see the Context guide for details. You may also fetch them per-template:
<?php
use App\Util\ACFFieldsUtil;use Timber\Timber;
$context = Timber::context();
$post = Timber::get_post();$context['post'] = $post;
$options = ACFFieldsUtil::getOptions();$context['options_page_option'] = $options['field_name'] ?? null;
Timber::render('templates/a-view-file.twig', $context);If the field stores raw HTML or script tags, use getRawOptions() instead — getOptions() applies ACF formatting which can corrupt raw HTML output:
$options = ACFFieldsUtil::getRawOptions();echo $options['my_script_field'] ?? '';Twig Template
Section titled “Twig Template”Meta fields may be fetched directly in Twig:
{# a-file.twig #}{{ post.meta('field_name') }}
