refactor(2meet-data-optimizer-hivepress-addon): remove comment mirror writes to never-created tables

- Favorites/Messages adapters reduced to detection only; Requests keeps hot_hp_request fields, drops hp_offer mirror
- Delete TMDO_HivePress_Comment_Router (read path to wpdo_comment_hp_* tables that no installer creates)
- Verify: addon unit 141 OK, integration 52 OK; phpcs 41E/57W → 35E/48W
- PR: PR-013
This commit is contained in:
2026-09-25 22:58:34 +08:00
parent f089b0934b
commit 5777210184
17 changed files with 77 additions and 1108 deletions
@@ -9,21 +9,9 @@
* — same access pattern as Listing (user dashboard + expiry cron)
*
* - Offer (comment_type=hp_offer, parent post_type=hp_request)
* comment-column based; benefit comes from comment-router using
* (comment_post_ID, comment_type) covering index + dedicated shadow
* table for "approved offers per request" aggregation.
*
* Shadow table for offers (analogous to favorites pattern):
*
* CREATE TABLE wp_wpdo_comment_hp_offer (
* comment_id BIGINT UNSIGNED NOT NULL PRIMARY KEY,
* request_id BIGINT UNSIGNED NOT NULL,
* bidder_id BIGINT UNSIGNED NOT NULL,
* approved TINYINT(1) NOT NULL DEFAULT 0,
* created_at DATETIME NOT NULL,
* KEY idx_request_approved (request_id, approved),
* KEY idx_bidder (bidder_id)
* );
* stored in comment columns only — no comment meta to flatten.
* (The adapter used to mirror offers into `wpdo_comment_hp_offer`,
* a table nothing ever created.)
*
* @package WP_Data_Optimizer
* @since 3.0.0
@@ -45,9 +33,6 @@ if ( ! class_exists( 'TMDO_HivePress_Requests_Adapter' ) ) {
/** Comment_type for the Offer side of Requests. */
public const OFFER_COMMENT_TYPE = 'hp_offer';
/** Shadow table for offers (without wpdb prefix). */
public const OFFER_TABLE = 'wpdo_comment_hp_offer';
/**
* Constructor — bind register hooks via inherited trait.
*/
@@ -105,104 +90,7 @@ if ( ! class_exists( 'TMDO_HivePress_Requests_Adapter' ) ) {
}
/**
* Declare offer shadow table.
*
* @param TMDO_Custom_Table_Registry $registry Registry singleton.
*/
public function on_register_custom_tables( TMDO_Custom_Table_Registry $registry ): void {
$this->register_custom_table(
$registry,
array(
'table_name' => self::OFFER_TABLE,
'primary_key' => 'comment_id',
'post_type_link' => 'hp_request',
'expected_columns' => array(
'comment_id' => 'BIGINT UNSIGNED NOT NULL PRIMARY KEY',
'request_id' => 'BIGINT UNSIGNED NOT NULL',
'bidder_id' => 'BIGINT UNSIGNED NOT NULL',
'approved' => 'TINYINT(1) NOT NULL DEFAULT 0',
'created_at' => 'DATETIME NOT NULL',
),
'indexes' => array(
'idx_request_approved' => '(request_id, approved)',
'idx_bidder' => '(bidder_id)',
),
'doctor_callback' => array( $this, 'doctor_check' ),
)
);
}
/**
* Mirror new hp_offer comments into the shadow table.
*/
public function on_register_event_hooks(): void {
add_action( 'wp_insert_comment', array( $this, 'mirror_offer_insert' ), 10, 2 );
add_action( 'edit_comment', array( $this, 'mirror_offer_update' ), 10, 2 );
add_action( 'deleted_comment', array( $this, 'mirror_offer_delete' ), 10, 2 );
}
/**
* Insert a hp_offer mirror row.
*
* @param int $comment_id Comment ID.
* @param object|\WP_Comment $comment Comment object.
*/
public function mirror_offer_insert( int $comment_id, $comment ): void {
if ( ! is_object( $comment ) || ( $comment->comment_type ?? '' ) !== self::OFFER_COMMENT_TYPE ) {
return;
}
global $wpdb;
$wpdb->query( // phpcs:ignore WordPress.DB.DirectDatabaseQuery, WordPress.DB.PreparedSQL.InterpolatedNotPrepared
$wpdb->prepare(
'INSERT INTO `' . $wpdb->prefix . self::OFFER_TABLE . '` (comment_id, request_id, bidder_id, approved, created_at) VALUES (%d, %d, %d, %d, %s) ON DUPLICATE KEY UPDATE approved = VALUES(approved)',
$comment_id,
(int) ( $comment->comment_post_ID ?? 0 ),
(int) ( $comment->user_id ?? 0 ),
(int) ( $comment->comment_approved ?? 0 ),
$comment->comment_date ?? current_time( 'mysql' )
)
);
}
/**
* Update mirror row when comment is edited (approval flip is the hot path).
*
* @param int $comment_id Comment ID.
* @param array $data Comment data array passed by edit_comment.
*/
public function mirror_offer_update( int $comment_id, $data ): void {
unset( $data );
global $wpdb;
// Re-fetch comment object for accurate state then re-mirror via insert path.
if ( function_exists( 'get_comment' ) ) {
$comment = get_comment( $comment_id );
if ( $comment ) {
$this->mirror_offer_insert( $comment_id, $comment );
}
}
unset( $wpdb );
}
/**
* Remove mirror row on hp_offer deletion.
*
* @param int $comment_id Comment ID.
* @param object|\WP_Comment $comment Comment object.
*/
public function mirror_offer_delete( int $comment_id, $comment ): void {
if ( ! is_object( $comment ) || ( $comment->comment_type ?? '' ) !== self::OFFER_COMMENT_TYPE ) {
return;
}
global $wpdb;
$wpdb->delete( // phpcs:ignore WordPress.DB.DirectDatabaseQuery
$wpdb->prefix . self::OFFER_TABLE,
array( 'comment_id' => $comment_id ),
array( '%d' )
);
}
/**
* Doctor probe — request hot table + offer shadow table.
* Doctor probe — request hot table.
*
* @return array{ok:bool, message:string, details?:array<string,mixed>}
*/
@@ -214,41 +102,21 @@ if ( ! class_exists( 'TMDO_HivePress_Requests_Adapter' ) ) {
'message' => 'wpdb global not available',
);
}
$details = array();
$ok = true;
foreach ( array(
'hp_request_hot' => $wpdb->prefix . 'wpdo_hot_hp_request',
'hp_offer_shadow' => $wpdb->prefix . self::OFFER_TABLE,
) as $key => $table ) {
try {
$exists = (bool) $wpdb->get_var( $wpdb->prepare( 'SHOW TABLES LIKE %s', $table ) );
$details[ $key ] = array(
'table' => $table,
'exists' => $exists,
);
if ( ! $exists ) {
$ok = false;
}
} catch ( \Throwable $e ) {
$details[ $key ] = array(
'table' => $table,
'error' => $e->getMessage(),
);
$ok = false;
}
$table = $wpdb->prefix . 'wpdo_hot_hp_request';
try {
$exists = (bool) $wpdb->get_var( $wpdb->prepare( 'SHOW TABLES LIKE %s', $table ) );
return array(
'ok' => $exists,
'message' => $exists
? sprintf( 'hivepress-requests: %s present', $table )
: sprintf( 'hivepress-requests: %s missing', $table ),
);
} catch ( \Throwable $e ) {
return array(
'ok' => false,
'message' => sprintf( 'hivepress-requests doctor failed: %s', $e->getMessage() ),
);
}
return array(
'ok' => $ok,
'message' => $ok ? 'hivepress-requests: tables OK' : 'hivepress-requests: one or more tables missing',
'details' => $details,
);
}
/**
* 8-D self-score.
*/
public function suitability_score(): array {
return $this->compose_score( array() );
}
/**
@@ -257,10 +125,7 @@ if ( ! class_exists( 'TMDO_HivePress_Requests_Adapter' ) ) {
* @return array<int,string>
*/
public function migrations(): array {
return array(
'hot_hp_request',
'comment_hp_offer',
);
return array( 'hot_hp_request' );
}
}