diff --git a/inc/duplication/data.php b/inc/duplication/data.php index d32807b7..c366cec0 100644 --- a/inc/duplication/data.php +++ b/inc/duplication/data.php @@ -154,10 +154,9 @@ public static function db_copy_tables($from_site_id, $to_site_id) { * * Runtime-only tables are skipped by default because queues, logs, caches, * analytics, and sessions are regenerated on the destination site. Empty - * optional/custom tables are also skipped to avoid spending most of the - * duplication time cloning schemas with no template data. WordPress core - * content/config tables are always copied because wpmu_create_blog() creates - * destination defaults that must be replaced with template values. + * per-site tables are copied by default so plugins retain the complete schema + * they expect on the destination. Installations can opt into skipping empty + * optional tables through the dedicated filter. * * @since 2.5.1 * @@ -182,7 +181,7 @@ public static function should_copy_table($table, $table_base_name, $from_site_id * * Returning true forces a table to be copied; returning false skips it. * This preserves extension control over custom table duplication while - * keeping the default path optimized for empty/runtime template tables. + * keeping runtime table exclusions centralized. * * @since 2.5.1 * @@ -297,7 +296,7 @@ private static function skip_empty_tables($from_site_id, $to_site_id) { * @param int $from_site_id Source site ID. * @param int $to_site_id Target site ID. */ - return (bool) apply_filters('wu_mucd_skip_empty_tables', true, $from_site_id, $to_site_id); + return (bool) apply_filters('wu_mucd_skip_empty_tables', false, $from_site_id, $to_site_id); } /** diff --git a/tests/WP_Ultimo/Duplication/MUCD_Data_Test.php b/tests/WP_Ultimo/Duplication/MUCD_Data_Test.php index 3cbfcab7..279f08ae 100644 --- a/tests/WP_Ultimo/Duplication/MUCD_Data_Test.php +++ b/tests/WP_Ultimo/Duplication/MUCD_Data_Test.php @@ -642,18 +642,19 @@ public function test_should_copy_table_skips_runtime_tables() { } /** - * Test empty optional template tables are skipped by default. + * Test empty optional template tables are copied by default. */ - public function test_should_copy_table_skips_empty_optional_tables() { + public function test_should_copy_table_keeps_empty_optional_tables_by_default() { global $wpdb; - $table = $wpdb->get_blog_prefix() . 'wu_empty_runtime_fixture'; + $table_base_name = 'fc_wp_ultimo_test_subscriber_pivot'; + $table = $wpdb->get_blog_prefix() . $table_base_name; $this->create_table_selection_fixture($table); try { - $this->assertFalse( - \MUCD_Data::should_copy_table($table, 'wu_empty_runtime_fixture', get_current_blog_id(), 123) + $this->assertTrue( + \MUCD_Data::should_copy_table($table, $table_base_name, get_current_blog_id(), 123) ); } finally { $this->drop_table_selection_fixture($table); @@ -695,6 +696,30 @@ public function test_should_copy_table_keeps_required_tables_even_when_empty() { ); } + /** + * Test installations can opt into skipping empty optional tables. + */ + public function test_should_copy_table_can_skip_empty_optional_tables_when_enabled() { + global $wpdb; + + $table = $wpdb->get_blog_prefix() . 'wu_empty_runtime_fixture'; + $filter = static function () { + return true; + }; + + $this->create_table_selection_fixture($table); + add_filter('wu_mucd_skip_empty_tables', $filter, 10, 3); + + try { + $this->assertFalse( + \MUCD_Data::should_copy_table($table, 'wu_empty_runtime_fixture', get_current_blog_id(), 123) + ); + } finally { + remove_filter('wu_mucd_skip_empty_tables', $filter, 10); + $this->drop_table_selection_fixture($table); + } + } + /** * Test filters can force-copy a table skipped by default. */ @@ -752,7 +777,8 @@ private function create_table_selection_fixture($table): void { $this->drop_table_selection_fixture($table); - $wpdb->query( // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Test fixture table name cannot be bound. + $wpdb->query( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Test fixture table name cannot be bound. + // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Test fixture table name cannot be bound. "CREATE TABLE `{$table}` (id bigint(20) unsigned NOT NULL AUTO_INCREMENT, value varchar(20) NOT NULL DEFAULT '', PRIMARY KEY (id))" ); }