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

У меня есть пользовательский тип сообщения Event это содержит запуск и конечную дату/времена пользовательские поля (как метаполя на экране постредактирования).

Я хотел бы удостовериться, что Событие не может быть опубликовано (или запланировал) без дат, являющихся заполненным, поскольку это вызовет проблемы с шаблонами, отображающими Данные о событии (помимо того, что это - необходимое требование!). Однако я хотел бы смочь иметь Draft событий, которые не содержат допустимую дату, в то время как они находятся в подготовке.

Я думал о сцеплении save_post сделать проверку, но как я могу предотвратить изменение состояния?

EDIT1: Это - рычаг, который я использую теперь для сохранения post_meta.

// Save the Metabox Data
function ep_eventposts_save_meta( $post_id, $post ) {

if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE )
    return;

if ( !isset( $_POST['ep_eventposts_nonce'] ) )
    return;

if ( !wp_verify_nonce( $_POST['ep_eventposts_nonce'], plugin_basename( __FILE__ ) ) )
    return;

// Is the user allowed to edit the post or page?
if ( !current_user_can( 'edit_post', $post->ID ) )
    return;

// OK, we're authenticated: we need to find and save the data
// We'll put it into an array to make it easier to loop though

//debug
//print_r($_POST);

$metabox_ids = array( '_start', '_end' );

foreach ($metabox_ids as $key ) {
    $events_meta[$key . '_date'] = $_POST[$key . '_date'];
    $events_meta[$key . '_time'] = $_POST[$key . '_time'];
    $events_meta[$key . '_timestamp'] = $events_meta[$key . '_date'] . ' ' . $events_meta[$key . '_time'];
}

$events_meta['_location'] = $_POST['_location'];

if (array_key_exists('_end_timestamp', $_POST))
    $events_meta['_all_day'] = $_POST['_all_day'];

// Add values of $events_meta as custom fields

foreach ( $events_meta as $key => $value ) { // Cycle through the $events_meta array!
    if ( $post->post_type == 'revision' ) return; // Don't store custom data twice
    $value = implode( ',', (array)$value ); // If $value is an array, make it a CSV (unlikely)
    if ( get_post_meta( $post->ID, $key, FALSE ) ) { // If the custom field already has a value
        update_post_meta( $post->ID, $key, $value );
    } else { // If the custom field doesn't have a value
        add_post_meta( $post->ID, $key, $value );
    }
    if ( !$value ) 
                delete_post_meta( $post->ID, $key ); // Delete if blank
}

}

add_action( 'save_post', 'ep_eventposts_save_meta', 1, 2 );

EDIT2: и это - то, что я пытаюсь использовать для проверки данных сообщения после сохранения к базе данных.

add_action( 'save_post', 'ep_eventposts_check_meta', 99, 2 );
function ep_eventposts_check_meta( $post_id, $post ) {
//check that metadata is complete when a post is published
//print_r($_POST);

if ( $_POST['post_status'] == 'publish' ) {

    $custom = get_post_custom($post_id);

    //make sure both dates are filled
    if ( !array_key_exists('_start_timestamp', $custom ) || !array_key_exists('_end_timestamp', $custom )) {
        $post->post_status = 'draft';
        wp_update_post($post);

    }
    //make sure start < end
    elseif ( $custom['_start_timestamp'] > $custom['_end_timestamp'] ) {
        $post->post_status = 'draft';
        wp_update_post($post);
    }
    else {
        return;
    }
}
}

Основным вопросом с этим является проблема, которая была на самом деле описана в другом вопросе: использование wp_update_post() в a save_post сцепитесь инициировал бесконечный цикл.

EDIT3: Я изобразил способ сделать это путем сцепления wp_insert_post_data вместо save_post. Единственная проблема - это теперь post_status вернулся, но теперь вводящее в заблуждение высказывание сообщения "Развешивает опубликованные" шоу (путем добавления &message=6 к перенаправленному URL), но состояние установлено Спроектировать.

add_filter( 'wp_insert_post_data', 'ep_eventposts_check_meta', 99, 2 );
function ep_eventposts_check_meta( $data, $postarr ) {
//check that metadata is complete when a post is published, otherwise revert to draft
if ( $data['post_type'] != 'event' ) {
    return $data;
}
if ( $postarr['post_status'] == 'publish' ) {
    $custom = get_post_custom($postarr['ID']);

    //make sure both dates are filled
    if ( !array_key_exists('_start_timestamp', $custom ) || !array_key_exists('_end_timestamp', $custom )) {
        $data['post_status'] = 'draft';
    }
    //make sure start < end
    elseif ( $custom['_start_timestamp'] > $custom['_end_timestamp'] ) {
        $data['post_status'] = 'draft';
    }
    //everything fine!
    else {
        return $data;
    }
}

return $data;
}
17
13.04.2017, 15:37
4 ответа

