ป้องกันไม่ให้โพสต์ถูกเผยแพร่หากไม่ได้กรอกฟิลด์ที่กำหนดเอง


17

ฉันมีประเภทโพสต์ที่กำหนดเองEventที่มีฟิลด์วันที่ / เวลาที่กำหนดเองเริ่มต้นและสิ้นสุด (เป็นเมท็อกซ์ในหน้าจอแก้ไขโพสต์)

ฉันต้องการตรวจสอบให้แน่ใจว่ากิจกรรมไม่สามารถเผยแพร่ (หรือกำหนดเวลา) โดยไม่ต้องกรอกวันที่เนื่องจากจะทำให้เกิดปัญหากับเทมเพลตที่แสดงข้อมูลกิจกรรม (นอกเหนือจากข้อเท็จจริงที่ว่ามันเป็นข้อกำหนดที่จำเป็น!) อย่างไรก็ตามฉันต้องการที่จะมีเหตุการณ์ฉบับร่างที่ไม่มีวันที่ที่ถูกต้องในขณะที่พวกเขากำลังเตรียมการ

ฉันกำลังคิดที่save_postจะทำการตรวจสอบ แต่ฉันจะป้องกันไม่ให้เกิดการเปลี่ยนแปลงสถานะได้อย่างไร

แก้ไข 1:นี่คือเบ็ดที่ฉันใช้ตอนนี้เพื่อบันทึก 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()ภายในsave_posthook จะทำให้เกิดการวนซ้ำไม่สิ้นสุด

edit3:ฉันคิดวิธีที่จะทำมันโดย hooking แทนwp_insert_post_data save_postปัญหาเดียวคือตอนนี้post_statusถูกเปลี่ยนกลับ แต่ตอนนี้ข้อความที่ทำให้เข้าใจผิดว่า "โพสต์เผยแพร่" ปรากฏขึ้น (โดยการเพิ่ม&message=6URL ที่เปลี่ยนเส้นทาง) แต่สถานะถูกตั้งค่าเป็นแบบร่าง

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;
}

คำตอบ:


16

ตามที่ m0r7if3r ชี้ให้เห็นไม่มีวิธีที่จะป้องกันไม่ให้โพสต์เผยแพร่โดยใช้save_posthook เนื่องจากเมื่อถึงเวลาที่ hook ถูกเปิดใช้งานโพสต์จะถูกบันทึกไว้แล้ว อย่างไรก็ตามต่อไปนี้จะอนุญาตให้คุณเปลี่ยนสถานะโดยไม่ต้องใช้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) อีกครั้งสิ่งนี้ยังไม่ได้ทดสอบ แต่ควรใช้งานได้ Codex ของการadd_query_argแนะนำว่าเมื่อตัวแปรตั้งค่าไว้แล้วฟังก์ชันจะแทนที่มัน (แต่อย่างที่ฉันบอกว่าฉันยังไม่ได้ทดสอบสิ่งนี้)


นอกเหนือจากที่หายไป; ในบรรทัด add_query_arg ของคุณเคล็ดลับตัวกรอง redirect_post_location นี้เป็นสิ่งที่ฉันต้องการ ขอบคุณ!
MadtownLems

@MadtownLems ได้รับการแก้ไข :)
Stephen Harris

9

ตกลงนี้เป็นที่สุดว่าฉันสิ้นสุดที่ทำมันมีสายเรียกอาแจ็กซ์ไปยังฟังก์ชัน PHP ที่จะตรวจสอบเรียงลำดับของแรงบันดาลใจจากคำตอบนี้และการใช้เคล็ดลับฉลาดจากคำถามที่ผมถามใน StackOverflow ที่สำคัญฉันตรวจสอบให้แน่ใจว่าเมื่อเราต้องการเผยแพร่การตรวจสอบเสร็จสิ้นเพื่อให้สามารถบันทึกแบบร่างได้ตลอดเวลาโดยไม่มีการตรวจสอบ สิ่งนี้กลายเป็นทางออกที่ง่ายกว่าในการป้องกันการเผยแพร่โพสต์ มันอาจช่วยคนอื่นได้ดังนั้นฉันเขียนมันที่นี่

ก่อนอื่นให้เพิ่ม Javascript ที่จำเป็น:

//AJAX to validate event before publishing
//adapted from /wordpress/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 /wordpress//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()และไม่ได้ส่งแบบฟอร์ม


ฉันได้ทำตามวิธีการเดียวกันและทำให้การโพสต์นั้นถูกบันทึกเป็น "ฉบับร่าง" แทนที่จะเป็น "เผยแพร่" เมื่อฟังก์ชันการตรวจสอบความถูกต้องกลับมาเป็นจริง ไม่แน่ใจว่าจะแก้ไขได้อย่างไร !!! <br/> ยังไม่ได้รับข้อมูลสำหรับฟิลด์ textarea (เช่น post_content, ฟิลด์ข้อความที่กำหนดเองพื้นที่อื่น ๆ ) ในระหว่างการโทร ajax?
Mahmudur

1
ฉันได้ใช้วิธีนี้แตกต่างเล็กน้อย: ก่อนอื่นฉันได้ใช้รหัสด้านล่างในจาวาสคริปต์ในกรณีที่ประสบความสำเร็จ: delayed_autosave(); //get data from textarea/tinymce field jQuery('#publish').data("valid", true).trigger('click'); //publish postขอบคุณมาก
Mahmudur

