WordPress.org

Make WordPress Core

Opened 17 months ago

Last modified 4 months ago

#47692 new enhancement

Optgroup in Customizer Select Control

Reported by: chintan1896 Owned by:
Milestone: Future Release Priority: normal
Severity: normal Version: 3.4
Component: Customize Keywords: has-patch needs-testing
Focuses: Cc:

Description

Optgroup add in Customizer Select Control

Attachments (4)

47692.diff (1.6 KB) - added by chintan1896 17 months ago.
wp-includes/class-wp-customize-control.php
47692-new.diff (1.8 KB) - added by chintan1896 12 months ago.
I attached new changes for optgroup
47692-updated.patch (1.2 KB) - added by chintan1896 11 months ago.
Changes for some choices in an optgroup and some at the top level of the select
customizer_javascript_optgroup.diff (2.0 KB) - added by Lwangaman 7 months ago.
patch for wp-includes/class-wp-customize-manager.php which enables optgroup in select choices

Download all attachments as: .zip

Change History (31)

@chintan1896
17 months ago

wp-includes/class-wp-customize-control.php

#1 @chintan1896
17 months ago

Example for select optgroup

<?php
$wp_customize->add_control( new WP_Customize_Control( $wp_customize, 'optgroup_example', array(
                'label'             => esc_attr__( 'Optgroup example', 'text-domain' ),
                'setting'           => 'optgroup_example',
                'type'              => 'select',
                'optgroup'          => true,
                'choices'           =>  array( 
                                    'optgroup-label-1' => array( 
                                                                'value-1'=> __( 'value-1', 'text-domain' ) 
                                                        ),
                                    'optgroup-label-2' => array( 
                                                                'value-2'=> __( 'value-2', 'text-domain' ) 
                                                        ),
                                ),
        ) ) );


Last edited 17 months ago by chintan1896 (previous) (diff)

#2 @silas2209
14 months ago

Any new updates here? I'd be very happy about this feature!

#3 @dlh
12 months ago

  • Keywords needs-patch added; has-patch removed
  • Milestone changed from Awaiting Review to Future Release
  • Version changed from 5.3 to 3.4

Support for optgroup would also needed to be added to the JavaScript control template, I think, not just the PHP template.

I also wonder about the $optgroup property in 47692.diff. What happens if a multidimensional array is used for $choices but $optgroup is false, or vice versa?

#4 @chintan1896
12 months ago

  • Keywords needs-testing has-patch added; needs-patch removed

Hey @dlh ,
Please review on latest patch.

@chintan1896
12 months ago

I attached new changes for optgroup

#5 @dlh
12 months ago

  • Keywords needs-patch added; needs-testing has-patch removed

Thanks for the updated patch, @chintan1896.

The new patch does guard against PHP errors, but it still seems to me to leave room for developer confusion. If $optgroup is changed without changing the shape of $choices, or vice versa, the control disappears.

Also, what if the developer wants some choices in an optgroup and some at the top level of the select?

I also don't see any change to the JavaScript control template in 47692-new.diff. Was it left out by accident?

@chintan1896
11 months ago

Changes for some choices in an optgroup and some at the top level of the select

#6 @chintan1896
11 months ago

Hey @dlh,
Please review on updated patch. It is overcome developer confusion and some choices in an optgroup and some at the top level of the select.

I have not enough knowledge in underscore.js . So i can't code in JavaScript control template.

This is a new example for optgroup and now we don't need to define optgroup it's automatically add optgroup if we added multidimensional array.

<?php
$wp_customize->add_control( new WP_Customize_Control( $wp_customize, 'optgroup_example', array(
        'label'         => esc_attr__( 'Optgroup example', 'text-domain' ),
        'setting'       => 'optgroup_example',
        'type'          => 'select',
        'section'       => 'title_tagline',
        'choices'       =>  array(
                            'simple-option'    => __( 'Simple option', 'text-domain' ) ,
                            'optgroup-label-1' => array( 
                                                    'value-1'=> __( 'value-1', 'text-domain' ) 
                                                ),
                            'optgroup-label-2' => array( 
                                                    'value-2'=> __( 'value-2', 'text-domain' ) 
                                                ),
                        ),
) ) );
Last edited 11 months ago by chintan1896 (previous) (diff)

