如何在添加帖子时检查ACF字段值是否重复?

时间:2021-12-04 作者:Алексей Сотников

我有一个字段,在其中添加原始语言记录的名称。我把标题翻译成另一种语言。添加新记录时,我需要检查此字段是否与其他记录重复。多亏了这段代码,我做到了这一点,但验证只在记录发布之后进行。

如何确保进行验证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;
}

1 个回复
SO网友:Aboelabbas

下面是一种在ACF字段中键入值时实现验证的方法,将代码放在主题函数中。php或为其创建插件:您需要将$fieldName、$fieldKey属性值更改为字段的正确值--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();
下面是我们在前面的代码中所做的操作:

我将所有代码放在一个单独的类中“;MyPrefix\\u MetaFieldValidation“;

我稍微修改了您在问题中输入的代码,以便验证方法;元值存在”;与在上运行的方法分离;acf/validate\\u value“;,因为我们需要在另一个地方使用它。

此外,我将负责从数据库中获取重复记录的查询更改为更轻量级的查询。

我删除了保存帖子id的隐藏自定义字段的使用,因为已经有一个字段保存当前帖子id。

我创建了一个新的管理ajax操作“;ajaxValidation“;它使用验证方法并以JSON结果响应。

每当用户在自定义字段中键入要验证的值时,JS代码使用jQuery创建ajax请求,如果键入的值重复,则显示错误。

Note:此代码仅在自定义字段中插入值时向用户显示错误,但不会阻止用户将帖子保存为草稿。