Files
2meet-data-optimizer/admin/templates/post-stress-test.php
T
wpdev d52d604d7a
Anti-EAV Lint + Quality Gate / anti-eav-lint (push) Successful in 8s
Tests / Unit Tests (push) Successful in 10s
Tests / Integration Tests (push) Successful in 35s
Tests / PHP Lint (push) Successful in 7s
Tests / PHPCS (push) Successful in 19s
Tests / PHPStan (push) Successful in 24s
style(admin): inline style 全面改用 CSS class(PR-H)
admin/ 的 inline style= 由 348 處降到 9 處,剩下的 9 處全是 CSS custom
property 載體(--wpdo-bar-width / --wpdo-cov-pct 等動態數值),與來源外掛的
設計一致。

- wpdo-admin.css 543 → 911 行:補上 148 個 class(來源檔在 selector 與
  rule-block 層級都是既有內容的超集,逐條核對過),另加 .wpdo-form-inline
- 5 個變數改為 class 版本:$mode_cls / $badge_mode_cls / $diffs_cls /
  $ap_cls / $e_mode_cls;3 個 stress-test template 補 $mode_text_cls /
  $mode_card_cls
- 刪掉因此變成孤兒的 $mode_badge / $style / $mode_style / $badge_style /
  $e_mode_bg / $badge_bg
- entity card 改 .wpdo-eb-card、pipeline dot 改 .wpdo-stage-pill、demote 按鈕
  改 .wpdo-eb-btn-dim;.wpdo-native-counts / .wpdo-recommendation /
  .wpdo-setup-banner-btn 的重複 inline style 移除
- dashboard 的 top-views 查詢一併改用上一個 commit 的 TMDO_Zone_Warm::VIEW_KEY

PHPStan 抓出自動轉換造成的 11 個未定義變數,已全數補回定義並複驗。
2026-07-31 10:34:57 +08:00

