如果自定义域未填写,则阻止发布帖子

时间:2012-02-11 作者:englebip

我有一个自定义的帖子类型Event 包含开始和结束日期/时间自定义字段(作为后期编辑屏幕中的元框)。

我希望确保在没有填写日期的情况下无法发布(或安排)事件,因为这将导致显示事件数据的模板出现问题(除了这是一个必要的要求!)。然而,我希望在准备期间能够有不包含有效日期的活动草案。

我在考虑勾搭save_post 进行检查,但如何防止状态更改的发生?

EDIT1: 这是我现在用来保存post\\u 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: 这就是我试图在保存到数据库后检查post数据的方法。

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;
    }
}
}
这方面的主要问题是中实际描述的问题another question: 使用wp_update_post()save_post 钩子触发无限循环。

EDIT3: 我想出了一个办法wp_insert_post_data 而不是save_post. 唯一的问题是现在post_status 已还原,但现在显示一条误导性消息,称“发布后”(通过添加&message=6 ,但状态设置为Draft。

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

5 个回复
最合适的回答,由SO网友:englebip 整理而成

好的,这就是我最终的做法:对PHP函数的Ajax调用,该函数执行检查,其灵感来自this answer 并使用question I asked on 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(), 未提交表格。

SO网友:Stephen Harris

正如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将我们重定向到一个urlmessage 变量现在不正确。

要改变它,我们可以使用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 建议当一个变量已经设置好时,函数会替换它(但正如我所说,我还没有对此进行测试)。

SO网友:mor7ifer

我认为,最好的办法不是阻止状态变化的发生,而是在发生的情况下恢复状态。例如:您钩住save_post, 具有非常高的优先级(这样钩子将很晚触发,即在您执行元插入之后),然后检查post_status 如果不符合您的标准,请将其更新为待定(或草稿或其他内容)。

另一种策略是wp_insert_post_data 直接设置post\\u状态。据我所知,这种方法的缺点是,您还没有将Posteta插入到数据库中,因此您必须对其进行处理,等等,以便进行检查,然后再次对其进行处理以将其插入到数据库中。。。无论是在性能方面还是在代码方面,这都可能会带来很大的开销。

SO网友:T.Todua

最好的方法可能是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>

SO网友:MIINIIM

对不起,我不能给你一个直截了当的答案,但我确实记得最近做过类似的事情,我只是不记得到底是怎么做的。我想我可能是这样做的——就像我把它作为默认值一样,如果这个人没有更改它,我会在if语句中选择它,所以->if(category==default category) {echo "You didn\'t pick a category!"; return them to the post creation page; } 抱歉,这不是一个直截了当的答案,但希望能有所帮助。

结束

相关推荐