diff --git a/features/search-replace.feature b/features/search-replace.feature index d6feee8a..84d67344 100644 --- a/features/search-replace.feature +++ b/features/search-replace.feature @@ -68,6 +68,31 @@ Feature: Do global search/replace wp_awesome """ + @require-mysql + Scenario: Skip views during search/replace + Given a WP install + And I run `wp db query "CREATE VIEW wp_posts_view AS SELECT ID, post_title FROM wp_posts;"` + + When I run `wp search-replace foo bar --all-tables-with-prefix` + Then STDOUT should contain: + """ + wp_posts_view + """ + And STDOUT should contain: + """ + skipped (view) + """ + + When I run `wp search-replace foo bar --all-tables` + Then STDOUT should contain: + """ + wp_posts_view + """ + And STDOUT should contain: + """ + skipped (view) + """ + @require-mysql Scenario: Run on unregistered, unprefixed tables with --all-tables flag Given a WP install diff --git a/src/Search_Replace_Command.php b/src/Search_Replace_Command.php index bbad1bdf..a5e2d291 100644 --- a/src/Search_Replace_Command.php +++ b/src/Search_Replace_Command.php @@ -465,14 +465,26 @@ public function __invoke( $args, $assoc_args ) { // Get table names based on leftover $args or supplied $assoc_args $tables = Utils\wp_get_table_names( $args, $assoc_args ); - foreach ( $tables as $table ) { + // Identify views so they can be skipped; views are dynamic and cannot be directly modified. + $views_args = $assoc_args; + $views_args['views-only'] = true; + $views = Utils\wp_get_table_names( [], $views_args ); + $view_set = array_flip( array_intersect( $views, $tables ) ); + foreach ( $tables as $table ) { foreach ( $this->skip_tables as $skip_table ) { if ( fnmatch( $skip_table, $table ) ) { continue 2; } } + if ( isset( $view_set[ $table ] ) ) { + if ( $this->report && ! $this->report_changed_only ) { + $report[] = array( $table, '', 'skipped (view)', '' ); + } + continue; + } + $table_sql = self::esc_sql_ident( $table ); if ( $this->export_handle ) {