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
This commit is contained in:
@@ -0,0 +1,267 @@
|
||||
<?php
|
||||
/**
|
||||
* Requests adapter — `hivepress-requests`.
|
||||
*
|
||||
* Two related models:
|
||||
*
|
||||
* - Request (post_type=hp_request)
|
||||
* hot fields: hp_drafted (bool), hp_expired_time (unix ts)
|
||||
* — 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)
|
||||
* );
|
||||
*
|
||||
* @package WP_Data_Optimizer
|
||||
* @since 3.0.0
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
if ( ! class_exists( 'TMDO_HivePress_Requests_Adapter' ) ) {
|
||||
|
||||
/**
|
||||
* Requests addon adapter.
|
||||
*/
|
||||
final class TMDO_HivePress_Requests_Adapter implements TMDO_HivePress_Adapter {
|
||||
|
||||
use TMDO_HivePress_Adapter_Trait;
|
||||
|
||||
/** 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.
|
||||
*/
|
||||
public function __construct() {
|
||||
$this->bind_anti_eav_hooks();
|
||||
}
|
||||
|
||||
/** Adapter slug (matches wp.org plugin slug). */
|
||||
public function plugin_slug(): string {
|
||||
return 'hivepress-requests';
|
||||
}
|
||||
|
||||
/** Class probed for addon presence. */
|
||||
public function detection_class(): string {
|
||||
return 'HivePress\\Requests\\Plugin';
|
||||
}
|
||||
|
||||
/** Version constant probed for addon presence. */
|
||||
public function detection_const(): string {
|
||||
return 'HIVEPRESS_REQUESTS_VERSION';
|
||||
}
|
||||
|
||||
/** Minimum addon version supported. */
|
||||
public function minimum_addon_version(): string {
|
||||
return '1.2.0';
|
||||
}
|
||||
|
||||
/**
|
||||
* Register hot fields for hp_request post type.
|
||||
*
|
||||
* @param TMDO_Schema_Registry $registry Schema registry singleton.
|
||||
*/
|
||||
public function on_register_fields( TMDO_Schema_Registry $registry ): void {
|
||||
$registry->register_many(
|
||||
$this->plugin_slug(),
|
||||
array(
|
||||
array(
|
||||
'post_type' => 'hp_request',
|
||||
'meta_key' => 'hp_drafted',
|
||||
'zone' => 'hot',
|
||||
'data_type' => 'tinyint(1) NOT NULL DEFAULT 0',
|
||||
'column' => 'hp_drafted',
|
||||
'indexed' => true,
|
||||
),
|
||||
array(
|
||||
'post_type' => 'hp_request',
|
||||
'meta_key' => 'hp_expired_time',
|
||||
'zone' => 'hot',
|
||||
'data_type' => 'bigint(20) UNSIGNED NOT NULL DEFAULT 0',
|
||||
'column' => 'hp_expired_time',
|
||||
'indexed' => true,
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @return array{ok:bool, message:string, details?:array<string,mixed>}
|
||||
*/
|
||||
public function doctor_check(): array {
|
||||
global $wpdb;
|
||||
if ( ! isset( $wpdb ) || ! is_object( $wpdb ) ) {
|
||||
return array(
|
||||
'ok' => false,
|
||||
'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;
|
||||
}
|
||||
}
|
||||
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() );
|
||||
}
|
||||
|
||||
/**
|
||||
* FSM modules this adapter contributes.
|
||||
*
|
||||
* @return array<int,string>
|
||||
*/
|
||||
public function migrations(): array {
|
||||
return array(
|
||||
'hot_hp_request',
|
||||
'comment_hp_offer',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
} // end if ( ! class_exists )
|
||||
Reference in New Issue
Block a user