Как валидировать произвольные поля в пользовательском типе записи?

28 авг. 2012 г., 23:15:25
Просмотры: 18.8K
Голосов: 9

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

Я предполагал, что функция хука save_post будет обрабатывать валидацию полей, но не могу найти простого способа отображения ошибок пользователю.

Есть ли встроенная функция WordPress для этого? Какой общий подход используется для валидации произвольных полей?

0
Все ответы на вопрос 5
9

Вы на правильном пути. Я проверяю поля в колбэке save_post, а затем использую админ-уведомления для отображения ошибок пользователю, если поле не прошло валидацию. Они появляются в выделенной области в верхней части страницы, так же, как любые ошибки/сообщения, генерируемые самим WordPress.

Вот простой пример создания админ-уведомления:

function my_admin_notice()
{
    ?>

    <div class="updated">
       <p>Aenean eros ante, porta commodo lacinia.</p>
    </div>

    <?php
}
add_action( 'admin_notices', 'my_admin_notice' );

Однако это не очень практично. В такой ситуации вам нужна функция, которой можно просто передать сообщение. Например:

if( $pizza != 'warm' )
    $notices->enqueue( 'Пицца не горячая', 'error' );

Таким образом, вы можете написать функцию enqueue() самостоятельно (вместе с функцией для вывода уведомлений) или использовать библиотеку, такую как IDAdminNotices.

Вот пример из плагина, который я написал. Здесь используются функции добавления и вывода уведомлений, встроенные в сам класс, а не подключение внешней библиотеки.

public function saveCustomFields( $postID )
{
    // ...

    if( filter_var( $_POST[ self::PREFIX . 'zIndex'], FILTER_VALIDATE_INT ) === FALSE )
    {
        update_post_meta( $post->ID, self::PREFIX . 'zIndex', 0 );
        $this->enqueueMessage( 'Порядок наложения должен быть целым числом.', 'error' );
    }   
    else
        update_post_meta( $post->ID, self::PREFIX . 'zIndex', $_POST[ self::PREFIX . 'zIndex'] );

    // ...
}
add_action( 'save_post',    array( $this, 'saveCustomFields' );
29 авг. 2012 г. 00:21:14
Комментарии

Мне не совсем понятно... требует ли ваш пример кода стороннего кода или он будет работать в WordPress как есть?

Force Flow Force Flow
29 авг. 2012 г. 03:52:44

Я добавил больше деталей в ответ.

Ian Dunn Ian Dunn
29 авг. 2012 г. 04:37:58

Это, кажется, работает только при первой загрузке страницы. Если нажать кнопку "Обновить/Опубликовать", уведомления не отображаются.

Force Flow Force Flow
30 авг. 2012 г. 19:32:08

Оба подхода мне подходят. Можешь прислать ссылку на полный код?

Ian Dunn Ian Dunn
30 авг. 2012 г. 22:43:27

Пример кода: http://pastebin.com/vTxv9cw1

Force Flow Force Flow
30 авг. 2012 г. 23:51:16

Думаю, проблема в том, что ты используешь глобальную переменную вместо сохранения уведомлений в базе данных. Данные в переменных не сохраняются между запросами. То есть, уведомление добавляется в $bh_errorMessages при запросе сохранения, затем WordPress перенаправляет обратно на экран редактирования записи (это новый запрос), и все переменные сбрасываются. Смотри http://en.wikipedia.org/wiki/Post/Redirect/Get. Внимательно изучи IDAdminNotices и убедись, что делаешь всё так же, как там.

Ian Dunn Ian Dunn
31 авг. 2012 г. 19:09:56

Я не совсем понимаю, что именно вы используете для сохранения переменных между запросами. Это включение переменной $instance? Или один из вызовов add_action? Или оба варианта? Или что-то ещё?

Force Flow Force Flow
4 сент. 2012 г. 16:38:14

Хорошо, кажется, я разобрался. Вся магия в функциях WordPress add_option и get_option, которые сохраняют и извлекают переменную, а хук shutdown полезен для вызова функции add_option только один раз за сессию, после того как всё остальное уже выполнено.

Force Flow Force Flow
4 сент. 2012 г. 17:40:38

Да, именно так :)

Ian Dunn Ian Dunn
4 сент. 2012 г. 21:48:10
Показать остальные 4 комментариев
0

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

Вот часть кода:

// Фильтры валидации

$title = $album->post_title;
if ( ! $title ) {
    $errors['title'] = "Заголовок обязателен";
}

// Если есть ошибки, настроим сообщения
if (! empty($errors)) {

    // Удаляем этот хук, чтобы избежать бесконечного цикла
    remove_action('save_post', 'album_save_post');

    // Сохраняем ошибки в настройках
    update_option('album_errors', $errors);

    // Меняем статус записи с "Опубликовано" на "Черновик"
    $album->post_status = 'draft';

    // Обновляем запись
    wp_update_post( $album );

    // Возвращаем хук обратно
    add_action('save_post', 'album_save_post');

    // admin_notice создается через $_GET['message'] с номером, который WordPress использует
    // для отображения сообщения. Добавляем фильтр для замены стандартного сообщения с редиректом
    add_filter( 'redirect_post_location', 'album_post_redirect_filter' );
}

Полный урок можно посмотреть здесь

