ACF Select Field — Use Choices as CSS Modifiers in PHP
Read an ACF Select field value and apply it as a BEM modifier class. Lets editors choose button style, card layout, or colour scheme from a fixed list.
Read a Select field value and apply it as a CSS modifier class on an HTML element.
Use this when editors need to choose a visual style — button colour, layout variant, card size — from a fixed list.
Building it step by step
Create the ACF Select field first, then build the PHP renderer in 4 small steps.
We’ll build this in 4 steps. Each step works on its own — stop at any point and you have a runnable result.
Step 1: Create the ACF field. Open Custom Fields → Add New and build the field group:
- Set the Title to Button.
- Click Add Field and configure:
- Label: Button Style
- Field Name:
button_style - Field Type: Select
- Choices: (one per line,
value : Labelformat)
primary : Primary
secondary : Secondary
ghost : Ghost / Outline - Default Value: primary
- Return Format: Value
- Set Location → Post Type is equal to Page.
- Click Save.
<?php
// ACF field reference — keep this open while writing PHP below.
//
// Field Name Type Return Format Returns
// ─────────────────────────────────────────────────────────────
// button_style Select Value String: "primary" | "secondary" | "ghost"
Step 2: Get the value. get_field('button_style') returns the stored key string — "primary", "secondary", or "ghost". A fallback with if ( empty() ) covers pages where no style was explicitly chosen.
<?php
$style = get_field( 'button_style' ); // ACF: Select — returns "primary" | "secondary" | "ghost"
if ( empty( $style ) ) {
$style = 'primary';
}
echo esc_html( $style );
Step 3: Apply it as a CSS modifier class. Concatenate the value onto a base BEM class — btn--primary, btn--secondary, btn--ghost. Your CSS handles the visual difference; PHP just passes the string through.
<?php
$style = get_field( 'button_style' ); // ACF: Select
if ( empty( $style ) ) {
$style = 'primary';
}
$class = 'btn btn--' . esc_attr( $style );
?>
<a href="#" class="<?php echo $class; ?>">
Get started
</a>
Step 4: Add conditional display logic. Sometimes the choice drives more than a class — for instance, the ghost style might need a different icon or no background fill. An explicit if/else keeps that logic readable.
<?php
$style = get_field( 'button_style' ); // ACF: Select
if ( empty( $style ) ) {
$style = 'primary';
}
$class = 'btn btn--' . esc_attr( $style );
if ( $style === 'ghost' ) {
$icon = 'arrow-right';
} else {
$icon = 'chevron-right';
}
?>
<a href="#" class="<?php echo $class; ?>">
Get started
<span class="icon icon--<?php echo esc_attr( $icon ); ?>"></span>
</a>
Step 5: Everything together. Steps 2–4 are teaching code. This is the production file: field read, fallback, CSS modifier class, and conditional icon — all combined in one clean template part.
<?php
/**
* Full file: template-parts/sections/cta-button.php
* Steps 2–4 combined — copy this into your theme as the production version.
*/
// ── 1. Read ACF field ─────────────────────────────────────────────────────────
$style = get_field( 'button_style' ); // ACF: Select
$label = get_field( 'button_label' ); // ACF: Text
$url = get_field( 'button_url' ); // ACF: URL
if ( empty( $style ) ) {
$style = 'primary';
}
// ── 2. Build class and icon ───────────────────────────────────────────────────
$class = 'btn btn--' . esc_attr( $style );
if ( $style === 'ghost' ) {
$icon = 'arrow-right';
} else {
$icon = 'chevron-right';
}
?>
<a href="<?php echo esc_url( $url ); ?>" class="<?php echo $class; ?>">
<?php echo esc_html( $label ); ?>
<span class="icon icon--<?php echo esc_attr( $icon ); ?>"></span>
</a>
Call this file from your page template: get_template_part( 'template-parts/sections/cta-button' );
How it works
One explanation per build step — what problem each layer solved.
Step 2 — Getting the value
Problem solved: reads the editor’s choice as a plain string. With Return Format set to Value, get_field('button_style') returns the stored key — "primary", "secondary", or "ghost". The if ( empty() ) fallback covers pages where no choice was made and ACF returns an empty string or NULL.
Step 3 — CSS modifier class
Problem solved: maps the editor’s choice to a visual style without a long if/else chain. Concatenating the value onto a BEM base class (btn--primary) means your CSS handles all visual logic — PHP just passes the string through. esc_attr() is used instead of esc_html() because this value appears inside an HTML attribute.
Step 4 — Conditional display logic
Problem solved: different icon or markup per choice, without entangling it in the CSS modifier logic. When the modifier class isn’t enough — for example the ghost variant needing a different icon — an explicit if/else keeps each choice readable. Ternary operators are avoided here because beginners find them harder to scan at a glance.
Setup
Create the field group in ACF admin, place the template file, and test.
Create the ACF field group
- Go to Custom Fields → Add New.
- Set the Title to Button.
- Click Add Field and configure:
- Field Type: Select
- Label: Button Style
- Field Name:
button_style - Choices: one per line as
key : Label— e.g.primary : Primary - Default Value: primary
- Return Format: Value
- Add a second field: Label → Button Label, Field Name →
button_label, Type → Text. - Add a third field: Label → Button URL, Field Name →
button_url, Type → URL. - Set Location → Post Type is equal to Page.
- Click Save.
Create the template file
Create template-parts/sections/cta-button.php and paste in the Step 5 production code. Call it from your page template:
<?php get_template_part( 'template-parts/sections/cta-button' ); ?>
Choose a style in the editor and test
Open a page, find the Button Style field, pick a choice, and publish. Inspect the rendered button in the browser — it should carry the class btn btn--primary (or whichever you selected). If the class is missing, run var_dump( get_field( 'button_style' ) ) to confirm the field is returning a value. A NULL usually means the field name in PHP doesn’t match ACF exactly.
The field names in the PHP must match ACF exactly — that’s the Field Name column in ACF admin, not the Label. If you rename a field in ACF, update the PHP to match.
Making it your own
Multiple values, both-value-and-label return, and size variants.
Allow multiple choices
In the ACF field settings, enable Allow Multiple Values. The field now returns an array of strings instead of a single string. Iterate with foreach and apply each as a modifier:
$styles = get_field( 'button_style' );
foreach ( $styles as $s ) {
$classes[] = 'btn--' . esc_attr( $s );
}
Return both value and label
Set Return Format to Both (Value and Label) in ACF. The field now returns an array: ['value' => 'primary', 'label' => 'Primary']. Use $style['value'] for the CSS class and $style['label'] for visible text — useful when you need to display the human-readable label alongside the modifier.
Add a size variant
Add a second Select field named button_size with choices like sm : Small, md : Medium, lg : Large. Read it the same way and concatenate onto the class: btn--md. Two independent Select fields give editors fine-grained control without a combinatorial explosion of CSS classes.
If you change the choice keys (the values before the colon) in an existing ACF Select field, any previously-saved data will no longer match. Update saved post meta or add the old key as an alias before removing it from the field choices.
No comments yet. Be the first.