fix(admin): 13 個破壞性動作由 GET 改 POST + nonce(A1-A4)

nonce 走 query string 會經 Referer 外洩,且 GET 觸發的破壞性動作(刪快照、
cutover、promote aeav_only、清 postmeta)可被 prefetch/爬蟲觸發。對應 A v3.3.1 P1-6。

Handler 端(admin/class-tmdo-admin.php:300-700):13 個動作與其附屬參數
(post_type / count / mode / samples)全部改讀 $_POST。唯讀的 tab /
classify_type / wpdo_msg / wpdo_module 維持 GET。

渲染端改為 <form method=post> + wp_nonce_field():
- admin:重置速率統計、建立/清除快照、刪除快照、啟用 module
- dashboard-widget:跑健康檢查、建立快照、一鍵清理 postmeta
- post-migration-wizard:5 個步驟動作
- setup-wizard:建立 baseline snapshot
- post-stress-test:移除已無呼叫端的 legacy GET $cleanup_url

註:A 的 dashboard-widget 仍以 wp_nonce_url 產生 postmeta_cleanup 連結,
但其 handler 已只收 POST → 該按鈕在 A 是壞的;B 這邊一併改成 form。

unit 379 / integration 398 GREEN

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TbG1keQQ7XBa7qMQY16KCY
This commit is contained in:
2026-07-31 05:27:57 +08:00
parent 6e81dc51c5
commit 68f7f6871c
5 changed files with 119 additions and 130 deletions
+19 -17
View File
@@ -59,9 +59,7 @@ class TMDO_Dashboard_Widget {
*/
public static function render(): void {
$page_url = admin_url( 'tools.php?page=wp-data-optimizer' );
$run_health_url = wp_nonce_url( add_query_arg( array( 'wpdo_run_health' => '1' ), $page_url ), 'wpdo_run_health' );
$create_snap_url = wp_nonce_url( add_query_arg( array( 'wpdo_create_snapshot' => '1' ), $page_url ), 'wpdo_create_snapshot' );
$bridge_url = add_query_arg( 'tab', 'entity-bridge', $page_url );
$bridge_url = add_query_arg( 'tab', 'entity-bridge', $page_url );
$status = self::compute_status();
$light = self::traffic_light( $status['level'] );
@@ -188,10 +186,6 @@ class TMDO_Dashboard_Widget {
? TMDO_Postmeta_Cleaner::count_garbage( TMDO_Postmeta_Cleaner::TARGET_ALL )
: array( 'total' => 0 );
if ( ! empty( $gc['total'] ) && (int) $gc['total'] > 0 ) :
$cleanup_url = wp_nonce_url(
add_query_arg( array( 'wpdo_postmeta_cleanup' => '1' ), $page_url ),
'wpdo_postmeta_cleanup'
);
$confirm_msg = sprintf(
/* translators: %s: total garbage row count */
esc_html__( '即將從 wp_postmeta 刪除 %s 行垃圾資料(transients + _wp_old_date + 過期 _edit_lock)。確認執行?', '2meet-data-optimizer' ),
@@ -211,10 +205,14 @@ class TMDO_Dashboard_Widget {
esc_html( number_format_i18n( (int) $gc['edit_locks'] ) )
);
?>
<a href="<?php echo esc_url( $cleanup_url ); ?>"
onclick="return confirm(<?php echo wp_json_encode( $confirm_msg ); ?>);">
<strong><?php esc_html_e( '一鍵清理 →', '2meet-data-optimizer' ); ?></strong>
</a>
<form method="post" action="<?php echo esc_url( $page_url ); ?>" style="display:inline">
<input type="hidden" name="wpdo_postmeta_cleanup" value="1">
<?php wp_nonce_field( 'wpdo_postmeta_cleanup' ); ?>
<button type="submit" class="button-link"
onclick="return confirm(<?php echo wp_json_encode( $confirm_msg ); ?>);">
<strong><?php esc_html_e( '一鍵清理 →', '2meet-data-optimizer' ); ?></strong>
</button>
</form>
</p>
<?php endif; ?>
@@ -275,15 +273,19 @@ class TMDO_Dashboard_Widget {
<?php endif; ?>
<div class="wpdo-widget-actions">
<a class="button button-small button-primary" href="<?php echo esc_url( $run_health_url ); ?>">
<?php esc_html_e( '跑健康檢查', '2meet-data-optimizer' ); ?>
</a>
<form method="post" action="<?php echo esc_url( $page_url ); ?>" style="display:inline">
<input type="hidden" name="wpdo_run_health" value="1">
<?php wp_nonce_field( 'wpdo_run_health' ); ?>
<button type="submit" class="button button-small button-primary"><?php esc_html_e( '跑健康檢查', '2meet-data-optimizer' ); ?></button>
</form>
<a class="button button-small" href="<?php echo esc_url( $bridge_url ); ?>">
<?php esc_html_e( 'Entity Bridge', '2meet-data-optimizer' ); ?>
</a>
<a class="button button-small" href="<?php echo esc_url( $create_snap_url ); ?>">
<?php esc_html_e( '建立快照', '2meet-data-optimizer' ); ?>
</a>
<form method="post" action="<?php echo esc_url( $page_url ); ?>" style="display:inline">
<input type="hidden" name="wpdo_create_snapshot" value="1">
<?php wp_nonce_field( 'wpdo_create_snapshot' ); ?>
<button type="submit" class="button button-small"><?php esc_html_e( '建立快照', '2meet-data-optimizer' ); ?></button>
</form>
<a href="<?php echo esc_url( $page_url ); ?>" style="float: right; padding-top: 4px;">
<?php esc_html_e( '完整儀表板 →', '2meet-data-optimizer' ); ?>
</a>