php - How can I check that the acf field value is not a duplicate when adding a post?

admin2025-01-07  3

I have a field in which I add the name of the record in the original language. And I translate the title into another language. When adding a new record, I need to check this field for duplication in other records. I did it thanks to this code, but the verification takes place only after the publication of the record.

How can I make sure that the verification is carried out in real time without publishing a record?

add_filter( 'posts_distinct', 'cf_search_distinct' );

// PREVENT POST THAT ALREADY EXIST
add_filter('acf/validate_value/name=original-title-mcpedl', 'validate_lien_video_filter', 10, 4);
add_filter('acf/load_value/name=hidden_post_id', 'add_post_id_as_value', 10, 3);
function add_post_id_as_value($value, $post_id, $field) {
  return $post_id;
}
function validate_lien_video_filter($valid, $value, $field, $input) {
    $post_id_field_key = 'field_61ab64673cad6';
  if (!$valid || $value == '' || !isset($_POST['acf'][$post_id_field_key])) {
    return $valid;
  }
    // change the field key below to the field key for your 
    // hide_post_id_field field
    $post_id = $_POST['acf'][$post_id_field_key];
  global $post; 
  $args = array(
    'post__not_in' => array($post_id), // do not check this post
    'meta_query' => array(
      array(
        'key' => 'original-title-mcpedl',
        'value' => $value
      )
    )
  );
  $query = new WP_Query($args);
  if (count($query->posts)) {
    // found at least one post that
    // already has $value
    $valid = 'This is a duplicate!';
  }
  return $valid;
}

I have a field in which I add the name of the record in the original language. And I translate the title into another language. When adding a new record, I need to check this field for duplication in other records. I did it thanks to this code, but the verification takes place only after the publication of the record.

How can I make sure that the verification is carried out in real time without publishing a record?

add_filter( 'posts_distinct', 'cf_search_distinct' );

// PREVENT POST THAT ALREADY EXIST
add_filter('acf/validate_value/name=original-title-mcpedl', 'validate_lien_video_filter', 10, 4);
add_filter('acf/load_value/name=hidden_post_id', 'add_post_id_as_value', 10, 3);
function add_post_id_as_value($value, $post_id, $field) {
  return $post_id;
}
function validate_lien_video_filter($valid, $value, $field, $input) {
    $post_id_field_key = 'field_61ab64673cad6';
  if (!$valid || $value == '' || !isset($_POST['acf'][$post_id_field_key])) {
    return $valid;
  }
    // change the field key below to the field key for your 
    // hide_post_id_field field
    $post_id = $_POST['acf'][$post_id_field_key];
  global $post; 
  $args = array(
    'post__not_in' => array($post_id), // do not check this post
    'meta_query' => array(
      array(
        'key' => 'original-title-mcpedl',
        'value' => $value
      )
    )
  );
  $query = new WP_Query($args);
  if (count($query->posts)) {
    // found at least one post that
    // already has $value
    $valid = 'This is a duplicate!';
  }
  return $valid;
}
Share Improve this question asked Dec 4, 2021 at 13:14 Алексей СотниковАлексей Сотников 11 bronze badge 2
  • If you mean by your question that the validation doesn't run also when saving the post as a draft; then that is the normal behavior of ACF validation, the validation runs only when trying to publish the post and publishing is prevented only when there is any validation error. support.advancedcustomfields.com/forums/topic/… – Aboelabbas Commented Dec 4, 2021 at 19:26
  • And how do I change the code so that the check is before saving or publishing? To immediately. – Алексей Сотников Commented Dec 4, 2021 at 20:45
Add a comment  | 

1 Answer 1

Reset to default 0

Here is a way to achieve the validation while typing the value in the ACF field, put the code inside your theme's functions.php or create a plugin for it: You will need to change the $fieldName, $fieldKey properties values to the correct values of your field --they are the field name and field key of the same field we are validating--

class MyPrefix_MetaFieldValidation
{
    protected static $instance;
    
    protected $fieldName = 'original-title-mcpedl'; // <- Change this with the ACF field name
    protected $fieldKey = 'field_61abaa164244a'; // <- Change this with the field key
    
    protected $ajaxAction = 'myprefix_validate_title';

    protected function __construct()
    {
    }

    public function run()
    {
        add_filter('acf/validate_value/key=' . $this->fieldKey, [$this, 'acfValidation'], 10, 2);
        add_action('wp_ajax_' . $this->ajaxAction, [$this, 'ajaxValidation']);
        add_action('admin_footer', [$this, 'ajaxValidationJS']);
    }

