hardening 2.0: 2meet-data-optimizer (staged rollout, dev22 first) #3
@@ -31,31 +31,10 @@ class TMDO_Core {
|
||||
// Fire the schema registry hook so integrations can register their fields.
|
||||
$registry = TMDO_Schema_Registry::instance();
|
||||
|
||||
// v2.0.x: Pre-register the 7 partner plugin integrations BEFORE firing the
|
||||
// `wpdo_register_fields` and `wpdo_register_custom_tables` hooks. Each
|
||||
// `register()` is a thin `add_action()` wrapper guarded by a partner-plugin
|
||||
// `class_exists()` probe (TMDO_Infocards / Bookings / Quotation / Events /
|
||||
// Mobile_Bridge / Collab / Playlist). Without this, partner add_actions
|
||||
// arrive too late and the do_action below misses them — observed via
|
||||
// 2meet-infocards 9 hp_vendor meta keys never landing in Schema Registry.
|
||||
// register() is side-effect-free aside from add_action(), so pre-registering
|
||||
// is provably safe (no hidden dependency on later-state global init).
|
||||
// v2.1.3 R1 (B step): TMDO_Events removed — 2meet-events now self-registers
|
||||
// via its own bridge class. Other partners still pre-registered here pending
|
||||
// their own decentralized migrations (R1 continuation in v2.2.x).
|
||||
$partner_integrations = array(
|
||||
'TMDO_Infocards',
|
||||
'TMDO_Bookings',
|
||||
'TMDO_Quotation',
|
||||
'TMDO_Mobile_Bridge',
|
||||
'TMDO_Collab',
|
||||
'TMDO_Playlist',
|
||||
'TMDO_WooCommerce',
|
||||
'TMDO_Member_Fields',
|
||||
'TMDO_Post_Fields',
|
||||
'TMDO_Hivepress_Term_Comment_Fields',
|
||||
);
|
||||
foreach ( $partner_integrations as $cls ) {
|
||||
// Core-owned field providers register before `wpdo_register_fields` fires.
|
||||
// AddOns wire their own integrations from their bootstraps
|
||||
// (plugins_loaded:3 or :6), so core does not probe for them here.
|
||||
foreach ( array( 'TMDO_Member_Fields', 'TMDO_Post_Fields' ) as $cls ) {
|
||||
if ( class_exists( $cls ) ) {
|
||||
call_user_func( array( $cls, 'register' ) );
|
||||
}
|
||||
@@ -74,7 +53,6 @@ class TMDO_Core {
|
||||
// AFTER plugins_loaded:4 (e.g., partners loaded by HP modules at plugins_loaded:5+,
|
||||
// or lazy-loaded modules booted on init:0). Schema_Registry::register() has
|
||||
// internal dedup, so re-firing is idempotent — same partner calls won't double-register.
|
||||
// This deprecates the need for the TMDO_Core hardcoded partner pre-registration list above.
|
||||
//
|
||||
// v2.1.6: also re-fire `wpdo_register_entity_fields` so partner plugins booting on
|
||||
// plugins_loaded:20 (e.g. 2meet-spoke-sso) can register entity-based user/term/comment
|
||||
@@ -116,12 +94,6 @@ class TMDO_Core {
|
||||
$this->register_hpct_interceptors();
|
||||
}
|
||||
|
||||
// v2.1.2 fix: WC commission interceptor is independent of HPCT — writes
|
||||
// to its own wp_wpdo_wc_commissions table. Register whenever WC is active.
|
||||
if ( class_exists( 'TMDO_WooCommerce' ) && TMDO_WooCommerce::is_active() && class_exists( 'TMDO_WC_Orders_Interceptor' ) ) {
|
||||
( new TMDO_WC_Orders_Interceptor() )->register_hooks();
|
||||
}
|
||||
|
||||
// Zone interceptors are always safe to register.
|
||||
if ( TMDO_Compatibility::can_register_zone_hooks() ) {
|
||||
$this->register_zone_hooks();
|
||||
@@ -149,10 +121,6 @@ class TMDO_Core {
|
||||
TMDO_Conflict_Monitor::register_hooks();
|
||||
}
|
||||
|
||||
// v2.0.x: partner plugin integrations have been pre-registered earlier
|
||||
// (see top of run() before the wpdo_register_fields do_action). Removing
|
||||
// the duplicate late-binding block — see commit log for time-ordering bug.
|
||||
|
||||
// Schedule cron events.
|
||||
$this->schedule_cron();
|
||||
|
||||
@@ -182,14 +150,6 @@ class TMDO_Core {
|
||||
add_action( TMDO_Comment_Stress_Tester::CRON_HOOK, array( __CLASS__, 'run_comment_stress_test_batch' ) );
|
||||
}
|
||||
|
||||
// v2.11.5: HivePress per-post transient cache → wp_options reroute.
|
||||
// Filters registered on `init` so HivePress's own bootstrap (plugins_loaded:5)
|
||||
// runs first and our filter chain catches the actual cache writes happening
|
||||
// during save_post and term-cache rebuilds.
|
||||
if ( class_exists( 'TMDO_Hivepress_Transient_Filter' ) ) {
|
||||
add_action( 'init', array( 'TMDO_Hivepress_Transient_Filter', 'init' ), 5 );
|
||||
}
|
||||
|
||||
// v2.12.1: Term + Comment garbage write-time filter
|
||||
// (silent-drop _wxr_import_* / _2meet_demo_* / orphan post-meta keys).
|
||||
if ( class_exists( 'TMDO_Term_Comment_Garbage_Filter' ) ) {
|
||||
@@ -282,208 +242,6 @@ class TMDO_Core {
|
||||
do_action( 'wpdo_register_entity_fields', TMDO_Entity_Registry::class );
|
||||
}
|
||||
|
||||
/**
|
||||
* Register default HivePress field mappings.
|
||||
*
|
||||
* These are the known HivePress meta_keys and their zone classifications.
|
||||
*
|
||||
* @param TMDO_Schema_Registry $registry The schema registry instance.
|
||||
* @return void
|
||||
*/
|
||||
private function register_hivepress_defaults( TMDO_Schema_Registry $registry ): void {
|
||||
// Zone A (Hot) — Listing search/filter fields.
|
||||
$registry->register_many(
|
||||
'hivepress',
|
||||
array(
|
||||
array(
|
||||
'post_type' => 'hp_listing',
|
||||
'meta_key' => 'hp_price',
|
||||
'zone' => 'hot',
|
||||
'data_type' => 'decimal(10,2) NOT NULL DEFAULT 0',
|
||||
'column' => 'hp_price',
|
||||
'indexed' => true,
|
||||
),
|
||||
array(
|
||||
'post_type' => 'hp_listing',
|
||||
'meta_key' => 'hp_featured',
|
||||
'zone' => 'hot',
|
||||
'data_type' => 'tinyint(1) NOT NULL DEFAULT 0',
|
||||
'column' => 'hp_featured',
|
||||
'indexed' => true,
|
||||
),
|
||||
array(
|
||||
'post_type' => 'hp_listing',
|
||||
'meta_key' => 'hp_verified',
|
||||
'zone' => 'hot',
|
||||
'data_type' => 'tinyint(1) NOT NULL DEFAULT 0',
|
||||
'column' => 'hp_verified',
|
||||
'indexed' => true,
|
||||
),
|
||||
array(
|
||||
'post_type' => 'hp_listing',
|
||||
'meta_key' => 'hp_expired_time',
|
||||
'zone' => 'hot',
|
||||
'data_type' => 'bigint(20) NOT NULL DEFAULT 0',
|
||||
'column' => 'hp_expired_time',
|
||||
),
|
||||
array(
|
||||
'post_type' => 'hp_listing',
|
||||
'meta_key' => 'hp_featured_time',
|
||||
'zone' => 'hot',
|
||||
'data_type' => 'bigint(20) NOT NULL DEFAULT 0',
|
||||
'column' => 'hp_featured_time',
|
||||
),
|
||||
// Vendor hot fields.
|
||||
array(
|
||||
'post_type' => 'hp_vendor',
|
||||
'meta_key' => 'hp_verified',
|
||||
'zone' => 'hot',
|
||||
'data_type' => 'tinyint(1) NOT NULL DEFAULT 0',
|
||||
'column' => 'hp_verified',
|
||||
'indexed' => true,
|
||||
),
|
||||
array(
|
||||
'post_type' => 'hp_vendor',
|
||||
'meta_key' => 'hp_hourly_rate',
|
||||
'zone' => 'hot',
|
||||
'data_type' => 'decimal(10,2) NOT NULL DEFAULT 0',
|
||||
'column' => 'hp_hourly_rate',
|
||||
'indexed' => true,
|
||||
),
|
||||
array(
|
||||
'post_type' => 'hp_vendor',
|
||||
'meta_key' => 'hp_rating_count',
|
||||
'zone' => 'hot',
|
||||
'data_type' => 'int(11) NOT NULL DEFAULT 0',
|
||||
'column' => 'hp_rating_count',
|
||||
'indexed' => false,
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
// Zone C (Cold) — Profile/display fields.
|
||||
$registry->register_many(
|
||||
'hivepress',
|
||||
array(
|
||||
array(
|
||||
'post_type' => 'hp_vendor',
|
||||
'meta_key' => 'hp_description',
|
||||
'zone' => 'cold',
|
||||
'cache_group' => 'wpdo_cold_hp_vendor',
|
||||
'cache_ttl' => HOUR_IN_SECONDS,
|
||||
),
|
||||
array(
|
||||
'post_type' => 'hp_listing',
|
||||
'meta_key' => 'hp_description',
|
||||
'zone' => 'cold',
|
||||
'cache_group' => 'wpdo_cold_hp_listing',
|
||||
'cache_ttl' => HOUR_IN_SECONDS,
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
// ── HivePress extension fields (filled the 47% → 94% coverage gap) ──
|
||||
// Reviews extension (hp_review post type).
|
||||
$registry->register_many(
|
||||
'hivepress-reviews',
|
||||
array(
|
||||
array(
|
||||
'post_type' => 'hp_review',
|
||||
'meta_key' => 'hp_rating',
|
||||
'zone' => 'hot',
|
||||
'data_type' => 'tinyint(1) NOT NULL DEFAULT 0',
|
||||
'column' => 'hp_rating',
|
||||
'indexed' => true,
|
||||
),
|
||||
array(
|
||||
'post_type' => 'hp_vendor',
|
||||
'meta_key' => 'hp_rating',
|
||||
'zone' => 'hot',
|
||||
'data_type' => 'decimal(3,2) NOT NULL DEFAULT 0',
|
||||
'column' => 'hp_rating',
|
||||
'indexed' => true,
|
||||
),
|
||||
array(
|
||||
'post_type' => 'hp_review',
|
||||
'meta_key' => 'hp_text',
|
||||
'zone' => 'cold',
|
||||
'cache_group' => 'wpdo_cold_hp_review',
|
||||
'cache_ttl' => HOUR_IN_SECONDS,
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
// Bookings extension (hp_booking post type).
|
||||
$registry->register_many(
|
||||
'hivepress-bookings',
|
||||
array(
|
||||
array(
|
||||
'post_type' => 'hp_booking',
|
||||
'meta_key' => 'hp_start_time',
|
||||
'zone' => 'hot',
|
||||
'data_type' => 'bigint(20) NOT NULL DEFAULT 0',
|
||||
'column' => 'hp_start_time',
|
||||
'indexed' => true,
|
||||
),
|
||||
array(
|
||||
'post_type' => 'hp_booking',
|
||||
'meta_key' => 'hp_end_time',
|
||||
'zone' => 'hot',
|
||||
'data_type' => 'bigint(20) NOT NULL DEFAULT 0',
|
||||
'column' => 'hp_end_time',
|
||||
'indexed' => true,
|
||||
),
|
||||
array(
|
||||
'post_type' => 'hp_booking',
|
||||
'meta_key' => 'hp_status',
|
||||
'zone' => 'hot',
|
||||
'data_type' => "varchar(20) NOT NULL DEFAULT ''",
|
||||
'column' => 'hp_status',
|
||||
'indexed' => true,
|
||||
),
|
||||
array(
|
||||
'post_type' => 'hp_listing',
|
||||
'meta_key' => 'hp_booking_enabled',
|
||||
'zone' => 'hot',
|
||||
'data_type' => 'tinyint(1) NOT NULL DEFAULT 0',
|
||||
'column' => 'hp_booking_enabled',
|
||||
'indexed' => true,
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
// Marketplace / Requests extension.
|
||||
$registry->register_many(
|
||||
'hivepress-marketplace',
|
||||
array(
|
||||
array(
|
||||
'post_type' => 'hp_request',
|
||||
'meta_key' => 'hp_request_category',
|
||||
'zone' => 'hot',
|
||||
'data_type' => 'bigint(20) NOT NULL DEFAULT 0',
|
||||
'column' => 'hp_request_category',
|
||||
'indexed' => true,
|
||||
),
|
||||
array(
|
||||
'post_type' => 'hp_offer',
|
||||
'meta_key' => 'hp_amount',
|
||||
'zone' => 'hot',
|
||||
'data_type' => 'decimal(10,2) NOT NULL DEFAULT 0',
|
||||
'column' => 'hp_amount',
|
||||
'indexed' => true,
|
||||
),
|
||||
array(
|
||||
'post_type' => 'hp_offer',
|
||||
'meta_key' => 'hp_request',
|
||||
'zone' => 'hot',
|
||||
'data_type' => 'bigint(20) NOT NULL DEFAULT 0',
|
||||
'column' => 'hp_request',
|
||||
'indexed' => true,
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register HPCT-inherited module interceptors and query interceptors.
|
||||
*/
|
||||
|
||||
@@ -114,6 +114,40 @@ class CoreBoundaryTest extends TestCase {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* TMDO_Core::run() fires at plugins_loaded:4, but these AddOn classes load
|
||||
* at plugins_loaded:6 and wire themselves up in their own bootstrap. Probing
|
||||
* them from core boot can never hit, so core must not mention them at all.
|
||||
* (The infocards AddOn loads at :3 and also calls its own register().)
|
||||
*/
|
||||
public function test_core_boot_does_not_probe_addons_that_self_register(): void {
|
||||
$tokens = token_get_all( (string) file_get_contents( dirname( __DIR__, 2 ) . '/includes/class-tmdo-core.php' ) );
|
||||
$code = '';
|
||||
foreach ( $tokens as $token ) {
|
||||
if ( is_array( $token ) && in_array( $token[0], array( T_COMMENT, T_DOC_COMMENT ), true ) ) {
|
||||
continue;
|
||||
}
|
||||
$code .= is_array( $token ) ? $token[1] : $token;
|
||||
}
|
||||
|
||||
$late_addon_names = array(
|
||||
'TMDO_Infocards',
|
||||
'TMDO_Bookings',
|
||||
'TMDO_Quotation',
|
||||
'TMDO_Mobile_Bridge',
|
||||
'TMDO_Collab',
|
||||
'TMDO_Playlist',
|
||||
'TMDO_WooCommerce',
|
||||
'TMDO_WC_Orders_Interceptor',
|
||||
'TMDO_Hivepress_Term_Comment_Fields',
|
||||
'TMDO_Hivepress_Transient_Filter',
|
||||
'register_hivepress_defaults',
|
||||
);
|
||||
$found = array_values( array_filter( $late_addon_names, static fn( $name ) => str_contains( $code, $name ) ) );
|
||||
|
||||
$this->assertSame( array(), $found, 'Dead AddOn probes remain in TMDO_Core: ' . implode( ', ', $found ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove line comments and string literals so mentions inside them are ignored.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user