terms = self::TERMS; $wpdb->termmeta = self::TERMMETA; $wpdb->comments = self::COMMENTS; $wpdb->commentmeta = self::COMMENTMETA; WPDO_Entity_Registry::register_adapter( 'term', new WPDO_Adapter_Term() ); WPDO_Entity_Registry::register_adapter( 'comment', new WPDO_Adapter_Comment() ); WPDO_Hivepress_Term_Comment_Fields::register_entity_fields(); // Test tables. $wpdb->query( 'DROP TABLE IF EXISTS `' . self::TERMS . '`' ); $wpdb->query( 'CREATE TABLE `' . self::TERMS . '` ( term_id bigint(20) unsigned NOT NULL AUTO_INCREMENT, name varchar(200) NOT NULL DEFAULT "", PRIMARY KEY (term_id) ) DEFAULT CHARACTER SET utf8mb4' ); $wpdb->query( 'DROP TABLE IF EXISTS `' . self::COMMENTS . '`' ); $wpdb->query( 'CREATE TABLE `' . self::COMMENTS . '` ( comment_ID bigint(20) unsigned NOT NULL AUTO_INCREMENT, comment_post_ID bigint(20) unsigned NOT NULL DEFAULT 0, PRIMARY KEY (comment_ID) ) DEFAULT CHARACTER SET utf8mb4' ); $wpdb->query( 'CREATE TABLE IF NOT EXISTS `' . self::TERMMETA . '` ( meta_id bigint(20) unsigned NOT NULL AUTO_INCREMENT, term_id bigint(20) unsigned NOT NULL DEFAULT 0, meta_key varchar(255) DEFAULT NULL, meta_value longtext, PRIMARY KEY (meta_id), KEY term_id (term_id), KEY meta_key (meta_key(191)) ) DEFAULT CHARACTER SET utf8mb4' ); $wpdb->query( 'CREATE TABLE IF NOT EXISTS `' . self::COMMENTMETA . '` ( meta_id bigint(20) unsigned NOT NULL AUTO_INCREMENT, comment_id bigint(20) unsigned NOT NULL DEFAULT 0, meta_key varchar(255) DEFAULT NULL, meta_value longtext, PRIMARY KEY (meta_id), KEY comment_id (comment_id), KEY meta_key (meta_key(191)) ) DEFAULT CHARACTER SET utf8mb4' ); $wpdb->query( 'DROP TABLE IF EXISTS `' . self::TERM_FLAT . '`' ); $wpdb->query( 'CREATE TABLE `' . self::TERM_FLAT . '` ( term_id bigint(20) unsigned NOT NULL, hp_sort_order int(11) DEFAULT NULL, hp_default tinyint(1) DEFAULT NULL, hp_icon varchar(64) DEFAULT NULL, PRIMARY KEY (term_id) ) DEFAULT CHARACTER SET utf8mb4' ); $wpdb->query( 'DROP TABLE IF EXISTS `' . self::COMMENT_FLAT . '`' ); $wpdb->query( 'CREATE TABLE `' . self::COMMENT_FLAT . '` ( comment_id bigint(20) unsigned NOT NULL, hp_rating tinyint(1) DEFAULT NULL, PRIMARY KEY (comment_id) ) DEFAULT CHARACTER SET utf8mb4' ); } public static function tearDownAfterClass(): void { global $wpdb; foreach ( array( self::TERMS, self::COMMENTS, self::TERM_FLAT, self::COMMENT_FLAT ) as $tbl ) { $wpdb->query( 'DROP TABLE IF EXISTS `' . $tbl . '`' ); } } protected function setUp(): void { global $wpdb; $wpdb->query( 'TRUNCATE TABLE `' . self::TERMS . '`' ); $wpdb->query( 'TRUNCATE TABLE `' . self::COMMENTS . '`' ); $wpdb->query( 'TRUNCATE TABLE `' . self::TERMMETA . '`' ); $wpdb->query( 'TRUNCATE TABLE `' . self::COMMENTMETA . '`' ); $wpdb->query( 'TRUNCATE TABLE `' . self::TERM_FLAT . '`' ); $wpdb->query( 'TRUNCATE TABLE `' . self::COMMENT_FLAT . '`' ); } // ── backfill_group ────────────────────────────────────────────────────── public function test_backfill_returns_zero_counts_for_empty_db(): void { $result = WPDO_Term_Comment_Backfill::backfill_group( 'term', 'hp_taxonomy', false ); $this->assertSame( 0, $result['candidates'] ); $this->assertSame( 0, $result['written'] ); } public function test_dry_run_does_not_write(): void { global $wpdb; $wpdb->insert( self::TERMS, array( 'term_id' => 1, 'name' => 'a' ) ); $wpdb->insert( self::TERMMETA, array( 'term_id' => 1, 'meta_key' => 'hp_sort_order', 'meta_value' => '5' ) ); $result = WPDO_Term_Comment_Backfill::backfill_group( 'term', 'hp_taxonomy', true ); $this->assertSame( 1, $result['candidates'] ); $this->assertSame( 0, $result['written'] ); $this->assertTrue( $result['dry_run'] ); $flat_count = (int) $wpdb->get_var( 'SELECT COUNT(*) FROM `' . self::TERM_FLAT . '`' ); $this->assertSame( 0, $flat_count, 'dry_run must not INSERT' ); } public function test_backfill_pivots_multi_key_into_single_row(): void { global $wpdb; $wpdb->insert( self::TERMS, array( 'term_id' => 1, 'name' => 'a' ) ); $wpdb->insert( self::TERMMETA, array( 'term_id' => 1, 'meta_key' => 'hp_sort_order', 'meta_value' => '5' ) ); $wpdb->insert( self::TERMMETA, array( 'term_id' => 1, 'meta_key' => 'hp_default', 'meta_value' => '1' ) ); $wpdb->insert( self::TERMMETA, array( 'term_id' => 1, 'meta_key' => 'hp_icon', 'meta_value' => 'fa-star' ) ); $result = WPDO_Term_Comment_Backfill::backfill_group( 'term', 'hp_taxonomy', false ); $this->assertSame( 1, $result['candidates'] ); $row = $wpdb->get_row( 'SELECT * FROM `' . self::TERM_FLAT . '` WHERE term_id = 1', ARRAY_A ); $this->assertNotNull( $row ); $this->assertSame( '5', (string) $row['hp_sort_order'] ); $this->assertSame( '1', (string) $row['hp_default'] ); $this->assertSame( 'fa-star', $row['hp_icon'] ); } public function test_backfill_handles_multiple_terms(): void { global $wpdb; for ( $i = 1; $i <= 5; $i++ ) { $wpdb->insert( self::TERMS, array( 'term_id' => $i, 'name' => 'term_' . $i ) ); $wpdb->insert( self::TERMMETA, array( 'term_id' => $i, 'meta_key' => 'hp_sort_order', 'meta_value' => $i * 10 ) ); } $result = WPDO_Term_Comment_Backfill::backfill_group( 'term', 'hp_taxonomy', false ); $this->assertSame( 5, $result['candidates'] ); $count = (int) $wpdb->get_var( 'SELECT COUNT(*) FROM `' . self::TERM_FLAT . '`' ); $this->assertSame( 5, $count ); } public function test_backfill_idempotent_on_re_run(): void { global $wpdb; $wpdb->insert( self::TERMS, array( 'term_id' => 1, 'name' => 'a' ) ); $wpdb->insert( self::TERMMETA, array( 'term_id' => 1, 'meta_key' => 'hp_sort_order', 'meta_value' => '5' ) ); WPDO_Term_Comment_Backfill::backfill_group( 'term', 'hp_taxonomy', false ); WPDO_Term_Comment_Backfill::backfill_group( 'term', 'hp_taxonomy', false ); $count = (int) $wpdb->get_var( 'SELECT COUNT(*) FROM `' . self::TERM_FLAT . '`' ); $this->assertSame( 1, $count, 'Re-running must not duplicate (PRIMARY KEY enforces)' ); } public function test_backfill_updates_existing_row_via_on_duplicate_key(): void { global $wpdb; $wpdb->insert( self::TERMS, array( 'term_id' => 1, 'name' => 'a' ) ); $wpdb->insert( self::TERM_FLAT, array( 'term_id' => 1, 'hp_sort_order' => 99 ) ); $wpdb->insert( self::TERMMETA, array( 'term_id' => 1, 'meta_key' => 'hp_sort_order', 'meta_value' => '5' ) ); WPDO_Term_Comment_Backfill::backfill_group( 'term', 'hp_taxonomy', false ); $value = $wpdb->get_var( 'SELECT hp_sort_order FROM `' . self::TERM_FLAT . '` WHERE term_id = 1' ); $this->assertSame( '5', (string) $value, 'wp_termmeta value should overwrite stale flat value' ); } public function test_backfill_handles_comment_entity(): void { global $wpdb; $wpdb->insert( self::COMMENTS, array( 'comment_ID' => 1, 'comment_post_ID' => 100 ) ); $wpdb->insert( self::COMMENTMETA, array( 'comment_id' => 1, 'meta_key' => 'hp_rating', 'meta_value' => '5' ) ); $result = WPDO_Term_Comment_Backfill::backfill_group( 'comment', 'hp_review', false ); $this->assertSame( 1, $result['candidates'] ); $value = $wpdb->get_var( 'SELECT hp_rating FROM `' . self::COMMENT_FLAT . '` WHERE comment_id = 1' ); $this->assertSame( '5', (string) $value ); } public function test_backfill_only_picks_registered_keys(): void { global $wpdb; $wpdb->insert( self::TERMS, array( 'term_id' => 1, 'name' => 'a' ) ); $wpdb->insert( self::TERMMETA, array( 'term_id' => 1, 'meta_key' => 'hp_sort_order', 'meta_value' => '5' ) ); $wpdb->insert( self::TERMMETA, array( 'term_id' => 1, 'meta_key' => 'unknown_key', 'meta_value' => 'x' ) ); $wpdb->insert( self::TERMMETA, array( 'term_id' => 1, 'meta_key' => 'note_group', 'meta_value' => 'foo' ) ); WPDO_Term_Comment_Backfill::backfill_group( 'term', 'hp_taxonomy', false ); // hp_icon and hp_default should be NULL (not in wp_termmeta). $row = $wpdb->get_row( 'SELECT * FROM `' . self::TERM_FLAT . '` WHERE term_id = 1', ARRAY_A ); $this->assertSame( '5', (string) $row['hp_sort_order'] ); $this->assertNull( $row['hp_default'] ); $this->assertNull( $row['hp_icon'] ); } public function test_backfill_unknown_group_returns_error(): void { $result = WPDO_Term_Comment_Backfill::backfill_group( 'term', 'bogus_group', false ); $this->assertArrayHasKey( 'error', $result ); $this->assertSame( 0, $result['candidates'] ); } public function test_backfill_unsupported_entity_returns_error(): void { $result = WPDO_Term_Comment_Backfill::backfill_group( 'user', 'hp_taxonomy', false ); $this->assertArrayHasKey( 'error', $result ); } // ── backfill_all ──────────────────────────────────────────────────────── public function test_backfill_all_runs_every_group(): void { global $wpdb; $wpdb->insert( self::TERMS, array( 'term_id' => 1, 'name' => 'a' ) ); $wpdb->insert( self::TERMMETA, array( 'term_id' => 1, 'meta_key' => 'hp_sort_order', 'meta_value' => '5' ) ); $wpdb->insert( self::COMMENTS, array( 'comment_ID' => 1, 'comment_post_ID' => 100 ) ); $wpdb->insert( self::COMMENTMETA, array( 'comment_id' => 1, 'meta_key' => 'hp_rating', 'meta_value' => '5' ) ); $results = WPDO_Term_Comment_Backfill::backfill_all( false ); $this->assertCount( 2, $results ); $this->assertArrayHasKey( 'hp_taxonomy', $results ); $this->assertArrayHasKey( 'hp_review', $results ); $this->assertSame( 1, $results['hp_taxonomy']['candidates'] ); $this->assertSame( 1, $results['hp_review']['candidates'] ); } }