    /**
     * Print the Validation JS on the post edit screen.
     */
    public function ajaxValidationJS()
    {
        if(! $this->isPostEditScreen()) {
            return;
        }

        $nonce = wp_create_nonce($this->ajaxAction);
        ?>
        <script>
            jQuery(document).ready(function(){
                jQuery('#acf-<?= $this->fieldKey; ?>').on('keyup', function (){
                    var field = jQuery(this);
                    var value = field.val();

                    if(! value) {
                        return;
                    }
                    var post_id = jQuery('#post_ID').val();
                    var formatError = function(msg) {
                        return '<div class="acf-notice -error acf-error-message"><p>' + msg + '</p></div>';
                    }

                    jQuery.ajax({
                        url: ajaxurl,
                        data: {"action": "<?= $this->ajaxAction; ?>", "nonce" : "<?= $nonce; ?>", "post_id" : post_id, "meta_value" : value },
                        type: "POST",
                        complete : function(response) {
                            var json = response.responseJSON;
                            field.parents('.acf-input').find('.acf-notice').remove();
                            if(response.status != 200) {
                                field.parents('.acf-input').prepend(formatError('Network or server error!'));
                                return;
                            }
                            if(! json.valid) {
                                field.parents('.acf-input').prepend(formatError(json.msg));
                            }
                        }
                    });
                });
            });
        </script>
    <?php
    }

    /**
     * Perform the ajax validation on the meta field
     */
    public function ajaxValidation()
    {
       $postId = $_REQUEST['post_id'] ? intval($_REQUEST) : 0;
       $metaValue = $_REQUEST['meta_value'] ? $_REQUEST['meta_value'] : '';
       $nonce = $_REQUEST['nonce'] ? $_REQUEST['nonce'] : '';

       if(! wp_verify_nonce($nonce, $this->ajaxAction)) {
           $this->ajaxResponse([
               'valid' => false,
               'msg' => 'Invalid nonce supplied'
           ]);
       }

       if(! $metaValue) {
           $this->ajaxResponse([
               'valid' => true,
               'msg' => 'Empty value'
           ]);
       }

        $existingTitle = $this->metaValueExists($this->fieldName, $metaValue, $postId);

       if($existingTitle) {
            $this->ajaxResponse([
                'valid' => false,
                'msg' => 'This title is already exists for the post id ' . $existingTitle->post_id,
            ]);
        }

        $this->ajaxResponse([
            'valid' => true,
            'msg' => '',
        ]);
    }

    public function acfValidation($valid, $value)
    {
        if(empty($value)) {
            return $valid;
        }

        $postId = isset($_POST['post_id']) ? intval($_POST['post_id']) : null;

        $existingTitle = $this->metaValueExists($this->fieldName, $value, $postId);

        if($existingTitle) {
            $valid = 'This title is already exists for the post id ' . $existingTitle->post_id;
        }

        return $valid;

    }

    /**
     * Create an ajax response
     * @param array $data
     */
    protected function ajaxResponse($data)
    {
        header('Content-Type: application/json;charset=UTF-8');
        echo json_encode($data);
        exit;
    }

    /**
     * Check if we are on the post editing screen
     * @return bool
     */
    protected function isPostEditScreen()
    {
        global $pagenow;
        return (is_admin() && ('post.php' === $pagenow || 'post-new.php' === $pagenow));
    }

    /**
     * Check if a given meta value is already in the database
     * @param string $metaKey
     * @param string $metaValue
     * @param null|int $currentPostId
     * @return false|object
     */
    protected function metaValueExists($metaKey, $metaValue, $currentPostId = null) {

        // Return early if the supplied meta key or value is empty
        $metaValue = trim($metaValue);
        if (empty($metaKey) || empty($metaValue)) {
            return false;
        }

        // Ensure that the supplied post id is integer
        $currentPostId = intval($currentPostId);

        // Query the wp_postmeta table for the meta value and meta key
        global $wpdb;
        $query = "SELECT * FROM $wpdb->postmeta WHERE meta_key LIKE '%s' AND meta_value LIKE '%s'";

        // Exclude the current post id only if it is not empty
        if($currentPostId) {
            $query .= " AND post_id != $currentPostId";
        }

        $result = $wpdb->get_row($wpdb->prepare($query, $metaKey, $metaValue));

        // Return the database row object or false if no record found
        return ($result) ?: false;
    }

    public static function getInstance()
    {
        if(! static::$instance) {
            static::$instance = new static();
        }

        return static::$instance;
    }

}
// Run our plugin
MyPrefix_MetaFieldValidation::getInstance()->run();

Here's whate we have done in the previous code:

I put all our code in a separate class "MyPrefix_MetaFieldValidation"

I changed the code you put in your question a bit so that the validation method "metaValueExists" is separated from the method that runs on "acf/validate_value", because we need to use it in another place.

Also, I changed the query responsible for getting the duplicate record from the database to be more lightweight.

I removed the use of the hidden custom field that holds the post id, as there is already a field that holds the current post id.

I created a new admin ajax action "ajaxValidation" that consumes the validation method and responds with a JSON result.

A JS code uses jQuery to create an ajax request whenever the user types a value inside the custom field that we want to valide and displays an error if the value he typed is duplicate.

Note: This code will only show an error to the user while inserting a value in the custom field, but won't prevent the user from saving the post as a draft.

转载请注明原文地址:http://conceptsofalgorithm.com/Algorithm/1736260145a643.html

最新回复(0)