query( 'DROP TABLE IF EXISTS `' . self::TABLE . '`' ); $wpdb->query( 'CREATE TABLE `' . self::TABLE . "` ( id BIGINT NOT NULL AUTO_INCREMENT, post_id BIGINT NOT NULL, rc_price DECIMAL(18,6) DEFAULT NULL, post_status VARCHAR(20) DEFAULT NULL, post_date DATETIME DEFAULT NULL, PRIMARY KEY (id), UNIQUE KEY uk_entity (post_id), KEY idx_post_status_date (post_status, post_date) ) ENGINE=InnoDB" ); $wpdb->query( 'INSERT INTO `' . self::TABLE . "` (post_id, rc_price, post_status, post_date) VALUES (1, 10, 'publish', '2026-01-01 00:00:00')" ); $GLOBALS['_wp_options'] = array( TMDO_Post_Status_Sync::OPTION => array( 'rc_core' => 'ready' ) ); $GLOBALS['_wp_is_admin'] = false; $ref = new ReflectionProperty( WPDO_Schema_Manager::class, 'table_exists_cache' ); $ref->setAccessible( true ); $ref->setValue( null, array() ); $mode = new ReflectionProperty( WPDO_Mode_Manager::class, 'cache' ); $mode->setAccessible( true ); $mode->setValue( null, array( 'post' => 'aeav_only', 'user' => 'disabled', 'term' => 'disabled', 'comment' => 'disabled' ) ); TMDO_Post_Query_Router::flush_copy_cache(); WPDO_Entity_Registry::init(); WPDO_Entity_Registry::register_adapter( 'post', new WPDO_Adapter_Post() ); WPDO_Entity_Registry::register_group( 'post', 'rc_core', array( array( 'key' => 'rc_price', 'type' => 'decimal' ) ), array( 'post_types' => array( 'rc_item' ) ) ); } protected function tearDown(): void { global $wpdb; $wpdb->query( 'DROP TABLE IF EXISTS `' . self::TABLE . '`' ); WPDO_Entity_Registry::init(); $mode = new ReflectionProperty( WPDO_Mode_Manager::class, 'cache' ); $mode->setAccessible( true ); $mode->setValue( null, null ); } /** @return array{join:string, where:string, orderby:string, groupby:string} */ private function sql( array $vars ): array { $query = new WP_Query(); foreach ( array_merge( array( 'post_type' => 'rc_item', 'post_status' => 'publish', 'meta_query' => array( array( 'key' => 'rc_price', 'value' => array( 5, 20 ), 'compare' => 'BETWEEN' ) ), ), $vars ) as $k => $v ) { $query->set( $k, $v ); } $router = new TMDO_Post_Query_Router(); $router->pre_get_posts( $query ); return array( 'join' => $router->posts_join( '', $query ), 'where' => $router->posts_where( " AND wp_posts.post_status = 'publish'", $query ), 'orderby' => $router->posts_orderby( 'wp_posts.post_date DESC', $query ), 'groupby' => $router->posts_groupby( '', $query ), ); } private function assert_legacy_shape( array $sql ): void { $this->assertStringContainsString( 'LEFT JOIN', $sql['join'] ); $this->assertStringNotContainsString( self::ALIAS . '.`post_status`', $sql['where'] ); $this->assertSame( 'wp_posts.post_date DESC', $sql['orderby'] ); $this->assertSame( '`wp_itest_posts`.`ID`', $sql['groupby'] ); } public function test_ready_copies_filter_status_and_order_by_date_on_the_flat_table(): void { $sql = $this->sql( array( 'order' => 'ASC' ) ); $this->assertStringContainsString( 'INNER JOIN', $sql['join'] ); $this->assertStringContainsString( self::ALIAS . ".`post_status` IN ('publish')", $sql['where'] ); $this->assertStringContainsString( "wp_posts.post_status = 'publish'", $sql['where'], 'WordPress status clause stays' ); $this->assertSame( self::ALIAS . '.`post_date` ASC', $sql['orderby'] ); $this->assertSame( '', $sql['groupby'], 'one row per post: no GROUP BY, so LIMIT can stop early' ); } public function test_several_explicit_statuses_are_kept(): void { $sql = $this->sql( array( 'post_status' => array( 'publish', 'private' ), 'orderby' => 'date' ) ); $this->assertStringContainsString( self::ALIAS . ".`post_status` IN ('publish','private')", $sql['where'] ); $this->assertSame( self::ALIAS . '.`post_date` DESC', $sql['orderby'] ); } public function test_copies_not_marked_ready_keep_the_legacy_shape(): void { $GLOBALS['_wp_options'] = array( TMDO_Post_Status_Sync::OPTION => array( 'rc_core' => 'columns' ) ); $this->assert_legacy_shape( $this->sql( array() ) ); } public function test_rows_with_missing_copies_keep_the_legacy_shape(): void { global $wpdb; $wpdb->query( 'INSERT INTO `' . self::TABLE . '` (post_id, rc_price) VALUES (2, 12)' ); $this->assert_legacy_shape( $this->sql( array() ) ); } public function test_other_orderings_or_implicit_statuses_keep_the_legacy_shape(): void { $this->assert_legacy_shape( $this->sql( array( 'orderby' => 'title' ) ) ); $this->assert_legacy_shape( $this->sql( array( 'post_status' => '' ) ) ); $this->assert_legacy_shape( $this->sql( array( 'post_status' => 'any' ) ) ); } }