Tips・WordPress custom fields (ACF / SCF)

How to output an ACF group field

How to output ACF (SCF) group fields in your template. Covers pulling values out as an array, the have_rows approach, how groups differ from repeaters, and why your values sometimes come back empty.

The group field in ACF (SCF) bundles related fields into a single box. The basic way to pull values out is “receive it as an array and name the key”—the get_field('company')['tel'] shape.

<?php $company = get_field('company'); ?>
<p>Phone: <?php echo esc_html($company['tel']); ?></p>
TipsACF or SCF—which one should I install?Still deciding between ACF and SCF? Start here

A group field is a box that bundles input fields

A group exists to turn fields that would otherwise scatter into a meaningful cluster. Using company details as an example, it looks like this.

Company details (group: company)
├── tel      +1 555-0123
├── address  123 Main Street…
└── hours    10:00–19:00

The visible benefit is that the admin screen groups them under a heading. The other practical win is that field names stop colliding. If you want to use the name tel for both shop details and a contact address, splitting them into groups lets tel inside shop and tel inside contact coexist.

TipsHow to output an ACF repeater fieldNeed as many as you want? Head over to outputting repeater fields

get_field() returns a group as an associative array. The keys are the sub field names.

<?php $company = get_field('company'); ?>
<?php if ($company) : ?>
  <table class="company">
    <tr><th>Phone</th><td><?php echo esc_html($company['tel']); ?></td></tr>
    <tr><th>Address</th><td><?php echo esc_html($company['address']); ?></td></tr>
    <tr><th>Hours</th><td><?php echo esc_html($company['hours']); ?></td></tr>
  </table>
<?php endif; ?>

Because you receive it into a variable once and reuse it, this is the shortest approach on a page that outputs several values from the same group.

When a sub field might be empty, add an individual if.

<?php if (!empty($company['tel'])) : ?>
  <p>Phone: <?php echo esc_html($company['tel']); ?></p>
<?php endif; ?>

Approach 2: enter a loop with have_rows

A group can also be seen as “a repeater with a single row,” so have_rows() handles it too. With this shape you pull the contents out with get_sub_field().

<?php if (have_rows('company')) : ?>
  <?php while (have_rows('company')) : the_row(); ?>
    <p>Phone: <?php the_sub_field('tel'); ?></p>
    <p>Address: <?php the_sub_field('address'); ?></p>
  <?php endwhile; ?>
<?php endif; ?>

The advantage is that it matches how you write repeater fields. It also cuts down on typo-an-array-key-and-never-notice accidents. Either is fine—but pick one style and stick to it within a page and it reads better.

Images inside a group

When you put an image field inside a group, you pull it out the same way. Match the approach to the return value setting.

<?php $hero = get_field('hero'); ?>
<?php if ($hero) : ?>
  <section class="hero">
    <?php echo wp_get_attachment_image($hero['image'], 'full'); ?>   <!-- return value = image ID -->
    <h1><?php echo esc_html($hero['catch']); ?></h1>
  </section>
<?php endif; ?>

If the return value is an image array, walk one more level down, like $hero['image']['url'].

TipsHow to display images with ACFChoosing between the image field’s return values (ID, URL, array)

Nested groups

When you put a group inside a group, you just keep walking the array.

<?php $s = get_field('shop'); ?>
<p><?php echo esc_html($s['sns']['twitter']); ?></p>

With the have_rows() style, you enter have_rows('sns') once more on the inside. Deep hierarchies make templates hard to read, so keeping nesting to two levels is a good rule of thumb in real projects.

A group inside a repeater field

When a repeater row contains a group, what get_sub_field() gives you back is an array.

<?php while (have_rows('staff')) : the_row(); ?>
  <?php $profile = get_sub_field('profile'); ?>
  <p><?php echo esc_html($profile['name']); ?> (<?php echo esc_html($profile['role']); ?>)</p>
<?php endwhile; ?>

Summary

  1. A group field is a box that bundles related input fields—and it stops field names from colliding
  2. The basic way to pull values is get_field('box')['contents']. have_rows() plus get_sub_field() works too
  3. One set means a group; many means a repeater—choose by count
  4. Passing a sub field name straight to get_field() won’t work. Open the box, then the contents

A tidy admin screen makes the site kinder to whoever you’re asking to keep it updated.

FAQ

How do I pull a value out of a group field?
Write $g = get_field('group_name'); and then $g['sub_name']. You can also enter a loop with have_rows('group_name') and use get_sub_field('sub_name'). Naming the inner field directly, like get_field('sub_name'), won't work.
What's the difference between a group field and a repeater field?
A group is a container that holds one set of the same fields (it returns an associative array); a repeater is a container you can add as many sets to as you like (it returns an array of arrays). Use a group for things there's only one of, like company details, and a repeater for things that grow, like staff profiles.
My group field displays "Array".
The group itself is an array, so the_field('group_name') can't display it. Pull out the sub fields by name and print those instead.
Can I put a group inside a group?
Yes. To pull values out, keep walking the array like $g['inner']['key'], or nest have_rows().