feat(2meet-data-optimizer-hivepress-addon): register Hot-only HivePress fields as entity groups

- New scoped post groups for fields only the Hot zone covered (ADR-003):
  hp_draft_flags (hp_listing, hp_request: hp_drafted), hp_booking_core,
  hp_membership_plan_core, hp_membership_core. hp_drafted lives in one group
  spanning both post types, so it adds no shared key.
- New groups register before the existing ones: the legacy (unscoped)
  owner of hp_expired_time stays hp_request_core; existing hashes unchanged.
- Reconciler now also plans hp_membership rows of hp_expired_time out of
  hp_request_core. dev20-22 hold 0 native rows for these keys.
- Verify: HP unit 151 / integration 49 green, phpcs clean
- PR: PR-036
This commit is contained in:
2026-09-26 01:09:34 +08:00
parent 69c8bf2a88
commit 0e260ee3a9
2 changed files with 148 additions and 1 deletions
@@ -8,6 +8,14 @@
* post:hp_vendor_core → wp_wpdo_post_hp_vendor_core (hp_vendor)
* user:hp_user → wp_wpdo_user_hp_user
*
* Fields only the Hot zone used to cover (ADR-003), as their own groups:
* post:hp_draft_flags (hp_listing, hp_request)
* post:hp_booking_core (hp_booking)
* post:hp_membership_plan_core (hp_membership_plan)
* post:hp_membership_core (hp_membership)
* They register FIRST so the legacy last-registered owner of hp_expired_time
* stays hp_request_core.
*
* The term/comment groups (hp_taxonomy, hp_review) live in
* TMDO_Hivepress_Term_Comment_Fields.
*
@@ -60,6 +68,10 @@ final class TMDO_HivePress_Entity_Groups {
return;
}
self::register_hp_draft_flags_group();
self::register_hp_booking_core_group();
self::register_hp_membership_plan_core_group();
self::register_hp_membership_core_group();
self::register_hp_listing_core_group();
self::register_hp_request_core_group();
self::register_hp_vendor_core_group();
@@ -68,6 +80,106 @@ final class TMDO_HivePress_Entity_Groups {
// ── Group definitions ────────────────────────────────────────────────────
/**
* Draft flag shared by listings and requests (user-dashboard filtering).
*
* @return void
*/
private static function register_hp_draft_flags_group(): void {
TMDO_Entity_Registry::register_group(
'post',
'hp_draft_flags',
array(
array(
'key' => 'hp_drafted',
'type' => 'integer',
'searchable' => true,
'label' => 'Drafted flag (0/1)',
),
),
array( 'post_types' => array( 'hp_listing', 'hp_request' ) )
);
}
/**
* HivePress Bookings (post_type=hp_booking): slot-availability lookups.
*
* @return void
*/
private static function register_hp_booking_core_group(): void {
TMDO_Entity_Registry::register_group(
'post',
'hp_booking_core',
array(
array(
'key' => 'hp_start_time',
'type' => 'integer',
'searchable' => true,
'label' => 'Booking start unix ts',
),
array(
'key' => 'hp_end_time',
'type' => 'integer',
'searchable' => true,
'label' => 'Booking end unix ts',
),
array(
'key' => 'hp_quantity',
'type' => 'integer',
'label' => 'Places booked',
),
),
array( 'post_types' => array( 'hp_booking' ) )
);
}
/**
* HivePress Memberships plan (post_type=hp_membership_plan).
*
* @return void
*/
private static function register_hp_membership_plan_core_group(): void {
TMDO_Entity_Registry::register_group(
'post',
'hp_membership_plan_core',
array(
array(
'key' => 'hp_expire_period',
'type' => 'integer',
'label' => 'Plan expiry period (days)',
),
array(
'key' => 'hp_primary',
'type' => 'integer',
'searchable' => true,
'label' => 'Primary plan flag (0/1)',
),
),
array( 'post_types' => array( 'hp_membership_plan' ) )
);
}
/**
* HivePress Memberships subscription (post_type=hp_membership).
*
* @return void
*/
private static function register_hp_membership_core_group(): void {
TMDO_Entity_Registry::register_group(
'post',
'hp_membership_core',
array(
array(
'key' => 'hp_expired_time',
'type' => 'integer',
'searchable' => true,
'label' => 'Expiry unix ts',
),
),
array( 'post_types' => array( 'hp_membership' ) )
);
}
/**
* HivePress listing core meta keys (post_type=hp_listing).
* Aligns with the existing wpdo_hot_hp_listing flat table; v2.9.5 will
+36 -1
View File
@@ -75,7 +75,41 @@ class HivePressEntityGroupsTest extends TestCase {
$this->assertNull( TMDO_Entity_Registry::get_field( 'post', 'hp_rating', 'post' ), 'HivePress keys stay native on other post types' );
}
public function test_reconciler_plans_the_eight_misrouted_hivepress_keys(): void {
/**
* Fields only the Hot zone used to cover (ADR-003), as their own groups.
*/
private const HOT_ONLY_GROUPS = array(
'hp_draft_flags' => array( array( 'hp_listing', 'hp_request' ), array( 'hp_drafted' ) ),
'hp_booking_core' => array( array( 'hp_booking' ), array( 'hp_start_time', 'hp_end_time', 'hp_quantity' ) ),
'hp_membership_plan_core' => array( array( 'hp_membership_plan' ), array( 'hp_expire_period', 'hp_primary' ) ),
'hp_membership_core' => array( array( 'hp_membership' ), array( 'hp_expired_time' ) ),
);
public function test_hot_only_fields_have_entity_groups_scoped_to_their_post_types(): void {
foreach ( self::HOT_ONLY_GROUPS as $group => list( $post_types, $keys ) ) {
$this->assertSame( $post_types, TMDO_Entity_Registry::get_group_post_types( 'post', $group ), $group );
$this->assertSame( $keys, TMDO_Entity_Registry::get_group_keys( 'post', $group ), $group );
}
}
public function test_hot_only_fields_route_to_their_group_when_scoped_routing_is_on(): void {
$GLOBALS['_wp_options'][ TMDO_Entity_Registry::SCOPED_ROUTING_OPTION ] = '1';
foreach ( self::HOT_ONLY_GROUPS as $group => list( $post_types, $keys ) ) {
foreach ( $post_types as $post_type ) {
foreach ( $keys as $key ) {
$this->assertSame( $group, TMDO_Entity_Registry::get_field( 'post', $key, $post_type )['group'], "{$post_type}:{$key}" );
}
}
}
$this->assertSame( 'hp_listing_core', TMDO_Entity_Registry::get_field( 'post', 'hp_expired_time', 'hp_listing' )['group'] );
}
public function test_hot_only_groups_add_no_collisions(): void {
$this->assertSame( array(), TMDO_Entity_Registry::get_collisions() );
}
public function test_reconciler_plans_the_misrouted_hivepress_keys(): void {
$moves = array();
foreach ( TMDO_Post_Group_Reconciler::plan() as $m ) {
$moves[] = "{$m['source']}>{$m['target']}:{$m['key']}";
@@ -87,6 +121,7 @@ class HivePressEntityGroupsTest extends TestCase {
'hp_request_core>hp_listing_core:hp_expired_time',
'hp_request_core>hp_listing_core:hp_status',
'hp_request_core>hp_listing_core:hp_view_count',
'hp_request_core>hp_membership_core:hp_expired_time',
'hp_vendor_core>hp_listing_core:hp_hourly_rate',
'hp_vendor_core>hp_listing_core:hp_rating',
'hp_vendor_core>hp_listing_core:hp_rating_count',