#7 @chintan1896
7 months ago

Hey @dlh,
Do you have any upadats on this ticket ?

#8 @dlh
7 months ago

No update, @chintan1896. This ticket still needs a patch that accounts for the JavaScript template.

#9 @Lwangaman
7 months ago

Which js file defines the components? I am also interested in having optgroup labels. I could take a look at the JavaScript templates but I'm not sure where to look?
Also, I believe some developer confusion could come from the fact that "choices" expect the "value" as the property name, and the "label" as the property value (in the current class-wp-customize-control.php code). Wouldn't it be more logical for the "label" to the property name, and the "value" to be the property value? Like this:

<?php
<select id="<?php echo esc_attr( $input_id ); ?>" <?php echo $describedby_attr; ?> <?php $this->link(); ?>>
        <?php
        foreach ( $this->choices as $label => $value ) {
                echo '<option value="' . esc_attr( $value ) . '"' . selected( $this->value(), $value, false ) . '>' . $label . '</option>';
        }
        ?>
</select>

Then it would be much easier to check if "$value" is an array, and in such a case "$label" would become the optgroup label and "$value" would be parsed for the options that fall under that optgroup label. There would be no need to set an "optgroup:true", it would be implicit when the value is an array of more "label=>value" associations.
The same would have to apply to radio groups for consistency. Changing this would obviously break current setups that use these components. But it would seem more logical to me...

Last edited 7 months ago by Lwangaman (previous) (diff)

#10 follow-up: @Lwangaman
7 months ago

Perhaps a way to transition this to new logic could be to add the possibility of using "options" instead of "choices" in a transition phase, explaining the difference in the documentation and inviting to transition to the new style "options" instead of "choices". Then it could be handled something like this:

<?php
case 'select':
        if ( empty( $this->choices ) && empty( $this->options ) ) {
                return;
        }
        ?>
        <?php if ( ! empty( $this->label ) ) : ?>
                <label for="<?php echo esc_attr( $input_id ); ?>" class="customize-control-title"><?php echo esc_html( $this->label ); ?></label>
        <?php endif; ?>
        <?php if ( ! empty( $this->description ) ) : ?>
                <span id="<?php echo esc_attr( $description_id ); ?>" class="description customize-control-description"><?php echo $this->description; ?></span>
        <?php endif; ?>


        <select id="<?php echo esc_attr( $input_id ); ?>" <?php echo $describedby_attr; ?> <?php $this->link(); ?>>
                <?php
                if( ! empty( $this->choices ) ){
                        foreach ( $this->choices as $value => $label ) {
                                echo '<option value="' . esc_attr( $value ) . '"' . selected( $this->value(), $value, false ) . '>' . $label . '</option>';
                        }
                }
                else if( ! empty( $this->options ) ){
                        foreach ( $this->options as $label => $value ) {
                                if(is_array($value) && !empty( $value ) ){
                                        echo '<optgroup label="' . esc_attr( $label ) . '">';
                                        foreach( $value as $optgrouplabel => $optgroupvalue ){
                                                echo '<option value="' . esc_attr( $optgroupvalue  ) . '"' . selected( $this->value(), $optgroupvalue , false ) . '>' . $optgrouplabel. '</option>';
                                        }
                                        echo '</optgroup>';
                                }
                                else{
                                        echo '<option value="' . esc_attr( $value ) . '"' . selected( $this->value(), $value, false ) . '>' . $label . '</option>';
                                }
                        }
                }
                ?>
        </select>

Last edited 7 months ago by Lwangaman (previous) (diff)

#11 @Lwangaman
7 months ago

I'm guessing this would be where the Javascript templates are defined?
/wp-includes/js/dist/vendor/react-dom.js
If not, where exactly?

#12 @dlh
7 months ago

@Lwangaman The JS templates are defined in \WP_Customize_Manager::render_control_templates().

#13 in reply to: ↑ 10 ; follow-up: @chintan1896
7 months ago

Hey @Lwangaman,

