Home › Forums › General Issues › How do I get optgroups in the Select field?
I’m using ACF 4.2.0.
I’ve hunted around the old/new support forums and the Web in general, and the only quasi-answer I found was this thread requesting the feature.
It looks like if choices are “2 levels deep,” optgroup is detected automatically. The problem: I can’t figure out how to make choices 2 levels deep. What’s the syntax for this?
Thanks!
Hi @chloe
The interface for entering choices only allows for 1 level of choices.
If you were to register the field via PHP, you could add in the multi-=level array of choices!
Hope that helps
Hi. Sorry for getting this up. But I have found in the same situation where I need 2 levels for Select field.
In my case, I wanted to use the interface to do that, so I have made a change in my ACF select field code to permit that. If the line in the interface starts with – (for instance -Europe ) it will assume there are optgroups, so everything that comes after that line will be for that group until next – is found.
In my case, in the interface I write:
-Europe
Spain
France
-America
Argentina
Peru
and then I get a select with optgroup where Europe and America are the group headlines and the rest are the selectable options.
In advanced_custom_fields/core/fields/select.php LINE 68 add
// Other way to group is using - in the field
if (!$optgroup) {
// vars
$new_choices = array();
// Determine if there are - to group the field
$group = false;
$choices_group = array();
$optgroup_key = "";
foreach ($field['choices'] as $k => $v) {
if (strpos($v, "-") !== false)
{
// Next elements are optgroup;
if ($group) {
$choices_group [$optgroup_key] = $new_choices;
$new_choices = array();
$optgroup_key = $v;
} else {
// Get ungrouped value from begining of the list
foreach ($new_choices as $l=>$w) {
$choices_group[$l] = $w;
}
$new_choices= array();
$group = true;
$optgroup_key = $v;
}
} else {
if(strpos($v, ' : ') !== false)
{
$choice = explode(' : ', $v);
$new_choices[ trim($choice[0]) ] = trim($choice[1]);
}
else
{
$new_choices[ trim($v) ] = trim($v);
}
}
}
if ($group) {
// End last group
$choices_group [$optgroup_key] = $new_choices;
$field['choices'] = $choices_group;
$optgroup = true;
}
}
Is this something we can expect to see in future versions of the plugin? The optgroup is something that I want to use too. Fiddeling in the plugin code isn’t really an option, since an update of the plugin will nullify the changes made.
A possibility is to develop an ACF-plugin that implements the new code and you can use it in your fields.
Anyway, yesterday I noticed a bug in my proposal regarding the value stored in the field. This is the new code:
<?php
class acf_field_select extends acf_field
{
/*
* __construct
*
* Set name / label needed for actions / filters
*
* @since 3.6
* @date 23/01/13
*/
function __construct()
{
// vars
$this->name = 'select';
$this->label = __("Select",'acf');
$this->category = __("Choice",'acf');
$this->defaults = array(
'multiple' => 0,
'allow_null' => 0,
'choices' => array(),
'default_value' => ''
);
// do not delete!
parent::__construct();
// extra
//add_filter('acf/update_field/type=select', array($this, 'update_field'), 5, 2);
add_filter('acf/update_field/type=checkbox', array($this, 'update_field'), 5, 2);
add_filter('acf/update_field/type=radio', array($this, 'update_field'), 5, 2);
}
/*
* create_field()
*
* Create the HTML interface for your field
*
* @param $field - an array holding all the field's data
*
* @type action
* @since 3.6
* @date 23/01/13
*/
function create_field( $field )
{
// vars
$optgroup = false;
// determin if choices are grouped (2 levels of array)
if( is_array($field['choices']) )
{
foreach( $field['choices'] as $k => $v )
{
if( is_array($v) )
{
$optgroup = true;
}
}
}
// Other way to group is using - in the field
if (!$optgroup) {
// vars
$new_choices = array();
// Determine if there are - to group the field
$group = false;
$choices_group = array();
$optgroup_key = "";
error_log(var_export($field['choices'],true));
foreach ($field['choices'] as $k => $v) {
if (strpos($v, "-") === 0)
{
// Next elements are optgroup;
if ($group) {
$choices_group [$optgroup_key] = $new_choices;
$new_choices = array();
$optgroup_key = $v;
} else {
// Get ungrouped value from begining of the list
foreach ($new_choices as $l=>$w) {
$choices_group[$l] = $w;
}
$new_choices= array();
$group = true;
$optgroup_key = $v;
}
} else {
if(strpos($v, ' : ') !== false)
{
$choice = explode(' : ', $v);
$new_choices[ trim($choice[0]) ] = trim($choice[1]);
}
else
{
// TODO: Change this in desdeelagua
$new_choices[ $k ] = trim($v);
}
}
}
if ($group) {
// End last group
$choices_group [$optgroup_key] = $new_choices;
$field['choices'] = $choices_group;
$optgroup = true;
}
}
// value must be array
if( !is_array($field['value']) )
{
// perhaps this is a default value with new lines in it?
if( strpos($field['value'], "\n") !== false )
{
// found multiple lines, explode it
$field['value'] = explode("\n", $field['value']);
}
else
{
$field['value'] = array( $field['value'] );
}
}
// trim value
$field['value'] = array_map('trim', $field['value']);
// multiple select
$multiple = '';
if( $field['multiple'] )
{
// create a hidden field to allow for no selections
echo '<input type="hidden" name="' . $field['name'] . '" />';
$multiple = ' multiple="multiple" size="5" ';
$field['name'] .= '[]';
}
// html
echo '<select id="' . $field['id'] . '" class="' . $field['class'] . '" name="' . $field['name'] . '" ' . $multiple . ' >';
// null
if( $field['allow_null'] )
{
echo '<option value="null">- ' . __("Select",'acf') . ' -</option>';
}
// loop through values and add them as options
if( is_array($field['choices']) )
{
foreach( $field['choices'] as $key => $value )
{
if( $optgroup )
{
// this select is grouped with optgroup
if($key != '') echo '<optgroup label="'.$key.'">';
if( is_array($value) )
{
foreach($value as $id => $label)
{
$selected = in_array($id, $field['value']) ? 'selected="selected"' : '';
echo '<option value="'.$id.'" '.$selected.'>'.$label.'</option>';
}
}
if($key != '') echo '</optgroup>';
}
else
{
$selected = in_array($key, $field['value']) ? 'selected="selected"' : '';
echo '<option value="'.$key.'" '.$selected.'>'.$value.'</option>';
}
}
}
echo '</select>';
}
/*
* create_options()
*
* Create extra options for your field. This is rendered when editing a field.
* The value of $field['name'] can be used (like bellow) to save extra data to the $field
*
* @type action
* @since 3.6
* @date 23/01/13
*
* @param $field - an array holding all the field's data
*/
function create_options( $field )
{
$key = $field['name'];
// implode choices so they work in a textarea
if( is_array($field['choices']) )
{
foreach( $field['choices'] as $k => $v )
{
$field['choices'][ $k ] = $k . ' : ' . $v;
}
$field['choices'] = implode("\n", $field['choices']);
}
?>
<tr class="field_option field_option_<?php echo $this->name; ?>">
<td class="label">
<label for=""><?php _e("Choices",'acf'); ?></label>
<p><?php _e("Enter each choice on a new line.",'acf'); ?></p>
<p><?php _e("For more control, you may specify both a value and label like this:",'acf'); ?></p>
<p><?php _e("red : Red",'acf'); ?><br /><?php _e("blue : Blue",'acf'); ?></p>
</td>
<td>
<?php
do_action('acf/create_field', array(
'type' => 'textarea',
'class' => 'textarea field_option-choices',
'name' => 'fields['.$key.'][choices]',
'value' => $field['choices'],
));
?>
</td>
</tr>
<tr class="field_option field_option_<?php echo $this->name; ?>">
<td class="label">
<label><?php _e("Default Value",'acf'); ?></label>
<p class="description"><?php _e("Enter each default value on a new line",'acf'); ?></p>
</td>
<td>
<?php
do_action('acf/create_field', array(
'type' => 'textarea',
'name' => 'fields['.$key.'][default_value]',
'value' => $field['default_value'],
));
?>
</td>
</tr>
<tr class="field_option field_option_<?php echo $this->name; ?>">
<td class="label">
<label><?php _e("Allow Null?",'acf'); ?></label>
</td>
<td>
<?php
do_action('acf/create_field', array(
'type' => 'radio',
'name' => 'fields['.$key.'][allow_null]',
'value' => $field['allow_null'],
'choices' => array(
1 => __("Yes",'acf'),
0 => __("No",'acf'),
),
'layout' => 'horizontal',
));
?>
</td>
</tr>
<tr class="field_option field_option_<?php echo $this->name; ?>">
<td class="label">
<label><?php _e("Select multiple values?",'acf'); ?></label>
</td>
<td>
<?php
do_action('acf/create_field', array(
'type' => 'radio',
'name' => 'fields['.$key.'][multiple]',
'value' => $field['multiple'],
'choices' => array(
1 => __("Yes",'acf'),
0 => __("No",'acf'),
),
'layout' => 'horizontal',
));
?>
</td>
</tr>
<?php
}
/*
* format_value_for_api()
*
* This filter is appied to the $value after it is loaded from the db and before it is passed back to the api functions such as the_field
*
* @type filter
* @since 3.6
* @date 23/01/13
*
* @param $value - the value which was loaded from the database
* @param $post_id - the $post_id from which the value was loaded
* @param $field - the field array holding all the field options
*
* @return $value - the modified value
*/
function format_value_for_api( $value, $post_id, $field )
{
if( $value == 'null' )
{
$value = false;
}
return $value;
}
/*
* update_field()
*
* This filter is appied to the $field before it is saved to the database
*
* @type filter
* @since 3.6
* @date 23/01/13
*
* @param $field - the field array holding all the field options
* @param $post_id - the field group ID (post_type = acf)
*
* @return $field - the modified field
*/
function update_field( $field, $post_id )
{
// check if is array. Normal back end edit posts a textarea, but a user might use update_field from the front end
if( is_array( $field['choices'] ))
{
return $field;
}
// vars
$new_choices = array();
// explode choices from each line
if( $field['choices'] )
{
// stripslashes ("")
$field['choices'] = stripslashes_deep($field['choices']);
if(strpos($field['choices'], "\n") !== false)
{
// found multiple lines, explode it
$field['choices'] = explode("\n", $field['choices']);
}
else
{
// no multiple lines!
$field['choices'] = array($field['choices']);
}
// key => value
foreach($field['choices'] as $choice)
{
if(strpos($choice, ' : ') !== false)
{
$choice = explode(' : ', $choice);
$new_choices[ trim($choice[0]) ] = trim($choice[1]);
}
else
{
$new_choices[ trim($choice) ] = trim($choice);
}
}
}
// update choices
$field['choices'] = $new_choices;
return $field;
}
}
new acf_field_select();
?>
Ok, cool.
Can I use this code in a new plugin? I see it extends the ACF class, so this works ‘stand-alone’?
This is the direct modification on the ACF core code for select. I think modifications are needed to have it as a plugin.
I don’t know if I’ll have time soon to make a plugin that uses this code, but of course you feel free to use it if you want
Hm, ok, if I do this programmaticly I can already use the optgroup. In that case, it can already do what I need it to 🙂
cool. My code was because I needed to do optgroup filling values in the admin dashboard. So I introduced the – before the first work to indicate an optgroup 🙂
Ah right. Mine will be filled programmaticly. So if I understand correctly, a multi-dimensional array will do the trick. something like
array(
'Optgroup' => array( 'choice1', 'choice2' );
)
etc.
Hi,
Do you know how can I display this optgroup and all the options set in this topic in my form as a select element? I mean exactly the way it looks like in the WordPress panel.
Thank you in advance.
As an update, this appears to be in the default ACF with a action hook now. For example:
add_filter('acf/load_field/key=field_12345678', 'acf_create_select');
function acf_create_select( $field ) {
$field['choices'] = array();
$choices = get_my_options();
foreach( $choices as $t ) {
if ( !isset( $field['choices'][ $t->optgroup ] ) )
$field['choices'][ $t->optgroup ] = array();
$field['choices'][ $t->optgroup ][ $t->item_value ] = $t->item_text;
}
return $field;
}
The topic ‘How do I get optgroups in the Select field?’ is closed to new replies.
Welcome to the Advanced Custom Fields community forum.
Browse through ideas, snippets of code, questions and answers between fellow ACF users
Helping others is a great way to earn karma, gain badges and help ACF development!
We use cookies to offer you a better browsing experience, analyze site traffic and personalize content. Read about how we use cookies and how you can control them in our Privacy Policy. If you continue to use this site, you consent to our use of cookies.