diff --git a/README.md b/README.md index a0a88377..24552a90 100644 --- a/README.md +++ b/README.md @@ -527,7 +527,7 @@ defined in the SQL. Finds a string in the database. ~~~ -wp db search [...] [--network] [--all-tables-with-prefix] [--all-tables] [--before_context=] [--after_context=] [--regex] [--regex-flags=] [--regex-delimiter=] [--table_column_once] [--one_line] [--matches_only] [--stats] [--table_column_color=] [--id_color=] [--match_color=] +wp db search [...] [--network] [--all-tables-with-prefix] [--all-tables] [--before_context=] [--after_context=] [--regex] [--regex-flags=] [--regex-delimiter=] [--table_column_once] [--one_line] [--matches_only] [--stats] [--table_column_color=] [--id_color=] [--match_color=] [--fields=] [--format=] ~~~ Searches through all of the text columns in a selection of database tables for a given string, Outputs colorized references to the string. @@ -593,6 +593,12 @@ Defaults to searching through all tables registered to $wpdb. On multisite, this [--match_color=] Percent color code to use for the match (unless both before and after context are 0, when no color code is used). For a list of available percent color codes, see below. Default '%3%k' (black on a mustard background). + [--fields=] + Get a specific subset of the fields. + + [--format=] + Render output in a particular format. + The percent color codes available are: | Code | Color @@ -661,6 +667,21 @@ They can be concatenated. For instance, the default match color of black on a mu # SQL search and delete records from database table 'wp_options' where 'option_name' match 'foo' wp db query "DELETE from wp_options where option_id in ($(wp db query "SELECT GROUP_CONCAT(option_id SEPARATOR ',') from wp_options where option_name like '%foo%';" --silent --skip-column-names))" + # Search for a string and print the result as a table + $ wp db search https://localhost:8889 --format=table --fields=table,column,match + +------------+--------------+-----------------------------+ + | table | column | match | + +------------+--------------+-----------------------------+ + | wp_options | option_value | https://localhost:8889 | + | wp_options | option_value | https://localhost:8889 | + | wp_posts | guid | https://localhost:8889/?p=1 | + | wp_users | user_url | https://localhost:8889 | + +------------+--------------+-----------------------------+ + + # Search for a string and get only the IDs (only works for a single table) + $ wp db search https://localhost:8889 wp_options --format=ids + 1 2 + ### wp db tables diff --git a/features/db-search.feature b/features/db-search.feature index 8e929d00..1f5e8f5b 100644 --- a/features/db-search.feature +++ b/features/db-search.feature @@ -1066,3 +1066,23 @@ Feature: Search through the database :aöXYXYX """ And STDERR should be empty + + Scenario: Search for a string and output the format as a table + Given a WP install + + When I run `wp db search mail.example.com --format=csv` + Then STDOUT should contain: + """ + wp_options,option_value,mail.example.com,option_id + """ + + When I try `wp db search example.com --format=ids` + Then STDERR should be: + """ + Error: The "ids" format can only be used for a single table. + """ + And STDOUT should be empty + And the return code should be 1 + + When I run `wp db search mail.example.com wp_options --format=ids` + Then STDOUT should not be empty diff --git a/src/DB_Command.php b/src/DB_Command.php index 484d259c..308fe357 100644 --- a/src/DB_Command.php +++ b/src/DB_Command.php @@ -1225,6 +1225,12 @@ public function prefix() { * [--match_color=] * : Percent color code to use for the match (unless both before and after context are 0, when no color code is used). For a list of available percent color codes, see below. Default '%3%k' (black on a mustard background). * + * [--fields=] + * : Get a specific subset of the fields. + * + * [--format=] + * : Render output in a particular format. + * * The percent color codes available are: * * | Code | Color @@ -1293,6 +1299,21 @@ public function prefix() { * # SQL search and delete records from database table 'wp_options' where 'option_name' match 'foo' * wp db query "DELETE from wp_options where option_id in ($(wp db query "SELECT GROUP_CONCAT(option_id SEPARATOR ',') from wp_options where option_name like '%foo%';" --silent --skip-column-names))" * + * # Search for a string and print the result as a table + * $ wp db search https://localhost:8889 --format=table --fields=table,column,match + * +------------+--------------+-----------------------------+ + * | table | column | match | + * +------------+--------------+-----------------------------+ + * | wp_options | option_value | https://localhost:8889 | + * | wp_options | option_value | https://localhost:8889 | + * | wp_posts | guid | https://localhost:8889/?p=1 | + * | wp_users | user_url | https://localhost:8889 | + * +------------+--------------+-----------------------------+ + * + * # Search for a string and get only the IDs (only works for a single table) + * $ wp db search https://localhost:8889 wp_options --format=ids + * 1 2 + * * @when after_wp_load */ public function search( $args, $assoc_args ) { @@ -1332,6 +1353,8 @@ public function search( $args, $assoc_args ) { $one_line = Utils\get_flag_value( $assoc_args, 'one_line', false ); $matches_only = Utils\get_flag_value( $assoc_args, 'matches_only', false ); $stats = Utils\get_flag_value( $assoc_args, 'stats', false ); + $fields = Utils\get_flag_value( $assoc_args, 'fields' ); + $format = Utils\get_flag_value( $assoc_args, 'format' ); $column_count = 0; $row_count = 0; @@ -1366,6 +1389,8 @@ public function search( $args, $assoc_args ) { $tables = Utils\wp_get_table_names( $args, $assoc_args ); + $search_results = []; + $start_search_time = microtime( true ); foreach ( $tables as $table ) { @@ -1409,7 +1434,7 @@ public function search( $args, $assoc_args ) { foreach ( $results as $result ) { $col_val = $result->$column; if ( preg_match_all( $search_regex, $col_val, $matches, PREG_OFFSET_CAPTURE ) ) { - if ( ! $matches_only && ( ! $table_column_once || ! $outputted_table_column_once ) && ! $one_line ) { + if ( ! $format && ! $matches_only && ( ! $table_column_once || ! $outputted_table_column_once ) && ! $one_line ) { WP_CLI::log( $table_column_val ); $outputted_table_column_once = true; } @@ -1457,13 +1482,50 @@ public function search( $args, $assoc_args ) { $match_count += $match_cnt; $col_val = implode( ' [...] ', $bits ); - WP_CLI::log( $matches_only ? $col_val : ( $one_line ? "{$table_column_val}:{$pk_val}{$col_val}" : "{$pk_val}{$col_val}" ) ); + if ( $format ) { + $search_results[] = [ + 'table' => $table, + 'column' => $column, + // Remove the colors for the format output. + 'match' => str_replace( + [ $colors['match'][0], $colors['match'][1] ], + [ '','' ], + $col_val + ), + 'primary_key_name' => $primary_key, + 'primary_key_value' => $result->$primary_key, + ]; + } else { + WP_CLI::log( $matches_only ? $col_val : ( $one_line ? "{$table_column_val}:{$pk_val}{$col_val}" : "{$pk_val}{$col_val}" ) ); + } } } } } } + if ( $format ) { + $formatter_args = [ + 'format' => $format, + ]; + $formatter_fields = [ 'table', 'column', 'match', 'primary_key_name', 'primary_key_value' ]; + + if ( $fields ) { + $fields = explode( ',', $assoc_args['fields'] ); + $formatter_fields = array_values( array_intersect( $formatter_fields, $fields ) ); + } + + if ( in_array( $format, [ 'ids', 'count' ], true ) ) { + if ( count( $tables ) > 1 ) { + WP_CLI::error( 'The "ids" format can only be used for a single table.' ); + } + $search_results = array_column( $search_results, 'primary_key_value' ); + } + + $formatter = new Formatter( $formatter_args, $formatter_fields ); + $formatter->display_items( $search_results ); + } + if ( $stats ) { $table_count = count( $tables ); $skipped_count = count( $skipped );