How to Create ACF Nested Select / Optgroup

A nested select using is still a missing basic feature from ACF. In today's tip, we are going to learn how to enable it.

Update 16 Oct 2020: Code snippet has been updated to support version 5.9.x

A nested select using <optgroup> is still a missing basic feature from ACF.

In today’s tip, we are going to learn how to enable nested options just like shown below:

ACF Select field with nested options

The Choices Format

ACF Select configuration

The Choices setting is just a plain textarea (shown above), so we need to determine a format to know which one is the group label.

For this example, the line that begins with # will be turned into group label.

Here’s the setting of our Choices:

#America
us : United States
ca : Canada
mx : Mexico
#Europe
uk : United Kingdom
de : German
fr : France

The Hook

What we are trying to achieve is to create a nested Array using the group label as it’s parent. Then pass it to the choices argument.

// Don't forget to change the 'name'
add_filter('acf/prepare_field/name=country', 'acf_allow_optgroup');

function acf_allow_optgroup( $field ) {
  // Abort if it's native option
  if( $field['ID'] === 0 ) { return $field; }

  $raw_choices = $field['choices'];
  $choices = [];

  $current_group = '';
  foreach( $raw_choices as $value => $label ) {

    // if first letter is hashtag, turn it into group label
    if( preg_match( '/^#(.+)/', $label, $matches ) ) {
      $current_group = str_replace( '#', '', $label );
      $choices[ $current_group ] = [];
    }
    // If group label already defined before this line
    elseif( !empty( $current_group ) ) {
      $choices[ $current_group ][ $value ] = $label;
    }
    else {
      $choices[ $value ] = $label;
    }
  }

  $field['choices'] = $choices;
  return $field;
}

That’s all! Don’t forget to change the filter name to fit your field.


Conclusion

This is one of those little things that make it easier for my client to edit their own site.

I hope the ACF developer will add a native way to do this. I actually notified him back in 2017 via this Github thread but I don’t think he will add it.

As always, ask any question about ACF Nested Select in the comment below 🙂

Default image
Henner Setyono
A web developer who mainly build custom theme for WordPress since 2013. Young enough to never had to deal with using Table as layout.
Leave a Reply

6 Comments

  1. Thanks and awesome job! It worked perfectly 🙂

    I did change it to work on all select fields w/:

    add_filter('acf/prepare_field/type=select', 'acf_allow_optgroup');
    • Thanks, glad you find it useful.

      The reason why I use a specific field name for the filter is to have better performance. But I don't think it's even slightly noticeable.

      • Thanks @Henner for this suggestion.

        How can we do this for Taxonomy ACF select field, where options are coming from taxonomy which has nested parent-child heirarcy?

        • Hi Sandy, I just checked my Taxonomy ACF Select. It automatically list them in parent-child order. So you don't need to write any custom code.

          • Thanks for prompt response 🙂

            Yes, it shows in parent-child by default by adding the prefix of a hyphen (-) and increments based on the child e.g. below.

            - Parent 1
            -- Child 1
            -- Child 2
            --- Parent 2
            ---- Child 3
            - Parent 3
            -- Child 4
            

            How can we make optgroup for all the parents, where all these choices are coming from taxonomy?

            • Hi, I guess we can use the prepare_field filter as seen in this article to do this. Use var_dump($field) to see what you can modify.

              If it works the same way as a SELECT field, then it will be an optgroup if you return a nested array.

              Unless you want to make the parent category not selectable by maknig it optgroup, just stick with the native one.