chore: initial snapshot of 2meet-data-optimizer v0.1.0
Baseline before backporting wp-data-optimizer v3.0.1-v3.4.6. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TbG1keQQ7XBa7qMQY16KCY
This commit is contained in:
@@ -0,0 +1,148 @@
|
||||
<?php
|
||||
/**
|
||||
* TMDO_Conflict_Detector — 偵測 UAE 與 UAEPG 同欄位衝突
|
||||
*
|
||||
* 背景:
|
||||
* UAEPG(PostgreSQL sidecar)以 metadata filter priority 5 攔截,
|
||||
* UAE 在 priority 10 攔截。若同一 meta_key 被雙方都登錄,
|
||||
* UAEPG 會先短路 return,UAE 寫入永遠不執行,資料靜默遺失。
|
||||
*
|
||||
* 本類別在欄位登錄階段完成後(init:25)掃描雙方 Registry,
|
||||
* 找出 overlap 並:
|
||||
* 1. 寫入 error log(供 CI / 監控系統消化)
|
||||
* 2. 在管理後台顯示紅色 admin_notices
|
||||
* 3. 提供 TMDO_Conflict_Detector::get_conflicts() 與 CLI 指令 wp uae conflicts 查詢
|
||||
*
|
||||
* 結果 cache 在 static property 內,單 request 內不重複掃描。
|
||||
*
|
||||
* @package WP_Data_Optimizer
|
||||
* @since 1.1.2
|
||||
*/
|
||||
|
||||
// phpcs:disable Squiz.Commenting,Generic.Commenting,WordPress.DB.PreparedSQL.NotPrepared,WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.PreparedSQLPlaceholders.ReplacementsWrongNumber,Generic.CodeAnalysis.UnusedFunctionParameter,Generic.CodeAnalysis.EmptyStatement,Squiz.PHP.DisallowMultipleAssignments,Squiz.PHP.DisallowSizeFunctionsInLoops,WordPress.WP.I18n.MissingTranslatorsComment,WordPress.PHP.NoSilencedErrors,WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents,Squiz.PHP.CommentedOutCode,Universal.NamingConventions.NoReservedKeywordParameterNames,WordPress.PHP.YodaConditions,Squiz.Commenting.InlineComment.InvalidEndChar -- PR-1 ported from UAE; cleanup PR scheduled.
|
||||
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
final class TMDO_Conflict_Detector {
|
||||
|
||||
/**
|
||||
* @var array<int, array{entity_type:string, meta_key:string, wpdo_group:string, uaepg_group:string}>|null
|
||||
*/
|
||||
private static ?array $cache = null;
|
||||
|
||||
public static function init(): void {
|
||||
// init:25 — register_default_fields 於 init:20 觸發 wpdo_register_fields,
|
||||
// UAEPG 亦在 init:20 觸發 uaepg_register_fields;此時 priority 25 可確保雙邊皆完成登錄。
|
||||
add_action( 'init', array( self::class, 'scan' ), 25 );
|
||||
|
||||
if ( is_admin() ) {
|
||||
add_action( 'admin_notices', array( self::class, 'maybe_render_admin_notice' ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 掃描並 cache 衝突清單。
|
||||
*
|
||||
* @return array<int, array{entity_type:string, meta_key:string, wpdo_group:string, uaepg_group:string}>
|
||||
*/
|
||||
public static function scan(): array {
|
||||
if ( self::$cache !== null ) {
|
||||
return self::$cache;
|
||||
}
|
||||
|
||||
if ( ! class_exists( 'UAEPG_Registry' ) ) {
|
||||
return self::$cache = array();
|
||||
}
|
||||
|
||||
$conflicts = array();
|
||||
|
||||
foreach ( TMDO_Entity_Registry::get_all_fields() as $entity_type => $fields_by_key ) {
|
||||
foreach ( $fields_by_key as $meta_key => $wpdo_field ) {
|
||||
if ( ! UAEPG_Registry::is_managed( $entity_type, $meta_key ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$uaepg_field = UAEPG_Registry::get_field( $entity_type, $meta_key );
|
||||
|
||||
$conflicts[] = array(
|
||||
'entity_type' => $entity_type,
|
||||
'meta_key' => $meta_key,
|
||||
'wpdo_group' => $wpdo_field['group'] ?? '(unknown)',
|
||||
'uaepg_group' => $uaepg_field['group'] ?? '(unknown)',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if ( $conflicts ) {
|
||||
TMDO_Logger::error(
|
||||
'field_registration_conflict',
|
||||
array(
|
||||
'count' => count( $conflicts ),
|
||||
'fields' => $conflicts,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return self::$cache = $conflicts;
|
||||
}
|
||||
|
||||
/**
|
||||
* 取得衝突清單(若尚未掃描,觸發掃描)。
|
||||
*/
|
||||
public static function get_conflicts(): array {
|
||||
return self::$cache ?? self::scan();
|
||||
}
|
||||
|
||||
/**
|
||||
* 測試用:強制清除 cache,下次 scan() 會重跑。
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
public static function reset_cache(): void {
|
||||
self::$cache = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 若有衝突則輸出管理後台紅色通知。
|
||||
*/
|
||||
public static function maybe_render_admin_notice(): void {
|
||||
$conflicts = self::get_conflicts();
|
||||
if ( ! $conflicts ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! TMDO_Capability::current_user_can_admin() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$count = count( $conflicts );
|
||||
$lines = array();
|
||||
foreach ( array_slice( $conflicts, 0, 5 ) as $c ) {
|
||||
$lines[] = sprintf(
|
||||
'%s / %s(UAE 群組「%s」 ↔ UAEPG 群組「%s」)',
|
||||
esc_html( $c['entity_type'] ),
|
||||
esc_html( $c['meta_key'] ),
|
||||
esc_html( $c['wpdo_group'] ),
|
||||
esc_html( $c['uaepg_group'] )
|
||||
);
|
||||
}
|
||||
$extra = $count > 5 ? sprintf( __( '… 另有 %d 個欄位未顯示', 'uae' ), $count - 5 ) : '';
|
||||
|
||||
printf(
|
||||
'<div class="notice notice-error"><p><strong>%s</strong></p><ul style="list-style:disc;margin-left:20px;"><li>%s</li></ul>%s<p>%s <code>wp uae conflicts</code></p></div>',
|
||||
esc_html(
|
||||
sprintf(
|
||||
/* translators: %d: conflict count */
|
||||
__( 'UAE × UAEPG 欄位衝突偵測:發現 %d 個同 meta_key 被雙方 Registry 重複登錄 — UAEPG 會搶先短路,UAE 寫入將被靜默跳過', 'uae' ),
|
||||
$count
|
||||
)
|
||||
),
|
||||
// $lines elements were each individually esc_html()'d above (lines 121-124).
|
||||
// implode joins escaped strings with literal HTML markers — safe.
|
||||
implode( '</li><li>', $lines ), // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- pre-escaped above.
|
||||
$extra ? '<p><em>' . esc_html( $extra ) . '</em></p>' : '',
|
||||
esc_html__( '查看完整清單:', 'uae' )
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user