Как я могу проверить, что значение поля ACF не является дубликатом при добавлении поста?

Вопрос или проблема

У меня есть поле, в которое я добавляю имя записи на оригинальном языке. И я перевожу заголовок на другой язык. При добавлении новой записи мне нужно проверять это поле на дублирование в других записях. Я сделал это благодаря этому коду, но проверка происходит только после публикации записи.

Как я могу сделать так, чтобы проверка проводилась в реальном времени, без публикации записи?

add_filter( 'posts_distinct', 'cf_search_distinct' );

// ПРЕДОТВРАТИТЬ ЗАПИСЬ, КОТОРАЯ УЖЕ СУЩЕСТВУЕТ
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;
  }
    // измените ключ поля ниже на ключ поля для вашего 
    // hide_post_id_field
    $post_id = $_POST['acf'][$post_id_field_key];
  global $post; 
  $args = array(
    'post__not_in' => array($post_id), // не проверять эту запись
    'meta_query' => array(
      array(
        'key' => 'original-title-mcpedl',
        'value' => $value
      )
    )
  );
  $query = new WP_Query($args);
  if (count($query->posts)) {
    // найдено хотя бы одна запись, которая
    // уже имеет $value
    $valid = 'Это дубликат!';
  }
  return $valid;
}

Вот способ достижения валидации во время ввода значения в поле ACF, поместите код в файл functions.php вашей темы или создайте для этого плагин:
Вам нужно будет изменить значения свойств $fieldName, $fieldKey на правильные значения вашего поля —это имя поля и ключ поля того же поля, которое мы валидируем

class MyPrefix_MetaFieldValidation
{
    protected static $instance;

    protected $fieldName="original-title-mcpedl"; // <- Измените это на имя поля ACF
    protected $fieldKey = 'field_61abaa164244a'; // <- Измените это на ключ поля

    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']);
    }

    /**
     * Выводит JS валидации на экране редактирования поста.
     */
    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('Ошибка сети или сервера!'));
                                return;
                            }
                            if(! json.valid) {
                                field.parents('.acf-input').prepend(formatError(json.msg));
                            }
                        }
                    });
                });
            });
        </script>
    <?php
    }

    /**
     * Выполняет ajax валидацию по мета полю
     */
    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' => 'Неверный nonce'
           ]);
       }

       if(! $metaValue) {
           $this->ajaxResponse([
               'valid' => true,
               'msg' => 'Пустое значение'
           ]);
       }

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

       if($existingTitle) {
            $this->ajaxResponse([
                'valid' => false,
                'msg' => 'Это заголовок уже существует для поста с 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 = 'Этот заголовок уже существует для поста с id ' . $existingTitle->post_id;
        }

        return $valid;

    }

    /**
     * Создает ajax ответ
     * @param array $data
     */
    protected function ajaxResponse($data)
    {
        header('Content-Type: application/json;charset=UTF-8');
        echo json_encode($data);
        exit;
    }

    /**
     * Проверяет, находимся ли мы на экране редактирования поста
     * @return bool
     */
    protected function isPostEditScreen()
    {
        global $pagenow;
        return (is_admin() && ('post.php' === $pagenow || 'post-new.php' === $pagenow));
    }

    /**
     * Проверяет, существует ли данное мета значение в базе данных
     * @param string $metaKey
     * @param string $metaValue
     * @param null|int $currentPostId
     * @return false|object
     */
    protected function metaValueExists($metaKey, $metaValue, $currentPostId = null) {

        // Возврат, если заданный мета ключ или значение пусты
        $metaValue = trim($metaValue);
        if (empty($metaKey) || empty($metaValue)) {
            return false;
        }

        // Убедитесь, что заданный id записи является целым числом
        $currentPostId = intval($currentPostId);

        // Запрос к таблице wp_postmeta для получения мета значения и мета ключа
        global $wpdb;
        $query = "SELECT * FROM $wpdb->postmeta WHERE meta_key LIKE '%s' AND meta_value LIKE '%s'";

        // Исключите текущий id записи только если он не пуст
        if($currentPostId) {
            $query .= " AND post_id != $currentPostId";
        }

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

        // Возврат объекта строки базы данных или false, если запись не найдена
        return ($result) ?: false;
    }

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

        return static::$instance;
    }

}
// Запустите наш плагин
MyPrefix_MetaFieldValidation::getInstance()->run();

Вот что мы сделали в предыдущем коде:

Я собрал весь наш код в отдельный класс “MyPrefix_MetaFieldValidation”

Я немного изменил код, который вы указали в своем вопросе, чтобы метод валидации “metaValueExists” был отделен от метода, который работает на “acf/validate_value”, потому что нам нужно использовать его в другом месте.

Кроме того, я изменил запрос, отвечающий за получение дубликата записи из базы данных, чтобы он был более легковесным.

