refactor(2meet-data-optimizer): resolve post_type/group/table mappings through the registry
- TMDO_Post_Fields::post_type_for_group() / groups_for_post_type() derive HivePress-style groups from their registry post_type scope (core keeps its own attachment / wc_product / nav_menu_item map); the three copy-pasted switches and the query router's POST_TYPE_GROUP_MAP use them - Term/comment backfill, shadow verifier and CLI take their groups from the registry (TMDO_Term_Comment_Backfill::registered_groups()); installer drops the hp_* entries already covered by its table patterns; REST listings default post type is filterable (tmdo_rest_default_post_type, default 'post') - Verify: NoHpMappingsTest guard + mapping/default tests; core unit 640 / integration 449, HP 146/49, WC 10/22 OK - PR: PR-020e
This commit is contained in:
@@ -843,18 +843,11 @@ class TMDO_Installer {
|
||||
$wpdb->prefix . 'wpdo_user_core_profile',
|
||||
$wpdb->prefix . 'wpdo_user_social',
|
||||
$wpdb->prefix . 'wpdo_user_commerce',
|
||||
$wpdb->prefix . 'wpdo_user_hp_user',
|
||||
$wpdb->prefix . 'wpdo_user_admin_prefs',
|
||||
$wpdb->prefix . 'wpdo_post_wp_core',
|
||||
$wpdb->prefix . 'wpdo_post_attachment',
|
||||
$wpdb->prefix . 'wpdo_post_wc_product',
|
||||
$wpdb->prefix . 'wpdo_post_hp_listing_core',
|
||||
$wpdb->prefix . 'wpdo_post_hp_request_core',
|
||||
$wpdb->prefix . 'wpdo_post_hp_vendor_core',
|
||||
$wpdb->prefix . 'wpdo_post_nav_menu_item',
|
||||
$wpdb->prefix . 'wpdo_hot_hp_listing',
|
||||
$wpdb->prefix . 'wpdo_term_hp_taxonomy',
|
||||
$wpdb->prefix . 'wpdo_comment_hp_review',
|
||||
$wpdb->prefix . 'wpdo_term_misc',
|
||||
$wpdb->prefix . 'wpdo_comment_misc',
|
||||
);
|
||||
|
||||
@@ -303,23 +303,7 @@ final class TMDO_Post_Shadow_Verifier {
|
||||
* @return string|null
|
||||
*/
|
||||
private static function group_post_type( string $group ): ?string {
|
||||
switch ( $group ) {
|
||||
case 'attachment':
|
||||
return 'attachment';
|
||||
case 'wc_product':
|
||||
return 'product';
|
||||
case 'hp_listing_core':
|
||||
return 'hp_listing';
|
||||
case 'hp_request_core':
|
||||
return 'hp_request';
|
||||
case 'hp_vendor_core':
|
||||
return 'hp_vendor';
|
||||
case 'nav_menu_item':
|
||||
return 'nav_menu_item';
|
||||
case 'wp_core':
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
return TMDO_Post_Fields::post_type_for_group( $group );
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -529,7 +529,7 @@ class TMDO_REST_API {
|
||||
* @return WP_REST_Response REST response.
|
||||
*/
|
||||
public function get_listings( WP_REST_Request $request ): WP_REST_Response {
|
||||
$post_type = $request->get_param( 'post_type' ) ?? 'hp_listing';
|
||||
$post_type = $request->get_param( 'post_type' ) ?? self::default_post_type();
|
||||
if ( ! post_type_exists( $post_type ) || ! is_post_type_viewable( $post_type ) ) {
|
||||
return new WP_REST_Response(
|
||||
array(
|
||||
@@ -1550,13 +1550,25 @@ class TMDO_REST_API {
|
||||
return $filters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Post type GET /listings serves when the request names none.
|
||||
*
|
||||
* Filter `tmdo_rest_default_post_type` lets an integration (e.g. the
|
||||
* HivePress AddOn) make its own post type the default.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function default_post_type(): string {
|
||||
return (string) apply_filters( 'tmdo_rest_default_post_type', 'post' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Argument definitions for GET /listings.
|
||||
*/
|
||||
private function listings_args(): array {
|
||||
return array(
|
||||
'post_type' => array(
|
||||
'default' => 'hp_listing',
|
||||
'default' => self::default_post_type(),
|
||||
'sanitize_callback' => 'sanitize_key',
|
||||
),
|
||||
'per_page' => array(
|
||||
|
||||
@@ -60,20 +60,22 @@ if ( ! defined( 'ABSPATH' ) ) {
|
||||
final class TMDO_Term_Comment_Backfill {
|
||||
|
||||
/**
|
||||
* Group → flat table suffix mapping. Mirror of TMDO_Hivepress_Term_Comment_Fields.
|
||||
* Term and comment groups registered in the entity registry.
|
||||
*
|
||||
* @var array<string, array{entity_type:string, table_suffix:string}>
|
||||
* @return array<string, string> Group name → entity type ('term' | 'comment').
|
||||
*/
|
||||
private const GROUP_MAP = array(
|
||||
'hp_taxonomy' => array(
|
||||
'entity_type' => 'term',
|
||||
'table_suffix' => 'wpdo_term_hp_taxonomy',
|
||||
),
|
||||
'hp_review' => array(
|
||||
'entity_type' => 'comment',
|
||||
'table_suffix' => 'wpdo_comment_hp_review',
|
||||
),
|
||||
);
|
||||
public static function registered_groups(): array {
|
||||
$groups = array();
|
||||
if ( ! class_exists( 'TMDO_Entity_Registry' ) ) {
|
||||
return $groups;
|
||||
}
|
||||
foreach ( array( 'term', 'comment' ) as $entity_type ) {
|
||||
foreach ( TMDO_Entity_Registry::get_groups_for_type( $entity_type ) as $group ) {
|
||||
$groups[ $group ] = $groups[ $group ] ?? $entity_type;
|
||||
}
|
||||
}
|
||||
return $groups;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run backfill for every registered term + comment group.
|
||||
@@ -83,8 +85,8 @@ final class TMDO_Term_Comment_Backfill {
|
||||
*/
|
||||
public static function backfill_all( bool $dry_run = false ): array {
|
||||
$results = array();
|
||||
foreach ( self::GROUP_MAP as $group_name => $cfg ) {
|
||||
$results[ $group_name ] = self::backfill_group( $cfg['entity_type'], $group_name, $dry_run );
|
||||
foreach ( self::registered_groups() as $group_name => $entity_type ) {
|
||||
$results[ $group_name ] = self::backfill_group( $entity_type, $group_name, $dry_run );
|
||||
}
|
||||
return $results;
|
||||
}
|
||||
@@ -110,7 +112,7 @@ final class TMDO_Term_Comment_Backfill {
|
||||
$result['error'] = 'Entity Registry unavailable';
|
||||
return $result;
|
||||
}
|
||||
if ( ! isset( self::GROUP_MAP[ $group_name ] ) ) {
|
||||
if ( ( self::registered_groups()[ $group_name ] ?? null ) !== $entity_type ) {
|
||||
$result['error'] = "Unknown group: {$group_name}";
|
||||
return $result;
|
||||
}
|
||||
@@ -140,7 +142,7 @@ final class TMDO_Term_Comment_Backfill {
|
||||
return $result;
|
||||
}
|
||||
|
||||
$flat_table = $wpdb->prefix . self::GROUP_MAP[ $group_name ]['table_suffix'];
|
||||
$flat_table = TMDO_Schema_Manager::get_table_name( $entity_type, $group_name );
|
||||
|
||||
// Count candidate entities — those with at least one of the registered keys in wp_*meta.
|
||||
$placeholders = implode( ',', array_fill( 0, count( $keys ), '%s' ) );
|
||||
|
||||
@@ -41,23 +41,6 @@ final class TMDO_Term_Comment_Shadow_Verifier {
|
||||
/** Default sample size per entity per cron tick. */
|
||||
public const DEFAULT_SAMPLE_SIZE = 100;
|
||||
|
||||
/**
|
||||
* Group → flat table suffix mapping. Keep in sync with
|
||||
* TMDO_Hivepress_Term_Comment_Fields registrations and the misc bucket.
|
||||
*
|
||||
* @var array<string, array{entity_type:string, table_suffix:string, has_misc:bool}>
|
||||
*/
|
||||
private const GROUP_MAP = array(
|
||||
'hp_taxonomy' => array(
|
||||
'entity_type' => 'term',
|
||||
'table_suffix' => 'wpdo_term_hp_taxonomy',
|
||||
),
|
||||
'hp_review' => array(
|
||||
'entity_type' => 'comment',
|
||||
'table_suffix' => 'wpdo_comment_hp_review',
|
||||
),
|
||||
);
|
||||
|
||||
/**
|
||||
* Run a sample-compare pass for a single entity group.
|
||||
*
|
||||
@@ -215,11 +198,7 @@ final class TMDO_Term_Comment_Shadow_Verifier {
|
||||
return;
|
||||
}
|
||||
|
||||
global $wpdb;
|
||||
|
||||
foreach ( self::GROUP_MAP as $group => $cfg ) {
|
||||
$entity_type = $cfg['entity_type'];
|
||||
|
||||
foreach ( TMDO_Term_Comment_Backfill::registered_groups() as $group => $entity_type ) {
|
||||
// Only run when the entity is in shadow_read mode.
|
||||
if ( 'term' === $entity_type && ! $term_shadow ) {
|
||||
continue;
|
||||
@@ -232,7 +211,7 @@ final class TMDO_Term_Comment_Shadow_Verifier {
|
||||
if ( empty( $keys ) ) {
|
||||
continue;
|
||||
}
|
||||
$flat_table = $wpdb->prefix . $cfg['table_suffix'];
|
||||
$flat_table = TMDO_Schema_Manager::get_table_name( $entity_type, $group );
|
||||
|
||||
try {
|
||||
self::sample_compare( $entity_type, $group, $flat_table, $keys, self::DEFAULT_SAMPLE_SIZE );
|
||||
@@ -337,16 +316,14 @@ final class TMDO_Term_Comment_Shadow_Verifier {
|
||||
return array();
|
||||
}
|
||||
|
||||
global $wpdb;
|
||||
$out = array();
|
||||
|
||||
foreach ( self::GROUP_MAP as $group => $cfg ) {
|
||||
$entity_type = $cfg['entity_type'];
|
||||
$keys = TMDO_Entity_Registry::get_group_keys( $entity_type, $group );
|
||||
foreach ( TMDO_Term_Comment_Backfill::registered_groups() as $group => $entity_type ) {
|
||||
$keys = TMDO_Entity_Registry::get_group_keys( $entity_type, $group );
|
||||
if ( empty( $keys ) ) {
|
||||
continue;
|
||||
}
|
||||
$flat_table = $wpdb->prefix . $cfg['table_suffix'];
|
||||
$flat_table = TMDO_Schema_Manager::get_table_name( $entity_type, $group );
|
||||
|
||||
try {
|
||||
$out[ $group ] = self::sample_compare( $entity_type, $group, $flat_table, $keys, $sample_size );
|
||||
|
||||
@@ -43,6 +43,46 @@ if ( ! defined( 'ABSPATH' ) ) {
|
||||
*/
|
||||
final class TMDO_Post_Fields {
|
||||
|
||||
/**
|
||||
* Post type of each core group that is not scoped to post types in the
|
||||
* registry (wp_core spans every post type and is absent on purpose).
|
||||
*/
|
||||
private const GROUP_POST_TYPES = array(
|
||||
'attachment' => 'attachment',
|
||||
'wc_product' => 'product',
|
||||
'nav_menu_item' => 'nav_menu_item',
|
||||
);
|
||||
|
||||
/**
|
||||
* Primary post type of a post group: the registry scope for scoped groups
|
||||
* (e.g. the HivePress AddOn's), the core mapping otherwise.
|
||||
*
|
||||
* @param string $group Entity group name.
|
||||
* @return string|null Null for cross-post-type groups such as wp_core.
|
||||
*/
|
||||
public static function post_type_for_group( string $group ): ?string {
|
||||
$scoped = class_exists( 'TMDO_Entity_Registry' ) ? TMDO_Entity_Registry::get_group_post_types( 'post', $group ) : array();
|
||||
return $scoped[0] ?? ( self::GROUP_POST_TYPES[ $group ] ?? null );
|
||||
}
|
||||
|
||||
/**
|
||||
* Post groups dedicated to a post type (wp_core excluded).
|
||||
*
|
||||
* @param string $post_type Post type slug.
|
||||
* @return string[]
|
||||
*/
|
||||
public static function groups_for_post_type( string $post_type ): array {
|
||||
$groups = array_keys( self::GROUP_POST_TYPES, $post_type, true );
|
||||
if ( class_exists( 'TMDO_Entity_Registry' ) ) {
|
||||
foreach ( TMDO_Entity_Registry::get_groups_for_type( 'post' ) as $group ) {
|
||||
if ( in_array( $post_type, TMDO_Entity_Registry::get_group_post_types( 'post', $group ), true ) ) {
|
||||
$groups[] = $group;
|
||||
}
|
||||
}
|
||||
}
|
||||
return array_values( array_unique( $groups ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook into WPDO entity field registration.
|
||||
*
|
||||
|
||||
@@ -546,8 +546,8 @@ final class TMDO_Post_Migration {
|
||||
}
|
||||
|
||||
/**
|
||||
* Map group name to the post_type it targets. The mapping is canonical
|
||||
* to v2.9.1 group definitions in TMDO_Post_Fields.
|
||||
* Map group name to the post_type it targets (see
|
||||
* TMDO_Post_Fields::post_type_for_group()).
|
||||
*
|
||||
* Returns null for cross-post_type groups (e.g. 'wp_core').
|
||||
*
|
||||
@@ -555,23 +555,7 @@ final class TMDO_Post_Migration {
|
||||
* @return string|null
|
||||
*/
|
||||
private static function group_post_type( string $group ): ?string {
|
||||
switch ( $group ) {
|
||||
case 'attachment':
|
||||
return 'attachment';
|
||||
case 'wc_product':
|
||||
return 'product';
|
||||
case 'hp_listing_core':
|
||||
return 'hp_listing';
|
||||
case 'hp_request_core':
|
||||
return 'hp_request';
|
||||
case 'hp_vendor_core':
|
||||
return 'hp_vendor';
|
||||
case 'nav_menu_item':
|
||||
return 'nav_menu_item';
|
||||
case 'wp_core':
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
return TMDO_Post_Fields::post_type_for_group( $group );
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -43,23 +43,6 @@ class TMDO_Post_Query_Router {
|
||||
/** Query var key for capturing routed clauses (consumed by posts_join/where). */
|
||||
private const QUERY_VAR = 'wpdo_post_clauses';
|
||||
|
||||
/**
|
||||
* Map post_type → entity group (mirror of TMDO_Post_Migration::group_post_type
|
||||
* but inverted; a post_type may map to multiple groups eventually, currently
|
||||
* we route to the most-specific *_core group plus the cross-cutting wp_core
|
||||
* group when the key is in wp_core).
|
||||
*
|
||||
* @var array<string,string>
|
||||
*/
|
||||
private const POST_TYPE_GROUP_MAP = array(
|
||||
'product' => 'wc_product',
|
||||
'hp_listing' => 'hp_listing_core',
|
||||
'hp_request' => 'hp_request_core',
|
||||
'hp_vendor' => 'hp_vendor_core',
|
||||
'attachment' => 'attachment',
|
||||
'nav_menu_item' => 'nav_menu_item',
|
||||
);
|
||||
|
||||
/**
|
||||
* Register all WP_Query hooks.
|
||||
*
|
||||
@@ -117,8 +100,7 @@ class TMDO_Post_Query_Router {
|
||||
// Confirm the field's group is appropriate for this post_type:
|
||||
// either cross-cutting wp_core (any) or the post_type-specific group.
|
||||
$group = $field['group'] ?? '';
|
||||
$expected_grp = self::POST_TYPE_GROUP_MAP[ $pt ] ?? null;
|
||||
$is_appropriate = ( 'wp_core' === $group ) || ( null !== $expected_grp && $expected_grp === $group );
|
||||
$is_appropriate = ( 'wp_core' === $group ) || in_array( $group, TMDO_Post_Fields::groups_for_post_type( (string) $pt ), true );
|
||||
if ( ! $is_appropriate ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user