392 lines
18 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
/**
* Post Stress Test template (v2.11.4).
*
* Full async + polling UI mirroring User Stress Test:
* 1. 設定並啟動測試(form: post_type / target / mode / batch_size + Start/Cancel
* 2. 即時進度(progress bar + processed/target/rate/ETA/peak memory
* 3. Benchmark 報告(write metrics + DB sizes + query performance
*
* The UI uses REST/AJAX exclusively; legacy admin action handlers now require POST.
*
* Variables in scope from render_post_stress_test():
* $test_post_count — int, posts matching TMDO_STRESS_TEST_ prefix
* $diagnose — TMDO_Post_Migration::diagnose() output
*
* @package WP_Data_Optimizer
*/
declare(strict_types=1);
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
$page_url = admin_url( 'tools.php?page=wp-data-optimizer&tab=post-stress-test' );
// Read-only display banner — server-set redirect message, no form processing.
// phpcs:ignore WordPress.Security.NonceVerification.Recommended
$msg_raw = isset( $_GET['wpdo_msg'] ) ? sanitize_text_field( wp_unslash( (string) $_GET['wpdo_msg'] ) ) : '';
$msg_text = '';
$msg_class = '';
if ( '' !== $msg_raw ) {
if ( str_starts_with( $msg_raw, 'stress_cleanup_' ) ) {
$n = (int) substr( $msg_raw, strlen( 'stress_cleanup_' ) );
$msg_text = sprintf(
/* translators: %s: count */
__( '已清除 %s 個 stress test posts(連同 wp_postmeta + 7 張 flat 表的對應 row)。', '2meet-data-optimizer' ),
number_format_i18n( $n )
);
$msg_class = 'notice-success';
} elseif ( str_starts_with( $msg_raw, 'err_' ) ) {
$msg_text = __( '錯誤:請查看 wpdo_errors 日誌。', '2meet-data-optimizer' );
$msg_class = 'notice-error';
}
}
// Live state from the new state machine — drives initial render of cards.
$state = class_exists( 'TMDO_Post_Stress_Tester' ) ? TMDO_Post_Stress_Tester::get_progress( false ) : array();
$wpdo_pst_stat = (string) ( $state['status'] ?? 'idle' );
$is_running = ( 'running' === $wpdo_pst_stat || 'benchmarking' === $wpdo_pst_stat );
// Map of post_type → seed key count, surfaced inline next to the dropdown.
$post_type_options = array(
'product' => array( 'product (WC)', 5 ),
'hp_listing' => array( 'hp_listing (HivePress)', 7 ),
'hp_request' => array( 'hp_request', 5 ),
'hp_vendor' => array( 'hp_vendor', 5 ),
'attachment' => array( 'attachment', 2 ),
'nav_menu_item' => array( 'nav_menu_item', 5 ),
'post' => array( 'post', 2 ),
);
?>
<div class="wpdo-post-stress-test-tab">
<h2><?php esc_html_e( 'Post Entity 壓力測試 & Benchmark', '2meet-data-optimizer' ); ?></h2>
<div class="wpdo-notice-error">
⚠️ <strong><?php esc_html_e( '此工具僅供開發 / 測試環境使用。', '2meet-data-optimizer' ); ?></strong>
<?php esc_html_e( '會建立大量測試 post 並填滿對應 wp_postmeta + flat 表。請勿在生產環境執行。', '2meet-data-optimizer' ); ?>
</div>
<p class="description">
<?php esc_html_e( '透過自動產生大量測試 post,評估 post entity 反 EAV 系統在不同規模下的寫入吞吐與查詢效能。所有測試 post 均以 TMDO_STRESS_TEST_ 為 post_title 前綴,可一鍵清除。', '2meet-data-optimizer' ); ?>
</p>
<?php if ( '' !== $msg_text ) : ?>
<div class="notice <?php echo esc_attr( $msg_class ); ?> is-dismissible">
<p><?php echo esc_html( $msg_text ); ?></p>
</div>
<?php endif; ?>
<!-- Diagnose snapshot -->
<?php
$current_post_mode = (string) ( $diagnose['mode'] ?? 'disabled' );
$mode_color = 'aeav_only' === $current_post_mode ? '#28a745' : '#dc3545';
$mode_optimal = 'aeav_only' === $current_post_mode;
$mode_text_cls = $mode_optimal ? 'wpdo-text-success' : 'wpdo-text-danger';
$mode_card_cls = $mode_optimal ? 'ok' : 'warn';
$settings_tab_url = admin_url( 'tools.php?page=wp-data-optimizer&tab=settings' );
?>
<div class="wpdo-card wpdo-mt-3">
<h3 class="wpdo-mt-0"><?php esc_html_e( '當前 Post Entity 狀態', '2meet-data-optimizer' ); ?></h3>
<table class="widefat striped">
<tr>
<td><?php esc_html_e( 'Posts', '2meet-data-optimizer' ); ?></td>
<td><strong><?php echo esc_html( number_format_i18n( $diagnose['posts'] ) ); ?></strong></td>
<td><?php esc_html_e( 'Postmeta', '2meet-data-optimizer' ); ?></td>
<td><strong><?php echo esc_html( number_format_i18n( $diagnose['postmeta'] ) ); ?></strong></td>
</tr>
<tr>
<td><?php esc_html_e( 'Ratio', '2meet-data-optimizer' ); ?></td>
<td><strong>1:<?php echo esc_html( (string) $diagnose['ratio'] ); ?></strong></td>
<td><?php esc_html_e( 'Mode', '2meet-data-optimizer' ); ?></td>
<td><strong class="<?php echo esc_attr( $mode_text_cls ); ?>"><?php echo esc_html( $current_post_mode ); ?></strong></td>
</tr>
<tr>
<td colspan="2"><?php esc_html_e( 'Stress 測試 post 數', '2meet-data-optimizer' ); ?></td>
<td colspan="2"><strong id="wpdo-pst-count" class="wpdo-count-danger"><?php echo esc_html( number_format_i18n( $test_post_count ) ); ?></strong></td>
</tr>
</table>
</div>
<!-- 驗證反 EAV 優化指南 -->
<div class="wpdo-card wpdo-mode-card wpdo-mode-card--<?php echo esc_attr( $mode_card_cls ); ?>">
<h3 class="wpdo-mt-0 wpdo-h3-sm">
<?php if ( $mode_optimal ) : ?>
✅ <?php esc_html_e( 'Post Mode = aeav_only — 已具備驗證優化的條件', '2meet-data-optimizer' ); ?>
<?php else : ?>
⚠️
<?php
printf(
/* translators: %s: current mode */
esc_html__( 'Post Mode = %s — 此模式下壓力測試結果不會展示反 EAV 優化效果', '2meet-data-optimizer' ),
'<code class="wpdo-code-white">' . esc_html( $current_post_mode ) . '</code>'
);
?>
<?php endif; ?>
</h3>
<p class="wpdo-mt-1">
<strong><?php esc_html_e( '想看 wp_postmeta 真實減量?必須同時滿足兩個條件:', '2meet-data-optimizer' ); ?></strong>
</p>
<ol class="wpdo-list-ol-tight">
<li>
<?php
printf(
/* translators: 1: settings tab anchor open, 2: settings tab anchor close */
esc_html__( 'Post mode 設為 %1$saeav_only%2$s(前往設定 tab → Entity Bridge → Post entity', '2meet-data-optimizer' ),
'<code class="wpdo-code-white">',
'</code>'
);
?>
<?php if ( ! $mode_optimal ) : ?>
<a href="<?php echo esc_url( $settings_tab_url ); ?>" class="button button-small wpdo-ml-2">→ <?php esc_html_e( '前往設定', '2meet-data-optimizer' ); ?></a>
<?php endif; ?>
</li>
<li>
<?php esc_html_e( '寫入模式選 🐢 Realistic(走 wp_insert_post + Hook Bus,會被攔截短路 wp_postmeta', '2meet-data-optimizer' ); ?>
</li>
</ol>
<details class="wpdo-mt-1">
<summary class="wpdo-summary-toggle"><?php esc_html_e( '📐 模式 × 寫入路徑 → 預期結果矩陣', '2meet-data-optimizer' ); ?></summary>
<table class="widefat wpdo-mt-1 wpdo-table-inset">
<thead>
<tr class="wpdo-tr-header">
<th><?php esc_html_e( 'Post Mode', '2meet-data-optimizer' ); ?></th>
<th>⚡ Fast</th>
<th>🐢 Realistic</th>
</tr>
</thead>
<tbody>
<tr class="<?php echo 'disabled' === $current_post_mode ? 'wpdo-tr-highlight' : ''; ?>">
<td><code>disabled</code></td>
<td>wp_postmeta 5 rows / flat 0 → <strong>1:5(無優化)</strong></td>
<td>wp_postmeta 5 / flat 0 → 1:5(無優化)</td>
</tr>
<tr class="<?php echo 'dual_write' === $current_post_mode ? 'wpdo-tr-highlight' : ''; ?>">
<td><code>dual_write</code></td>
<td>wp_postmeta 5 / flat 0 → 1:5</td>
<td>wp_postmeta 5 + flat 1 → 1:5(有 flat 但 wp_postmeta 不減)</td>
</tr>
<tr class="<?php echo 'shadow_read' === $current_post_mode ? 'wpdo-tr-highlight' : ''; ?>">
<td><code>shadow_read</code></td>
<td>wp_postmeta 5 / flat 0 → 1:5</td>
<td>wp_postmeta 5 + flat 1 → 1:5(讀走 flat,寫仍雙寫)</td>
</tr>
<tr class="<?php echo 'aeav_only' === $current_post_mode ? 'wpdo-tr-success' : ''; ?>">
<td><code>aeav_only</code></td>
<td>wp_postmeta 5(直 SQL 繞過 Hook Bus/ flat 0 → 1:5 ⚠️</td>
<td>wp_postmeta <strong>0</strong> / flat 1 → <strong>0:1(完全優化)</strong> ✅</td>
</tr>
</tbody>
</table>
<p class="description wpdo-mt-1">
<?php esc_html_e( '範例以 nav_menu_item5 keys/post)為基準。Fast 模式直接 $wpdb->insert,故意繞過 Hook Bus → 即使 mode=aeav_only 也會寫滿 wp_postmeta(用途:快速灌 fixture 給 Query Router benchmark)。驗證反 EAV 優化效果一律用 Realistic。', '2meet-data-optimizer' ); ?>
</p>
</details>
</div>
<div class="wpdo-grid-2col">
<!-- Left: Configure & Start -->
<div class="wpdo-card">
<h3 class="wpdo-mt-0"><?php esc_html_e( '1. 設定並啟動測試', '2meet-data-optimizer' ); ?></h3>
<table class="form-table wpdo-mt-0">
<tr>
<th class="wpdo-th-main"><label for="wpdo-pst-post-type"><?php esc_html_e( 'Post Type', '2meet-data-optimizer' ); ?></label></th>
<td>
<select id="wpdo-pst-post-type" class="regular-text">
<?php foreach ( $post_type_options as $pt => $info ) : ?>
<?php
list( $label, $key_count ) = $info;
?>
<option value="<?php echo esc_attr( $pt ); ?>" data-keys="<?php echo esc_attr( (string) $key_count ); ?>">
<?php
printf(
/* translators: 1: post_type slug, 2: human label, 3: number of seeded keys */
esc_html__( '%1$s — %2$s · %3$d keys/post', '2meet-data-optimizer' ),
esc_html( $pt ),
esc_html( $label ),
(int) $key_count
);
?>
</option>
<?php endforeach; ?>
</select>
<p class="description"><?php esc_html_e( '每筆 post 會 seed 該 post_type 對應 entity group 的標準 meta keysv2.9.1 entity registry)。', '2meet-data-optimizer' ); ?></p>
</td>
</tr>
<tr>
<th><label for="wpdo-pst-target"><?php esc_html_e( '要建立的 post 數', '2meet-data-optimizer' ); ?></label></th>
<td>
<input type="number" id="wpdo-pst-target" min="1" max="100000" value="500" class="regular-text" />
<p class="description"><?php esc_html_e( '常用:100 / 500 / 1,000 / 10,000(上限 100,000', '2meet-data-optimizer' ); ?></p>
</td>
</tr>
<tr>
<th><label><?php esc_html_e( '寫入模式', '2meet-data-optimizer' ); ?></label></th>
<td>
<label class="wpdo-label-block">
<input type="radio" name="wpdo-pst-mode" value="fast" checked />
<strong>Fast</strong> — <?php esc_html_e( '直接 $wpdb->insert,跳過 WP filter chain(最快,但不測 Hook Bus', '2meet-data-optimizer' ); ?>
</label>
<label class="wpdo-label-block">
<input type="radio" name="wpdo-pst-mode" value="realistic" />
<strong>Realistic</strong> — <?php esc_html_e( '走 wp_insert_post + update_post_meta(較慢,模擬生產路徑 + 觸發 Hook Bus → mode=dual_write+ 時 flat 表自動填入)', '2meet-data-optimizer' ); ?>
</label>
</td>
</tr>
<tr>
<th><label for="wpdo-pst-batch"><?php esc_html_e( '批次大小', '2meet-data-optimizer' ); ?></label></th>
<td>
<input type="number" id="wpdo-pst-batch" min="1" max="1000" value="200" class="small-text" />
<p class="description"><?php esc_html_e( '每批執行有 8 秒 wall-clock 上限(避免 nginx 504)。Fast 建議 200-1000Realistic 建議 5-20(每 post ~100-300ms)。', '2meet-data-optimizer' ); ?></p>
</td>
</tr>
</table>
<p>
<button type="button" class="button button-primary button-large" id="wpdo-pst-start" <?php disabled( $is_running ); ?>>
<?php esc_html_e( '🚀 啟動壓力測試', '2meet-data-optimizer' ); ?>
</button>
<button type="button" class="button" id="wpdo-pst-cancel" <?php disabled( ! $is_running ); ?>>
<?php esc_html_e( '⏹ 取消', '2meet-data-optimizer' ); ?>
</button>
</p>
</div>
<!-- Right: Cleanup + Re-run benchmark -->
<div class="wpdo-card">
<h3 class="wpdo-mt-0"><?php esc_html_e( '清除測試資料', '2meet-data-optimizer' ); ?></h3>
<p>
<?php esc_html_e( '目前 stress test post 數:', '2meet-data-optimizer' ); ?>
<strong id="wpdo-pst-count-mirror" class="wpdo-count-danger">
<?php echo esc_html( number_format_i18n( $test_post_count ) ); ?>
</strong>
</p>
<p class="description">
<?php esc_html_e( '一鍵清除所有 post_title 前綴 TMDO_STRESS_TEST_ 的 post,連同 wp_postmeta + 7 張 flat 表的對應 row。', '2meet-data-optimizer' ); ?>
</p>
<p>
<button type="button" class="button button-secondary" id="wpdo-pst-cleanup" <?php disabled( $is_running || 0 === $test_post_count ); ?>>
<?php esc_html_e( '🗑 清除全部測試 post', '2meet-data-optimizer' ); ?>
</button>
</p>
<hr class="wpdo-hr-section" />
<p>
<button type="button" class="button" id="wpdo-pst-rerun-bench" <?php disabled( $is_running || 0 === $test_post_count ); ?>>
<?php esc_html_e( '📊 重跑 Benchmark(不新增資料)', '2meet-data-optimizer' ); ?>
</button>
</p>
<p class="description">
<?php esc_html_e( '針對最後一次啟動所選的 post_type 重新量測寫入指標(保留)+ DB 容量 + 查詢效能。', '2meet-data-optimizer' ); ?>
</p>
</div>
</div>
<!-- Progress section (live) -->
<div id="wpdo-pst-progress-card" class="wpdo-card wpdo-mt-3<?php echo $is_running ? '' : ' wpdo-hidden'; ?>">
<h3 class="wpdo-mt-0"><?php esc_html_e( '2. 即時進度', '2meet-data-optimizer' ); ?></h3>
<div class="wpdo-bar-section">
<div class="wpdo-bar-header">
<span>
<strong id="wpdo-pst-pg-status"><?php echo esc_html( $wpdo_pst_stat ); ?></strong>
· <code id="wpdo-pst-pg-post-type"><?php echo esc_html( (string) ( $state['post_type'] ?? '' ) ); ?></code>
· <span id="wpdo-pst-pg-mode"><?php echo esc_html( (string) ( $state['mode'] ?? '' ) ); ?></span> mode
</span>
<span id="wpdo-pst-pg-pct" class="wpdo-bar-pct"><?php echo esc_html( (string) ( $state['pct'] ?? 0 ) ); ?>%</span>
</div>
<div class="wpdo-bar-track">
<div id="wpdo-pst-pg-bar" class="wpdo-bar-fill" style="--wpdo-bar-width:<?php echo esc_attr( (string) ( $state['pct'] ?? 0 ) ); ?>%"></div>
</div>
</div>
<table class="wpdo-stats-table">
<tr>
<td class="wpdo-td-muted"><?php esc_html_e( '已建立', '2meet-data-optimizer' ); ?></td>
<td class="wpdo-td-val"><span id="wpdo-pst-pg-processed"><?php echo esc_html( (string) ( $state['processed'] ?? 0 ) ); ?></span> / <span id="wpdo-pst-pg-target"><?php echo esc_html( (string) ( $state['target'] ?? 0 ) ); ?></span></td>
<td class="wpdo-td-muted"><?php esc_html_e( '速率', '2meet-data-optimizer' ); ?></td>
<td class="wpdo-td-val"><span id="wpdo-pst-pg-rate"><?php echo esc_html( (string) ( $state['rate_per_sec'] ?? 0 ) ); ?></span> posts/sec</td>
</tr>
<tr>
<td class="wpdo-td-muted"><?php esc_html_e( '已耗時', '2meet-data-optimizer' ); ?></td>
<td class="wpdo-td"><span id="wpdo-pst-pg-elapsed"><?php echo esc_html( (string) ( $state['elapsed_sec'] ?? 0 ) ); ?></span> 秒</td>
<td class="wpdo-td-muted"><?php esc_html_e( '預估剩餘', '2meet-data-optimizer' ); ?></td>
<td class="wpdo-td"><span id="wpdo-pst-pg-eta"><?php echo esc_html( (string) ( $state['eta_sec'] ?? 0 ) ); ?></span> 秒</td>
</tr>
<tr>
<td class="wpdo-td-muted"><?php esc_html_e( '完成批次', '2meet-data-optimizer' ); ?></td>
<td class="wpdo-td"><span id="wpdo-pst-pg-batches"><?php echo esc_html( (string) ( $state['batches_done'] ?? 0 ) ); ?></span></td>
<td class="wpdo-td-muted"><?php esc_html_e( 'PHP Peak Mem', '2meet-data-optimizer' ); ?></td>
<td class="wpdo-td"><span id="wpdo-pst-pg-mem"><?php echo esc_html( (string) round( ( (int) ( $state['peak_memory'] ?? 0 ) ) / 1048576, 1 ) ); ?></span> MB</td>
</tr>
</table>
</div>
<!-- Benchmark report -->
<div id="wpdo-pst-bench-card" class="wpdo-card wpdo-mt-3<?php echo ! empty( $state['benchmark'] ) ? '' : ' wpdo-hidden'; ?>">
<h3 class="wpdo-mt-0"><?php esc_html_e( '3. Benchmark 報告', '2meet-data-optimizer' ); ?></h3>
<div id="wpdo-pst-bench-content"></div>
</div>
<!-- 7-group seed map info -->
<div class="wpdo-card wpdo-mt-3">
<h3 class="wpdo-mt-0"><?php esc_html_e( '4. TMDO_Post_Stress_Tester seed map7 個 post_type', '2meet-data-optimizer' ); ?></h3>
<p class="description">
<?php esc_html_e( '每個 stress post 自動 seed 對應 group 的 canonical meta keysv2.9.1 entity registry 定義)。', '2meet-data-optimizer' ); ?>
</p>
<table class="widefat striped">
<thead>
<tr>
<th><?php esc_html_e( 'post_type', '2meet-data-optimizer' ); ?></th>
<th><?php esc_html_e( 'Seeded keys', '2meet-data-optimizer' ); ?></th>
<th><?php esc_html_e( 'Flat 表', '2meet-data-optimizer' ); ?></th>
</tr>
</thead>
<tbody>
<tr>
<td><code>product</code></td>
<td>_price, _regular_price, _stock, _stock_status, _sku</td>
<td><code>wp_wpdo_post_wc_product</code></td>
</tr>
<tr>
<td><code>hp_listing</code></td>
<td>hp_price, hp_status, hp_featured, hp_verified, hp_vendor, hp_view_count, hp_expired_time</td>
<td><code>wp_wpdo_post_hp_listing_core</code></td>
</tr>
<tr>
<td><code>hp_request</code></td>
<td>hp_status, hp_user, hp_budget, hp_view_count, hp_expired_time</td>
<td><code>wp_wpdo_post_hp_request_core</code></td>
</tr>
<tr>
<td><code>hp_vendor</code></td>
<td>hp_user, hp_verified, hp_hourly_rate, hp_rating_count, hp_rating</td>
<td><code>wp_wpdo_post_hp_vendor_core</code></td>
</tr>
<tr>
<td><code>attachment</code></td>
<td>_wp_attached_file, _wp_attachment_image_alt</td>
<td><code>wp_wpdo_post_attachment</code></td>
</tr>
<tr>
<td><code>nav_menu_item</code></td>
<td>_menu_item_type, _menu_item_object_id, _menu_item_object, _menu_item_target, _menu_item_url</td>
<td><code>wp_wpdo_post_nav_menu_item</code></td>
</tr>
<tr>
<td><code>post</code></td>
<td>_thumbnail_id, _edit_last</td>
<td><code>wp_wpdo_post_wp_core</code></td>
</tr>
</tbody>
</table>
</div>
</div>