Provides access to --path= , --url= , and other values of
the global configuration parameters.
WP_CLI::log( 'The --url= value is: ' . WP_CLI::get_config( 'url' ) );
public static get_config ( string $key = null ) : mixed | ||
$key | string | Get value for a specific global configuration parameter. |
리턴 | mixed |
/** * Registers just a 'list' and 'run' command to the WC CLI * since we only want to enable certain actions on the system status * tools endpoints. */ public static function register_commands() { global $wp_rest_server; $request = new WP_REST_Request('OPTIONS', '/wc/v1/system_status/tools'); $response = $wp_rest_server->dispatch($request); $response_data = $response->get_data(); $parent = "wc tool"; $supported_commands = array('list', 'run'); foreach ($supported_commands as $command) { $synopsis = array(); if ('run' === $command) { $synopsis[] = array('name' => 'id', 'type' => 'positional', 'description' => __('The id for the resource.', 'woocommerce'), 'optional' => false); $method = 'update_item'; $route = '/wc/v1/system_status/tools/(?P<id>[\\w-]+)'; } elseif ('list' === $command) { $synopsis[] = array('name' => 'fields', 'type' => 'assoc', 'description' => __('Limit response to specific fields. Defaults to all fields.', 'woocommerce'), 'optional' => true); $synopsis[] = array('name' => 'field', 'type' => 'assoc', 'description' => __('Get the value of an individual field.', 'woocommerce'), 'optional' => true); $synopsis[] = array('name' => 'format', 'type' => 'assoc', 'description' => __('Render response in a particular format.', 'woocommerce'), 'optional' => true, 'default' => 'table', 'options' => array('table', 'json', 'csv', 'ids', 'yaml', 'count', 'headers', 'body', 'envelope')); $method = 'list_items'; $route = '/wc/v1/system_status/tools'; } $before_invoke = null; if (empty($command_args['when']) && WP_CLI::get_config('debug')) { $before_invoke = function () { if (!defined('SAVEQUERIES')) { define('SAVEQUERIES', true); } }; } $rest_command = new WC_CLI_REST_Command('system_status_tool', $route, $response_data['schema']); WP_CLI::add_command("{$parent} {$command}", array($rest_command, $method), array('synopsis' => $synopsis, 'when' => !empty($command_args['when']) ? $command_args['when'] : '', 'before_invoke' => $before_invoke)); } }
public function run() { if (!function_exists('get_plugins')) { require_once \WP_CLI::get_config('path') . '/wp-admin/includes/plugin.php'; } $all_plugins = get_plugins(); $update = get_plugin_updates(); $report = array(); foreach ($all_plugins as $plugin_path => $data) { $slug = $plugin_path; if (stripos($plugin_path, '/')) { $slug = substr($plugin_path, 0, stripos($plugin_path, '/')); } $vulnerable = $this->is_vulnerable($slug, $data['Version']); $needs_update = 0; $available = '-'; if (isset($update[$plugin_path])) { $needs_update = 1; $available = $update[$plugin_path]->update->new_version; } if (false === $vulnerable) { $vulnerable = "None"; } else { $vulnerable = sprintf('<a href="https://wpvulndb.com/plugins/%s" target="_blank" >more info</a>', $slug); } $report[$slug] = array('slug' => $slug, 'installed' => (string) $data['Version'], 'available' => (string) $available, 'needs_update' => (string) $needs_update, 'vulnerable' => $vulnerable); } $this->alerts = $report; }
function wp_debug_mode() { if (\WP_CLI::get_config('debug')) { if (!defined('WP_DEBUG')) { define('WP_DEBUG', true); } error_reporting(E_ALL & ~E_DEPRECATED & ~E_STRICT); } else { if (WP_DEBUG) { error_reporting(E_ALL); if (WP_DEBUG_DISPLAY) { ini_set('display_errors', 1); } elseif (null !== WP_DEBUG_DISPLAY) { ini_set('display_errors', 0); } if (WP_DEBUG_LOG) { ini_set('log_errors', 1); ini_set('error_log', WP_CONTENT_DIR . '/debug.log'); } } else { error_reporting(E_CORE_ERROR | E_CORE_WARNING | E_COMPILE_ERROR | E_ERROR | E_WARNING | E_PARSE | E_USER_ERROR | E_USER_WARNING | E_RECOVERABLE_ERROR); } if (defined('XMLRPC_REQUEST') || defined('REST_REQUEST') || defined('DOING_AJAX') && DOING_AJAX) { @ini_set('display_errors', 0); } } // XDebug already sends errors to STDERR ini_set('display_errors', function_exists('xdebug_debug_zval') ? false : 'STDERR'); }
function wp_debug_mode() { if (\WP_CLI::get_config('debug')) { if (!defined('WP_DEBUG')) { define('WP_DEBUG', true); } error_reporting(E_ALL & ~E_DEPRECATED & ~E_STRICT); } else { \wp_debug_mode(); } // XDebug already sends errors to STDERR ini_set('display_errors', function_exists('xdebug_debug_zval') ? false : 'STDERR'); }
/** * Searches php files for the provided regex * * @param $dir string directory to start from * @param $regex string undelimited pattern to match * * @return array an array of matched files or empty if none found **/ public static function search_php_files($dir, $regex) { $fs = self::load_fs(); $finder = new Finder(); // find all files ending in PHP $files = $finder->files()->in($dir)->name("*.php"); $alerts = array(); foreach ($files as $file) { if (\WP_CLI::get_config('debug')) { \WP_CLI::line(sprintf("-> %s", $file->getRelativePathname())); } if (preg_match('#' . $regex . '#s', $file->getContents()) !== 0) { $alerts[] = $file->getRelativePathname(); } } return $alerts; }
public function execute() { foreach ($this->callbacks() as $class => $object) { $object->init(); } $files = $this->finder->files()->in($this->dir)->name("*.php"); foreach ($files as $file) { if (\WP_CLI::get_config('debug')) { \WP_CLI::line(sprintf("-> %s", $file->getRelativePathname())); } foreach ($this->callbacks() as $class => $object) { $object->run($file); } } foreach ($this->callbacks() as $class => $object) { $object->message(Messenger::instance()); } }
/** * Download and install theme unit test datafile * * @param string $option --data value * @since 0.2 */ private function import_test_data($option = NULL) { if ('skip' === $option) { return; } $option = NULL === $option ? 'unit-test' : $option; $datafiles = array('unit-test' => 'https://wpcom-themes.svn.automattic.com/demo/theme-unit-test-data.xml', 'wpcom-theme' => 'https://wpcom-themes.svn.automattic.com/demo/wordpress-com-theme-test.xml', 'wpcom-demo' => 'https://wpcom-themes.svn.automattic.com/demo/demo-data.xml', 'wptest' => 'https://raw.github.com/manovotny/wptest/master/wptest.xml'); $keys = array_values(array_keys($datafiles)); if (in_array($option, $keys)) { $download_url = $datafiles[$option]; } elseif (false != $option) { $download_url = $option; } else { WP_CLI::error('Missing WXR path/URL.'); } WP_CLI::line('WXR data URL: ' . $download_url); $silent = WP_CLI::get_config('quiet') ? '--silent ' : ''; $cmdline = "curl -f {$silent} {$download_url} -o /tmp/wp-cli-test-data.xml"; WP_CLI::launch($cmdline); WP_CLI::launch('wp import /tmp/wp-cli-test-data.xml --authors=skip'); }
/** * Do a REST Request * * @param string $method * */ private function do_request($method, $route, $assoc_args) { if (!defined('REST_REQUEST')) { define('REST_REQUEST', true); } $request = new WP_REST_Request($method, $route); if (in_array($method, array('POST', 'PUT'))) { $request->set_body_params($assoc_args); } else { foreach ($assoc_args as $key => $value) { $request->set_param($key, $value); } } if (defined('SAVEQUERIES') && SAVEQUERIES) { $original_queries = is_array($GLOBALS['wpdb']->queries) ? array_keys($GLOBALS['wpdb']->queries) : array(); } $response = rest_do_request($request); if (defined('SAVEQUERIES') && SAVEQUERIES) { $performed_queries = array(); foreach ((array) $GLOBALS['wpdb']->queries as $key => $query) { if (in_array($key, $original_queries)) { continue; } $performed_queries[] = $query; } usort($performed_queries, function ($a, $b) { if ($a[1] === $b[1]) { return 0; } return $a[1] > $b[1] ? -1 : 1; }); $query_count = count($performed_queries); $query_total_time = 0; foreach ($performed_queries as $query) { $query_total_time += $query[1]; } $slow_query_message = ''; if ($performed_queries && 'wc' === WP_CLI::get_config('debug')) { $slow_query_message .= '. Ordered by slowness, the queries are:' . PHP_EOL; foreach ($performed_queries as $i => $query) { $i++; $bits = explode(', ', $query[2]); $backtrace = implode(', ', array_slice($bits, 13)); $seconds = round($query[1], 6); $slow_query_message .= <<<EOT {$i}: - {$seconds} seconds - {$backtrace} - {$query[0]} EOT; $slow_query_message .= PHP_EOL; } } elseif ('wc' !== WP_CLI::get_config('debug')) { $slow_query_message = '. Use --debug=wc to see all queries.'; } $query_total_time = round($query_total_time, 6); WP_CLI::debug("wc command executed {$query_count} queries in {$query_total_time} seconds{$slow_query_message}", 'wc'); } if ($error = $response->as_error()) { WP_CLI::error($error); } return array($response->get_status(), $response->get_data(), $response->get_headers()); }
/** * Invoke the subcommand with the supplied arguments. * Given a --prompt argument, interactively request input * from the end user. * * @param array $args * @param array $assoc_args */ public function invoke($args, $assoc_args, $extra_args) { if (\WP_CLI::get_config('prompt')) { list($args, $assoc_args) = $this->prompt_args($args, $assoc_args); } $to_unset = $this->validate_args($args, $assoc_args, $extra_args); foreach ($to_unset as $key) { unset($assoc_args[$key]); } $path = get_path($this->get_parent()); \WP_CLI::do_hook('before_invoke:' . implode(' ', array_slice($path, 1))); call_user_func($this->when_invoked, $args, array_merge($extra_args, $assoc_args)); }
function apache_get_modules() { return WP_CLI::get_config('apache_modules'); }
/** * 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); } } }
/** * Generates command information and tells WP CLI about all * commands avaiable from a route. * * @param string $rest_command * @param string $route * @param array $route_data * @param array $command_args */ private static function register_route_commands($rest_command, $route, $route_data, $command_args = array()) { $parent = "wc {$route_data['schema']['title']}"; $supported_commands = array(); // Get a list of supported commands for each route. foreach ($route_data['endpoints'] as $endpoint) { $parsed_args = preg_match_all('#\\([^\\)]+\\)#', $route, $matches); $first_match = $matches[0]; $resource_id = !empty($matches[0]) ? array_pop($matches[0]) : null; $trimmed_route = rtrim($route); $is_singular = $resource_id === substr($trimmed_route, -strlen($resource_id)); if (!$is_singular) { $resource_id = $first_match; } $command = ''; // List a collection if (array('GET') == $endpoint['methods'] && !$is_singular) { $supported_commands['list'] = !empty($endpoint['args']) ? $endpoint['args'] : array(); } // Create a specific resource if (array('POST') == $endpoint['methods'] && !$is_singular) { $supported_commands['create'] = !empty($endpoint['args']) ? $endpoint['args'] : array(); } // Get a specific resource if (array('GET') == $endpoint['methods'] && $is_singular) { $supported_commands['get'] = !empty($endpoint['args']) ? $endpoint['args'] : array(); } // Update a specific resource if (in_array('POST', $endpoint['methods']) && $is_singular) { $supported_commands['update'] = !empty($endpoint['args']) ? $endpoint['args'] : array(); } // Delete a specific resource if (array('DELETE') == $endpoint['methods'] && $is_singular) { $supported_commands['delete'] = !empty($endpoint['args']) ? $endpoint['args'] : array(); } } foreach ($supported_commands as $command => $endpoint_args) { $synopsis = array(); $arg_regs = array(); if (strpos($route, '<product_id>') !== false) { $synopsis[] = array('name' => 'product_id', 'type' => 'positional', 'description' => __('Product ID.', 'woocommerce')); } if (strpos($route, '<customer_id>') !== false) { $synopsis[] = array('name' => 'customer_id', 'type' => 'positional', 'description' => __('Customer ID.', 'woocommerce')); } if (strpos($route, '<order_id>') !== false) { $synopsis[] = array('name' => 'order_id', 'type' => 'positional', 'description' => __('Order ID.', 'woocommerce')); } if (strpos($route, '<refund_id>') !== false) { $synopsis[] = array('name' => 'refund_id', 'type' => 'positional', 'description' => __('Refund ID.', 'woocommerce')); } if (in_array($command, array('delete', 'get', 'update'))) { $synopsis[] = array('name' => 'id', 'type' => 'positional', 'description' => __('The id for the resource.', 'woocommerce'), 'optional' => false); } foreach ($endpoint_args as $name => $args) { $arg_regs[] = array('name' => $name, 'type' => 'assoc', 'description' => !empty($args['description']) ? $args['description'] : '', 'optional' => empty($args['required']) ? true : false); } foreach ($arg_regs as $arg_reg) { $synopsis[] = $arg_reg; } if (in_array($command, array('list', 'get'))) { $synopsis[] = array('name' => 'fields', 'type' => 'assoc', 'description' => __('Limit response to specific fields. Defaults to all fields.', 'woocommerce'), 'optional' => true); $synopsis[] = array('name' => 'field', 'type' => 'assoc', 'description' => __('Get the value of an individual field.', 'woocommerce'), 'optional' => true); $synopsis[] = array('name' => 'format', 'type' => 'assoc', 'description' => __('Render response in a particular format.', 'woocommerce'), 'optional' => true, 'default' => 'table', 'options' => array('table', 'json', 'csv', 'ids', 'yaml', 'count', 'headers', 'body', 'envelope')); } if (in_array($command, array('create', 'update', 'delete'))) { $synopsis[] = array('name' => 'porcelain', 'type' => 'flag', 'description' => __('Output just the id when the operation is successful.', 'woocommerce'), 'optional' => true); } $methods = array('list' => 'list_items', 'create' => 'create_item', 'delete' => 'delete_item', 'get' => 'get_item', 'update' => 'update_item'); $before_invoke = null; if (empty($command_args['when']) && \WP_CLI::get_config('debug')) { $before_invoke = function () { if (!defined('SAVEQUERIES')) { define('SAVEQUERIES', true); } }; } WP_CLI::add_command("{$parent} {$command}", array($rest_command, $methods[$command]), array('synopsis' => $synopsis, 'when' => !empty($command_args['when']) ? $command_args['when'] : '', 'before_invoke' => $before_invoke)); } }
/** * 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 all tables and will replace all * appearances of the old string with the new one. * * 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. * * [--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 * * [--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. 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 */ 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'); $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')); // 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'; } // 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) { WP_CLI::success("Made {$total} replacements."); } } }
/** * 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); } } }
/** * Lint your WordPress code using WP CLI. * * ### Config * You can add the path to the `phpcs` bin to use in WP CLI's config file and/or the standard that should be used. * * Example of `~/.wp-cli/config.yml`: * * lint: * phpcs: /path/to/phpcs * standard: `WordPress-Extra` * * ### Options * * #### `[<directory>]` * The directory to lint code in. **Default: '__DIR__'** * * #### `[--standard=<standard>]` * The standard to use when running `phpcs`. **Default: 'WordPress-Core'** * * ### Examples * * wp lint * wp lint path/to/code --standard=WordPress-Extra * * @param array $args * @param array $options * * @when before_wp_load */ public function __invoke(array $args = [], array $options = []) { if (empty($args)) { $args[] = getcwd(); } if (!file_exists($args[0])) { WP_CLI::error(sprintf('The file "%s" does not exist', $args[0])); } $root_path = rtrim(ABSPATH, '/'); $phpcs_bin = $this->get_phpcs_bin($root_path); $phpcs_standard = $this->get_phpcs_standard($root_path, $options); $command_args = '-s --extensions=php --standard=' . $phpcs_standard; $command = sprintf('%s %s %s', $phpcs_bin, $command_args, $args[0]); if (WP_CLI::get_config('debug')) { echo sprintf("Running command: %s \n", $command); } exec($command, $output, $status); if (count($output) === 1 && strpos($output[0], 'ERROR') === false) { $output = []; } foreach ($output as $line) { if (strpos($output[0], 'ERROR') === false) { WP_CLI::log($line); } else { WP_CLI::error(str_replace('ERROR: ', '', $line)); } } if ($status !== 0) { WP_CLI::error('Sorry, but your code does not follow the code style. Please fix before commit.'); } else { WP_CLI::success('Good job! Your code follows the code style.'); } }
/** * Invoke the subcommand with the supplied arguments. * Given a --prompt argument, interactively request input * from the end user. * * @param array $args * @param array $assoc_args */ public function invoke($args, $assoc_args, $extra_args) { static $prompted_once = false; if (\WP_CLI::get_config('prompt') && !$prompted_once) { list($args, $assoc_args) = $this->prompt_args($args, $assoc_args); $prompted_once = true; } list($to_unset, $args, $assoc_args, $extra_args) = $this->validate_args($args, $assoc_args, $extra_args); foreach ($to_unset as $key) { unset($assoc_args[$key]); } $path = get_path($this->get_parent()); $parent = implode(' ', array_slice($path, 1)); $cmd = $parent . ' ' . $this->name; WP_CLI::do_hook("before_invoke:{$parent}"); WP_CLI::do_hook("before_invoke:{$cmd}"); call_user_func($this->when_invoked, $args, array_merge($extra_args, $assoc_args)); WP_CLI::do_hook("after_invoke:{$parent}"); WP_CLI::do_hook("after_invoke:{$cmd}"); }
/** * Search/replace strings in the database. * * ## DESCRIPTION * * This command will go through all rows in all tables and will replace all * appearances of the old string with the new one. * * 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. * * [--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 * * ## 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 */ public function __invoke($args, $assoc_args) { global $wpdb; $old = array_shift($args); $new = array_shift($args); $total = 0; $report = array(); $dry_run = isset($assoc_args['dry-run']); $php_only = isset($assoc_args['precise']); $recurse_objects = isset($assoc_args['recurse-objects']); if (isset($assoc_args['skip-columns'])) { $skip_columns = explode(',', $assoc_args['skip-columns']); } else { $skip_columns = array(); } // never mess with hashed passwords $skip_columns[] = 'user_pass'; $tables = self::get_table_list($args, isset($assoc_args['network'])); 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 || NULL !== $serialRow) { $type = 'PHP'; $count = self::php_handle_col($col, $primary_keys, $table, $old, $new, $dry_run, $recurse_objects); } else { $type = 'SQL'; $count = self::sql_handle_col($col, $table, $old, $new, $dry_run); } $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) { WP_CLI::success("Made {$total} replacements."); } } }