Home › Forums › General Issues › Disable Options for Select Field
Hi We are using ACF Pro for some plugin we developed.
We have a frontend form where anonymous users could submit and draft entries of some custum post type is generated.
We have now the problem that we wanted to replace some options for some select field.
Were some options shouldn’t be not available any more for new entries.
But of course still should be selectable for admins (e.g. update old entries), frontend update by the entry owners (link to some form with update mode via email).
And for the frontend search form and item listing we also need old options to be selectable.
function filter_choices($field, $all_choices = false)
{
if (is_admin()) {
$all_choices = true;
}
if ($all_choices) {
$field['choices'] = array(
'key1' => 'value 1',
'key2' => 'value 2'
'key3' => 'value 3'
);
} else {
$field['choices'] = array(
'key3' => 'value 3'
);
}
return $field;
}
add_filter('acf/load_field/name=select_field_name', 'filter_choices', 10 , 2);
with that we could have
– all options available for admins
– only the new options available for new inserts via the frontend form
– have the possibility to apply the filter with all_choices= true for the search form.
But we have the problem when the user edits an existing entry.
Everything would be easy if the “post_id” is given to the filter functions
because for new entries it would be something like $post_id= ‘new_post’;
but for existing entries a real post_id.
We also tried to just disable some options by adding the following to the filter.
which was mentioned here:
https://support.advancedcustomfields.com/forums/topic/field-object-shows-load_field-as-working-but-it-doesnt-render-that-way/
$disabled_options = array('key1', 'key2');
foreach ($disabled_options as $value) {
$disabled[$value] = true;
}
$field['disabled'] = $disabled;
but sadly this only disables the complete select field.
From the look into the source code i also couldn’t find a possibility how single options could be disabled.
try changing your priority to 20
add_filter('acf/load_field/name=select_field_name', 'filter_choices', 20 , 2);
I take that back, it will not help. The ACF select field does not have the ability to disable individual options. You might want to contact them and ask to have this feature added https://www.advancedcustomfields.com/contact/
In the mean time the only solution I can think of it to do it with JavaScript.
What should increasing the priority to 20 change?
From the “class-acf-field-select.php” i see that there isn’t an possibility to “disable” options.
The select itself use the “disable” in line 318.
if( !empty($field['disabled']) ) $select['disabled'] = 'disabled';
the select itself is rendered via
acf_select_input( $select );
which is in acf-input-functions.php
acf_get_select_input calls acf_walk_select_input($choices, $value)
where the “option tags are rended with “value”, “selected” and “data-i” attributes.
So no “disabled” html attribute.
// single (option)
} else {
$attrs = array(
'value' => $value
);
// If is selected.
$pos = array_search( esc_attr($value), $values );
if( $pos !== false ) {
$attrs['selected'] = 'selected';
$attrs['data-i'] = $pos;
}
$html .= sprintf( '<option %s>%s</option>', acf_esc_attr($attrs), esc_html($label) );
}
If there would be a way to access the form “post_id” to filter function of the field i could delete the “not wanted options” from the array when post_id is e.g. “new_post”.
Sorry, increasing the priority was a quick answer before I actually looked into the ACF code and posted my second answer.
Increasing the priority is my first step whenever I’m debugging some issue in ACF. Why? because ACF initializes the field on the same hook that you use. There are filters in ACF itself for acf/load_field...
and all of the ACF filters run with a priority of 10. ACF’s filters do not look any changes that may have already been made and loads the field with all default settings, meaning that if you’re filter runs before ACF’s filter that anything you change is ignored and replaced with the original values. Changing the priority to > 10 ensures that you filter runs only after ACF is done an eliminates that as a cause. When I tested your issue myself, this is the first thing I tried before looking at the ACF code.
At any rate, that is not the solution. There are other fields that do allow disabling of individual options. The checkbox and radio field have this ability by passing the array you have in the OP. More than likely it is an oversight that it is not also include for the select field, which is why I suggested contacting support.
Thx John for the explanation of the priority.
I already thought that this is the intention.
My Problem also isn’t that I don’t able to change the options (remove some) on specific conditions.
My problem is that i couldn’t fulfil all the requirements we have.
The missing option to disable individual options entries (weird sentence ^^) is an additional point.
We have already contacted the support but still waiting for some answer.
have a nice weekend 🙂
Looking at the OP.
You want to remove some values for new entries, but allow them on current entries, or when an admin is editing. I would simply remove them from the front end of the site or based on other things. Removing an choice in a select field will not remove that value where it has already been selected.
add_filter('acf/prepare_field/name=select_field_name', 'filter_choices', 20);
function filter_choices($field) {
if (is_user_logged_in() && current_user_can('administrator')) {
// not for admins
return $field;
}
// values to remove
$remove = array(1, 2, 3);
// get the current value of the field
$value = acf_get_array($field['value']);
// get all field choices
$choices = field['choices'];
// clear the field choices
$field['choices'] = array();
foreach ($choices as $v => $l) {
if (!in_array($v, $remove) || in_array($v, $value)) {
// this value should not be removed
// or it might have been previously selected
// so keep it
$field['choices'][$v] = $l;
} // end if keep it
} // end foreach choices
return $field;
}
The problem is we also have an “edit” possibility for not logined users by some “hidden key value” which they receive through email.
The post_id is then selected and given to the acf_form object
acf_form(array(
'id' => 'acf-form',
/* (int|string) The post ID to load data from and save data to. Defaults to the current post ID.
Can also be set to 'new_post' to create a new post on submit */
'post_id' => $post_id,
...
Sadly in the called filters function for select field the value is always “null” even When the priority is set to 1 / 10 / 20 / 1000.
A quick look into the source code even shows me that even in the filter ‘acf/pre_render_fields’ the values aren’t set….
from acf_field_functions.php
/**
* acf_render_fields
*
* Renders an array of fields. Also loads the field's value.
*
* @date 8/10/13
* @since 5.0.0
* @since 5.6.9 Changed parameter order.
*
* @param array $fields An array of fields.
* @param (int|string) $post_id The post ID to load values from.
* @param string $element The wrapping element type.
* @param string $instruction The instruction render position (label|field).
* @return void
*/
function acf_render_fields( $fields, $post_id = 0, $el = 'div', $instruction = 'label' ) {
// Parameter order changed in ACF 5.6.9.
if( is_array($post_id) ) {
$args = func_get_args();
$fields = $args[1];
$post_id = $args[0];
}
/**
* Filters the $fields array before they are rendered.
*
* @date 12/02/2014
* @since 5.0.0
*
* @param array $fields An array of fields.
* @param (int|string) $post_id The post ID to load values from.
*/
$fields = apply_filters( 'acf/pre_render_fields', $fields, $post_id );
// Filter our false results.
$fields = array_filter( $fields );
// Loop over and render fields.
if( $fields ) {
foreach( $fields as $field ) {
// Load value if not already loaded.
if( $field['value'] === null ) {
$field['value'] = acf_get_value( $post_id, $field );
}
// Render wrap.
acf_render_field_wrap( $field, $el, $instruction );
}
}
/**
* Fires after fields have been rendered.
*
* @date 12/02/2014
* @since 5.0.0
*
* @param array $fields An array of fields.
* @param (int|string) $post_id The post ID to load values from.
*/
do_action( 'acf/render_fields', $fields, $post_id );
}
the filter add_filter('acf/load_field/name=myselect'..
is called by far before the actual render of the select field and sadly also way before the value is set.
So your code doesn’t work.
Ups i have just seen that you have changed the filter function from acf/load_field
to acf/prepare_field
.
With prepare_field
the value is indeed available.
I will check if with this filter all requirements could be set.
With the acf/prepare_field
it would work to remove the options for all my requirements.
So thanks @hube2 for pointing me at that direction.
I used some different code because i also have optgroups.
function filter_choices($field)
{
if (is_user_logged_in() && current_user_can('administrator')) {
// don't filter for admins
return $field;
}
$value = acf_get_array($field['value']);
$choices = acf_get_array($field['choices']);
// keys which will be removed
$disabled_options = array(1, 2, 3);
// value should be kept as selectable option for edit therefore remove it from disabled options
if (!is_null($value)) {
if (is_array($value)) {
$disabled_options = array_diff($disabled_options, $value);
} else {
$disabled_options = array_diff($disabled_options, array($value));
}
}
// delete keys in in normal options
$choices = array_diff_key($choices, array_flip((array) $disabled_options));
foreach ($choices as $choice_key => $choice_value) {
// delete keys in option groups
if (is_array($choice_value)) {
$choices[$choice_key] = array_diff_key($choice_value, array_flip((array) $disabled_options));
//remove empty groups from choices
if (sizeof($choices[$choice_key])==0) {
unset($choices[$choice_key]);
}
}
}
$field['choices'] = $choices;
return $field;
}
add_filter('acf/prepare_field/name=select_field_name', 'filter_choices', 20);
Anyhow a possibility to disable single options would also be good if this would be implemented in future acf versions.
The topic ‘Disable Options for 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.