не публиковать пользовательский тип сообщения, если поле метаданных недопустимо

12

У меня есть пользовательский тип записи (CPT) под названием event. У меня есть мета-поле для типа с несколькими полями. Я хотел бы проверить некоторые поля перед публикацией события. Например, если дата события не указана, я хотел бы отобразить информативное сообщение об ошибке, сохранить событие для будущего редактирования, но запретить его публикацию. Является ли статус «ожидающий» для сообщения CPT без всей необходимой информации правильным способом обработки?

Рекомендуется проверять поля CPT и предотвращать публикацию сообщения, но сохранять его для дальнейшего редактирования.

Большое спасибо, Даша

dashaluna
источник
Слегка подтолкните, чтобы напомнить вам, что этот вопрос все еще нуждается в принятом ответе.
t31os

Ответы:

14

Вы можете запретить посту сохранять все вместе с незначительными взломами JQuery и проверить поля перед сохранением на стороне клиента или на сервере с помощью ajax:

Сначала мы добавляем наш JavaScript для захвата события submit / publish и используем его для отправки нашей собственной функции ajax до фактической отправки:

 add_action('wp_print_scripts','my_publish_admin_hook');

function my_publish_admin_hook(){
if (is_admin()){
        ?>
        <script language="javascript" type="text/javascript">
            jQuery(document).ready(function() {
                jQuery('#post').submit(function() {

                    var form_data = jQuery('#post').serializeArray();
                    form_data = jQuery.param(form_data);
                    var data = {
                        action: 'my_pre_submit_validation',
                        security: '<?php echo wp_create_nonce( 'pre_publish_validation' ); ?>',
                        form_data: form_data
                    };
                    jQuery.post(ajaxurl, data, function(response) {
                        if (response.indexOf('True') > -1 || response.indexOf('true') > -1 || response === true ||  response) {
                            jQuery('#ajax-loading').hide();
                            jQuery('#publish').removeClass('button-primary-disabled');
                            return true;
                        }else{
                            alert("please correct the following errors: " + response);
                            jQuery('#ajax-loading').hide();
                            jQuery('#publish').removeClass('button-primary-disabled');
                            return false;
                        }
                    });
                    return false;
                });
            });
        </script>
        <?php
    }
}

Затем мы создаем функцию для фактической проверки:

add_action('wp_ajax_my_pre_submit_validation', 'pre_submit_validation');
function pre_submit_validation(){
    //simple Security check
    check_ajax_referer( 'pre_publish_validation', 'security' );

    //do your validation here
    //all of the form fields are in $_POST['form_data'] array
    //and return true to submit: echo 'true'; die();
    //or your error message: echo 'bal bla bla'; die();
}

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

Bainternet
источник
Нет ли серверного способа сделать это?
Джефф
1
Это серверный способ сделать это.
Bainternet
1
Может быть, я что-то неправильно понимаю. Похоже, вы просто используете PHP для визуализации JavaScript, который выполняет проверку. Это не проверка на стороне сервера. Я не очень понимаю, как это pre_submit_validationвписывается.
Джефф
Первый my_publish_admin_hookблок перехватывает пост-отправку на стороне клиента, но затем он выполняет AJAX-вызов на сервер (pre-official-submit in pre_submit_validation), который выполняет проверку на стороне сервера.
EMC
1
Это все еще проверка на стороне клиента, даже если она использует AJAX для проверки. Клиент должен запустить JavaScript в первую очередь для того, чтобы любая проверка прошла. Однако ... Я все еще нашел этот ответ полезным для проверки перед отправкой. Спасибо!
cr0ybot
7

Метод состоит из двух этапов: во-первых, функция для сохранения данных вашего пользовательского поля метабокса (подключенная к save_post), а во-вторых, функция для чтения этого нового post_meta (который вы только что сохранили), проверки его и изменения результата сохранение по мере необходимости (также подключается к save_post, но после первого). Функция проверки, если проверка не пройдена, фактически изменяет post_status обратно на «ожидающий», эффективно предотвращая публикацию публикации.

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

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

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

add_action('save_post', 'save_my_fields', 10, 2);
add_action('save_post', 'completion_validator', 20, 2);

function save_my_fields($pid, $post) {
    // don't do on autosave or when new posts are first created
    if ( ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) || $post->post_status == 'auto-draft' ) return $pid;
    // abort if not my custom type
    if ( $post->post_type != 'mycustomtype' ) return $pid;

    // save post_meta with contents of custom field
    update_post_meta($pid, 'mymetafield', $_POST['mymetafield']);
}


