Support

Account

Forum Replies Created

  • ok ! indeed you are right, it will not be saved in the database, so that does not help me, I need to find another way 🙂

    What additional information i need to store ? it depends, but sometimes I would like to store additional information about a field, for example I used the value:label of the checkbox to store information in the ‘value’ part, and then i did some string manipulation to extract the values (ie. separating the portions with slash : for_action_email_notification/7days : send email -> extract the ‘7days’ part with explode('/', $value)[1])

    but it’s just a trick, I could also use one of the class or id of the field or it’s wrapper the same way, but I’m only cheating by using a property that is not made for that

  • 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

  • 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, i’ve got something better :

    1. first, the ‘disabled’ capacity of the acf fields is actually just directly the html ‘disabled’ attribute that acf adds to form elements that supports it
    2. so, for some acf fields it is prety simple, because the field is a simple input on which acf can add the ‘disabled’ attributes :
      • text
      • textarea
      • number
      • email
      • url
      • password (is actually using text render function)
      • date picker
      • date time picker (is actually using date-picker class)
      • time picker
      • select
    3. for some fields, the disabled attribute in html is a little bit more complicated, it is an array of elements :
      • radio
      • checkbox
    4. for the rest, it’s not natively supported by acf, and for some fields it would not make sens anyway (‘message’ for example). So if i want to disable them anyway, i found a simple and better way than checking for the _POST[‘acf’] :
      1. first, add a special property to the field object (ex. ‘client_side_disabled’)
      2. then use the ‘acf/pre_update_value’ filter to check if the field have this property, and in that case prevent to save it
      3. and last, use the ‘acf/field_wrapper_attributes’ filter to add an attribute to the wrapper : ‘inert’ -> it will prevent all focus, from tab and mouse, but it will not prevent the form element to be submit, hence the previous filter

    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

Viewing 4 posts - 1 through 4 (of 4 total)