3

ฉันคิดว่าวิธีที่ดีที่สุดในการดำเนินเรื่องนี้ไม่ใช่เพื่อป้องกันการเปลี่ยนแปลงสถานะจากการเกิดขึ้นมากเท่าที่จะเป็นการย้อนกลับหากทำได้ ตัวอย่างเช่น: คุณขอsave_postพร้อมด้วยลำดับความสำคัญสูงมาก (ดังนั้นตะขอจะเริ่มช้ามากคือหลังจากที่คุณทำการแทรกเมตาของคุณ) จากนั้นตรวจสอบpost_statusการโพสต์ที่เพิ่งบันทึกและอัปเดตเป็นรอดำเนินการ (หรือร่างหรือ อะไรก็ตาม) ถ้ามันไม่เป็นไปตามเกณฑ์ของคุณ

กลยุทธ์ทางเลือกคือขอเกี่ยวwp_insert_post_dataกับการตั้งค่า post_status โดยตรง ข้อเสียของวิธีนี้เท่าที่ฉันกังวลก็คือคุณจะไม่ได้แทรก postmeta ลงในฐานข้อมูลดังนั้นคุณจะต้องทำการประมวลผลและอื่น ๆ เพื่อทำการตรวจสอบของคุณจากนั้นดำเนินการอีกครั้งเพื่อแทรก ลงในฐานข้อมูล ... ซึ่งอาจกลายเป็นค่าใช้จ่ายจำนวนมากไม่ว่าจะในประสิทธิภาพหรือในรหัส


ขณะนี้ฉันกำลังขอsave_postความสำคัญกับ 1 เพื่อบันทึกเขตข้อมูล meta จาก metaboxes สิ่งที่คุณกำลังเสนอนั้นคือการมีเบ็ดที่สองที่save_postมีลำดับความสำคัญพูดว่า 99? สิ่งนี้จะช่วยรับรองความซื่อสัตย์หรือไม่? จะทำอย่างไรถ้ามีฮุกแรกเกิดขึ้นเมตาดาต้าจะถูกแทรกและโพสต์ที่เผยแพร่ แต่ด้วยเบ็ดที่สองไม่ได้ดังนั้นคุณจึงจบลงด้วยฟิลด์ที่ไม่ถูกต้อง
englebip

ฉันไม่สามารถนึกถึงสถานการณ์ที่เบ็ดแรกจะยิงได้ แต่ไม่ใช่ฉากที่สอง ... คุณคิดว่าสถานการณ์แบบไหนที่จะเป็นสาเหตุ หากคุณกังวลเกี่ยวกับเรื่องนี้คุณสามารถแทรกเมตาโพสต์ตรวจสอบโพสต์เมตาจากนั้นอัปเดตpost_statusทั้งหมดในฟังก์ชั่นเดียวที่หมดการโทรครั้งเดียวไปยังฮุกถ้าคุณต้องการ
mor7ifer

ฉันโพสต์รหัสเพื่อแก้ไขคำถามของฉัน ฉันพยายามใช้ตะขอตัวที่สองเพื่อsave_postทำให้เกิดการวนซ้ำไม่สิ้นสุด
englebip

ปัญหาของคุณคือคุณควรตรวจสอบโพสต์ที่สร้างขึ้น ดังนั้นif( get_post_status( $post_id ) == 'publish' )คือสิ่งที่คุณต้องการที่จะใช้เพราะคุณจะได้รับการกําหนดข้อมูลในไม่ใช่ข้อมูลใน$wpdb->posts $_POST[]
mor7ifer

0

วิธีที่ดีที่สุดอาจเป็น JAVASCRIPT:

<script type="text/javascript">
var field_id =  "My_field_div__ID";    // <----------------- CHANGE THIS

var SubmitButton = document.getElementById("save-post") || false;
var PublishButton = document.getElementById("publish")  || false; 
if (SubmitButton)   {SubmitButton.addEventListener("click", SubmCLICKED, false);}
if (PublishButton)  {PublishButton.addEventListener("click", SubmCLICKED, false);}
function SubmCLICKED(e){   
  var passed= false;
  if(!document.getElementById(field_id)) { alert("I cant find that field ID !!"); }
  else {
      var Enabled_Disabled= document.getElementById(field_id).value;
      if (Enabled_Disabled == "" ) { alert("Field is Empty");   }  else{passed=true;}
  }
  if (!passed) { e.preventDefault();  return false;  }
}
</script>

-1

ขออภัยฉันไม่สามารถให้คำตอบได้โดยตรง แต่ฉันจำได้ว่าทำสิ่งที่คล้ายกันเมื่อเร็ว ๆ นี้ฉันแค่จำไม่ได้ว่า ฉันคิดว่าฉันอาจจะทำแบบนี้ - ฉันคิดว่ามันเป็นค่าเริ่มต้นและถ้าคนไม่เปลี่ยนฉันก็หยิบมันมาในคำสั่ง if ดังนั้น -> if(category==default category) {echo "You didn't pick a category!"; return them to the post creation page; }ขอโทษนี่ไม่ใช่คำตอบที่ตรง แต่หวังว่า มันช่วยเล็กน้อย

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.