ตามที่ระบุโดยbirgireในคำตอบของเขา WordPress ใช้ AJAX เพื่ออัปเดตสถานะ metaboxes และข้อมูลที่ส่งผ่านในคำขอ AJAX ไม่รวมรหัสโพสต์และทำให้การอัปเดตสถานะของกล่องเป็นเรื่องยากสำหรับแต่ละโพสต์
เมื่อฉันพบการกระทำ AJAX ที่ใช้โดย WordPress 'closed-postboxes'
ฉันค้นหาสตริงนี้ในโฟลเดอร์ admin js เพื่อค้นหาว่า WordPress ทำให้การร้องขอ AJAX เป็นอย่างไร
ผมพบว่ามันเกิดขึ้นในpostbox.js
ที่บรรทัด #
ดูเหมือนว่า:
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 จะมองรายการ DOM ด้วยคลาส 'ตู้ไปรษณีย์' และคลาส 'ปิด' และสร้างรายการที่คั่นด้วยจุลภาคของ ID ของพวกเขา เช่นเดียวกับรายการ DOM ที่ซ่อนอยู่ซึ่งมีคลาส 'ตู้ไปรษณีย์'
ดังนั้นความคิดของฉันคือ: ฉันสามารถสร้างเมท็อกซ์ปลอมที่มีคลาสที่ถูกต้องและถูกซ่อนไว้ตั้งค่ารหัสเพื่อให้มี 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 );
}
});
ด้วยวิธีนี้ฉันสร้าง metabox ที่ถูกปิดและซ่อนอยู่เสมอดังนั้น WordPress จะส่ง ID ในรูปแบบ$_POST
var ในคำขอ AJAX และเมื่อ ID กล่องปลอมมี ID โพสต์ในวิธีที่คาดเดาได้ฉันสามารถจดจำโพสต์ได้
หลังจากนั้นฉันดูว่า WordPress ทำงานอย่างไรกับ AJAX
ในadmin-ajax.php
บรรทัดที่ 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 );
การมีข้อมูลที่บันทึกในโพสต์เมตาทำให้สามารถกรองget_user_option_closedpostboxes_mycpt
และget_user_option_metaboxhidden_mycpt
(ทั้งสองรูปแบบของget_user_option_{$option}
ตัวกรอง) เพื่อบังคับใช้ตัวเลือกการโหลด 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 );
'get_user_option_*_post'
เพื่อทำให้ WP รู้จักข้อมูลที่กำหนดเอง เพียงคิดว่าฉันไม่ชอบมากเกินไปคือการใช้งานwp_get_referer
ใน$_SERVER
var ที่ไม่น่าเชื่อถือจริงๆแต่ฉันคิดว่าฉันมีความคิดที่จะเอาชนะ "ปัญหาหลัก";)