正如所指出的birgire 在里面his answer, WordPress使用AJAX更新元框状态,AJAX请求中传递的数据不包括帖子id,这使得很难根据帖子更新框状态。
一旦我发现WordPress使用的AJAX操作是\'closed-postboxes\'
, 我在admin js文件夹中搜索了这个字符串,以找到WordPress是如何发出AJAX请求的。
我发现它发生在postbox.js
at line #118.
看起来是这样的:
save_state : function(page) {
var closed = $(\'.postbox\').filter(\'.closed\').map(function() {
return this.id;
}).get().join(\',\');
var hidden = $(\'.postbox\').filter(\':hidden\').map(function() {
return this.id;
}).get().join(\',\');
$.post(ajaxurl, {
action: \'closed-postboxes\',
closed: closed,
hidden: hidden,
closedpostboxesnonce: jQuery(\'#closedpostboxesnonce\').val(),
page: page
});
}
本质上,WordPress查看类为“postbox”和类为“closed”的DOM项,并创建以逗号分隔的ID列表。对于类为“postbox”的隐藏DOM项,也会执行相同的操作。
因此,我的想法是:我可以创建一个具有正确类且隐藏的伪元盒,将其id设置为包含post id,这样我就可以在AJAX请求中检索它。
这就是我所做的:
add_action( \'dbx_post_sidebar\', function() {
global $post;
if ( $post->post_type === \'mycpt\' ) {
$id = $post->ID;
$f = \'<span id="fakebox_pid_%d" class="postbox closed" style="display:none;"></span>\';
printf( $f, $id );
}
});
通过这种方式,我创建了一个始终处于关闭和隐藏状态的元盒,因此WordPress将以
$_POST
AJAX请求中的var,并且一旦假框id以可预测的方式包含帖子id,我就能够识别帖子。
之后,我研究了WordPress如何执行AJAX任务。
在里面admin-ajax.php
at line 72, WordPress挂钩\'wp_ajax_closed-postboxes\'
优先级为1。
所以,要在WordPress之前执行操作,我可以挂接优先级为0的相同操作。
add_action( \'wp_ajax_closed-postboxes\', function() {
// check if we are in right post type: WordPress passes it in \'page\' post var
$page = filter_input( INPUT_POST, \'page\', FILTER_SANITIZE_STRING );
if ( $page !== \'mycpt\' ) return;
// get post data
$data = filter_input_array( INPUT_POST, array(
\'closed\' => array( \'filter\' => FILTER_SANITIZE_STRING ),
\'hidden\' => array( \'filter\' => FILTER_SANITIZE_STRING )
) );
// search among closed boxes for the "fake" one, and return if not found
$look_for_fake = array_filter( explode( \',\', $data[ \'closed\' ] ), function( $id ) {
return strpos( $id, \'fakebox_pid_\' ) === 0;
} );
if ( empty( $look_for_fake ) ) return;
$post_id = str_replace( \'fakebox_pid_\', \'\', $look_for_fake[0] );
$user_id = get_current_user_id();
// remove fake id from values
$closed = implode(\',\', array_diff( explode(\',\', $data[\'closed\'] ), $look_for_fake ) );
$hidden = implode(\',\', array_diff( explode(\',\', $data[\'hidden\'] ), $look_for_fake ) );
// save metabox status on a per-post and per-user basis in a post meta
update_post_meta( $post_id, "_mycpt_closed_boxes_{user_id}", $closed );
update_post_meta( $post_id, "_mycpt_hidden_boxes_{user_id}", $hidden );
}, 0 );
将数据保存在post meta中可以进行筛选
get_user_option_closedpostboxes_mycpt
和
get_user_option_metaboxhidden_mycpt
(两种不同的
get_user_option_{$option}
过滤器)强制从post meta加载WordPress选项:
add_filter( \'get_user_option_closedpostboxes_mycpt\', function ( $result, $key, $user ) {
global $post;
$meta = get_post_meta( $post->ID, "_mycpt_closed_boxes_{$user->ID}", TRUE );
if ( ! empty( $meta ) ) {
$result = $meta;
}
return $result;
}, 10, 3 );
以及
add_filter( \'get_user_option_metaboxhidden_mycpt\', function ( $result, $key, $user ) {
global $post;
$meta = get_post_meta( $post->ID, "_mycpt_hidden_boxes_{$user->ID}", TRUE );
if ( ! empty( $meta ) ) {
$result = $meta;
}
return $result;
}, 10, 3 );