Files
2meet-data-optimizer/tests/bootstrap.php
T
wpdev efab023289 fix(back-compat): hook 橋改雙向 + alias 表修補 + 函式 shim(E1/E2/E5)
E1 雙向 hook 橋
  原本只做 tmdo_* → wpdo_* 單向轉發,但核心一律 do_action('wpdo_*')
  (core:69,275、custom-table-registry:110、options-manager:59),
  所以任何 add_action('tmdo_after_write') 之類的新契約永遠收不到事件。
  改為雙向,並以 $GLOBALS['tmdo_hook_relay_active'] 共用旗標防止
  A→B→A 迴圈與 listener 重複觸發。
  連帶:兩個 test bootstrap 補 do_action_ref_array() stub(單向時不會走到)。

E2 alias 表
  - 刪死條目 'TMDO_Notifier'(B 沒有這個類別,此行永不生效)
  - 補 'TMDO_Abstract_Notifier' => 'WPDO_Abstract_Notifier'(自訂 notifier 基底)
  - trait-wpdo-anti-eav-aware-alias.php 移除與 interface-wpdo-entity-adapter-alias.php
    重複的 WPDO_Entity_Adapter_Interface 宣告(composer 曾警告 Ambiguous class resolution)

E5 函式 shim:wpdo_run() / wpdo_load_textdomain() 委派到 tmdo_ 版本

unit 451 / integration 398 GREEN

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TbG1keQQ7XBa7qMQY16KCY
2026-07-31 06:00:17 +08:00

672 lines
29 KiB
PHP

