我有一个自定义的帖子类型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;
}
最合适的回答,由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将我们重定向到一个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
建议当一个变量已经设置好时,函数会替换它(但正如我所说,我还没有对此进行测试)。