Support

Account

Home Forums Front-end Issues Accept only unique values

Solving

Accept only unique values

  • Hello
    I have an SKU text field, how to not accept duplicated value ?
    Thank you

  • Not accepting duplicate values takes several steps.

    The first thing you need to do is to have the post id available during validation. The post id is not submitted with the rest of the acf field values when it does validation so what you need to do is create a field to hold it.

    After you create a field to hold the post id you need to create a load_field filter to add the post id value and make the field readonly.

    
    add_filter('acf/load_field/name=hidden_post_id', 'make_hidden_post_id_readonly');
    function make_field_readonly($field) {
      // sets readonly attribute for field
      $field['readonly'] = 1;
      return field;
    }
    add_filter('acf/load_value/name=hidden_post_id', 'set_hidden_post_id_value'), 10, 3);
    function set_hidden_post_id_value($value, $post_id, $field) {
      // set the value of the field to the current post id
      return $post_id;
    }
    

    The next thing I do is hide the field, there’s no reason to see it

    
    add_action('admin_head', 'hide_hidden_post_id');
    function hide_hidden_post_id() {
      ?>
        <style type="text/css">
          /* the field key for the post id field */
          div[data-key="field_56e06fe24d3e7"] {
            display: none;
          }
        </style>
      <?php 
    }
    

    Now we can validate a field so that we don’t allow duplicate values

    
    add_filter('acf/validate_value/name=your_field_name', require_unique', 10, 4);
    function require_unique($valid, $value, $field, $input) {
      if (!$valid) {
        return $valid;
      }
      // get the post id
      // using field key of post id field
      $post_id = $_POST['acf']['field_56e06fe24d3e7'];
      // query existing posts for matching value
      $args = array(
        'post_type' => 'your-post-type',
        'posts_per_page' = 1, // only need to see if there is 1
        'post_status' => 'publish, draft, trash',
        // don't include the current post
        'post__not_in' => array($post_id),
        'meta_query' => array(
          array(
            'key' => $field['name'],
            'value' => $value
          )
        )
      );
      $query = new WP_Query($args);
      if (count($query->posts)){
        $valid = 'This Value is not Unique';
      }
      return $valid;
    }
    
  • Thanks John! I have no idea what I’m doing but your code got me close. I’m making a lyrics site / hymn book and want to prevent duplicate hymns, but I’m stuck. Can you get my code to validate?

    add_filter('acf/load_value/name=hidden_post_id', 'set_hidden_post_id_value', 10, 3);
    function set_hidden_post_id_value($value, $post_id, $field) {
      // set the value of the field to the current post id
      return $post_id;
    }
    add_action('admin_head', 'hide_hidden_post_id');
    function hide_hidden_post_id() {
      ?>
        <style type="text/css">
          /* the field key for the post id field */
          div[data-field_key="field_581bff482f898"] {
            display: none;
          }
        </style>
      <?php
    }
    add_filter('acf/validate_value/type=number', 'require_unique', 10, 4);
    function require_unique($valid, $value, $field, $input) {
      if (!$valid) {
        return $valid;
      }
      // get the post id
      // using field key of post id field
      $post_id = $_POST['acf']['field_581bff482f898'];
      // query existing posts for matching value
      $args = array(
        'post_type' => 'hymn',
        'posts_per_page' => 1, // only need to see if there is 1
        'post_status' => 'publish, draft, trash',
        // don't include the current post
        'post__not_in' => array($post_id),
        'meta_query' => array(
          array(
            'key' => $field['type'],
            'value' => $value
          )
        )
      );
      $query = new WP_Query($args);
      if (count($query->posts)){
        $valid = 'This Value is not Unique';
      }
      return $valid;
    }

    I added the hidden_post_id to the field group in the ACF menu.The hidden_post_id is working, although the acf/load_field wasn’t working for some reason.

    acf/load_field gives me issues similar to these:
    https://support.advancedcustomfields.com/forums/topic/acf-disappearing/
    https://support.advancedcustomfields.com/forums/topic/strange-error-field-type-does-not-exist/

    Lastly, while WP_Query looks like a better solution. Is there an easier way to do it with $wpdb?

  • Since posting that I’ve leaned some thing, like I don’t need to create a post ID field and hide it. I’ve also refined the function so that I can use the same function for any field where I want to have a unique value, just add it as a filter to any field you want to be unique.

    
    <?php 
      
      add_filter('acf/validate_value/name='.$field_name, 'acf_unique_value_field', 10, 4);
      
      function acf_unique_value_field($valid, $value, $field, $input) {
        if (!$valid || (!isset($_POST['post_ID']) && !isset($_POST['post_id']))) {
          return $valid;
        }
        if (isset($_POST['post_ID'])) {
          $post_id = intval($_POST['post_ID']);
        } else {
          $post_id = intval($_POST['post_id']);
        }
        if (!$post_id) {
          return $valid;
        }
        $post_type = get_post_type($post_id);
        $field_name = $field['name'];
        $args = array(
          'post_type' => $post_type,
          'post_status' => 'publish, draft, trash',
          'post__not_in' => array($post_id),
          'meta_query' => array(
            array(
              'key' => $field_name,
              'value' => $value
            )
          )
        );
        $query = new WP_Query($args);
        if (count($query->posts)){
          return 'This Value is not Unique. Please enter a unique '.$field['label'];
        }
        return true;
      }
        
    ?>
    

    I did notice an error in your code, this:

    
    'key' => $field['type'],
    

    should be

    
    'key' => $field['name'],
    
  • Thanks! You’re awesome!

  • I am wanting to prevent a user from entering a value that has already been entered. I am looking at John’s final code above. Does this go in the functions.php file or somewhere else? Will it create a new field type called unique value or will I have to edit the code whenever I create a new field that I want to restrict unique values?

  • You put it in your functions.php file. The single function that I last posted will work for all field but you need to add a new line

    
    add_filter('acf/validate_value/name=your_field_name, 'acf_unique_value_field', 10, 4);
    

    for each field you want to be unique replacing your_field_name with the name of each field.

  • It doesn’t seem to be working. I created a field called gallery_group_id. Here is the code I added to functions.php. When I enter two values of the same I am not given any error and it accepts them.

     
      add_filter('acf/validate_value/name='.$field_name, 'acf_unique_value_field', 10, 4);
      
      function acf_unique_value_field($valid, $value, $field, $input) {
        if (!$valid || (!isset($_POST['post_ID']) && !isset($_POST['post_id']))) {
          return $valid;
        }
        if (isset($_POST['post_ID'])) {
          $post_id = intval($_POST['post_ID']);
        } else {
          $post_id = intval($_POST['post_id']);
        }
        if (!$post_id) {
          return $valid;
        }
        $post_type = get_post_type($post_id);
        $field_name = $field['name'];
        $args = array(
          'post_type' => $post_type,
          'post_status' => 'publish, draft, trash',
          'post__not_in' => array($post_id),
          'meta_query' => array(
            array(
              'key' => $field_name,
              'value' => $value
            )
          )
        );
        $query = new WP_Query($args);
        if (count($query->posts)){
          return 'This Value is not Unique. Please enter a unique '.$field['label'];
        }
        return true;
      }
        
    add_filter('acf/validate_value/name=gallery_group_id', 'acf_unique_value_field', 10, 4);
  • It might help to know that this is inside of a repeater field used on the same wordpress page.

    The repeater field is called gallery_group.
    The inner field is called gallery_group_id.

  • It would also help a bit if you put your code into code tags so that it’s easier to read.

    But, no, what has been posted here will not work for a repeater/sub field, only a top level field.

    Are you trying to have a unique value in only the sub field for one post or all posts?

  • Sorry, I’m trying to have a unique value for the sub-field in one post. I am creating a gallery page. Each page has several groups of images (gallery groups). I would like to have a unique ID (<div id=”home-entertainment”>) that I can use as an anchor to link to.

    For example:

    <div class="gallery-group" id="home-entertainment">
    <h2>Home Entertainment</h2>
    <img src="image1.jpg" />
    <img src="image2.jpg" />
    </div>
    
    <div class="gallery-group" id="home-security">
    <h2>Home Security</h2>
    <img src="image3.jpg" />
    <img src="image4.jpg" />
    </div>
    
    <div class="gallery-group" id="home-automation">
    <h2>Home Automation</h2>
    <img src="image5.jpg" />
    <img src="image6.jpg" />
    </div>
  • validating a row against other rows is a little different. For this you need to look at the other values in $_POST[‘acf’] and you’ll need to use the field keys.

    So, let’s for this example say that the field key of the repeater is field_1111 and the field key of the text field is field_2222

    
    add_filter('acf/validate_value/key=field_2222', 'acf_unique_repeater_sub_field', 10, 4);
    function acf_unique_repeater_sub_field($valid, $value, $field, $input) {
      // set up an array to hold all submitted values for rows
      $list = array();
      foreach ($_POST['acf']['field_1111'] as $row) {
        if (in_array($row['field_2222'], $list)) {
          // this one already exists
          $valid = 'There are duplicate '.$field['name'].' values';
          // found a duplicate so we don't need to continue looping
          break;
        }
        // add the value of this row to the list
        $list[] = $row['field_2222'];
      }
      return $valid;
    }
    
  • How do I find the keys?

  • When you are editing the field group, Screen Options, there is a checkbox to toggle display of field keys

  • Thanks, I found the keys. Now the only issue is that it says there are 4 errors when only two of the 4 entries are duplicates. It puts a red flag on each of the 4 fields.

    Example:
    gallery_id: network
    gallery_id: network
    gallery_id: automation
    gallery_id: security

     add_filter('acf/validate_value/key=field_58d453ce55ea1', 'acf_unique_repeater_sub_field', 10, 4);
    function acf_unique_repeater_sub_field($valid, $value, $field, $input) {
      // set up an array to hold all submitted values for rows
      $list = array();
      foreach ($_POST['acf']['field_58bbc19f95a04'] as $row) {
        if (in_array($row['field_58d453ce55ea1'], $list)) {
          // this one already exists
          $valid = 'There are duplicate '.$field['name'].' values';
          // found a duplicate so we don't need to continue looping
          break;
        }
        // add the value of this row to the list
        $list[] = $row['field_58d453ce55ea1'];
      }
      return $valid;
    }
  • Only flagging the ones that have the duplicates is much harder.

    The 4th parameter given to your filter is $input. This value contains a string that represents the current field being validating. It will look something like

    
    [acf][field_1111][0][field_2222]
    

    or possibly like this

    
    [acf][field_1111][789abc123][field_222]
    

    in the second case [789abc123] is a temporary value created when adding a field.
    In this case you’d need to match this index with the index of the array to see if it’s the row you’re checking. Honestly, I’m not sure how to do that in any easy way, and I’m not 100% confident that I have the format of $input correct

    
    foreach ($_POST['acf']['field_1111'] as $index => $row) {
      if (in_array($row['field_2222'], $list)) {
        // check $index for a match to the index value given in $input
        // if they match then set $valid to error message
        // maybe a solution, not sure, you'll have to do some testing
        if (strstr($input, '[field_1111]['.$index.'][field_2222]')) {
          $valid = 'There are duplicate '.$field['name'].' values';
        }
        // rest of code follows ....
    
  • where do I put these scripts?

    add_filter('acf/load_field/name=hidden_post_id', 'make_hidden_post_id_readonly');
    function make_field_readonly($field) {
      // sets readonly attribute for field
      $field['readonly'] = 1;
      return field;
    }
    
    add_filter('acf/load_value/name=hidden_post_id', 'set_hidden_post_id_value'), 10, 3);
    function set_hidden_post_id_value($value, $post_id, $field) {
      // set the value of the field to the current post id
      return $post_id;
    }
    
    add_action('admin_head', 'hide_hidden_post_id');
    function hide_hidden_post_id() {
      ?>
        <style type="text/css">
          /* the field key for the post id field */
          div[data-key="field_566aa87938bba"] {
            display: none;
          }
        </style>
      <?php 
    }
    
    add_filter('acf/validate_value/name=book_number', require_unique', 10, 4);
    function require_unique($valid, $value, $field, $input) {
      if (!$valid) {
        return $valid;
      }
      // get the post id
      // using field key of post id field
      $post_id = $_POST['acf']['field_566aa87938bba'];
      // query existing posts for matching value
      $args = array(
        'post_type' => 'post',
        'posts_per_page' = 1, // only need to see if there is 1
        'post_status' => 'publish, draft, trash',
        // don't include the current post
        'post__not_in' => array($post_id),
        'meta_query' => array(
          array(
            'key' => $field['book_number'],
            'value' => $value
          )
        )
      );
      $query = new WP_Query($args);
      if (count($query->posts)){
        $valid = 'This Value is not Unique';
      }
      return $valid;
    }
  • Most of the scripts go in functions.php

  • Hello John,

    I need your help.

    I am creating one text field “place_id” on “property” taxonomy.

    How to check duplicate entry when submitting post, and set validation ??

    Thanks

  • I believe that ACF sets other values in $_POST for the taxonomy and the term id, but I am not sure. It should allow you to see if it’s a term page then alter the query to check terms instead of posts.

    To see whats in $_POST during the ajax request you can do something like this

    
    ob_start(); print_r($_POST); error_log(ob_get_clean());
    

    This will print out the value of $_POST to your error log so you can inspect what’s in it.

  • This reply has been marked as private.
  • This reply has been marked as private.
  • This is absolute gold, thank you for posting this sample! 🙂

  • What about user fields? cant get it to work with user fields, obviously “post_type=” doesn’t apply while getting user info. So if there a way to prevent duplicate values from all user form? say user needs to have a unique mobile number, so how do i do that?

Viewing 25 posts - 1 through 25 (of 31 total)

The topic ‘Accept only unique values’ is closed to new replies.