<?php
declare(strict_types=1);
/**
* PHPUnit bootstrap for 2meet Data Optimizer unit tests.
*
* No WordPress installation required — stubs all globals and functions.
* WPDO_* aliases are created via class-tmdo-back-compat.php so existing
* tests that reference WPDO_* class names continue to work.
*/
require_once dirname( __DIR__ ) . '/vendor/autoload.php';
// ── Constants ──────────────────────────────────────────────────────────────
define( 'ABSPATH', '/fake/wordpress/' );
define( 'TMDO_PATH', dirname( __DIR__ ) . '/' );
define( 'TMDO_URL', 'http://localhost/wp-content/plugins/2meet-data-optimizer/' );
define( 'TMDO_FILE', dirname( __DIR__ ) . '/2meet-data-optimizer.php' );
define( 'TMDO_VERSION', '0.1.0' );
define( 'TMDO_DB_VERSION', '2.1.0' );
define( 'TMDO_IS_SQLITE', false );
define( 'TMDO_IS_MYSQL', true );
// Back-compat: tests and AddOns may still reference WPDO_ constants.
define( 'WPDO_PLUGIN_DIR', TMDO_PATH );
define( 'WPDO_PLUGIN_URL', TMDO_URL );
define( 'WPDO_PLUGIN_FILE', TMDO_FILE );
define( 'WPDO_VERSION', TMDO_VERSION );
define( 'WPDO_DB_VERSION', TMDO_DB_VERSION );
define( 'WPDO_IS_SQLITE', TMDO_IS_SQLITE );
define( 'WPDO_IS_MYSQL', TMDO_IS_MYSQL );
define( 'DAY_IN_SECONDS', 86400 );
define( 'HOUR_IN_SECONDS', 3600 );
define( 'MINUTE_IN_SECONDS', 60 );
if ( ! defined( 'TMDO_TABLE_PREFIX' ) ) {
define( 'TMDO_TABLE_PREFIX', 'wpdo_' );
}
if ( ! defined( 'TMDO_CACHE_GROUP' ) ) {
define( 'TMDO_CACHE_GROUP', 'wpdo' );
}
if ( ! defined( 'TMDO_MIN_PHP' ) ) {
define( 'TMDO_MIN_PHP', '8.1' );
}
if ( ! defined( 'TMDO_MIN_WP' ) ) {
define( 'TMDO_MIN_WP', '6.0' );
}
if ( ! defined( 'WPDO_TABLE_PREFIX' ) ) {
define( 'WPDO_TABLE_PREFIX', TMDO_TABLE_PREFIX );
}
if ( ! defined( 'WPDO_CACHE_GROUP' ) ) {
define( 'WPDO_CACHE_GROUP', TMDO_CACHE_GROUP );
}
// Raw-PHP harness has no snapshot storage — disable the FSM transition guard so
// tests can force module states directly (mirrors wp-data-optimizer harness).
if ( ! defined( 'TMDO_FSM_GUARD_DISABLED' ) ) {
define( 'TMDO_FSM_GUARD_DISABLED', true );
}
if ( ! defined( 'WPDO_FSM_GUARD_DISABLED' ) ) {
define( 'WPDO_FSM_GUARD_DISABLED', TMDO_FSM_GUARD_DISABLED );
}
// ── Stub $wpdb ─────────────────────────────────────────────────────────────
global $wpdb;
$wpdb = new class {
public string $prefix = 'wp_';
public string $postmeta = 'wp_postmeta';
public string $posts = 'wp_posts';
public string $options = 'wp_options';
public string $usermeta = 'wp_usermeta';
public string $comments = 'wp_comments';
public int $insert_id = 0;
public string $last_error = '';
public function prepare( string $sql, ...$args ): string {
$i = 0;
return preg_replace_callback( '/%[sdf]/', function () use ( &$i, $args ) {
return $args[ $i++ ] ?? '?';
}, $sql );
}
public function get_var( string $sql ): ?string { return null; }
public function get_row( string $sql, $output = OBJECT ) { return null; }
public function get_results( string $sql, $output = OBJECT ): array { return []; }
public function get_col( string $sql, int $col = 0 ): array { return []; }
public function insert( string $table, array $data, $format = null ): int|false { return 1; }
public function update( string $table, array $data, array $where, $format = null, $wf = null ): int|false { return 1; }
public function delete( string $table, array $where, $format = null ): int|false { return 1; }
public function replace( string $table, array $data, $format = null ): int|false { return 1; }
public function query( string $sql ): int|bool { return 1; }
public function get_charset_collate(): string { return 'DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci'; }
public function esc_like( string $s ): string { return addcslashes( $s, '_%\\' ); }
};
if ( ! defined( 'OBJECT' ) ) { define( 'OBJECT', 'OBJECT' ); }
if ( ! defined( 'ARRAY_A' ) ) { define( 'ARRAY_A', 'ARRAY_A' ); }
// ── WordPress function stubs ───────────────────────────────────────────────
if ( ! function_exists( 'trailingslashit' ) ) {
function trailingslashit( string $s ): string { return rtrim( $s, '/' ) . '/'; }
}
if ( ! function_exists( 'sanitize_key' ) ) {
function sanitize_key( string $key ): string {
return preg_replace( '/[^a-z0-9_\-]/', '', strtolower( $key ) );
}
}
if ( ! function_exists( 'absint' ) ) {
function absint( $v ): int { return abs( (int) $v ); }
}
if ( ! function_exists( 'wp_unslash' ) ) {
function wp_unslash( $v ) { return is_string( $v ) ? stripslashes( $v ) : $v; }
}
if ( ! function_exists( 'esc_like' ) ) {
function esc_like( string $s ): string { return addcslashes( $s, '_%\\' ); }
}
if ( ! function_exists( 'current_time' ) ) {
function current_time( string $type, bool $gmt = false ): string|int {
if ( 'timestamp' === $type || 'U' === $type ) { return time(); }
return gmdate( 'Y-m-d H:i:s' );
}
}
if ( ! function_exists( 'wp_parse_args' ) ) {
function wp_parse_args( $args, array $defaults = [] ): array {
if ( is_string( $args ) ) { parse_str( $args, $parsed ); return array_merge( $defaults, $parsed ); }
return array_merge( $defaults, (array) $args );
}
}
// Minimal filter registry — supports add_filter / remove_filter / apply_filters.
$GLOBALS['_wp_filter_callbacks'] = [];
if ( ! function_exists( 'add_action' ) ) {
function add_action( string $hook, $cb, int $p = 10, int $a = 1 ): bool {
$GLOBALS['_wp_filter_callbacks'][ $hook ][] = $cb;
return true;
}
}
if ( ! function_exists( 'add_filter' ) ) {
function add_filter( string $hook, $cb, int $p = 10, int $a = 1 ): bool {
$GLOBALS['_wp_filter_callbacks'][ $hook ][] = $cb;
return true;
}
}
if ( ! function_exists( 'remove_filter' ) ) {
function remove_filter( string $hook, $cb, int $p = 10 ): bool {
if ( isset( $GLOBALS['_wp_filter_callbacks'][ $hook ] ) ) {
$GLOBALS['_wp_filter_callbacks'][ $hook ] = array_values(
array_filter( $GLOBALS['_wp_filter_callbacks'][ $hook ], fn( $c ) => $c !== $cb )
);
}
return true;
}
}
if ( ! function_exists( 'remove_action' ) ) {
function remove_action( string $hook, $cb, int $p = 10 ): bool {
return remove_filter( $hook, $cb, $p );
}
}
if ( ! function_exists( 'apply_filters' ) ) {
function apply_filters( string $hook, $value, ...$args ) {
foreach ( $GLOBALS['_wp_filter_callbacks'][ $hook ] ?? [] as $cb ) {
$value = $cb( $value, ...$args );
}
return $value;
}
}
if ( ! function_exists( 'do_action' ) ) {
function do_action( string $hook, ...$args ): void {
foreach ( $GLOBALS['_wp_filter_callbacks'][ $hook ] ?? [] as $cb ) {
$cb( ...$args );
}
}
}
if ( ! function_exists( 'do_action_ref_array' ) ) {
function do_action_ref_array( string $hook, array $args ): void {
do_action( $hook, ...$args );
}
}
if ( ! function_exists( 'wp_next_scheduled' ) ) {
function wp_next_scheduled( string $hook ): int|false { return false; }
}
if ( ! function_exists( 'wp_schedule_event' ) ) {
function wp_schedule_event( int $t, string $r, string $h ): bool { return true; }
}
if ( ! function_exists( 'wp_schedule_single_event' ) ) {
function wp_schedule_single_event( int $ts, string $hook ): bool { return true; }
}
if ( ! function_exists( 'wp_clear_scheduled_hook' ) ) {
function wp_clear_scheduled_hook( string $hook ): int|false { return 0; }
}
if ( ! function_exists( 'is_admin' ) ) {
function is_admin(): bool { return false; }
}
if ( ! function_exists( 'is_singular' ) ) {
function is_singular( $t = '' ): bool { return false; }
}
if ( ! function_exists( 'get_the_ID' ) ) {
function get_the_ID(): int|false { return false; }
}
if ( ! function_exists( 'wp_doing_ajax' ) ) {
function wp_doing_ajax(): bool { return false; }
}
if ( ! function_exists( 'sanitize_text_field' ) ) {
function sanitize_text_field( string $s ): string { return trim( strip_tags( $s ) ); }
}
if ( ! function_exists( '__' ) ) {
function __( string $text, string $domain = 'default' ): string { return $text; }
}
if ( ! function_exists( 'esc_html' ) ) {
function esc_html( string $text ): string { return htmlspecialchars( $text, ENT_QUOTES, 'UTF-8' ); }
}
if ( ! function_exists( 'esc_html__' ) ) {
function esc_html__( string $text, string $domain = 'default' ): string { return htmlspecialchars( $text, ENT_QUOTES, 'UTF-8' ); }
}
if ( ! function_exists( 'esc_html_e' ) ) {
function esc_html_e( string $text, string $domain = 'default' ): void { echo htmlspecialchars( $text, ENT_QUOTES, 'UTF-8' ); }
}
if ( ! function_exists( 'esc_attr' ) ) {
function esc_attr( string $text ): string { return htmlspecialchars( $text, ENT_QUOTES, 'UTF-8' ); }
}
if ( ! function_exists( 'esc_url' ) ) {
function esc_url( string $url ): string { return filter_var( $url, FILTER_SANITIZE_URL ) ?: ''; }
}
if ( ! function_exists( 'esc_sql' ) ) {
function esc_sql( $s ): string {
$s = is_string( $s ) ? $s : (string) $s;
return addslashes( $s );
}
}
if ( ! function_exists( '_doing_it_wrong' ) ) {
function _doing_it_wrong( string $fn, string $msg, string $ver ): void {}
}
if ( ! function_exists( 'get_option' ) ) {
function get_option( string $key, $default = false ) { return $GLOBALS['_wp_options'][ $key ] ?? $default; }
}
if ( ! function_exists( 'update_option' ) ) {
function update_option( string $key, $value ): bool { $GLOBALS['_wp_options'][ $key ] = $value; return true; }
}
if ( ! function_exists( 'delete_option' ) ) {
function delete_option( string $key ): bool { unset( $GLOBALS['_wp_options'][ $key ] ); return true; }
}
if ( ! function_exists( 'get_post_meta' ) ) {
function get_post_meta( int $post_id, string $key = '', bool $single = false ) {
return $GLOBALS['_wp_postmeta'][ $post_id ][ $key ] ?? ( $single ? '' : [] );
}
}
if ( ! function_exists( 'update_post_meta' ) ) {
function update_post_meta( int $post_id, string $key, $value, $prev = '' ): int|bool {
$GLOBALS['_wp_postmeta'][ $post_id ][ $key ] = $value;
return true;
}
}
if ( ! function_exists( 'get_user_meta' ) ) {
function get_user_meta( int $uid, string $key = '', bool $single = false ) {
return $GLOBALS['_wp_usermeta'][ $uid ][ $key ] ?? ( $single ? '' : [] );
}
}
if ( ! function_exists( 'update_user_meta' ) ) {
function update_user_meta( int $uid, string $key, $value, $prev = '' ): int|bool {
$GLOBALS['_wp_usermeta'][ $uid ][ $key ] = $value;
return true;
}
}
if ( ! function_exists( 'get_term_meta' ) ) {
function get_term_meta( int $tid, string $key = '', bool $single = false ) {
return $GLOBALS['_wp_termmeta'][ $tid ][ $key ] ?? ( $single ? '' : [] );
}
}
if ( ! function_exists( 'update_term_meta' ) ) {
function update_term_meta( int $tid, string $key, $value, $prev = '' ): int|bool {
$GLOBALS['_wp_termmeta'][ $tid ][ $key ] = $value;
return true;
}
}
if ( ! function_exists( 'get_comment_meta' ) ) {
function get_comment_meta( int $cid, string $key = '', bool $single = false ) {
return $GLOBALS['_wp_commentmeta'][ $cid ][ $key ] ?? ( $single ? '' : [] );
}
}
if ( ! function_exists( 'update_comment_meta' ) ) {
function update_comment_meta( int $cid, string $key, $value, $prev = '' ): int|bool {
$GLOBALS['_wp_commentmeta'][ $cid ][ $key ] = $value;
return true;
}
}
if ( ! function_exists( 'get_post_type' ) ) {
function get_post_type( $post_id ) {
return $GLOBALS['_wp_post_types'][ (int) $post_id ] ?? false;
}
}
if ( ! function_exists( 'get_post_status' ) ) {
function get_post_status( $post_id ) {
return $GLOBALS['_wp_post_status'][ (int) $post_id ] ?? 'publish';
}
}
if ( ! function_exists( 'is_post_publicly_viewable' ) ) {
function is_post_publicly_viewable( $post_id ): bool {
if ( isset( $GLOBALS['_wp_post_publicly_viewable'][ (int) $post_id ] ) ) {
return (bool) $GLOBALS['_wp_post_publicly_viewable'][ (int) $post_id ];
}
return 'publish' === ( $GLOBALS['_wp_post_status'][ (int) $post_id ] ?? 'publish' );
}
}
if ( ! function_exists( 'wp_die' ) ) {
function wp_die( $message = '' ): void { throw new RuntimeException( is_string( $message ) ? $message : 'wp_die' ); }
}
if ( ! function_exists( 'wp_verify_nonce' ) ) {
function wp_verify_nonce( $nonce, string $action = '' ) {
return $GLOBALS['_wp_valid_nonces'][ (string) $nonce ] ?? false;
}
}
if ( ! function_exists( 'wp_create_nonce' ) ) {
function wp_create_nonce( string $action = '' ): string {
$nonce = 'test_nonce_' . md5( $action );
$GLOBALS['_wp_valid_nonces'][ $nonce ] = 1;
return $nonce;
}
}
if ( ! function_exists( 'current_user_can' ) ) {
function current_user_can( string $cap, ...$args ): bool {
if ( ! empty( $args ) ) {
$key = $cap . ':' . implode( ',', array_map( 'strval', $args ) );
if ( isset( $GLOBALS['_wp_current_user_can'][ $key ] ) ) {
return (bool) $GLOBALS['_wp_current_user_can'][ $key ];
}
}
return $GLOBALS['_wp_current_user_can'][ $cap ] ?? false;
}
}
if ( ! function_exists( 'get_current_user_id' ) ) {
function get_current_user_id(): int { return (int) ( $GLOBALS['_wp_current_user_id'] ?? 0 ); }
}
if ( ! function_exists( 'is_multisite' ) ) {
function is_multisite(): bool { return (bool) ( $GLOBALS['_wp_is_multisite'] ?? false ); }
}
if ( ! function_exists( 'is_super_admin' ) ) {
function is_super_admin( ?int $uid = null ): bool { return (bool) ( $GLOBALS['_wp_is_super_admin'] ?? false ); }
}
if ( ! function_exists( 'switch_to_blog' ) ) {
function switch_to_blog( int $blog_id ): bool { $GLOBALS['_wp_current_blog_id'] = $blog_id; return true; }
}
if ( ! function_exists( 'restore_current_blog' ) ) {
function restore_current_blog(): bool { unset( $GLOBALS['_wp_current_blog_id'] ); return true; }
}
if ( ! function_exists( 'get_sites' ) ) {
function get_sites( array $args = [] ): array { return $GLOBALS['_wp_sites'] ?? []; }
}
if ( ! function_exists( 'is_plugin_active_for_network' ) ) {
function is_plugin_active_for_network( string $plugin ): bool {
return (bool) ( $GLOBALS['_wp_plugin_active_for_network'][ $plugin ] ?? false );
}
}
if ( ! function_exists( 'plugin_basename' ) ) {
function plugin_basename( string $file ): string {
return basename( dirname( $file ) ) . '/' . basename( $file );
}
}
if ( ! function_exists( 'wp_generate_password' ) ) {
function wp_generate_password( int $len = 12, bool $special = true ): string {
return substr( str_replace( [ '/', '+', '=' ], '', base64_encode( random_bytes( $len ) ) ), 0, $len );
}
}
if ( ! function_exists( 'wp_json_encode' ) ) {
function wp_json_encode( $data, int $flags = 0 ): string|false { return json_encode( $data, $flags ); }
}
if ( ! function_exists( 'is_serialized' ) ) {
function is_serialized( $data ): bool {
return is_string( $data ) && strlen( $data ) >= 4
&& in_array( $data[0], [ 'a', 's', 'i', 'd', 'b', 'O', 'N' ], true )
&& str_ends_with( $data, ';' );
}
}
if ( ! function_exists( 'maybe_serialize' ) ) {
function maybe_serialize( $data ) { return is_array( $data ) || is_object( $data ) ? serialize( $data ) : $data; }
}
if ( ! function_exists( 'maybe_unserialize' ) ) {
function maybe_unserialize( $value ) {
if ( ! is_string( $value ) ) { return $value; }
$u = @unserialize( $value );
return ( false !== $u || 'b:0;' === $value ) ? $u : $value;
}
}
if ( ! function_exists( 'get_transient' ) ) {
function get_transient( string $key ) { return $GLOBALS['_wp_options'][ '_transient_' . $key ] ?? false; }
}
if ( ! function_exists( 'set_transient' ) ) {
function set_transient( string $key, $value, int $expiry = 0 ): bool {
$GLOBALS['_wp_options'][ '_transient_' . $key ] = $value;
return true;
}
}
if ( ! function_exists( 'delete_transient' ) ) {
function delete_transient( string $key ): bool { unset( $GLOBALS['_wp_options'][ '_transient_' . $key ] ); return true; }
}
if ( ! function_exists( 'wp_rand' ) ) {
function wp_rand( int $min = 0, int $max = 0 ): int { return random_int( $min, $max ?: PHP_INT_MAX ); }
}
if ( ! function_exists( 'is_wp_error' ) ) {
function is_wp_error( $thing ): bool { return $thing instanceof WP_Error; }
}
// Object cache simulation.
$GLOBALS['_wp_cache'] = [];
if ( ! function_exists( 'wp_cache_get' ) ) {
function wp_cache_get( $key, $group = '' ) { return $GLOBALS['_wp_cache'][ $group ][ $key ] ?? false; }
}
if ( ! function_exists( 'wp_cache_set' ) ) {
function wp_cache_set( $key, $value, $group = '', $ttl = 0 ): bool {
$GLOBALS['_wp_cache'][ $group ][ $key ] = $value;
return true;
}
}
if ( ! function_exists( 'wp_cache_delete' ) ) {
function wp_cache_delete( $key, $group = '' ): bool { unset( $GLOBALS['_wp_cache'][ $group ][ $key ] ); return true; }
}
// ── Stub classes ───────────────────────────────────────────────────────────
if ( ! class_exists( 'WP_Query' ) ) {
class WP_Query {
public array $posts = [];
public int $found_posts = 0;
public int $max_num_pages = 0;
private array $args = [];
public function __construct( array $args = [] ) { $this->args = $args; }
public function get( string $key, $default = '' ) { return $this->args[ $key ] ?? $default; }
public function set( string $key, $value ): void { $this->args[ $key ] = $value; }
}
}
if ( ! class_exists( 'WP_Error' ) ) {
class WP_Error {
private string $code;
private string $message;
private array $data;
public function __construct( string $code = '', string $message = '', $data = [] ) {
$this->code = $code;
$this->message = $message;
$this->data = is_array( $data ) ? $data : [];
}
public function get_error_code(): string { return $this->code; }
public function get_error_message(): string { return $this->message; }
public function get_error_data() { return $this->data; }
}
}
if ( ! class_exists( 'WP_REST_Request' ) ) {
class WP_REST_Request {
private array $params = [];
private array $headers = [];
public function __construct( string $method = 'GET', string $route = '' ) {}
public function get_param( string $key ) { return $this->params[ $key ] ?? null; }
public function set_param( string $key, $value ): void { $this->params[ $key ] = $value; }
public function get_header( string $key ): ?string { return $this->headers[ strtolower( $key ) ] ?? null; }
public function set_header( string $key, string $value ): void { $this->headers[ strtolower( $key ) ] = $value; }
}
}
if ( ! class_exists( 'WP_REST_Response' ) ) {
class WP_REST_Response {
private $data;
private int $status;
private array $headers = [];
public function __construct( $data = null, int $status = 200 ) { $this->data = $data; $this->status = $status; }
public function get_data() { return $this->data; }
public function get_status(): int { return $this->status; }
public function header( string $k, string $v ): void { $this->headers[ $k ] = $v; }
public function get_headers(): array { return $this->headers; }
}
}
if ( ! class_exists( 'WP_REST_Server' ) ) {
class WP_REST_Server {
const READABLE = 'GET';
const CREATABLE = 'POST';
const EDITABLE = 'POST, PUT, PATCH';
const DELETABLE = 'DELETE';
}
}
if ( ! function_exists( 'register_rest_route' ) ) {
function register_rest_route( string $ns, string $route, array $args ): bool { return true; }
}
// WP_CLI stub (needed before loading CLI classes).
if ( ! class_exists( 'WP_CLI' ) ) {
class WP_CLI {
public static function log( string $msg ): void {}
public static function warning( string $msg ): void {}
public static function success( string $msg ): void {}
public static function error( string $msg ): void {}
public static function add_command( string $name, $class ): void {}
}
}
// ── Load plugin classes (TMDO_ prefix, dependency order) ──────────────────
require_once TMDO_PATH . 'includes/class-tmdo-capability.php';
require_once TMDO_PATH . 'includes/class-tmdo-crypto.php';
require_once TMDO_PATH . 'includes/class-tmdo-safe-unserialize.php';
require_once TMDO_PATH . 'includes/class-tmdo-db.php';
require_once TMDO_PATH . 'includes/class-tmdo-logger.php';
require_once TMDO_PATH . 'includes/class-tmdo-feature-flags.php';
require_once TMDO_PATH . 'includes/class-tmdo-sqlite-compat.php';
require_once TMDO_PATH . 'includes/class-tmdo-installer.php';
require_once TMDO_PATH . 'includes/class-tmdo-schema-registry.php';
require_once TMDO_PATH . 'includes/class-tmdo-custom-table-registry.php';
require_once TMDO_PATH . 'includes/trait-tmdo-anti-eav-aware.php';
require_once TMDO_PATH . 'includes/class-tmdo-hook-bus-bridge.php';
require_once TMDO_PATH . 'includes/class-tmdo-conflict-monitor.php';
require_once TMDO_PATH . 'includes/class-tmdo-compatibility.php';
// Interceptors.
require_once TMDO_PATH . 'includes/interceptors/class-tmdo-interceptor-base.php';
require_once TMDO_PATH . 'includes/interceptors/class-tmdo-sync-bridge.php';
// Zones.
require_once TMDO_PATH . 'includes/zones/class-tmdo-zone-router.php';
require_once TMDO_PATH . 'includes/class-tmdo-routing-predicate.php';
require_once TMDO_PATH . 'includes/zones/class-tmdo-zone-hot.php';
require_once TMDO_PATH . 'includes/zones/class-tmdo-zone-warm.php';
require_once TMDO_PATH . 'includes/zones/class-tmdo-zone-cold.php';
require_once TMDO_PATH . 'includes/zones/class-tmdo-zone-archive.php';
// Query.
require_once TMDO_PATH . 'includes/query/class-tmdo-query-interceptor-base.php';
require_once TMDO_PATH . 'includes/query/class-tmdo-query-router.php';
require_once TMDO_PATH . 'includes/query/class-tmdo-post-query-router.php';
// Migration.
require_once TMDO_PATH . 'includes/migration/class-tmdo-migration-base.php';
require_once TMDO_PATH . 'includes/migration/class-tmdo-migration-engine.php';
require_once TMDO_PATH . 'includes/migration/class-tmdo-hot-migration.php';
require_once TMDO_PATH . 'includes/migration/class-tmdo-warm-migration.php';
require_once TMDO_PATH . 'includes/migration/class-tmdo-cold-migration.php';
require_once TMDO_PATH . 'includes/migration/class-tmdo-archive-migration.php';
// Integrations.
require_once TMDO_PATH . 'includes/integrations/class-tmdo-term-comment-garbage-filter.php';
require_once TMDO_PATH . 'includes/integrations/class-tmdo-term-comment-misc-bucket.php';
require_once TMDO_PATH . 'includes/integrations/class-tmdo-member-fields.php';
require_once TMDO_PATH . 'includes/integrations/class-tmdo-post-fields.php';
require_once TMDO_PATH . 'includes/integrations/class-tmdo-points-manager.php';
require_once TMDO_PATH . 'includes/integrations/class-tmdo-demo-entity-counter.php';
// Cache + Classifier.
require_once TMDO_PATH . 'includes/class-tmdo-cache-layer.php';
require_once TMDO_PATH . 'includes/class-tmdo-zone-classifier.php';
// Public API.
require_once TMDO_PATH . 'includes/class-tmdo-api.php';
// v2 Upgrader.
require_once TMDO_PATH . 'includes/class-tmdo-v2-upgrader.php';
// Snapshot system.
require_once TMDO_PATH . 'includes/snapshots/class-tmdo-snapshot-manager.php';
require_once TMDO_PATH . 'includes/snapshots/class-tmdo-snapshot-writer.php';
require_once TMDO_PATH . 'includes/snapshots/class-tmdo-snapshot-reader.php';
require_once TMDO_PATH . 'includes/snapshots/class-tmdo-snapshot-pruner.php';
// FSM safety guard.
require_once TMDO_PATH . 'includes/safety/class-tmdo-fsm-guard.php';
// Diagnostic — do NOT load site-health here; its DB checks would fail with
// the stub $wpdb and trigger false schema_drift criticals in HealthCronTest.
// TMDO_Site_Health loads lazily if needed by integration tests.
require_once TMDO_PATH . 'includes/diagnostic/class-tmdo-health-cron.php';
require_once TMDO_PATH . 'includes/diagnostic/class-tmdo-monthly-summary.php';
require_once TMDO_PATH . 'includes/diagnostic/class-tmdo-site-metrics-collector.php';
// Notifiers.
require_once TMDO_PATH . 'includes/notifications/abstract-class-tmdo-notifier.php';
require_once TMDO_PATH . 'includes/notifications/class-tmdo-email-notifier.php';
require_once TMDO_PATH . 'includes/notifications/class-tmdo-slack-notifier.php';
require_once TMDO_PATH . 'includes/notifications/class-tmdo-discord-notifier.php';
require_once TMDO_PATH . 'includes/notifications/class-tmdo-telegram-notifier.php';
// FSM advisor.
require_once TMDO_PATH . 'includes/advisor/class-tmdo-fsm-advisor.php';
require_once TMDO_PATH . 'includes/advisor/class-tmdo-module-rules.php';
require_once TMDO_PATH . 'includes/advisor/class-tmdo-module-detector.php';
require_once TMDO_PATH . 'includes/advisor/class-tmdo-fsm-automator.php';
// Export.
require_once TMDO_PATH . 'includes/export/class-tmdo-csv-writer.php';
// REST API.
require_once TMDO_PATH . 'includes/class-tmdo-rest-api.php';
// Engine (v2.0.0).
require_once TMDO_PATH . 'includes/engine/class-tmdo-type-caster.php';
require_once TMDO_PATH . 'includes/engine/class-tmdo-mode-manager.php';
require_once TMDO_PATH . 'includes/engine/class-tmdo-audit-logger.php';
require_once TMDO_PATH . 'includes/engine/class-tmdo-shadow-diff-logger.php';
require_once TMDO_PATH . 'includes/engine/class-tmdo-conflict-detector.php';
require_once TMDO_PATH . 'includes/engine/class-tmdo-cache-orchestrator.php';
require_once TMDO_PATH . 'includes/engine/class-tmdo-query-compiler.php';
require_once TMDO_PATH . 'includes/engine/class-tmdo-schema-manager.php';
require_once TMDO_PATH . 'includes/engine/class-tmdo-entity-registry.php';
require_once TMDO_PATH . 'includes/engine/class-tmdo-entity-migration-engine.php';
require_once TMDO_PATH . 'includes/engine/class-tmdo-entity-health.php';
require_once TMDO_PATH . 'includes/adapters/interface-entity-adapter.php';
require_once TMDO_PATH . 'includes/adapters/class-tmdo-adapter-post.php';
require_once TMDO_PATH . 'includes/adapters/class-tmdo-adapter-user.php';
require_once TMDO_PATH . 'includes/adapters/class-tmdo-adapter-term.php';
require_once TMDO_PATH . 'includes/adapters/class-tmdo-adapter-comment.php';
// Migration Orchestrator (needs Entity_Registry).
require_once TMDO_PATH . 'includes/migration/interface-migration-phase.php';
require_once TMDO_PATH . 'includes/migration/class-tmdo-migration-phase-base.php';
require_once TMDO_PATH . 'includes/migration/phases/class-tmdo-phase-diagnose.php';
require_once TMDO_PATH . 'includes/migration/phases/class-tmdo-phase-backup.php';
require_once TMDO_PATH . 'includes/migration/phases/class-tmdo-phase-demote.php';
require_once TMDO_PATH . 'includes/migration/phases/class-tmdo-phase-install-schema.php';
require_once TMDO_PATH . 'includes/migration/phases/class-tmdo-phase-backfill-bulk.php';
require_once TMDO_PATH . 'includes/migration/phases/class-tmdo-phase-backfill-unserialize.php';
require_once TMDO_PATH . 'includes/migration/phases/class-tmdo-phase-promote-shadow.php';
require_once TMDO_PATH . 'includes/migration/phases/class-tmdo-phase-verify-sample.php';
require_once TMDO_PATH . 'includes/migration/phases/class-tmdo-phase-promote-aeav.php';
require_once TMDO_PATH . 'includes/migration/phases/class-tmdo-phase-cleanup.php';
require_once TMDO_PATH . 'includes/migration/phases/class-tmdo-phase-completed.php';
require_once TMDO_PATH . 'includes/migration/class-tmdo-migration-orchestrator.php';
require_once TMDO_PATH . 'includes/migration/class-tmdo-post-migration.php';
// Options Manager.
require_once TMDO_PATH . 'modules/options/class-tmdo-options-manager.php';
// Stress testers + shadow verifiers.
require_once TMDO_PATH . 'includes/class-tmdo-postmeta-cleaner.php';
require_once TMDO_PATH . 'includes/class-tmdo-termmeta-cleaner.php';
require_once TMDO_PATH . 'includes/class-tmdo-commentmeta-cleaner.php';
require_once TMDO_PATH . 'includes/class-tmdo-term-comment-shadow-verifier.php';
require_once TMDO_PATH . 'includes/class-tmdo-term-comment-backfill.php';
require_once TMDO_PATH . 'includes/class-tmdo-term-stress-tester.php';
require_once TMDO_PATH . 'includes/class-tmdo-comment-stress-tester.php';
require_once TMDO_PATH . 'includes/class-tmdo-user-stress-tester.php';
require_once TMDO_PATH . 'includes/class-tmdo-post-stress-tester.php';
require_once TMDO_PATH . 'includes/class-tmdo-post-shadow-verifier.php';
// Core.
require_once TMDO_PATH . 'includes/class-tmdo-core.php';
// CLI.
require_once TMDO_PATH . 'cli/class-tmdo-cli.php';
require_once TMDO_PATH . 'cli/class-tmdo-cli-v2.php';
require_once TMDO_PATH . 'cli/class-tmdo-cli-member.php';
require_once TMDO_PATH . 'cli/class-tmdo-cli-post.php';
require_once TMDO_PATH . 'cli/class-tmdo-cli-term-comment.php';
// Back-compat aliases (WPDO_* → TMDO_*) — must be last.
require_once TMDO_PATH . 'includes/class-tmdo-back-compat.php';
// Global FSM Guard bypass for all unit tests except FSMGuardTest itself.
// FSMGuardTest::setUp() clears _wp_filter_callbacks to restore guard behavior.
if ( ! function_exists( '__return_true' ) ) {
function __return_true(): bool { return true; }
}
add_filter( 'wpdo/fsm_guard/bypass', '__return_true' );
// ── AddOn stubs (classes moved to optional AddOns) ─────────────────────────
// TMDO_Listing_Stats → 2meet-data-optimizer-hivepress-addon.
// Tests that hit REST endpoints using listing stats receive stub responses.
if ( ! class_exists( 'TMDO_Listing_Stats' ) ) {
class TMDO_Listing_Stats {
public static function register(): void {}
public static function get_view_count( int $post_id ): int { return 0; }
public static function increment_view( int $post_id, string $ip = '' ): int { return 0; }
public static function is_rate_limited( int $post_id, string $ip ): bool { return false; }
}
class_alias( 'TMDO_Listing_Stats', 'WPDO_Listing_Stats' );
}