What if the developer wants some choices in an optgroup and some at the top level of the select? So i believe with this patch code 47692-updated.patch developer can easily manage if developer add multidimensional array so it will convert automatically in optgroup otherwise work as per current working. If you have knowledge about JavaScript template so please help me to add this functionality in WordPress.

Thanks,
Chintan

#14 in reply to: ↑ 13 @Lwangaman
7 months ago

Replying to chintan1896:

Hey @Lwangaman,

What if the developer wants some choices in an optgroup and some at the top level of the select? So i believe with this patch code 47692-updated.patch developer can easily manage if developer add multidimensional array so it will convert automatically in optgroup otherwise work as per current working. If you have knowledge about JavaScript template so please help me to add this functionality in WordPress.

Thanks,
Chintan

Oh I see, the boolean flag was in the original patch and not in the updated patch.
I also can see why the option label would be declared as the property value, if you want to have spaces in the label for example it would not be recommended practice to have a property name with spaces, so I guess it is best to leave the option label as the property value. Considering that, your updated patch is the closest to the current logic. I will look into the javascript portion and update here if I have any luck.

#15 @chintan1896
7 months ago

I have code in JavaScript template. But i am confused how to test my code working properly or not?

Below file code - wp-includes/class-wp-customize-manager.php

<select
     <# _.each( _.extend( inputAttrs ), function( value, key ) { #>
                                                                {{{ key }}}="{{ value }}"
        <# }); #>
        >
        <# _.each( data.choices, function( val, data ) { #>
                <# var value, text;
                if ( _.isObject( val ) ) {
                        value = val.value;
                        text = val.text;
                } else {
                        value = data;
                        text = val;
                }
                if ( _.isArray( value ) && ! _.isEmpty( value ) ) { 
                        #>
                                <optgroup label="{{ value }}">
                                        <# _.each( value, function( optgroup_val, optgroup_data ) { #>
                                                <option value="{{ optgroup_val }}">{{ optgroup_data }}</option>
                                        <# } #>
                                </optgroup>
                        <#
                } else {
                #>
                        <option value="{{ value }}">{{ text }}</option>
                <#
                }
                #>
        <# } ); #>
</select>
Last edited 7 months ago by chintan1896 (previous) (diff)

#16 @Lwangaman
7 months ago

I can see a problem there already: in javascript arrays are also objects. I'm not sure of all the use cases of the select component in the customizer but I have a hunch there could be a problem here if

_.isObject( val )

evaluates to true because we are using an array as the value. It probably would not however find a val.value property in this object.

It would be useful to know in which cases the choices value is a string and in which cases it is an object, in the current state of things.

Last edited 6 months ago by Lwangaman (previous) (diff)

#17 @Lwangaman
7 months ago

I'm guessing this might work, I will test it now:

<# } else if ( 'select' === data.type ) { #>
        <# delete inputAttrs.type; #>
        <select
                <# _.each( _.extend( inputAttrs ), function( value, key ) { #>
                        {{{ key }}}="{{ value }}"
                <# }); #>
                >
                <# _.each( data.choices, function( val, key ) { #>
                        <#
                        var value, text;
                        if ( _.isObject( val ) && _.isArray( val ) ) {
                                var optgpval, optgptext, data;
                                value = key;
                                data = val;
                                #>
                                <optgroup label="{{ value }}">
                                <# _.each(data, function(val, key ) { 
                                        optgpval = key;
                                        optgptext = val; #>
                                        <option value="{{ optgpval }}">{{ optgptext }}</option>
                                <# } ); #>
                                </optgroup>
                                <#
                        }
                        else if( _.isObject( val ) && !_.isArray( val ) ){
                                value = val.value;
                                text = val.text;
                        } else {
                                value = key;
                                text = val;
                        }
                        #>
                        <option value="{{ value }}">{{ text }}</option>
                <# } ); #>
        </select>
<# } else { #>

Last edited 7 months ago by Lwangaman (previous) (diff)

#18 @Lwangaman
7 months ago

Something else is missing. I have an InspectorControls panel for a plugin's Gutenberg block that I created. Here is some sample (simplified, exemplified) code with the Select component.

First I build my choices or options as an array of objects:

let favouriteFoodsSelectOptions = [
        { value: "peas",        label: "Green Peas" },
        { value: "apples",      label: "Red apples" },
        { value: "carrots",     label: "Carrots" },
        { value: "chocolate",   label: "Chocolate" },
        { value: "oranges",     label: "Oranges" },
        { value: "chicken",     label: "Grilled chicken breast" },
        { value: "turkey",      label: "Roasted turkey" },
        { value: "pudding",     label: "Tapioca pudding" },
];

Then inside of my edit(props) I have:

return createElement('div', {}, [
        createElement(Fragment, {},
                createElement(InspectorControls, {},
                        createElement(PanelBody, { title: __('Some options', 'plugin_namespace'), initialOpen: true, icon: 'download' },
                                createElement(PanelRow, {},
                                        //Select one or more options
                                        createElement(SelectControl, {
                                                value: attributes.foods,
                                                label: __('Your favourite foods', 'plugin_namespace'),
                                                onChange: changeFoods,
                                                multiple: true,
                                                options: favouriteFoodsSelectOptions,
                                                help: __('You can select one or more of these options. In order to select more than one, hold down the CTRL key while clicking.', 'plugin_namespace')
                                        })
                                ) //end PanelRow
                        ) //end PanelBody
                ) //end InspectorControls
        ) //end Fragment
])

And this is currently working.
However, I would like to be able to organize these options by food category. After implementing the PHP patch and the javascript patch I posted, I tried modifying my options array like this:

let favouriteFoodsSelectOptions = [
        { label: "Vegetables",  value: [
                                        { value: "peas",        label: "Green Peas" }
                                        { value: "carrots",     label: "Carrots" },
                                ]
        },
        { label: "Meats",       value: [
                                        { value: "chicken",     label: "Grilled chicken breast" },
                                        { value: "turkey",      label: "Roasted turkey" },
                                ]
        },
        { label: "Fruits",      value: [
                                        { value: "apples",      label: "Red apples" },
                                        { value: "oranges",     label: "Oranges" },
                                ]
        },
        { label: "Desserts",    value: [
                                        { value: "chocolate",   label: "Chocolate" },
                                        { value: "pudding",     label: "Tapioca pudding" },
                                ]
        }
];

But this doesn't work, I just see the labels in the rendered select, no optgroups and no values.

There must be another intermediate file somewhere that translates between react components and \WP_Customize_Manager::render_control_templates()

Last edited 7 months ago by Lwangaman (previous) (diff)

#19 @Lwangaman
7 months ago

I see where it is in the Gutenberg development repository on Github, but where would this be in the actual WordPress source code?

https://github.com/WordPress/gutenberg/blob/master/packages/components/src/select-control/index.js

#20 @dlh
7 months ago

@Lwangaman I'm having a little trouble following these comments. The Customizer doesn't currently use React or any Gutenberg components. Are you working from an installation with no active plugins and a default theme?

#21 @Lwangaman
7 months ago

Oh I see, so React components as used in Gutenberg blocks are defined elsewhere. I guess the Customizer components are distinct from the Gutenberg block editor components? My interest was that of implementing a SelectControl component for Gutenberg block development which allowed for optgroups, but I guess that code (in WordPress core) has nothing to do with this thread then? In that case, I can perhaps try to open a similar thread on the above linked Gutenberg source code for the SelectControl component...

Last edited 7 months ago by Lwangaman (previous) (diff)

#22 @Lwangaman
7 months ago

Using PHP I can confirm that the updated patch by @chintan1896 is working correctly, here is the result in the WordPress Customizer: https://imgur.com/3rQwSHi

And here is my PHP code:

<?php
                $wp_customize->add_setting(
                        'myoptgroup', //No need to use a SERIALIZED name, as `theme_mod` settings already live under one db record
                        array(
                                'default'    => 'carrots', //Default setting/value to save
                                'type'       => 'theme_mod', //Is this an 'option' or a 'theme_mod'?
                                'capability' => 'edit_theme_options', //Optional. Special permissions for accessing this setting.
                                'transport'  => 'postMessage' //What triggers a refresh of the setting? 'refresh' or 'postMessage' (instant)?
                        )
                );

                $wp_customize->add_control(
                        'myoptgroup_ctl',
                        array(
                                'label'                 => 'My OptGroup with Food choices',
                                'settings'              => 'myoptgroup',
                                'priority'              => 10,
                                'section'               => 'a_section_of_my_options',
                                'type'                  => 'select',
                                'choices'               => array(
                                                        'Fruits'                => array('apples' => 'Green apples', 'pears' => 'Pears', 'bananas' => 'Chiquita bananas' ),
                                                        'Vegetables'    => array('peas' => 'Peas', 'carrots' => 'Carrots', 'tomatoes' => 'Cherry tomatoes' ),
                                                        'Meats'                 => array('chicken' => 'Grilled chicken breast', 'turkey' => 'Roasted turkey', 'sausages' => 'Blood sausages' ),
                                                        'Desserts'              => array('icecream' => 'Mint chocolate chip ice cream', 'pudding' => 'Tapioca pudding'),
                                                        'supper'                => 'Home cooked dinner meal',
                                                        'lunch'                 => 'Fast food take-away lunch'
                                                )
                        )
                );
        }

#23 @Lwangaman
7 months ago

BTW, is there no support for the "multiple" attribute in the WordPress Customizer controls? The "multiple" attribute is supported for Gutenberg (react) components...

#24 @Lwangaman
7 months ago

After some testing in javascript, I have come up with this working code:

<select
        <# _.each( _.extend( inputAttrs ), function( value, key ) { #>
                {{{ key }}}="{{ value }}"
        <# }); #>
        >
        <# _.each( data.choices, function( val, key ) { #>
                <#
                var value, text;
                if ( _.isObject( val ) ) {
                        if(val.hasOwnProperty('value') && val.hasOwnProperty('text') ){
                                value = val.value;
                                text = val.text;
                                #>
                                <option value="{{ value }}">{{ text }}</option>
                                <#
                        }
                        else{
                                //if val is an object but doesn't directly have "value" or "text" properties, we are probably dealing with an optgroup
                                text = key;
                                value = val;
                                #>
                                <optgroup label="{{ text }}">                                                                           
                                <#
                                var optgroupvalue, optgrouptext;
                                if( _.isArray( value ) ){
                                        _.each( value, function( val, key ) {
                                                if( _.isObject( val ) && val.hasOwnProperty('value') && val.hasOwnProperty('text') ){
                                                        optgroupvalue = val.value;
                                                        optgrouptext = val.text;
                                                        #>
                                                        <option value="{{ optgroupvalue }}">{{ optgrouptext }}</option>
                                                        <#
                                                }
                                        } );
                                }
                                else{
                                        _.each( value, function( val, key ) {
                                                optgroupvalue = key;
                                                optgrouptext = val;
                                                #>
                                                <option value="{{ optgroupvalue }}">{{ optgrouptext }}</option>
                                                <#
                                        } );
                                }
                                #>
                                </optgroup>
                                <#
                        }
                } else {
                        value = key;
                        text = val;
                        #>
                        <option value="{{ value }}">{{ text }}</option>                                                         
                        <#
                }
                #>
        <# } ); #>
</select>