31 мар. 2013 г. 13:59:03
0

Когда срабатывает save_post, запись уже сохранена в базе данных.

Если вы используете ACF, в нем есть встроенная валидация.

Однако, если вам нужно проверять данные вне ACF, такие как post_title, все становится немного сложнее.

Изучая исходный код WordPress, в частности функцию update_post() в файле wp-includes/post.php, нет встроенного способа перехватить запрос до его сохранения в базе данных.

Тем не менее, мы можем использовать хук pre_post_update и функции header() и get_post_edit_link() для предотвращения сохранения записи.

<?php

/**
*   Выполняет пользовательскую валидацию для произвольного типа записи "Site"
*/
function custom_post_site_save($post_id, $post_data) {
    # Если это просто ревизия, ничего не делаем.
    if (wp_is_post_revision($post_id))
        return;

    if ($post_data['post_type'] == 'site') {
        # В этом примере мы вызовем ошибку для заголовков записей короче 5 символов
        if (strlen($post_data['post_title']) < 5) {
            # Добавляем уведомление
            update_option('my_notifications', json_encode(array('error', 'Заголовок записи не может быть короче 5 символов.')));
            # И перенаправляем
            header('Location: '.get_edit_post_link($post_id, 'redirect'));
            exit;
        }
    }
}
add_action( 'pre_post_update', 'custom_post_site_save', 10, 2);

/**
*   Показывает пользовательские уведомления в админ-панели WordPress
*/
function my_notification() {
    $notifications = get_option('my_notifications');

    if (!empty($notifications)) {
        $notifications = json_decode($notifications);
        #notifications[0] = (string) Тип уведомления: error, updated или update-nag
        #notifications[1] = (string) Сообщение
        #notifications[2] = (boolean) Можно закрыть?
        switch ($notifications[0]) {
            case 'error': # красный
            case 'updated': # зеленый
            case 'update-nag': # ?
                $class = $notifications[0];
                break;
            default:
                # По умолчанию error на всякий случай
                $class = 'error';
                break;
        }

        $is_dismissable = '';
        if (isset($notifications[2]) && $notifications[2] == true)
            $is_dismissable = 'is_dismissable';

        echo '<div class="'.$class.' notice '.$is_dismissable.'">';
           echo '<p>'.$notifications[1].'</p>';
        echo '</div>';

        # Сбрасываем уведомление
        update_option('my_notifications', false);
    }
}
add_action( 'admin_notices', 'my_notification' );
30 июл. 2018 г. 01:24:03
1

Я хочу дополнить отличный ответ @Lucas Bustamante тем, что значение произвольных полей можно получить через глобальную переменную $_POST.

Таким образом, ответ @Lucas Bustamante также применим, если валидация относится к произвольному полю. Например:

<?php

/**
*   Выполняет пользовательскую валидацию для произвольного типа записи "Site"
*/
function custom_post_site_save($post_id, $post_data) {
    # Если это просто ревизия, ничего не делаем
    if (wp_is_post_revision($post_id))
        return;

    if ($post_data['post_type'] == 'site') {
        # В этом примере мы вызовем ошибку для почтовых индексов короче 5 символов
        if (strlen($_POST['zip_code']) < 5) {
            # Добавляем уведомление
            update_option('my_notifications', json_encode(array('error', 'Почтовый индекс не может быть короче 5 символов.')));
            # И перенаправляем
            header('Location: '.get_edit_post_link($post_id, 'redirect'));
            exit;
        }
    }
}
add_action( 'pre_post_update', 'custom_post_site_save', 10, 2);

/**
*   Показывает пользовательские уведомления в админке WordPress
*/
function my_notification() {
    $notifications = get_option('my_notifications');

    if (!empty($notifications)) {
        $notifications = json_decode($notifications);
        #notifications[0] = (string) Тип уведомления: error, updated или update-nag
        #notifications[1] = (string) Сообщение
        #notifications[2] = (boolean) Можно закрыть?
        switch ($notifications[0]) {
            case 'error': # красный
            case 'updated': # зеленый
            case 'update-nag': # ?
                $class = $notifications[0];
                break;
            default:
                # По умолчанию error на всякий случай
                $class = 'error';
                break;
        }

        $is_dismissable = '';
        if (isset($notifications[2]) && $notifications[2] == true)
            $is_dismissable = 'is_dismissable';

        echo '<div class="'.$class.' notice '.$is_dismissable.'">';
           echo '<p>'.$notifications[1].'</p>';
        echo '</div>';

        # Сбрасываем уведомление
        update_option('my_notifications', false);
    }
}
add_action( 'admin_notices', 'my_notification' );
23 нояб. 2019 г. 00:22:31
Комментарии

Перенаправление — не лучший вариант, так как вы теряете все введенные данные из-за одного поля.

Picard Picard
13 окт. 2021 г. 16:19:00
0

Вы можете использовать фильтр "wp_insert_post_data" для изменения или проверки данных перед их вставкой в базу данных

add_filter( 'wp_insert_post_data', 'validate_posttypes' );
function wpb_custom_excerpt($data) {
    // Если заголовок поста начинается с 'wp', добавляем префикс 'wp'
    str_starts_with($data['post_title'],'wp')?$data['post_title']='wp'.$data['post_title']:null;
    return $data;
}
7 мая 2021 г. 17:20:26