Хорошо, это наконец, как я закончил тем, что делал его: вызов Ajax к функции PHP, которая делает проверку, вид вдохновленных этим ответом и использованием умной подсказки от вопроса, который я задал на StackOverflow. Значительно, я удостоверяюсь, что только то, когда мы хотим Опубликовать проверку, сделано, так, чтобы Проект мог всегда сохраняться без проверки. Это закончило тем, что было более легким решением на самом деле предотвратить публикацию сообщения. Это могло бы помочь кому-то еще, таким образом, я описал его здесь.

Во-первых, добавьте необходимый JavaScript:

//AJAX to validate event before publishing
//adapted from https://wordpress.stackexchange.com/questions/15546/dont-publish-custom-post-type-post-if-a-meta-data-field-isnt-valid
add_action('admin_enqueue_scripts-post.php', 'ep_load_jquery_js');   
add_action('admin_enqueue_scripts-post-new.php', 'ep_load_jquery_js');   
function ep_load_jquery_js(){
global $post;
if ( $post->post_type == 'event' ) {
    wp_enqueue_script('jquery');
}
}

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 == 'event' ){
    ?>
    <script language="javascript" type="text/javascript">
        jQuery(document).ready(function() {
            jQuery('#publish').click(function() {
                if(jQuery(this).data("valid")) {
                    return true;
                }
                var form_data = jQuery('#post').serializeArray();
                var data = {
                    action: 'ep_pre_submit_validation',
                    security: '<?php echo wp_create_nonce( 'pre_publish_validation' ); ?>',
                    form_data: jQuery.param(form_data),
                };
                jQuery.post(ajaxurl, data, function(response) {
                    if (response.indexOf('true') > -1 || response == true) {
                        jQuery("#post").data("valid", true).submit();
                    } else {
                        alert("Error: " + response);
                        jQuery("#post").data("valid", false);

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

Затем функция, которая обрабатывает проверку:

add_action('wp_ajax_ep_pre_submit_validation', 'ep_pre_submit_validation');
function ep_pre_submit_validation() {
//simple Security check
check_ajax_referer( 'pre_publish_validation', 'security' );

//convert the string of data received to an array
//from https://wordpress.stackexchange.com/a/26536/10406
parse_str( $_POST['form_data'], $vars );

//check that are actually trying to publish a post
if ( $vars['post_status'] == 'publish' || 
    (isset( $vars['original_publish'] ) && 
     in_array( $vars['original_publish'], array('Publish', 'Schedule', 'Update') ) ) ) {
    if ( empty( $vars['_start_date'] ) || empty( $vars['_end_date'] ) ) {
        _e('Both Start and End date need to be filled');
        die();
    }
    //make sure start < end
    elseif ( $vars['_start_date'] > $vars['_end_date'] ) {
        _e('Start date cannot be after End date');
        die();
    }
    //check time is also inputted in case of a non-all-day event
    elseif ( !isset($vars['_all_day'] ) ) {
        if ( empty($vars['_start_time'] ) || empty( $vars['_end_time'] ) ) {
            _e('Both Start time and End time need to be specified if the event is not an all-day event');
            die();              
        }
        elseif ( strtotime( $vars['_start_date']. ' ' .$vars['_start_time'] ) > strtotime( $vars['_end_date']. ' ' .$vars['_end_time'] ) ) {
            _e('Start date/time cannot be after End date/time');
            die();
        }
    }
}

//everything ok, allow submission
echo 'true';
die();
}

Эта функция возвраты true если все прекрасно, и отправляет форму, чтобы опубликовать сообщение нормальным каналом. Иначе функция возвращает сообщение об ошибке, которое показывают как alert(), и форма не отправлена.

9
19.02.2020, 21:57
  • 1
    справки, я следовал за тем же подходом и получением сообщения, сохраняемого, как "Проект" вместо "Публикуют", когда функция проверки возвращает true. Не уверенный, как зафиксировать это!!! <br/> Также не получение данных для поля текстовой области (напр. post_content, какая-либо другая текстовая область пользовательское поле) во время вызова ajax? –  Mahmudur 10.08.2012, 06:47
  • 2
    , я применил это решение немного по-другому: в первую очередь, я использовал ниже кода в JavaScript в случае успеха: delayed_autosave(); //get data from textarea/tinymce field jQuery('#publish').data("valid", true).trigger('click'); //publish post Большое спасибо. –  Mahmudur 13.08.2012, 05:25

Как m0r7if3r указанный, нет никакого способа препятствовать тому, чтобы сообщение было опубликовано с помощью save_post рычаг, начиная с к тому времени, когда рычаг запущен, сообщение, уже сохраняется. Следующее, однако, позволит Вам возвращаться состояние без использования wp_insert_post_data и не вызывая бесконечный цикл.

Следующее не тестируется, но должно работать.

<?php
add_action('save_post', 'my_save_post');
function my_save_post($post_id) {
    if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE )
         return;

    if ( !isset( $_POST['ep_eventposts_nonce'] ) )
         return;

    if ( !wp_verify_nonce( $_POST['ep_eventposts_nonce'], plugin_basename( __FILE__ ) ) )
         return;

    // Is the user allowed to edit the post or page?
     if ( !current_user_can( 'edit_post', $post->ID ) )
         return;

   // Now perform checks to validate your data. 
   // Note custom fields (different from data in custom metaboxes!) 
   // will already have been saved.
    $prevent_publish= false;//Set to true if data was invalid.
    if ($prevent_publish) {
        // unhook this function to prevent indefinite loop
        remove_action('save_post', 'my_save_post');

        // update the post to change post status
        wp_update_post(array('ID' => $post_id, 'post_status' => 'draft'));

        // re-hook this function again
        add_action('save_post', 'my_save_post');
    }
}
?>

Я не проверил, но рассмотрение кода, сообщение обратной связи отобразит неправильное сообщение, что сообщение было опубликовано. Это вызвано тем, что WordPress перенаправляет нас к URL где message переменная является теперь неправильной.

Для изменения его мы можем использовать redirect_post_location фильтр:

add_filter('redirect_post_location','my_redirect_location',10,2);
function my_redirect_location($location,$post_id){
    //If post was published...
    if (isset($_POST['publish'])){
        //obtain current post status
        $status = get_post_status( $post_id );

        //The post was 'published', but if it is still a draft, display draft message (10).
        if($status=='draft')
            $location = add_query_arg('message', 10, $location);
    }

    return $location;
}

Суммировать вышеупомянутый фильтр перенаправления: Если сообщение установлено быть опубликованным, но является все еще проектом затем, мы изменяем сообщение соответственно (который является message=10). Снова, это не тестируется, но должно работать. Кодекс add_query_arg предполагает, что, когда переменная уже, она установила, функция заменяет ее (но как я говорю, я не протестировал это).

16
19.02.2020, 21:57
  • 1
    Кроме пропавших без вести; на Вашей add_query_arg строке этот прием фильтра redirect_post_location точно, в чем я нуждался.спасибо! –  MadtownLems 02.04.2014, 22:04
  • 2
    @MadtownLems сообщения зафиксировало :) –  Stephen Harris 03.04.2014, 03:18

Я думаю, что лучший способ пойти об этом не состоит в том, чтобы ПРЕДОТВРАТИТЬ изменение состояния так, поскольку это должно ВЕРНУТЬСЯ он, если это делает. Например: Вы сцепляетесь save_post, с действительно высоким приоритетом (так, чтобы рычаг стрелял очень поздно, а именно, после того, как Вы, Ваши meta вставляют), затем проверьте post_status из сообщения это было просто сохранено и обновляет его к ожиданию (или проект или безотносительно), если это не соответствует Вашим критериям.

Альтернативная стратегия состояла бы в том, чтобы сцепиться wp_insert_post_data установить post_status непосредственно. Недостаток к этому методу, что касается меня, то, что Вы еще не будете вставлять postmeta в базу данных, таким образом, необходимо будет обработать его, и т.д. на месте, чтобы сделать проверки, затем обработать его снова для вставки его в базу данных..., которая могла стать большим количеством издержек, или в производительности или в коде.

3
19.02.2020, 21:57
  • 1
    я в настоящее время сцепляюсь save_post с приоритетом 1 для сохранения meta полей от метаполей; что Вы предлагаете, затем должен иметь второй рычаг к save_post с приоритетом, скажем, 99? Это гарантировало бы целостность? Что, если по некоторым причинам первые огни рычага, метаданные вставляются и опубликовано сообщение, но второй рычаг не делает, таким образом, Вы заканчиваете с недопустимыми полями? –  englebip 12.02.2012, 14:00
  • 2
    я не могу думать о ситуации, где первый рычаг стрелял бы, но не второе..., какой сценарий Вы думаете, что это могло вызвать это? Если Вы - то, который волновался об этом, можно вставить сообщение meta, проверить сообщение meta и затем обновить post_status все в одном функциональном убегании единственного вызова к рычагу, если Вы предпочли бы. –  mor7ifer 12.02.2012, 15:36
  • 3
    я отправил свой код как редактирование к моему вопросу; я пытался использовать второй рычаг для save_post но это инициировало бесконечный цикл. –  englebip 12.02.2012, 21:58
  • 4
    , который Ваша проблема - то, что необходимо проверять созданное сообщение. Так if( get_post_status( $post_id ) == 'publish' ) то, что Вы хотите использовать, так как Вы будете переопределять данные в $wpdb->posts, не данные в $_POST[]. –  mor7ifer 12.02.2012, 23:05

Извините я не могу дать Вам, прямое отвечает, но я действительно вспоминаю выполнение чего-то подобного совсем недавно я просто, наклон помнит точно как. Я думаю, что, возможно, сделал это вокруг о пути - что-то как у меня был он являющийся значением по умолчанию и если человек не изменил его, я взял это в если оператор так-> if(category==default category) {echo "You didn't pick a category!"; return them to the post creation page; } извините это не прямое, отвечают, но надеются, что это помогает немного.

-1
19.02.2020, 21:57

Теги

Похожие вопросы