Files
2meet-data-optimizer-hivepr…/includes/hivepress/class-tmdo-hivepress-bootstrap.php
T
wpdev b4400a68e5 chore: initial snapshot of 2meet-data-optimizer-hivepress-addon 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
2026-07-31 05:06:36 +08:00

243 lines
7.6 KiB
PHP

<?php
/**
* HivePress family integration bootstrap.
*
* Single entry point for the WPDO ↔ HivePress integration:
*
* 1. Run conflict guard (hp-custom-tables / hp-info-cards detection)
* 2. Detect installed HivePress family addons
* 3. For each detected addon, instantiate the matching adapter and bind
* its lifecycle hooks (register_fields / register_custom_tables /
* register_entity_fields / query / event)
* 4. Honour the `wpdo_hivepress_should_bind` filter (conflict-aware)
*
* Booted by `TMDO_Core::run()` once during request boot. Idempotent —
* subsequent calls return early. Order:
*
* plugins_loaded:4 → TMDO_Core::run() → calls Bootstrap::boot()
* plugins_loaded:5+ → adapters' on_register_* hooks fire when WPDO actions dispatch
* init:1 → re-fired by WPDO core safety net
*
* @package WP_Data_Optimizer
* @since 3.0.0
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
if ( ! class_exists( 'TMDO_HivePress_Bootstrap' ) ) {
/**
* Bootstrap orchestrator for HivePress family adapters.
*
* Stateful only across the current request (instantiated adapters cached
* for `wp wpdo hivepress score/doctor` access). Reset between tests via
* `reset_for_tests()`.
*/
final class TMDO_HivePress_Bootstrap {
/** Slug → adapter class name registry. */
private const ADAPTER_MAP = array(
'hivepress' => 'TMDO_HivePress_Core_Adapter',
'hivepress-reviews' => 'TMDO_HivePress_Reviews_Adapter',
'hivepress-favorites' => 'TMDO_HivePress_Favorites_Adapter',
'hivepress-messages' => 'TMDO_HivePress_Messages_Adapter',
'hivepress-memberships' => 'TMDO_HivePress_Memberships_Adapter',
'hivepress-requests' => 'TMDO_HivePress_Requests_Adapter',
'hivepress-tags' => 'TMDO_HivePress_Tags_Adapter',
'hivepress-seo' => 'TMDO_HivePress_Seo_Adapter',
'hivepress-social-links' => 'TMDO_HivePress_Social_Links_Adapter',
'hivepress-blocks' => 'TMDO_HivePress_Blocks_Adapter',
'hivepress-bookings' => 'TMDO_HivePress_Bookings_Adapter',
'hivepress-marketplace' => 'TMDO_HivePress_Marketplace_Adapter',
'hivepress-statistics' => 'TMDO_HivePress_Statistics_Adapter',
);
/**
* Whether boot() has already run this request.
*
* @var bool
*/
private static bool $booted = false;
/**
* Instantiated adapters keyed by addon slug.
*
* @var array<string, TMDO_HivePress_Adapter>
*/
private static array $adapters = array();
/**
* Detection snapshot at boot time (captured for diagnostics).
*
* @var array<string,string>
*/
private static array $detected = array();
/**
* Boot the integration.
*
* @return void
*/
public static function boot(): void {
if ( self::$booted ) {
return;
}
self::$booted = true;
// Step 1: conflict guard. Detection + admin_notice + filter install.
if ( class_exists( 'TMDO_HivePress_Conflict_Guard' ) ) {
TMDO_HivePress_Conflict_Guard::check_and_warn();
}
// Step 2: detect addons. Empty array on non-HP sites = zero overhead.
self::$detected = class_exists( 'TMDO_HivePress_Detector' )
? TMDO_HivePress_Detector::detect()
: array();
if ( empty( self::$detected ) ) {
return;
}
// Step 3: respect the should_bind filter (conflict guard short-circuits here).
$context = array(
'detected' => self::$detected,
'adapters' => self::ADAPTER_MAP,
'conflicts' => class_exists( 'TMDO_HivePress_Conflict_Guard' )
? TMDO_HivePress_Conflict_Guard::detect_conflicts()
: array(),
);
$should = apply_filters( 'wpdo_hivepress_should_bind', true, $context );
if ( ! $should ) {
return;
}
// Step 4: instantiate + bind each adapter.
foreach ( self::$detected as $slug => $version ) {
self::bind_adapter( $slug, $version );
}
// Step 5: register cross-cutting components (router + cron optimizer).
// Both are gated by their own opt-in option and only activate when
// the operator flips it; safe to call here unconditionally.
if ( class_exists( 'TMDO_HivePress_Comment_Router' ) ) {
TMDO_HivePress_Comment_Router::register();
}
if ( class_exists( 'TMDO_HivePress_Cron_Optimizer' ) ) {
TMDO_HivePress_Cron_Optimizer::register();
}
/**
* Action: wpdo_hivepress_booted
*
* Fires after all adapters are bound. Listeners can introspect
* `TMDO_HivePress_Bootstrap::adapters()` for the active set.
*
* @param array<string,string> $detected Slug → version map.
* @param array<string,TMDO_HivePress_Adapter> $adapters Slug → adapter instance.
*/
do_action( 'wpdo_hivepress_booted', self::$detected, self::$adapters );
}
/**
* Force re-boot on next call (for tests + plugin activation).
*
* @internal
*/
public static function reset_for_tests(): void {
self::$booted = false;
self::$adapters = array();
self::$detected = array();
}
/**
* Read-only accessor for active adapters.
*
* @return array<string, TMDO_HivePress_Adapter>
*/
public static function adapters(): array {
return self::$adapters;
}
/**
* Read-only accessor for detection snapshot at boot time.
*
* @return array<string,string>
*/
public static function detected(): array {
return self::$detected;
}
/**
* Look up the adapter for a given addon slug, or null when none active.
*
* @param string $slug Addon slug.
*/
public static function adapter_for( string $slug ): ?object {
return self::$adapters[ $slug ] ?? null;
}
// ── Internal: per-adapter binding ───────────────────────────────────
/**
* Instantiate and wire one adapter's lifecycle hooks.
*
* @param string $slug Detected addon slug.
* @param string $version Detected version string ('' if unknown).
*/
private static function bind_adapter( string $slug, string $version ): void {
$class = self::ADAPTER_MAP[ $slug ] ?? '';
if ( '' === $class || ! class_exists( $class ) ) {
// Adapter for this slug not yet implemented (future Sprint).
return;
}
try {
$adapter = new $class();
} catch ( \Throwable $e ) {
if ( class_exists( 'TMDO_Logger' ) && method_exists( 'TMDO_Logger', 'error' ) ) {
TMDO_Logger::error(
'hivepress-integration',
sprintf( 'Failed to instantiate %s: %s', $class, $e->getMessage() )
);
}
return;
}
if ( ! $adapter instanceof TMDO_HivePress_Adapter ) {
if ( class_exists( 'TMDO_Logger' ) && method_exists( 'TMDO_Logger', 'warn' ) ) {
TMDO_Logger::warn(
'hivepress-integration',
sprintf( '%s does not implement TMDO_HivePress_Adapter — skipping', $class )
);
}
return;
}
// Version floor check.
$min = $adapter->minimum_addon_version();
if ( '' !== $min && '' !== $version && version_compare( $version, $min, '<' ) ) {
if ( class_exists( 'TMDO_Logger' ) && method_exists( 'TMDO_Logger', 'warn' ) ) {
TMDO_Logger::warn(
'hivepress-integration',
sprintf( '%s installed version %s is below minimum %s — adapter idle', $slug, $version, $min )
);
}
return;
}
self::$adapters[ $slug ] = $adapter;
// Adapter constructor is contractually responsible for calling
// `$this->bind_anti_eav_hooks()` (inherited from
// TMDO_Anti_EAV_Aware via TMDO_HivePress_Adapter_Trait) so the
// three `wpdo_register_*` actions get wired. Bootstrap then only
// triggers the addon-specific extras: query/event hooks.
$adapter->on_register_query_hooks();
$adapter->on_register_event_hooks();
}
}
} // end if ( ! class_exists )