diff --git a/includes/engine/class-tmdo-post-status-sync.php b/includes/engine/class-tmdo-post-status-sync.php index 03743a5..1e91217 100644 --- a/includes/engine/class-tmdo-post-status-sync.php +++ b/includes/engine/class-tmdo-post-status-sync.php @@ -65,6 +65,10 @@ final class TMDO_Post_Status_Sync { unset( $new_status, $old_status ); foreach ( self::groups_with_columns() as $group ) { $table = TMDO_Schema_Manager::get_table_name( 'post', $group ); + if ( ! TMDO_Schema_Manager::table_exists( $table ) ) { + self::forget( $group ); // The table was dropped (retired or uninstalled group). + continue; + } $wpdb->query( $wpdb->prepare( "UPDATE `{$table}` SET `post_status` = %s, `post_date` = %s WHERE `post_id` = %d", // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Registry table name. @@ -220,6 +224,20 @@ final class TMDO_Post_Status_Sync { return is_array( $states ) ? array_keys( $states ) : array(); } + /** + * Drop a group from the recorded states. + * + * @param string $group Group name. + * @return void + */ + private static function forget( string $group ): void { + $states = get_option( self::OPTION, array() ); + if ( is_array( $states ) && isset( $states[ $group ] ) ) { + unset( $states[ $group ] ); + update_option( self::OPTION, $states, true ); + } + } + /** * Record a group's state. * diff --git a/tests/integration/PostStatusSyncTest.php b/tests/integration/PostStatusSyncTest.php index b4b4310..21654bb 100644 --- a/tests/integration/PostStatusSyncTest.php +++ b/tests/integration/PostStatusSyncTest.php @@ -134,6 +134,23 @@ class PostStatusSyncTest extends TestCase { $this->assertSame( array( 'draft', '2026-02-01 10:00:00' ), $this->copies( self::A )[2], 'other posts untouched' ); } + public function test_a_group_whose_table_was_dropped_is_forgotten(): void { + global $wpdb; + TMDO_Post_Status_Sync::run(); + $wpdb->query( 'DROP TABLE `' . self::B . '`' ); + $ref = new ReflectionProperty( WPDO_Schema_Manager::class, 'table_exists_cache' ); + $ref->setAccessible( true ); + $ref->setValue( null, array() ); + $wpdb->last_error = ''; + + TMDO_Post_Status_Sync::on_transition( 'trash', 'publish', (object) array( 'ID' => 1, 'post_status' => 'trash', 'post_date' => '2026-01-05 00:00:00' ) ); + + $this->assertSame( '', (string) $wpdb->last_error, 'no UPDATE of a missing table' ); + $this->assertSame( '', TMDO_Post_Status_Sync::state( 'ps_b' ), 'forgotten' ); + $this->assertSame( 'ready', TMDO_Post_Status_Sync::state( 'ps_a' ) ); + $this->assertSame( array( 'trash', '2026-01-05 00:00:00' ), $this->copies( self::A )[1] ); + } + public function test_transition_leaves_tables_without_the_columns_alone(): void { global $wpdb; $wpdb->last_error = '';