function completion_validator($pid, $post) {
    // don't do on autosave or when new posts are first created
    if ( ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) || $post->post_status == 'auto-draft' ) return $pid;
    // abort if not my custom type
    if ( $post->post_type != 'mycustomtype' ) return $pid;

    // init completion marker (add more as needed)
    $meta_missing = false;

    // retrieve meta to be validated
    $mymeta = get_post_meta( $pid, 'mymetafield', true );
    // just checking it's not empty - you could do other tests...
    if ( empty( $mymeta ) ) {
        $meta_missing = true;
    }

    // on attempting to publish - check for completion and intervene if necessary
    if ( ( isset( $_POST['publish'] ) || isset( $_POST['save'] ) ) && $_POST['post_status'] == 'publish' ) {
        //  don't allow publishing while any of these are incomplete
        if ( $meta_missing ) {
            global $wpdb;
            $wpdb->update( $wpdb->posts, array( 'post_status' => 'pending' ), array( 'ID' => $pid ) );
            // filter the query URL to change the published message
            add_filter( 'redirect_post_location', create_function( '$location','return add_query_arg("message", "4", $location);' ) );
        }
    }
}

Для нескольких полей метабокса просто добавьте больше маркеров завершения, получите больше post_meta и сделайте больше тестов.

соматический
источник
1

Вы должны проверить / проверить значение вашего метаполя на ajax, т.е. когда пользователь нажмет кнопку «Опубликовать / обновить». Здесь я проверяю продукт woocommerce, имеющий метаполе "product_number" для пустого значения.

add_action('admin_head-post.php','ep_publish_admin_hook');
add_action('admin_head-post-new.php','ep_publish_admin_hook');

function ep_publish_admin_hook(){
    global $post;
    if ( is_admin() && $post->post_type == 'product' ){
        ?>
        <script language="javascript" type="text/javascript">
            (function($){
                jQuery(document).ready(function() {

                    jQuery('#publish').click(function() {
                        if(jQuery(this).data("valid")) {
                            return true;
                        }

                        //hide loading icon, return Publish button to normal
                        jQuery('#publishing-action .spinner').addClass('is-active');
                        jQuery('#publish').addClass('button-primary-disabled');
                        jQuery('#save-post').addClass('button-disabled');

                        var data = {
                            action: 'ep_pre_product_submit',
                            security: '<?php echo wp_create_nonce( "pre_publish_validation" ); ?>',
                            'product_number': jQuery('#acf-field-product_number').val()
                        };
                        jQuery.post(ajaxurl, data, function(response) {

                            jQuery('#publishing-action .spinner').removeClass('is-active');
                            if ( response.success ){
                                jQuery("#post").data("valid", true).submit();
                            } else {
                                alert("Error: " + response.data.message );
                                jQuery("#post").data( "valid", false );

                            }
                            //hide loading icon, return Publish button to normal
                            jQuery('#publish').removeClass('button-primary-disabled');
                            jQuery('#save-post').removeClass('button-disabled');
                        });
                        return false;
                    });
                });
            })(jQuery);
        </script>
        <?php
    }
}

После этого добавьте функцию обработчика AJAX,

add_action('wp_ajax_ep_pre_product_submit', 'ep_pre_product_submit_func');
function ep_pre_product_submit_func() {
    //simple Security check
    check_ajax_referer( 'pre_publish_validation', 'security' );

    if ( empty( $_POST['product_number'] ) || empty( $_POST['file_attachment'] ) ) {
         $data = array(
            'message' => __('Please enter part number and specification document.'),
        );
        wp_send_json_error( $data );
    }
    wp_send_json_success();
}
Мохан Дере
источник
0

Просто хотел добавить, что для чтения пост-переменных, используя решение Bainternet, вам придется анализировать строку с $_POST['form_data']помощью parse_strфункции PHP (просто чтобы сэкономить вам время на исследования).

$vars = parse_str( $_POST['form_data'] );

Затем вы можете получить доступ к каждой переменной, просто используя $varname. Например, если у вас есть мета-поле с именем «my_meta», вы получите к нему доступ следующим образом:

$vars = parse_str ( $_POST['form_data'] ) 
if ( $my_meta == "something" ) { // do something }
АГУС
источник