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:
2026-07-31 05:06:36 +08:00
commit d36bb954d1
206 changed files with 66538 additions and 0 deletions
@@ -0,0 +1,322 @@
<?php
/**
* TMDO_Query_Compiler - 跨實體查詢編譯器
*
* 將 wpdo_meta_query 編譯為高效 SQL
* - 單次 JOIN UAE 表(而非原生 meta_query 多次 JOIN wp_*meta
* - 型別正確的比較(避免 CAST 開銷)
* - 命中索引
*
* @package WP_Data_Optimizer
*/
// 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_Query_Compiler {
/** @var array 合法的 SQL 比較運算子 */
private const VALID_OPERATORS = array(
'=',
'!=',
'<>',
'>',
'>=',
'<',
'<=',
'LIKE',
'NOT LIKE',
'IN',
'NOT IN',
'BETWEEN',
'NOT BETWEEN',
'EXISTS',
'NOT EXISTS',
);
/**
* 注入 wpdo_meta_query 至 WP_Querypost 實體)
*
* @param WP_Query $query
* @param array $wpdo_meta_query 結構同 meta_query
*/
public static function inject_into_wp_query( WP_Query $query, array $wpdo_meta_query ): void {
$post_type = $query->get( 'post_type' );
if ( is_array( $post_type ) ) {
$post_type = $post_type[0] ?? 'post';
}
if ( empty( $post_type ) || $post_type === 'any' ) {
$post_type = 'post';
}
// 編譯 JOIN 與 WHERE
$compiled = self::compile( 'post', $wpdo_meta_query );
if ( empty( $compiled['joins'] ) && empty( $compiled['where'] ) ) {
return;
}
// 注入 posts_clauses filter
add_filter(
'posts_clauses',
function ( $clauses ) use ( $compiled ) {
global $wpdb;
if ( ! empty( $compiled['joins'] ) ) {
$clauses['join'] .= ' ' . implode( ' ', $compiled['joins'] );
}
if ( ! empty( $compiled['where'] ) ) {
$clauses['where'] .= ' AND (' . implode( ' AND ', $compiled['where'] ) . ')';
}
return $clauses;
},
10,
1
);
// wpdo_orderby 支援
$wpdo_orderby = $query->get( 'wpdo_orderby' );
if ( $wpdo_orderby ) {
$order_dir = strtoupper( $query->get( 'order' ) ?: 'DESC' );
if ( ! in_array( $order_dir, array( 'ASC', 'DESC' ), true ) ) {
$order_dir = 'DESC';
}
$wpdo_col = TMDO_Schema_Manager::sanitize_column_name( $wpdo_orderby );
// 找出該欄位所在的群組
$field_def = TMDO_Entity_Registry::get_field( 'post', $wpdo_orderby );
if ( $field_def ) {
$alias = 'wpdo_' . $field_def['group'];
add_filter(
'posts_orderby',
function ( $orderby ) use ( $alias, $wpdo_col, $order_dir ) {
return "`{$alias}`.`{$wpdo_col}` {$order_dir}";
},
10,
1
);
}
}
}
/**
* 注入至 WP_User_Query
*/
public static function inject_into_user_query( WP_User_Query $query, array $wpdo_meta_query ): void {
$compiled = self::compile( 'user', $wpdo_meta_query );
if ( empty( $compiled['joins'] ) && empty( $compiled['where'] ) ) {
return;
}
global $wpdb;
// 透過 reflection 存取 WP_User_Query 的 query_vars 來注入
$query_orderby = &$query->query_orderby;
$query_where = &$query->query_where;
$query_from = &$query->query_from;
if ( ! empty( $compiled['joins'] ) ) {
$query_from .= ' ' . implode( ' ', $compiled['joins'] );
}
if ( ! empty( $compiled['where'] ) ) {
$query_where .= ' AND (' . implode( ' AND ', $compiled['where'] ) . ')';
}
// wpdo_orderby
$wpdo_orderby = $query->get( 'wpdo_orderby' );
if ( $wpdo_orderby ) {
$field_def = TMDO_Entity_Registry::get_field( 'user', $wpdo_orderby );
if ( $field_def ) {
$order_dir = strtoupper( $query->get( 'order' ) ?: 'DESC' );
if ( ! in_array( $order_dir, array( 'ASC', 'DESC' ), true ) ) {
$order_dir = 'DESC';
}
$alias = 'wpdo_' . $field_def['group'];
$col = TMDO_Schema_Manager::sanitize_column_name( $wpdo_orderby );
$query_orderby = "ORDER BY `{$alias}`.`{$col}` {$order_dir}";
}
}
}
/**
* 注入至 get_terms() 的 clauses
*/
public static function inject_into_terms_clauses( array $clauses, array $wpdo_meta_query ): array {
$compiled = self::compile( 'term', $wpdo_meta_query );
if ( empty( $compiled['joins'] ) && empty( $compiled['where'] ) ) {
return $clauses;
}
if ( ! empty( $compiled['joins'] ) ) {
$clauses['join'] .= ' ' . implode( ' ', $compiled['joins'] );
}
if ( ! empty( $compiled['where'] ) ) {
$clauses['where'] .= ' AND (' . implode( ' AND ', $compiled['where'] ) . ')';
}
return $clauses;
}
/**
* 核心編譯邏輯
*
* @param string $entity_type
* @param array $meta_query 結構範例:
* [
* 'relation' => 'AND',
* [ 'key' => 'price', 'value' => [100, 500], 'compare' => 'BETWEEN' ],
* [ 'key' => 'stock', 'value' => 'instock' ],
* ]
* @return array{joins: array<string>, where: array<string>}
*/
public static function compile( string $entity_type, array $meta_query ): array {
$adapter = TMDO_Entity_Registry::get_adapter( $entity_type );
if ( ! $adapter ) {
return array(
'joins' => array(),
'where' => array(),
);
}
$relation = strtoupper( $meta_query['relation'] ?? 'AND' );
if ( ! in_array( $relation, array( 'AND', 'OR' ), true ) ) {
$relation = 'AND';
}
unset( $meta_query['relation'] );
$needed_groups = array(); // group → true
$where_clauses = array();
foreach ( $meta_query as $clause ) {
if ( ! is_array( $clause ) || empty( $clause['key'] ) ) {
continue;
}
$field_def = TMDO_Entity_Registry::get_field( $entity_type, $clause['key'] );
if ( ! $field_def ) {
// 非 UAE 管理的欄位,跳過(讓原生 meta_query 接手)
continue;
}
$group = $field_def['group'];
$needed_groups[ $group ] = true;
$compare = strtoupper( $clause['compare'] ?? '=' );
if ( ! in_array( $compare, self::VALID_OPERATORS, true ) ) {
$compare = '=';
}
$alias = 'wpdo_' . $group;
$col = TMDO_Schema_Manager::sanitize_column_name( $clause['key'] );
$value = $clause['value'] ?? null;
$where_clauses[] = self::build_comparison( $alias, $col, $compare, $value, $field_def );
}
// 建立 JOIN
$joins = array();
$prim_table = $adapter->get_primary_table();
$prim_id = $adapter->get_primary_id_column();
$id_col = $adapter->get_entity_id_column();
foreach ( array_keys( $needed_groups ) as $group ) {
$wpdo_table = TMDO_Schema_Manager::get_table_name( $entity_type, $group );
if ( ! TMDO_Schema_Manager::table_exists( $wpdo_table ) ) {
continue;
}
$alias = 'wpdo_' . $group;
$joins[] = "LEFT JOIN `{$wpdo_table}` `{$alias}` ON `{$prim_table}`.`{$prim_id}` = `{$alias}`.`{$id_col}`";
}
// 組合 where,依 relation 連接
$where_sql = array();
if ( ! empty( $where_clauses ) ) {
$where_sql[] = implode( " {$relation} ", $where_clauses );
}
return array(
'joins' => $joins,
'where' => $where_sql,
);
}
/**
* 產生單一比較子句
*/
private static function build_comparison(
string $alias,
string $col,
string $compare,
$value,
array $field_def
): string {
global $wpdb;
$col_ref = "`{$alias}`.`{$col}`";
switch ( $compare ) {
case 'EXISTS':
return "{$col_ref} IS NOT NULL";
case 'NOT EXISTS':
return "{$col_ref} IS NULL";
case 'BETWEEN':
case 'NOT BETWEEN':
if ( ! is_array( $value ) || count( $value ) !== 2 ) {
return '1=1';
}
$v1 = self::escape_value( $value[0], $field_def );
$v2 = self::escape_value( $value[1], $field_def );
return "{$col_ref} {$compare} {$v1} AND {$v2}";
case 'IN':
case 'NOT IN':
if ( ! is_array( $value ) ) {
$value = array( $value );
}
if ( empty( $value ) ) {
return $compare === 'IN' ? '1=0' : '1=1';
}
$escaped = array_map( fn( $v ) => self::escape_value( $v, $field_def ), $value );
return "{$col_ref} {$compare} (" . implode( ',', $escaped ) . ')';
case 'LIKE':
case 'NOT LIKE':
$like_val = '%' . $wpdb->esc_like( (string) $value ) . '%';
return "{$col_ref} {$compare} '" . esc_sql( $like_val ) . "'";
default:
$escaped = self::escape_value( $value, $field_def );
return "{$col_ref} {$compare} {$escaped}";
}
}
/**
* 型別安全地轉義值
*/
private static function escape_value( $value, array $field_def ): string {
$type = $field_def['type'] ?? 'text';
return match ( $type ) {
'integer', 'boolean' => (string) (int) $value,
'decimal' => (string) (float) $value,
default => "'" . esc_sql( (string) $value ) . "'",
};
}
}