Phone number, address, social links, a shared tagline—hard-code site-wide information into your templates and you have to touch code every time it changes. Build an ACF (SCF) options page and it becomes editable from the admin screen.
There are only two steps. Add the page in functions.php, and pass 'option' when you retrieve values—that’s it.
Step 1: add the options page
function my_acf_options_page() {
if (!function_exists('acf_add_options_page')) {
return; // so the site doesn't break where the plugin isn't installed
}
acf_add_options_page([
'page_title' => 'Site settings',
'menu_title' => 'Site settings',
'menu_slug' => 'site-settings',
'capability' => 'edit_posts', // let editors touch it too
'position' => 30, // where it sits in the menu
'icon_url' => 'dashicons-admin-generic',
'redirect' => false, // false if you aren't creating sub pages
]);
}
add_action('acf/init', 'my_acf_options_page');“Site settings” is added to the left-hand admin menu. From there, set the field group’s “Location” to “Options Page = Site settings” and your input fields appear on it.
Step 2: pass 'option' when retrieving
This is the big one. Without 'option' as the second argument, you get nothing.
<p class="tel">Phone: <?php echo esc_html(get_field('tel', 'option')); ?></p>
<p class="address"><?php echo esc_html(get_field('address', 'option')); ?></p>If you’re only printing, the_field() works the same way.
<?php the_field('tel', 'option'); ?>Repeaters and groups work as usual
For things where you don’t know how many there will be—social links, say—putting a repeater field on the options page is handy. Pass 'option' as the second argument to have_rows() as well.
<?php if (have_rows('sns', 'option')) : ?>
<ul class="sns">
<?php while (have_rows('sns', 'option')) : the_row(); ?>
<li>
<a href="<?php echo esc_url(get_sub_field('url')); ?>">
<?php the_sub_field('name'); ?>
</a>
</li>
<?php endwhile; ?>
</ul>
<?php endif; ?>For a group, walk the array as always: get_field('company', 'option')['tel'].
Organize with sub pages
Once the number of items grows, laying sub pages out under a parent menu keeps things findable.
acf_add_options_page([
'page_title' => 'Site settings',
'menu_slug' => 'site-settings',
'redirect' => true, // open the parent and jump to the first sub page
]);
acf_add_options_sub_page([
'page_title' => 'Company details',
'menu_title' => 'Company details',
'parent_slug' => 'site-settings',
]);
acf_add_options_sub_page([
'page_title' => 'Social',
'menu_title' => 'Social',
'parent_slug' => 'site-settings',
]);When you use sub pages, setting 'redirect' => true on the parent prevents an empty page from showing when someone clicks the parent.
What’s worth putting there?
These are the ones that come up most in real projects.
- Contact details—phone number, opening hours, address (shared by the footer and the contact page)
- Social links—a repeater field so they can be added and removed freely
- A shared notice bar—a one-liner like “Holiday closing dates”
- Logo and OG image—an image field so they can be swapped out
- Copyright line—the year from PHP, the company name from the admin screen
“Any wording that appears in two or more places” is a candidate for the options page—apply that rule and hard-coded text keeps shrinking.
An alternative that doesn’t depend on the plugin
Options pages are a plugin feature, so deactivating the plugin means losing the ability to edit them. If you want to stay plugin-independent, a static page can stand in.
<?php
$settings_id = 12; // ID of the "Site settings" page
echo esc_html(get_field('tel', $settings_id));
?>You create an unpublished page called “Site settings,” put the fields on it, and read them by naming its ID. If you’d rather not hard-code the ID, get_page_by_path('site-settings') can look it up from the slug.
If you want to stick to core features only, there’s also the theme customizer (customize_register). Building out the input fields, though, is far easier with ACF.
Summary
acf_add_options_page()infunctions.phpadds a shared-settings page to the admin screen- Retrieve with
get_field('name', 'option'). Forget'option'and you always get nothing - Repeaters and groups work too (
have_rows('sns', 'option')). As items grow, organize with sub pages - Wording that appears in two or more places is a candidate. To stay plugin-independent, use a static page instead
The less you hard-code, the less “please change one line of text” turns into development work.