Я убрал использование скрытого настраиваемого поля, которое хранит id поста, так как уже существует поле, которое хранит текущий id поста.

Я создал новое действие ajax для админки “ajaxValidation”, которое использует метод валидации и отвечает JSON-результатом.

JS код использует jQuery для создания ajax-запроса всякий раз, когда пользователь вводит значение в настраиваемое поле, которое мы хотим валидировать, и отображает ошибку, если введенное значение является дубликатом.

Примечание: Этот код будет показывать ошибку пользователю только при вставке значения в настраиваемое поле, но не будет препятствовать пользователю сохранить пост как черновик.

Ответ или решение

Для проверки уникальности поля ACF (Advanced Custom Fields) при добавлении записи в WordPress без публикации записи в реальном времени, вы можете воспользоваться следующими рекомендациями. Этот подход позволит вам осуществлять валидацию "на лету" во время ввода текста в поле, и выводить сообщение об ошибке, если введенное значение уже существует.

Основные шаги для реализации валидации ACF поля на уникальность

  1. Создание AJAX-обработчика: Вам необходимо реализовать AJAX-обработчик, который будет проверять, существует ли введенное значение в базе данных.

  2. AJAX-запрос: Используя jQuery, вы можете отправлять запрос на сервер при каждом событии ввода в поле.

  3. Обновление кода функций: Код, который вы уже использовали для валидации, можно модифицировать для обработки данной логики.

Пример реализации

class MyPrefix_AcfFieldValidation
{
    protected static $instance;
    protected $fieldName = "original-title-mcpedl"; // Название поля ACF
    protected $fieldKey = 'field_61abaa164244a'; // Ключ поля ACF
    protected $ajaxAction = 'myprefix_validate_title';

    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, 'enqueueScripts']);
    }

    public function enqueueScripts()
    {
        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('Ошибка сети или сервера!'));
                                return;
                            }
                            if (!json.valid) {
                                field.parents('.acf-input').prepend(formatError(json.msg));
                            }
                        }
                    });
                });
            });
        </script>
        <?php
    }

    public function ajaxValidation()
    {
        $postId = isset($_REQUEST['post_id']) ? intval($_REQUEST['post_id']) : 0;
        $metaValue = isset($_REQUEST['meta_value']) ? sanitize_text_field($_REQUEST['meta_value']) : '';
        $nonce = isset($_REQUEST['nonce']) ? $_REQUEST['nonce'] : '';

        if (!wp_verify_nonce($nonce, $this->ajaxAction)) {
            $this->ajaxResponse(['valid' => false, 'msg' => 'Недействительный токен.']);
        }

        if (!$metaValue) {
            $this->ajaxResponse(['valid' => true, 'msg' => 'Пустое значение.']);
        }

        $existingTitle = $this->metaValueExists($this->fieldName, $metaValue, $postId);
        if ($existingTitle) {
            $this->ajaxResponse(['valid' => false, 'msg' => 'Это название уже существует для поста с ID ' . $existingTitle->post_id]);
        }

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

    protected function ajaxResponse($data)
    {
        wp_send_json($data);
    }

    protected function metaValueExists($metaKey, $metaValue, $currentPostId = null)
    {
        global $wpdb;
        $currentPostId = intval($currentPostId);
        $metaValue = trim($metaValue);

        $query = $wpdb->prepare("SELECT * FROM $wpdb->postmeta WHERE meta_key = %s AND meta_value = %s", $metaKey, $metaValue);
        if ($currentPostId) {
            $query .= $wpdb->prepare(" AND post_id != %d", $currentPostId);
        }
        return $wpdb->get_row($query);
    }

    protected function isPostEditScreen()
    {
        global $pagenow;
        return is_admin() && ($pagenow === 'post.php' || $pagenow === 'post-new.php');
    }

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

MyPrefix_AcfFieldValidation::getInstance()->run();

Как работает этот код?

  1. AJAX Запрос: Каждый раз при нажатии клавиши в поле ACF отправляется запрос на сервер для проверки уникальности введенного значения.

  2. Валидация: Серверная функция ajaxValidation проверяет, существует ли значение в базе данных, и возвращает ответ в формате JSON.

  3. Обновление интерфейса: Если значение оказывается дублирующим, сообщение об ошибке отображается прямо под полем ACF без необходимости публиковать запись.

Примечания

  • Код обеспечит реализацию валидации в реальном времени, однако учтите, что это не предотвратит сохранение записи в черновики; пользователи все равно смогут это делать.

Используя приведенный выше код, вы сможете обеспечить отличную пользовательскую практику, минимизируя количество ошибок при добавлении записей и улучшая качество контента на вашем сайте.

Оцените материал
Добавить комментарий

Капча загружается...