And here are my working examples:

  • Example 1 : only top level options, using objects with "value" and "text" properties (already available in current wordpress core)
    wp.customize.control.add(new wp.customize.Control('myoptgroup2', {
            type: 'select',
            settings: 'myoptgroup2',
            section: 'a_section_of_my_options',
            label: 'My OptGroup with Animal choices',
            choices: [
                    { value: 'tiger', text: 'Tiger' },
                    { value: 'lion', text: 'Lion' },
                    { value: 'eagle', text: 'Eagle' },
                    { value: 'whale', text: 'Whale' },
            ]
    }));
    
    
  • Example 2: only top level options, using key => value pairs (already available in current wordpress core)
    wp.customize.control.add(new wp.customize.Control('myoptgroup2', {
            type: 'select',
            settings: 'myoptgroup2',
            section: 'a_section_of_my_options',
            label: 'My OptGroup with Animal choices',
            choices: {
                    'tiger' : 'Tiger',
                    'lion' : 'Lion',
                    'eagle' : 'Eagle',
                    'whale' : 'Whale',
            }
    }));
    
    
  • Example 3: both top level options and optgroup options, using array of objects with "value" and "text" properties
    wp.customize.control.add(new wp.customize.Control('myoptgroup2', {
            type: 'select',
            settings: 'myoptgroup2',
            section: 'a_section_of_my_options',
            label: 'My OptGroup with Animal choices',
            choices: {
                    'Land' : [
                            { value: 'tiger', text: 'Tiger' }, 
                            { value: 'lion', text: 'Lion' }
                    ],
                    'Sea': [
                            { value: 'whale', text: 'Whale' }, 
                            { value: 'salmon', text: 'Salmon' }
                    ],
                    'Air': [
                            { value: 'eagle', text: 'Eagle' }, 
                            { value: 'woodpecker', text: 'Woodpecker' }
                    ],
                    'mammals' : 'Mammals',
                    'jungle' : 'Jungle wildlife'
            },
    }));
    
    
  • Example 4: both top level options and optgroup options, using objects with key => value pairs
    wp.customize.control.add(new wp.customize.Control('myoptgroup2', {
            type: 'select',
            settings: 'myoptgroup2',
            section: 'a_section_of_my_options',
            label: 'My OptGroup with Animal choices',
            choices: {
                    'Land': { 'tiger': 'Tiger', 'lion': 'Lion' },
                    'Sea': { 'whale': 'Whale', 'salmon': 'Salmon' },
                    'Air': { 'eagle': 'Eagle', 'woodpecker': 'Woodpecker' },
                    'mammals' : 'Mammals',
                    'jungle' : 'Jungle wildlife'
            },
    }));
    
    

Of course in the last two examples, you could insert the top level options either with key:value pairs, or with an object that has "value" and "text" properties. So you can mix the flavours every which way, and they all work.
Here is an image of the result of the last two examples: https://imgur.com/bMA4n3k

@Lwangaman
7 months ago

patch for wp-includes/class-wp-customize-manager.php which enables optgroup in select choices

#25 @Lwangaman
4 months ago

  • Keywords has-patch needs-testing added; needs-patch removed

So to summarize, there are now two patches which will bring about this functionality:
1) @chintan1896 's patch https://core.trac.wordpress.org/attachment/ticket/47692/47692-updated.patch
for the PHP portion
2) my own patch https://core.trac.wordpress.org/attachment/ticket/47692/customizer_javascript_optgroup.diff for the javascript portion

My own local testing confirms that these patches are working as expected, producing the desired results. If a committing developer could please test these two patches and confirm that they add the requested functionality correctly, we could perhaps proceed to apply them?

This ticket was mentioned in PR #430 on WordPress/wordpress-develop by JohnRDOrazio.


4 months ago

  1. Applied patch by @chintan1896 which allows for optgroups in Customizer Select Controls when created in PHP (just fixed whitespacing and changed $optgroup_data variable to $optgroup_label ($optgroup_value => $optgroup_data to $optgroup_value => $optgroup_label) in order to be more in line with the original code for creating Select Controls, which uses $value => $label)
  2. Applied patch by yours truly @JohnRDOrazio (@Lwangaman) which allows for optgroups in Customizer Select Controls when created using the Javascript API

Examples of creating a Customizer Select Control after applying the patches (tested locally, working according to my testing):

  1. Creation of Customizer Select Control in PHP allowing for both *top level options* and *optgroup options* together:

{{{php
<?php

$wp_customize->add_setting(

'myoptgroup', No need to use a SERIALIZED name, as theme_mod settings already live under one db record
array(

'default' => 'carrots', Default setting/value to save
'type' => 'theme_mod',
Is this an 'option' or a 'theme_mod'?
'capability' => 'edit_theme_options', Optional. Special permissions for accessing this setting.
'transport' => 'postMessage'
What triggers a refresh of the setting? 'refresh' or 'postMessage' (instant)?

)

);

$wp_customize->add_control(

'myoptgroup_ctl',
array(

'label' => 'My OptGroup with Food choices',
'settings' => 'myoptgroup',
'priority' => 10,
'section' => 'a_section_of_my_options',
'type' => 'select',
'choices' => array(

'Fruits' => array('apples' => 'Green apples', 'pears' => 'Pears', 'bananas' => 'Chiquita bananas' ),
'Vegetables' => array('peas' => 'Peas', 'carrots' => 'Carrots', 'tomatoes' => 'Cherry tomatoes' ),
'Meats' => array('chicken' => 'Grilled chicken breast', 'turkey' => 'Roasted turkey', 'sausages' => 'Blood sausages' ),
'Desserts' => array('icecream' => 'Mint chocolate chip ice cream', 'pudding' => 'Tapioca pudding'),
'supper' => 'Home cooked dinner meal',
'lunch' => 'Fast food take-away lunch'

)

)

);

}

}}}

  1. Creation of Customizer Select Control in Javascript using only *top level options* and using an array of objects with value and text properties (already available in current wordpress core without applying the patch, useful for comparison with the example that comes after):

