/** * Attempts to determine which object cache is being used. * * Note that the guesses made by this function are based on the * WP_Object_Cache classes that define the 3rd party object cache extension. * Changes to those classes could render problems with this function's * ability to determine which object cache is being used. * * ## EXAMPLES * * # Check cache type. * $ wp cache type * Default */ public function type($args, $assoc_args) { $message = WP_CLI\Utils\wp_get_cache_type(); WP_CLI::line($message); }
/** * Search/replace strings in the database. * * ## DESCRIPTION * * This command will go through all rows in a selection of tables * and will replace all appearances of the old string with the new one. The * default tables are those registered on the $wpdb object (usually * just WordPress core tables). * * It will correctly handle serialized values, and will not change primary key values. * * ## OPTIONS * * <old> * : The old string. * * <new> * : The new string. * * [<table>...] * : List of database tables to restrict the replacement to. Wildcards are supported, e.g. wp_\*_options or wp_post\?. * * [--network] * : Search/replace through all the tables in a multisite install. * * [--skip-columns=<columns>] * : Do not perform the replacement in the comma-separated columns. * * [--dry-run] * : Show report, but don't perform the changes. * * [--precise] * : Force the use of PHP (instead of SQL) which is more thorough, but slower. Use if you see issues with serialized data. * * [--recurse-objects] * : Enable recursing into objects to replace strings. Defaults to true; pass --no-recurse-objects to disable. * * [--all-tables-with-prefix] * : Enable replacement on any tables that match the table prefix even if not registered on wpdb * * [--all-tables] * : Enable replacement on ALL tables in the database, regardless of the prefix, and even if not registered on $wpdb. Overrides --network and --all-tables-with-prefix. * * [--verbose] * : Prints rows to the console as they're updated. * * [--regex] * : Runs the search using a regular expression. Warning: search-replace will take about 15-20x longer when using --regex. * * ## EXAMPLES * * wp search-replace 'http://example.dev' 'http://example.com' --skip-columns=guid * * wp search-replace 'foo' 'bar' wp_posts wp_postmeta wp_terms --dry-run * * # Turn your production database into a local database * wp search-replace --url=example.com example.com example.dev wp_\*_options */ public function __invoke($args, $assoc_args) { global $wpdb; $old = array_shift($args); $new = array_shift($args); $total = 0; $report = array(); $dry_run = \WP_CLI\Utils\get_flag_value($assoc_args, 'dry-run'); $php_only = \WP_CLI\Utils\get_flag_value($assoc_args, 'precise'); $recurse_objects = \WP_CLI\Utils\get_flag_value($assoc_args, 'recurse-objects', true); $verbose = \WP_CLI\Utils\get_flag_value($assoc_args, 'verbose'); $regex = \WP_CLI\Utils\get_flag_value($assoc_args, 'regex'); $skip_columns = explode(',', \WP_CLI\Utils\get_flag_value($assoc_args, 'skip-columns')); if ($old === $new && !$regex) { WP_CLI::warning("Replacement value '{$old}' is identical to search value '{$new}'. Skipping operation."); exit; } // never mess with hashed passwords $skip_columns[] = 'user_pass'; // Determine how to limit the list of tables. Defaults to 'wordpress' $table_type = 'wordpress'; if (\WP_CLI\Utils\get_flag_value($assoc_args, 'network')) { $table_type = 'network'; } if (\WP_CLI\Utils\get_flag_value($assoc_args, 'all-tables-with-prefix')) { $table_type = 'all-tables-with-prefix'; } if (\WP_CLI\Utils\get_flag_value($assoc_args, 'all-tables')) { $table_type = 'all-tables'; } if (!empty($args)) { $new_tables = array(); foreach ($args as $key => $table) { if (false !== strpos($table, '*') || false !== strpos($table, '?')) { $expanded_tables = self::get_tables_for_glob($table); if (empty($expanded_tables)) { WP_CLI::error("Couldn't find any tables matching: {$table}"); } $new_tables = array_merge($new_tables, $expanded_tables); } else { $new_tables[] = $table; } } $args = $new_tables; } // Get the array of tables to work with. If there is anything left in $args, assume those are table names to use $tables = empty($args) ? self::get_table_list($table_type) : $args; foreach ($tables as $table) { list($primary_keys, $columns) = self::get_columns($table); // since we'll be updating one row at a time, // we need a primary key to identify the row if (empty($primary_keys)) { $report[] = array($table, '', 'skipped'); continue; } foreach ($columns as $col) { if (in_array($col, $skip_columns)) { continue; } if (!$php_only) { $serialRow = $wpdb->get_row("SELECT * FROM `{$table}` WHERE `{$col}` REGEXP '^[aiO]:[1-9]' LIMIT 1"); } if ($php_only || $regex || NULL !== $serialRow) { $type = 'PHP'; $count = self::php_handle_col($col, $primary_keys, $table, $old, $new, $dry_run, $recurse_objects, $verbose, $regex); } else { $type = 'SQL'; $count = self::sql_handle_col($col, $table, $old, $new, $dry_run, $verbose); } $report[] = array($table, $col, $count, $type); $total += $count; } } if (!WP_CLI::get_config('quiet')) { $table = new \cli\Table(); $table->setHeaders(array('Table', 'Column', 'Replacements', 'Type')); $table->setRows($report); $table->display(); if (!$dry_run) { $success_message = "Made {$total} replacements."; if ($total && 'Default' !== WP_CLI\Utils\wp_get_cache_type()) { $success_message .= ' Please remember to flush your persistent object cache with `wp cache flush`.'; } WP_CLI::success($success_message); } } }
/** * Search/replace strings in the database. * * ## DESCRIPTION * * This command will go through all rows in a selection of tables * and will replace all appearances of the old string with the new one. The * default tables are those registered on the $wpdb object (usually * just WordPress core tables). * * It will correctly handle serialized values, and will not change primary key values. * * ## OPTIONS * * <old> * : The old string. * * <new> * : The new string. * * [<table>...] * : List of database tables to restrict the replacement to. Wildcards are supported, e.g. wp_\*_options or wp_post\?. * * [--network] * : Search/replace through all the tables in a multisite install. * * [--skip-columns=<columns>] * : Do not perform the replacement in the comma-separated columns. * * [--dry-run] * : Show report, but don't perform the changes. * * [--precise] * : Force the use of PHP (instead of SQL) which is more thorough, but slower. Use if you see issues with serialized data. * * [--recurse-objects] * : Enable recursing into objects to replace strings. Defaults to true; pass --no-recurse-objects to disable. * * [--all-tables-with-prefix] * : Enable replacement on any tables that match the table prefix even if not registered on wpdb * * [--all-tables] * : Enable replacement on ALL tables in the database, regardless of the prefix, and even if not registered on $wpdb. Overrides --network and --all-tables-with-prefix. * * [--verbose] * : Prints rows to the console as they're updated. * * [--regex] * : Runs the search using a regular expression. Warning: search-replace will take about 15-20x longer when using --regex. * * [--export[=<file>]] * : Write transformed data as SQL file instead of performing in-place replacements. If <file> is not supplied, will output to STDOUT. * * ## EXAMPLES * * wp search-replace 'http://example.dev' 'http://example.com' --skip-columns=guid * * wp search-replace 'foo' 'bar' wp_posts wp_postmeta wp_terms --dry-run * * # Turn your production database into a local database * wp search-replace --url=example.com example.com example.dev wp_\*_options * * # Search/replace to a SQL file without transforming the database * wp search-replace foo bar --export=database.sql */ public function __invoke($args, $assoc_args) { global $wpdb; $old = array_shift($args); $new = array_shift($args); $total = 0; $report = array(); $this->dry_run = \WP_CLI\Utils\get_flag_value($assoc_args, 'dry-run'); $php_only = \WP_CLI\Utils\get_flag_value($assoc_args, 'precise'); $this->recurse_objects = \WP_CLI\Utils\get_flag_value($assoc_args, 'recurse-objects', true); $this->verbose = \WP_CLI\Utils\get_flag_value($assoc_args, 'verbose'); $this->regex = \WP_CLI\Utils\get_flag_value($assoc_args, 'regex'); $this->skip_columns = explode(',', \WP_CLI\Utils\get_flag_value($assoc_args, 'skip-columns')); if ($old === $new && !$this->regex) { WP_CLI::warning("Replacement value '{$old}' is identical to search value '{$new}'. Skipping operation."); exit; } if (null !== ($export = \WP_CLI\Utils\get_flag_value($assoc_args, 'export'))) { if ($this->dry_run) { WP_CLI::error('You cannot supply --dry-run and --export at the same time.'); } if (true === $export) { $this->export_handle = STDOUT; $this->verbose = false; } else { $this->export_handle = fopen($assoc_args['export'], 'w'); if (false === $this->export_handle) { WP_CLI::error(sprintf('Unable to open "%s" for writing.', $assoc_args['export'])); } } $php_only = true; } // never mess with hashed passwords $this->skip_columns[] = 'user_pass'; // Get table names based on leftover $args or supplied $assoc_args $tables = \WP_CLI\Utils\wp_get_table_names($args, $assoc_args); foreach ($tables as $table) { if ($this->export_handle) { fwrite($this->export_handle, "\nDROP TABLE IF EXISTS `{$table}`;\n"); $row = $wpdb->get_row("SHOW CREATE TABLE `{$table}`", ARRAY_N); fwrite($this->export_handle, $row[1] . ";\n"); list($table_report, $total_rows) = $this->php_export_table($table, $old, $new); $report = array_merge($report, $table_report); $total += $total_rows; // Don't perform replacements on the actual database continue; } list($primary_keys, $columns, $all_columns) = self::get_columns($table); // since we'll be updating one row at a time, // we need a primary key to identify the row if (empty($primary_keys)) { $report[] = array($table, '', 'skipped'); continue; } foreach ($columns as $col) { if (in_array($col, $this->skip_columns)) { continue; } if ($this->verbose) { $this->start_time = microtime(true); WP_CLI::log(sprintf('Checking: %s.%s', $table, $col)); } if (!$php_only && !$this->regex) { $serialRow = $wpdb->get_row("SELECT * FROM `{$table}` WHERE `{$col}` REGEXP '^[aiO]:[1-9]' LIMIT 1"); } if ($php_only || $this->regex || NULL !== $serialRow) { $type = 'PHP'; $count = $this->php_handle_col($col, $primary_keys, $table, $old, $new); } else { $type = 'SQL'; $count = $this->sql_handle_col($col, $table, $old, $new); } $report[] = array($table, $col, $count, $type); $total += $count; } } if ($this->export_handle && STDOUT !== $this->export_handle) { fclose($this->export_handle); } // Only informational output after this point if (WP_CLI::get_config('quiet') || STDOUT === $this->export_handle) { return; } $table = new \cli\Table(); $table->setHeaders(array('Table', 'Column', 'Replacements', 'Type')); $table->setRows($report); $table->display(); if (!$this->dry_run) { if (!empty($assoc_args['export'])) { $success_message = "Made {$total} replacements and exported to {$assoc_args['export']}."; } else { $success_message = "Made {$total} replacements."; if ($total && 'Default' !== WP_CLI\Utils\wp_get_cache_type()) { $success_message .= ' Please remember to flush your persistent object cache with `wp cache flush`.'; } } WP_CLI::success($success_message); } }
/** * Search/replace strings in the database. * * ## DESCRIPTION * * This command will go through all rows in a selection of tables * and will replace all appearances of the old string with the new one. The * default tables are those registered on the $wpdb object (usually * just WordPress core tables). * * It will correctly handle serialized values, and will not change primary key values. * * ## OPTIONS * * <old> * : The old string. * * <new> * : The new string. * * [<table>...] * : List of database tables to restrict the replacement to. Wildcards are supported, e.g. wp_\*_options or wp_post\?. * * [--network] * : Search/replace through all the tables in a multisite install. * * [--skip-columns=<columns>] * : Do not perform the replacement in the comma-separated columns. * * [--dry-run] * : Show report, but don't perform the changes. * * [--precise] * : Force the use of PHP (instead of SQL) which is more thorough, but slower. Use if you see issues with serialized data. * * [--recurse-objects] * : Enable recursing into objects to replace strings. Defaults to true; pass --no-recurse-objects to disable. * * [--all-tables-with-prefix] * : Enable replacement on any tables that match the table prefix even if not registered on wpdb * * [--all-tables] * : Enable replacement on ALL tables in the database, regardless of the prefix, and even if not registered on $wpdb. Overrides --network and --all-tables-with-prefix. * * [--verbose] * : Prints rows to the console as they're updated. * * [--regex] * : Runs the search using a regular expression. Warning: search-replace will take about 15-20x longer when using --regex. * * ## EXAMPLES * * wp search-replace 'http://example.dev' 'http://example.com' --skip-columns=guid * * wp search-replace 'foo' 'bar' wp_posts wp_postmeta wp_terms --dry-run * * # Turn your production database into a local database * wp search-replace --url=example.com example.com example.dev wp_\*_options */ public function __invoke($args, $assoc_args) { global $wpdb; $old = array_shift($args); $new = array_shift($args); $total = 0; $report = array(); $dry_run = \WP_CLI\Utils\get_flag_value($assoc_args, 'dry-run'); $php_only = \WP_CLI\Utils\get_flag_value($assoc_args, 'precise'); $recurse_objects = \WP_CLI\Utils\get_flag_value($assoc_args, 'recurse-objects', true); $verbose = \WP_CLI\Utils\get_flag_value($assoc_args, 'verbose'); $regex = \WP_CLI\Utils\get_flag_value($assoc_args, 'regex'); $skip_columns = explode(',', \WP_CLI\Utils\get_flag_value($assoc_args, 'skip-columns')); if ($old === $new && !$regex) { WP_CLI::warning("Replacement value '{$old}' is identical to search value '{$new}'. Skipping operation."); exit; } // never mess with hashed passwords $skip_columns[] = 'user_pass'; // Get table names based on leftover $args or supplied $assoc_args $tables = \WP_CLI\Utils\wp_get_table_names($args, $assoc_args); foreach ($tables as $table) { list($primary_keys, $columns) = self::get_columns($table); // since we'll be updating one row at a time, // we need a primary key to identify the row if (empty($primary_keys)) { $report[] = array($table, '', 'skipped'); continue; } foreach ($columns as $col) { if (in_array($col, $skip_columns)) { continue; } if ($verbose) { $this->start_time = microtime(true); WP_CLI::log(sprintf('Checking: %s.%s', $table, $col)); } if (!$php_only) { $serialRow = $wpdb->get_row("SELECT * FROM `{$table}` WHERE `{$col}` REGEXP '^[aiO]:[1-9]' LIMIT 1"); } if ($php_only || $regex || NULL !== $serialRow) { $type = 'PHP'; $count = $this->php_handle_col($col, $primary_keys, $table, $old, $new, $dry_run, $recurse_objects, $verbose, $regex); } else { $type = 'SQL'; $count = $this->sql_handle_col($col, $table, $old, $new, $dry_run, $verbose); } $report[] = array($table, $col, $count, $type); $total += $count; } } if (!WP_CLI::get_config('quiet')) { $table = new \cli\Table(); $table->setHeaders(array('Table', 'Column', 'Replacements', 'Type')); $table->setRows($report); $table->display(); if (!$dry_run) { $success_message = "Made {$total} replacements."; if ($total && 'Default' !== WP_CLI\Utils\wp_get_cache_type()) { $success_message .= ' Please remember to flush your persistent object cache with `wp cache flush`.'; } WP_CLI::success($success_message); } } }