Home › Forums › General Issues › how to disable non-text fields, like a checkbox field
marking a textarea field as disabled works perfectly, it prevent the field from being updated from the admin panel, but let the field being update in php with ‘update_field()’. I do it by adding a class, then checking for this class in the ‘acf/load_field’ filter. Something like that :
function disable_acf_field($field) {
if (!isset($field['wrapper'], $field['wrapper']['class'])) {
return $field;
}
$class = $field['wrapper']['class'];
if (!str_contains($class, 'read_only_acf')) {
return $field;
}
$field['disabled'] = 1;
return $field;
}
add_filter('acf/load_field', 'disable_acf_field');
But unfortunately it wont work for lots of fields, like checkbox for example.
So I tried a solution, but I don’t know if it is robust, and if there are better ways. I use the ‘acf/pre_update_value’ filter, and i check once again for the class, but also i check if $_POST[‘acf’] is set, because i imagine it will always be there if the update happens from front and admin, but never there if the update is not initiated by a form being submited with post, is it true ? this looks something like this :
function disable_acf_field($null, $value, $post_id, $field) {
if (!isset($_POST['acf'])) {
return $null;
}
if (!isset($field['wrapper'], $field['wrapper']['class'])) {
return $null;
}
$class = $field['wrapper']['class'];
if (!str_contains($class, 'read_only_acf')) {
return $null;
}
return false;
}
add_filter('acf/pre_update_value', 'disable_acf_field', 10, 4);
is there a better way to do that ? a more native way ? do you think this will work in all situations or did i missed a flaw ?
it would be better if i had a way to explicitly inform the ‘acf/pre_update_value’ filter that i want to make the update, but i didn’t find how to do that ?
thank you for your help 🙂
ok, i’ve got something better :
the code looks like this :
/*
* utility function, to check if the field contains the class 'disable_acf'
* I added the class in the admin acf field panel, for each field i want to disable
*
*/
function is_acf_field_disabled($field) {
if (!isset($field['wrapper'], $field['wrapper']['class'])) {
return false;
}
$class = $field['wrapper']['class'];
if (!str_contains($class, 'disable_acf')) {
return false;
}
return true;
}
/*
* filter the fields when they render, to disable them
* acf have a way to do it for some fields
* for the others, add a property that will allow to use other filters on them
* and only if it was render first (so it will not affect server side field updates)
*
*/
function disable_acf_field($field) {
if (!is_acf_field_disabled($field)) {
return $field;
}
$type = $field['type'];
if (in_array($type, array('text', 'textarea', 'number', 'email', 'url', 'password', 'date_picker', 'time_picker', 'select'))) {
$field['disabled'] = 1;
}
else if (in_array($type, array('checkbox', 'radio'))) {
if (!isset($field['choices'])) {
return $field;
}
$choices = $field['choices'];
$to_disable = array_keys($choices);
// acf cast the strings, so do i
// line 128 : advanced-custom-fields/includes/fields/class-acf-field-radio.php
$to_disable = array_map(function($e){return (string)$e;}, $to_disable);
$field['disabled'] = $to_disable;
}
else {
$field['client_side_disabled'] = 1;
}
return $field;
}
add_filter('acf/load_field', 'disable_acf_field');
/*
* add 'inert' attribute to the wrapper of the field
* it prevents all focus actions, keyboard and mouse
* but it does not prevents to submit values, instead of 'disabled' attribute
*
*/
function change_acf_field_wrapper($wrapper, $field) {
if (!isset($field['client_side_disabled'])) {
return $wrapper;
}
error_log("+field: " . json_encode($field));
$wrapper["inert"] = "true";
return $wrapper;
}
add_filter('acf/field_wrapper_attributes', 'change_acf_field_wrapper', 10, 2);
/*
* if the field has property 'client_side_disabled'
* don't save it
* it does not prevent updates with update_field() on server side
*
*/
function disable_other_acf_field($null, $value, $post_id, $field) {
if (isset($field['client_side_disabled'])) {
return false;
}
return $null;
}
add_filter('acf/pre_update_value', 'disable_other_acf_field', 10, 4);
I think it’s better
nop :p I don’t know how i did my tests, but the filter ‘acf/load_field’ change the object properties for all the way to get the field, front-end or server side, so my previous code don’t allow server side updates
OK, after more tests I realize I was wrong on multiple aspects :
1. the ‘disabled’ attribute don’t do what I expected : if a field is marked as disabled, and you are on the post edit panel in admin for example, then when you update the post, the field will be updated by acf with empty values, that’s not what want. I want to not be able to modify the field from front, only seeing it.
2. the field object that is updated with different filters is always the real object. That’s obvious actually, but I misunderstood that, so my previous approach could not work : we cant use the field object properties to know if the field is updated from front or not, because it will be the same properties, no matter where it is updated from.
3. and I think it is not safe to add a property to the object anyway, because it could be cleaned by acf at any time, even if I don’t think it’s the case so far.
So i’m back to my first solution, using $_POST[‘acf’] to check if the field is updated from client side or not, but I’m still not sure if it’s robust.
there is this proposition to use debug_backtrace() but I haven’t tried it : https://stackoverflow.com/questions/42032848/how-create-read-only-afc-field
You must be logged in to reply to this topic.
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.