{{{javascript
wp.customize.control.add(new wp.customize.Control('myoptgroup2', {

type: 'select',
settings: 'myoptgroup2',
section: 'a_section_of_my_options',
label: 'My OptGroup with Animal choices',
choices: [

{ value: 'tiger', text: 'Tiger' },
{ value: 'lion', text: 'Lion' },
{ value: 'eagle', text: 'Eagle' },
{ value: 'whale', text: 'Whale' },

]

}));
}}}

  1. Creation of Customizer Select Control in Javascript using both *top level options* and *optgroup options*, using an array of objects with value and text properties (after patch is applied):

{{{javascript
wp.customize.control.add(new wp.customize.Control('myoptgroup2', {

type: 'select',
settings: 'myoptgroup2',
section: 'a_section_of_my_options',
label: 'My OptGroup with Animal choices',
choices: {

'Land' : [

{ value: 'tiger', text: 'Tiger' },
{ value: 'lion', text: 'Lion' }

],
'Sea': [

{ value: 'whale', text: 'Whale' },
{ value: 'salmon', text: 'Salmon' }

],
'Air': [

{ value: 'eagle', text: 'Eagle' },
{ value: 'woodpecker', text: 'Woodpecker' }

],
'mammals' : 'Mammals',
'jungle' : 'Jungle wildlife'

},

}));
}}}

  1. Creation of Customizer Select Control in Javascript using only *top level options* and using an object with key : value pairs (already available in current wordpress core without applying the patch, useful for comparison with the example that comes after):

{{{javascript
wp.customize.control.add(new wp.customize.Control('myoptgroup2', {

type: 'select',
settings: 'myoptgroup2',
section: 'a_section_of_my_options',
label: 'My OptGroup with Animal choices',
choices: {

'tiger' : 'Tiger',
'lion' : 'Lion',
'eagle' : 'Eagle',
'whale' : 'Whale',

}

}));
}}}

  1. Creation of Customizer Select Control in Javascript using both *top level options* and *optgroup options*, using an object with key : value pairs (after patch is applied):

{{{javascript
wp.customize.control.add(new wp.customize.Control('myoptgroup2', {

type: 'select',
settings: 'myoptgroup2',
section: 'a_section_of_my_options',
label: 'My OptGroup with Animal choices',
choices: {

'Land': { 'tiger': 'Tiger', 'lion': 'Lion' },
'Sea': { 'whale': 'Whale', 'salmon': 'Salmon' },
'Air': { 'eagle': 'Eagle', 'woodpecker': 'Woodpecker' },
'mammals' : 'Mammals',
'jungle' : 'Jungle wildlife'

},

}));
}}}

In the examples 3 and 5, I believe you would only be able to insert the top level options as key:value pairs, you would not be able to use an object that has value and text properties because choices can only take an object with key:value pairs, it can no longer be an array of objects with value and text properties. So as long as there are *only* top-level options, you can use either style, but if you use optgoups the top-level options could only be simple key:value pairs.

Here is an image of the result of the last examples 3 and 5 from my local testing after applying the patch:

https://imgur.com/bMA4n3k

Trac ticket: #47692

#27 @Lwangaman
4 months ago

I made a Pull request for code review on the WordPress Github repo to see in the meantime if all build tests pass, and that is currently the case. I guess we just need someone with committer rights to test and do a last review on the code?

Note: See TracTickets for help on using tickets.