Error message is written to STDERR. Defaults to halting script execution
with return code 1.
Use WP_CLI::warning() instead when script execution should be permitted
to continue.
# wp cache flush considers flush failure to be a fatal error.
if ( false === wp_cache_flush() ) {
WP_CLI::error( 'The object cache could not be flushed.' );
}
/** * Forces a full Varnish Purge of the entire site (provided * regex is supported). * * ## EXAMPLES * * wp varnish purge * * wp varnish purge http://example.com/wp-content/themes/twentyeleventy/style.css * * wp vanrish purge "/wp-content/themes/twentysixty/style.css" * * wp varnish purge http://example.com/wp-content/themes/ --wildcard * * wp varnish purge "/wp-content/themes/" --wildcard * */ function purge($args, $assoc_args) { $wp_version = get_bloginfo('version'); $cli_version = WP_CLI_VERSION; // Set the URL/path list($url) = $args; // If wildcard is set, or the URL argument is empty // then treat this as a full purge if (isset($assoc_args['wildcard']) || empty($url)) { $pregex = '/?vhp-regex'; $wild = ".*"; } else { $pregex = $wild = ''; } wp_create_nonce('vhp-flush-cli'); // Make sure the URL is a URL: if (!empty($url)) { // If the URL isn't a URL, make it a URL if (empty(esc_url($url))) { $url = $this->varnish_purge->the_home_url() . $url; } } else { $url = $this->varnish_purge->the_home_url(); } if (version_compare($wp_version, '4.6', '>=') && (version_compare($cli_version, '0.25.0', '<') || version_compare($cli_version, '0.25.0-alpha', 'eq'))) { WP_CLI::log(sprintf('This plugin does not work on WP 4.6 and up, unless WP-CLI is version 0.25.0 or greater. You\'re using WP-CLI %s and WordPress %s.', $cli_version, $wp_version)); WP_CLI::log('To flush your cache, please run the following command:'); WP_CLI::log(sprintf('$ curl -X PURGE "%s"', $url . $wild)); WP_CLI::error('Varnish Cache must be purged manually.'); } $this->varnish_purge->purgeUrl($url . $pregex); WP_CLI::success('The Varnish cache was purged.'); }
/** * Flush cache by hash, post id, url or all posts. * * ## OPTIONS * * [--all] * : Flush all posts. * * [--hash=<hash>] * : Flush by cache hash. * * [--post_id=<post_id>] * : Flush by post id * * [--url=<url>] * : Flush by url. * * @param array $args * @param array $assoc_args */ public function flush($args, $assoc_args) { // Flush all posts. if (isset($assoc_args['all'])) { if (cachetop_flush_all_posts()) { WP_CLI::success('Cache flushed'); } else { WP_CLI::error('Cached not flushed'); } } // Flush by hash. if (isset($assoc_args['hash'])) { if (cachetop_flush_hash($assoc_args['hash'])) { WP_CLI::success(sprintf('Cache flushed for hash: %s', $assoc_args['hash'])); } else { WP_CLI::error('Cached not flushed'); } } // Flush post by id. if (isset($assoc_args['post_id']) && is_numeric($assoc_args['post_id'])) { if (cachetop_flush_post($args[0])) { WP_CLI::success(sprintf('Cache flushed for post id: %s', $assoc_args['post_id'])); } else { WP_CLI::error('Cached not flushed'); } } // Flush by url. if (isset($assoc_args['url'])) { if (cachetop_flush_url($assoc_args['url'])) { WP_CLI::success(sprintf('Cache flushed for url: %s', $assoc_args['url'])); } else { WP_CLI::error('Cached not flushed'); } } }
/** * "exercise" one or more URLs * * This is just a dispatcher and iterator, the real work is done in other methods. * * Args: * A URL or filename containing a list of URLs * ...A list of URLs should be a text file with one URL per line * --count: the integer number of times to test the named URL(s) * --rand: if present will cause the exerciser to insert random get vars that (maybe) will prevent page caching * --redirection: the number of redirects to follow, 0 is default * --user_id: if present, will cause the request to be made with the specified user's authentication tokens * * Examples: * wp --url=wpsite.example.org go-newrelic exercise "http://wpsite.example.org/" --count=13 --rand * wp --url=wpsite.example.org go-newrelic exercise url-list.txt --count=13 --rand * while true; do wp --url=wpsite.example.org go-newrelic exercise url-list.txt --count=7 --rand; sleep 100; done * * TODO: * Metrics are collected for summation, but none is done. * Summation by URL and among a group of URLs would be great * Output in CSV form, maybe... */ public function exercise($args, $assoc_args) { // don't this in New Relic if (function_exists('newrelic_ignore_transaction')) { newrelic_ignore_transaction(); } //end if if (empty($args)) { WP_CLI::error('Please specify a URL (or file with URLs) to test.'); return; } //end if if (!is_array($assoc_args)) { $assoc_args = array(); } //end if if (file_exists($args[0]) && ($lines = file($args[0], FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES))) { shuffle($lines); foreach ($lines as $url) { $assoc_args['url'] = $this->find_url($url); self::test_url($assoc_args); } } else { $assoc_args['url'] = $this->find_url($args[0]); self::test_url($assoc_args); } //end else }
/** * Fixes issues with slow saving in wp-admin due to no audio/video media files * * Core Ticket: https://core.trac.wordpress.org/ticket/31071 * * eg.: `wp vip-go-one-time-fixers blank-media-fix --allow-root --url=beta.thesun.co.uk` * * @subcommand blank-media-fix */ public function blank_media_fix($args, $assoc_args) { if (!function_exists('wpcom_vip_download_image')) { WP_CLI::error('This script requires the wpcom_vip_download_image() function, https://vip.wordpress.com/functions/wpcom_vip_download_image/'); } $audio_file_url = 'https://cldup.com/xmre07YagX.mp3'; // 1sec.mp3 $video_file_url = 'https://cldup.com/KHsK5yZkvv.avi'; // 1sec.avi $args = array('post_type' => 'attachment', 'post_status' => 'inherit', 'meta_query' => array(array('key' => '_vip_blank_media_fix', 'value' => 'video'))); $video_query = new WP_Query($args); if (!$video_query->post_count) { WP_CLI::log('Video fix not found, applying...'); $video_file_id = $this->wpcom_vip_download_image($video_file_url, 0, 'VIP: Fix for slow post saving'); if (!is_wp_error($video_file_id)) { $args = array('ID' => $video_file_id, 'post_date' => '2000-01-01', 'post_date_gmt' => '2000-01-01', 'post_modified' => '2000-01-01', 'post_modified_gmt' => '2000-01-01'); $updated_video_file_id = wp_update_post($args, true); if (!is_wp_error($updated_video_file_id)) { WP_CLI::success('Video fix applied'); $video_meta = update_post_meta($updated_video_file_id, '_vip_blank_media_fix', 'video'); if (false === $video_meta) { WP_CLI::warning('Could not update video _vip_blank_media_fix meta'); } } else { // Video date was not updated WP_CLI::error($updated_video_file_id->get_error_message()); } } else { // Sideload failed WP_CLI::error($video_file_id->get_error_message()); } } else { WP_CLI::warning('Blank video fix already exists for this site'); } $args = array('post_type' => 'attachment', 'post_status' => 'inherit', 'meta_query' => array(array('key' => '_vip_blank_media_fix', 'value' => 'audio'))); $audio_query = new WP_Query($args); if (!$audio_query->post_count) { WP_CLI::log('Audio fix not found, applying...'); $audio_file_id = $this->wpcom_vip_download_image($audio_file_url, 0, 'VIP: Fix for slow post saving'); if (!is_wp_error($audio_file_id)) { $args = array('ID' => $audio_file_id, 'post_date' => '2000-01-01', 'post_date_gmt' => '2000-01-01', 'post_modified' => '2000-01-01', 'post_modified_gmt' => '2000-01-01'); $updated_audio_file_id = wp_update_post($args, true); if (!is_wp_error($updated_audio_file_id)) { WP_CLI::success('Audio fix applied'); $audio_meta = update_post_meta($updated_audio_file_id, '_vip_blank_media_fix', 'audio'); if (false === $audio_meta) { WP_CLI::warning('Could not update audio _vip_blank_media_fix meta'); } } else { // Audio date was not updated WP_CLI::error($updated_audio_file_id->get_error_message()); } } else { // Sideload failed WP_CLI::error($video_file_id->get_error_message()); } } else { WP_CLI::warning('Blank video fix already exists for this site'); } }
/** * Sets up Developer Plugin * @subcommand install-plugins * @synopsis --type=<type> [--activate] */ function install_plugins($args, $assoc_args) { global $automattic_developer; // wp-cli doesn't fire admin_init since 0.11.2 if (!did_action('admin_init')) { $automattic_developer->admin_init(); } $type = $assoc_args['type']; $activate = isset($assoc_args['activate']) && $assoc_args['activate'] == "true"; $reco_plugins = $automattic_developer->recommended_plugins; $installed_plugins = array_keys(get_plugins()); $types = array_keys($automattic_developer->get_project_types()); if (in_array($type, $types)) { $automattic_developer->save_project_type($type); foreach ($reco_plugins as $slug => $plugin) { $path = $automattic_developer->get_path_for_recommended_plugin($slug); $activate_plugin = $activate && ('all' == $plugin['project_type'] || $type == $plugin['project_type']); // Download the plugin if we don't already have it if (!in_array($path, $installed_plugins)) { WP_CLI::run_command(explode(" ", "plugin install {$slug}")); } // Install the plugin if --activate and it's the right type if (is_plugin_inactive($path) && $activate_plugin) { if (NULL == activate_plugin($path)) { WP_CLI::success("Activated " . $plugin['name']); } } } } else { WP_CLI::error("Specify a valid type to install: <" . implode("|", $types) . ">"); } }
/** * Import originals for a project from a file * * ## OPTIONS * * <project> * : Project name * * <file> * : File to import from * * [--format=<format>] * : Accepted values: po, mo, android, resx, strings. Default: po */ public function __invoke($args, $assoc_args) { // Double-check for compatibility if ($args[0] === '-p' || $args[1] === '-f') { WP_CLI::error(__('-p and -f are no longer required and should be removed.', 'glotpress')); } $project = GP::$project->by_path($args[0]); if (!$project) { WP_CLI::error(__('Project not found!', 'glotpress')); } $format = isset($assoc_args['format']) ? $assoc_args['format'] : 'po'; $format = gp_array_get(GP::$formats, $format, null); if (!$format) { WP_CLI::error(__('No such format.', 'glotpress')); } $translations = $format->read_originals_from_file($args[1], $project); if (!$translations) { WP_CLI::error(__("Couldn't load translations from file!", 'glotpress')); } list($originals_added, $originals_existing, $originals_fuzzied, $originals_obsoleted, $originals_error) = GP::$original->import_for_project($project, $translations); $notice = sprintf(__('%1$s new strings added, %2$s updated, %3$s fuzzied, and %4$s obsoleted.', 'glotpress'), $originals_added, $originals_existing, $originals_fuzzied, $originals_obsoleted); if ($originals_error) { $notice = ' ' . sprintf(_n('%s new string was not imported due to an error.', '%s new strings were not imported due to an error.', $originals_error, 'glotpress'), $originals_error); } WP_CLI::line($notice); }
/** * Delete orphaned tables * * @synopsis [--force] */ function delete($args, $assoc_args) { if (!isset($assoc_args['force'])) { WP_CLI::error('Use the --force'); return; } $orphanTables = $this->get_orphan_tables(); if (count($orphanTables) == 0) { WP_CLI::success('No orphan tables were found'); return; } global $wpdb; $i = 0; foreach ($orphanTables as $tableName) { $tableName = $tableName['Orphaned Table Name']; $result = $wpdb->query('DROP TABLE ' . $tableName); if ($result === false) { WP_CLI::error('Could not drop table ' . $tableName . ' - ' . $wpdb->last_error); continue; } WP_CLI::success('Dropped Table ' . $tableName); $i++; } WP_CLI::success('Dropped ' . $i . ' orphaned tables.'); }
private function log($msg, $error = false) { if ($error) { WP_CLI::error($msg); } WP_CLI::warning($msg); }
/** * Retrieve the current event queue * * @subcommand get-queue */ public function get_queue($args, $assoc_args) { // Build and make request $queue_request = new \WP_REST_Request('POST', '/' . \Automattic\WP\Cron_Control\REST_API::API_NAMESPACE . '/' . \Automattic\WP\Cron_Control\REST_API::ENDPOINT_LIST); $queue_request->add_header('Content-Type', 'application/json'); $queue_request->set_body(wp_json_encode(array('secret' => \WP_CRON_CONTROL_SECRET))); $queue_request = rest_do_request($queue_request); // Oh well if ($queue_request->is_error()) { \WP_CLI::error($queue_request->as_error()->get_error_message()); } // Get the decoded JSON object returned by the API $queue_response = $queue_request->get_data(); // No events, nothing more to do if (empty($queue_response['events'])) { \WP_CLI::warning(__('No events in the current queue', 'automattic-cron-control')); return; } // Prepare items for display $events_for_display = $this->format_events($queue_response['events']); $total_events_to_display = count($events_for_display); \WP_CLI::line(sprintf(_n('Displaying one event', 'Displaying %s events', $total_events_to_display, 'automattic-cron-control'), number_format_i18n($total_events_to_display))); // And reformat $format = 'table'; if (isset($assoc_args['format'])) { if ('ids' === $assoc_args['format']) { \WP_CLI::error(__('Invalid output format requested', 'automattic-cron-control')); } else { $format = $assoc_args['format']; } } \WP_CLI\Utils\format_items($format, $events_for_display, array('timestamp', 'action', 'instance', 'scheduled_for', 'internal_event', 'schedule_name', 'event_args')); }
/** * Import content from a WXR file. * * ## OPTIONS * * <file>... * : Path to one or more valid WXR files for importing. Directories are also accepted. * * [--verbose[=<level>]] * : Should we print verbose statements? * (No value for 'info'; or one of 'emergency', 'alert', 'critical', * 'error', 'warning', 'notice', 'info', 'debug') * * [--default-author=<id>] * : Default author ID to use if invalid user is found in the import data. */ public function import($args, $assoc_args) { $logger = new WP_Importer_Logger_CLI(); if (!empty($assoc_args['verbose'])) { if ($assoc_args['verbose'] === true) { $logger->min_level = 'info'; } else { $valid = $logger->level_to_numeric($assoc_args['verbose']); if (!$valid) { WP_CLI::error('Invalid verbosity level'); return; } $logger->min_level = $assoc_args['verbose']; } } $options = array('fetch_attachments' => true); if (isset($assoc_args['default-author'])) { $options['default_author'] = absint($assoc_args['default-author']); if (!get_user_by('ID', $options['default_author'])) { WP_CLI::error('Invalid default author ID specified.'); } } $importer = new WXR_Importer($options); $importer->set_logger($logger); $importer->import(realpath($args[0])); }
protected function get_arg_or_error($args, $index, $name) { if (!isset($args[$index])) { WP_CLI::error("{$name} required"); } return $args[$index]; }
/** * Destroy a session for the given user. * * ## OPTIONS * * <user> * : User ID, user email, or user login. * * [<token>] * : The token of the session to destroy. Defaults to the most recently created session. * * [--all] * : Destroy all of the user's sessions. * * ## EXAMPLES * * # Destroy the most recent session of the given user. * $ wp user session destroy admin * Success: Destroyed session. 3 sessions remaining. * * # Destroy a specific session of the given user. * $ wp user session destroy admin e073ad8540a9c2... * Success: Destroyed session. 2 sessions remaining. * * # Destroy all the sessions of the given user. * $ wp user session destroy admin --all * Success: Destroyed all sessions. * * # Destroy all sessions for all users. * $ wp user list --field=ID | xargs wp user session destroy --all * Success: Destroyed all sessions. * Success: Destroyed all sessions. */ public function destroy($args, $assoc_args) { $user = $this->fetcher->get_check($args[0]); $token = \WP_CLI\Utils\get_flag_value($args, 1, null); $all = \WP_CLI\Utils\get_flag_value($assoc_args, 'all', false); $manager = WP_Session_Tokens::get_instance($user->ID); if ($token && $all) { WP_CLI::error('The --all flag cannot be specified along with a session token.'); } if ($all) { $manager->destroy_all(); WP_CLI::success('Destroyed all sessions.'); return; } $sessions = $this->get_all_sessions($manager); if (!$token) { if (empty($sessions)) { WP_CLI::success('No sessions to destroy.'); } $last = end($sessions); $token = $last['token']; } if (!isset($sessions[$token])) { WP_CLI::error('Session not found.'); } $this->destroy_session($manager, $token); $remaining = count($manager->get_all()); WP_CLI::success(sprintf('Destroyed session. %s remaining.', $remaining)); }
/** * Lists one-time logins * * ## EXAMPLES * * wp one-time-login list * * @subcommand list */ function _list($args, $assoc_args) { // Get all one-time logins $otl_posts = get_posts(array('posts_per_page' => -1, 'post_type' => 'onetimelogin', 'order' => ASC)); // Error if no logins found if (empty($otl_posts)) { WP_CLI::error(__('No one time logins found.', 'one-time-login')); } // Set table headers $headers = array(__('ID', 'one-time-login'), __('Password', 'one-time-login'), __('User ID', 'one-time-login'), __('Date Generated', 'one-time-login'), __('Status', 'one-time-login'), __('Date Used', 'one-time-login')); $data = array(); // loop through logins and format foreach ($otl_posts as $otl) { $id = $otl->ID; $password = $otl->post_title; $user_id = get_post_meta($otl->ID, 'otl_user', true); $generated = $otl->post_date; $status = '0' === get_post_meta($otl->ID, 'otl_times_used', true) ? __('Available', 'one-time-login') : __('Expired', 'one-time-login'); $used = get_post_meta($otl->ID, 'otl_datetime_used', true); $data[] = array($id, $password, $user_id, $generated, $status, $used); } // Output table $table = new \cli\Table(); $table->setHeaders($headers); $table->setRows($data); $table->display(); }
public function uploads($command = array(), $args = array()) { if (count($command) == 1 && reset($command) == 'help') { return $this->uploads_help(); } $dir = wp_upload_dir(); $defaults = array('ssh_host' => defined('IMPORT_UPLOADS_SSH_HOST') ? IMPORT_UPLOADS_SSH_HOST : '', 'ssh_user' => defined('IMPORT_UPLOADS_SSH_USER') ? IMPORT_UPLOADS_SSH_USER : '', 'remote_path' => defined('IMPORT_UPLOADS_REMOTE_PATH') ? IMPORT_UPLOADS_REMOTE_PATH : '', 'uploads_dir' => '', 'local_path' => $dir['basedir']); $args = wp_parse_args($args, $defaults); if ($args['uploads_dir']) { $args['remote_path'] = $args['remote_path'] ? trailingslashit($args['remote_path']) . trailingslashit(ltrim($args['uploads_dir'], '/')) : ''; $args['local_path'] = trailingslashit($args['local_path']) . untrailingslashit(ltrim($args['uploads_dir'], '/')); } else { $args['remote_path'] = $args['remote_path'] ? trailingslashit($args['remote_path']) : ''; $args['local_path'] = untrailingslashit($args['local_path']); } if (empty($args['remote_path'])) { WP_CLI::error('You must specify a remote path. Use --remote_path=~/foo/bar'); return; } if (empty($args['ssh_host'])) { WP_CLI::error('You must specify a ssh host. Use --ssh_host=example.com'); return; } if (empty($args['ssh_user'])) { WP_CLI::error('You must specify a ssh user. Use --ssh_user=root'); return; } WP_CLI::line(sprintf('Running rsync from %s:%s to %s', $args['ssh_host'], $args['remote_path'], $args['local_path'])); WP_CLI::launch(sprintf("rsync -avz -e ssh %s@%s:%s %s --exclude 'cache' --exclude '*backup*'", $args['ssh_user'], $args['ssh_host'], $args['remote_path'], $args['local_path'])); }
/** * Set a single thumbnail ID as the featured image of every post * * ## OPTIONS * * --thumbnail_id=<int> * : The post ID of the thumbnail to use * * [--dryrun=<bool>] * : Whether this is a dryrun or not * --- * default: true * options: * - true * - false * * ## EXAMPLES * * wp sudoers single-featured-image --thumbnail_id=123456 --dryrun=false * * @subcommand single-featured-image * @synopsis --thumbnail_id=<int> [--dryrun=<true|false>] */ public function single_featured_image($args, $assoc_args) { // Get the thumbnail ID from argument $thumbnail_id = isset($assoc_args['thumbnail_id']) ? absint($assoc_args['thumbnail_id']) : false; $thumbnail = get_post($thumbnail_id); // Bail if given a non-attachment post ID if (!$thumbnail || 'attachment' !== $thumbnail->post_type) { WP_CLI::error('Invalid thumbnail ID.'); exit; } // Get dryrun parameter $is_dryrun = isset($assoc_args['dryrun']) && 'false' == $assoc_args['dryrun'] ? false : true; // Get all posts $post_ids = get_posts(array('posts_per_page' => -1, 'post_status' => 'any', 'fields' => 'ids')); foreach ($post_ids as $post_id) { if ($is_dryrun) { WP_CLI::log("(dryrun) Set thumbnail {$thumbnail_id} to post {$post_id}"); } else { // Set the post thumbnail $status = set_post_thumbnail($post_id, $thumbnail_id); if ($status) { WP_CLI::log("Successfully set thumbnail {$thumbnail_id} to post {$post_id}"); } else { WP_CLI::warning("Error setting thumbnail {$thumbnail_id} to post {$post_id}"); } } } }
/** * Checks one or more comments against the Akismet API. * * ## OPTIONS * <comment_id>... * : The ID(s) of the comment(s) to check. * * [--noaction] * : Don't change the status of the comment. Just report what Akismet thinks it is. * * ## EXAMPLES * * wp akismet check 12345 * * @alias comment-check */ public function check($args, $assoc_args) { foreach ($args as $comment_id) { if (isset($assoc_args['noaction'])) { // Check the comment, but don't reclassify it. $api_response = Akismet::check_db_comment($comment_id, 'wp-cli'); } else { $api_response = Akismet::recheck_comment($comment_id, 'wp-cli'); } if ('true' === $api_response) { WP_CLI::line(sprintf(__("Comment #%d is spam.", 'akismet'), $comment_id)); } else { if ('false' === $api_response) { WP_CLI::line(sprintf(__("Comment #%d is not spam.", 'akismet'), $comment_id)); } else { if (false === $api_response) { WP_CLI::error(__("Failed to connect to Akismet.", 'akismet')); } else { if (is_wp_error($api_response)) { WP_CLI::warning(sprintf(__("Comment #%d could not be checked.", 'akismet'), $comment_id)); } } } } } }
/** * Grant super-admin privileges to one or more users. * * <user>... * : One or more user IDs, user emails, or user logins. */ public function add($args, $_) { $users = $this->fetcher->get_many($args); $user_logins = wp_list_pluck($users, 'user_login'); $super_admins = self::get_admins(); $num_super_admins = count($super_admins); foreach ($user_logins as $user_login) { $user = get_user_by('login', $user_login); if (!$user) { WP_CLI::warning("Couldn't find {$user_login} user."); continue; } if (in_array($user->user_login, $super_admins)) { WP_CLI::warning("User {$user_login} already has super-admin capabilities."); continue; } $super_admins[] = $user->user_login; } if ($num_super_admins === count($super_admins)) { WP_CLI::log('No changes.'); } else { if (update_site_option('site_admins', $super_admins)) { WP_CLI::success('Granted super-admin capabilities.'); } else { WP_CLI::error('Site options update failed!'); } } }
/** * Reset the post_date field on your posts. * A sadly necessary step after you change your timezone in WordPress * * @synopsis --post_type=<post-type> */ public function __invoke($args, $assoc_args) { global $wpdb; $query_args = array('post_type' => $assoc_args['post_type'], 'posts_per_page' => -1, 'post_status' => 'publish'); $query = new WP_Query($query_args); if (empty($query->posts)) { WP_CLI::error("No posts found"); } WP_CLI::line(sprintf("Updating post_date on %d posts.", count($query->posts))); foreach ($query->posts as $key => $post) { if (empty($post->post_date_gmt) || "0000-00-00 00:00:00" == $post->post_date_gmt) { WP_CLI::line(sprintf("Error: Post %d is missing a publish date.", $post->ID)); continue; } $original = $post->post_date; $new = get_date_from_gmt($post->post_date_gmt); if ($new == $original) { WP_CLI::line(sprintf("No Change: Post %d has the correct post_date of %s", $post->ID, $original)); continue; } $wpdb->update($wpdb->posts, array('post_date' => $new), array('ID' => $post->ID)); clean_post_cache($post->ID); WP_CLI::line(sprintf("Updated: Post %d changed from %s to %s", $post->ID, $original, $new)); if ($key && $key % 10 == 0) { sleep(1); } } WP_CLI::success("Posts were updated with the correct post_date."); }
/** * Setup Elasticsearch. * * ## OPTIONS * * [--host=<url>] * : The name of the person to greet. * * [--port=<number>] * : Accepted values: csv, json. Default: csv * * ## EXAMPLES * * wp elasticsearch setup --host=example.com --port=9200 * * @subcommand setup */ function setup($args, $assoc_args) { $param = array(); $param['endpoint'] = preg_replace('/(^https:\\/\\/|^http:\\/\\/)/is', '', $assoc_args['host']); $param['port'] = $assoc_args['port']; $tries = 5; $sleep = 3; do { $response = wp_remote_get(esc_url($assoc_args['host']) . ':' . $assoc_args['port']); if (200 == wp_remote_retrieve_response_code($response)) { // Looks good! break; } else { WP_CLI::log("\nInvalid response from ES, sleeping {$sleep} seconds and trying again...\n"); sleep($sleep); } } while (--$tries); if (200 != wp_remote_retrieve_response_code($response)) { WP_CLI::error('Could not connect to Elasticsearch server.'); exit; } update_option('wpels_settings', $param); try { if (!\MegumiTeam\WooCommerceElasticsearch\Loader::get_instance()->data_sync()) { WP_CLI::error('Elasticsearch built index failed.'); } } catch (Exception $e) { WP_CLI::error($e->getMessage()); exit; } WP_CLI::success("Elasticsearch built index completed."); }
public function sync($args, $assoc_args) { $websites = MainWP_DB::Instance()->query(MainWP_DB::Instance()->getSQLWebsitesForCurrentUser()); WP_CLI::line('Syncing ' . MainWP_DB::num_rows($websites) . ' sites'); $warnings = 0; $errors = 0; while ($websites && ($website = @MainWP_DB::fetch_object($websites))) { WP_CLI::line(' -> ' . $website->name . ' (' . $website->url . ')'); try { if (MainWP_Sync::syncSite($website)) { WP_CLI::success(' Sync succeeded'); } else { WP_CLI::warning(' Sync failed'); $warnings++; } } catch (Exception $e) { WP_CLI::error(' Sync failed'); $errors++; } } @MainWP_DB::free_result($websites); if ($errors > 0) { WP_CLI::error('Sync completed with errors'); } else { if ($warnings > 0) { WP_CLI::warning('Sync completed with warnings'); } else { WP_CLI::success('Sync completed'); } } }
/** * Import content from a WXR file. * * ## OPTIONS * * <file>... * : Path to one or more valid WXR files for importing. * * --authors=<authors> * : How the author mapping should be handled. Options are 'create', 'mapping.csv', or 'skip'. The first will create any non-existent users from the WXR file. The second will read author mapping associations from a CSV, or create a CSV for editing if the file path doesn't exist. The CSV requires two columns, and a header row like "old_user_login,new_user_login". The last option will skip any author mapping. * * [--skip=<data-type>] * : Skip importing specific data. Supported options are: 'attachment' and 'image_resize' (skip time-consuming thumbnail generation). */ public function __invoke($args, $assoc_args) { $defaults = array('authors' => null, 'skip' => array()); $assoc_args = wp_parse_args($assoc_args, $defaults); if (!is_array($assoc_args['skip'])) { $assoc_args['skip'] = explode(',', $assoc_args['skip']); } $importer = $this->is_importer_available(); if (is_wp_error($importer)) { WP_CLI::error($importer); } $this->add_wxr_filters(); WP_CLI::log('Starting the import process...'); foreach ($args as $file) { if (!is_readable($file)) { WP_CLI::warning("Can't read {$file} file."); } $ret = $this->import_wxr($file, $assoc_args); if (is_wp_error($ret)) { WP_CLI::warning($ret); } else { WP_CLI::line(); // WXR import ends with HTML, so make sure message is on next line WP_CLI::success("Finished importing from {$file} file."); } } }
/** * Perform an option action on a remote site */ private function perform_option_action($action, $args, $assoc_args) { $site_id = $assoc_args['site-id']; unset($assoc_args['site-id']); list($option_name) = $args; $this->set_account(); $method = strtoupper($action); if ('update' == $action) { $method = 'POST'; $api_args = array('option_value' => WP_CLI::read_value($args[1], $assoc_args)); } else { $api_args = array(); } $args = array('endpoint' => 'site/' . (int) $site_id . '/option/' . $option_name, 'method' => $method, 'body' => $api_args); $response = $this->api_request($args); if (is_wp_error($response)) { WP_CLI::error($response->get_error_message()); } switch ($action) { case 'get': if (empty($response)) { die(1); } WP_CLI::print_value($response, $assoc_args); break; case 'update': WP_CLI::success("Updated '{$option_name}' option."); break; case 'delete': WP_CLI::success("Deleted '{$option_name}' option."); break; } }
/** * Bulk import redirects from a CSV file matching the following structure: * * redirect_from_path,(redirect_to_post_id|redirect_to_path|redirect_to_url) * * @subcommand import-from-csv * @synopsis --csv=<path-to-csv> */ function import_from_csv($args, $assoc_args) { define('WP_IMPORTING', true); if (empty($assoc_args['csv']) || !file_exists($assoc_args['csv'])) { WP_CLI::error("Invalid 'csv' file"); } global $wpdb; if (($handle = fopen($assoc_args['csv'], "r")) !== FALSE) { while (($data = fgetcsv($handle, 2000, ",")) !== FALSE) { $row++; $redirect_from = $data[0]; $redirect_to = $data[1]; WP_CLI::line("Adding (CSV) redirect for {$redirect_from} to {$redirect_to}"); WP_CLI::line("-- at {$row}"); WPCOM_Legacy_Redirector::insert_legacy_redirect($redirect_from, $redirect_to); if (0 == $row % 100) { if (function_exists('stop_the_insanity')) { stop_the_insanity(); } sleep(1); } } fclose($handle); } }
/** * Launch PHP's built-in web server for this specific WordPress installation. * * Uses `php -S` to launch a web server serving the WordPress webroot. * <http://php.net/manual/en/features.commandline.webserver.php> * * ## OPTIONS * * [--host=<host>] * : The hostname to bind the server to. * --- * default: localhost * --- * * [--port=<port>] * : The port number to bind the server to. * --- * default: 8080 * --- * * [--docroot=<path>] * : The path to use as the document root. * * [--config=<file>] * : Configure the server with a specific .ini file. * * ## EXAMPLES * * # Make the instance available on any address (with port 8080) * $ wp server --host=0.0.0.0 * PHP 5.6.9 Development Server started at Tue May 24 01:27:11 2016 * Listening on http://0.0.0.0:8080 * Document root is / * Press Ctrl-C to quit. * * # Run on port 80 (for multisite) * $ sudo wp server --host=localhost.localdomain --port=80 * PHP 5.6.9 Development Server started at Tue May 24 01:30:06 2016 * Listening on http://localhost1.localdomain1:8080 * Document root is / * Press Ctrl-C to quit. * * # Configure the server with a specific .ini file * $ wp server --config=development.ini * PHP 7.0.9 Development Server started at Mon Aug 22 12:09:04 2016 * Listening on http://localhost:8080 * Document root is / * Press Ctrl-C to quit. * * @when before_wp_load */ function __invoke($_, $assoc_args) { $min_version = '5.4'; if (version_compare(PHP_VERSION, $min_version, '<')) { WP_CLI::error("The `wp server` command requires PHP {$min_version} or newer."); } $defaults = array('host' => 'localhost', 'port' => 8080, 'docroot' => false, 'config' => get_cfg_var('cfg_file_path')); $assoc_args = array_merge($defaults, $assoc_args); $docroot = $assoc_args['docroot']; if (!$docroot) { $config_path = WP_CLI::get_runner()->project_config_path; if (!$config_path) { $docroot = ABSPATH; } else { $docroot = dirname($config_path); } } $cmd = \WP_CLI\Utils\esc_cmd('%s -S %s -t %s -c %s %s', PHP_BINARY, $assoc_args['host'] . ':' . $assoc_args['port'], $docroot, $assoc_args['config'], \WP_CLI\Utils\extract_from_phar(WP_CLI_ROOT . '/php/router.php')); $descriptors = array(STDIN, STDOUT, STDERR); // https://bugs.php.net/bug.php?id=60181 $options = array(); if (\WP_CLI\Utils\is_windows()) { $options["bypass_shell"] = TRUE; } exit(proc_close(proc_open($cmd, $descriptors, $pipes, NULL, NULL, $options))); }
/** * Generate random users. * * ## OPTIONS * * <count> * : Number of users to generate * * ## EXAMPLES * * wp usergen generate 10 * * @access public * @param array $args * @param array $assoc_args * @return void */ public function generate($args, $assoc_args) { list($count) = $args; // Verify the number is integer and greater than 0 if (filter_var($count, FILTER_VALIDATE_INT) == false || $count < 0) { WP_CLI::error('You must specify the amount of users you wish to generate.'); return; } $mock_data = $this->retrieve_mock_data(); $total = count($mock_data); // Verify the requested amount is available within the mock data. if ($count > $total) { WP_CLI::error(sprintf('You must specify an amount less than %s or generate your custom json data.', $total)); return; } $mock_data = array_slice($mock_data, 0, $count); // Get the selected amount from the array. $notify = \WP_CLI\Utils\make_progress_bar("Generating {$count} users(s)", $count); for ($i = 0; $i < count($mock_data); $i++) { $notify->tick(); $this->register_user($mock_data[$i]); } $notify->finish(); WP_CLI::success('Done.'); }
/** * Delete an option * * @synopsis <key> */ public function delete($args) { list($key) = $args; if (!delete_option($key)) { WP_CLI::error("Could not delete '{$key}' option. Does it exist?"); } }
/** * Migrate meta values to taxonomy terms. Delete meta after import * * ## OPTIONS * * <meta-key> * : Meta key to convert * * <taxonomy-slug> * : Taxonomy to move values into * * [--<field>=<value>] * : One or more args to pass to WP_Query. * * ## EXAMPLES * * wp mtt migrate meta_key taxonomy_slug * wp mtt migrate meta_key taxonomy_slug --posts_per_page=200 --paged=2 * */ function migrate($args, $assoc_args) { list($meta_key, $taxonomy) = $args; if (!($taxonomy_object = get_taxonomy($taxonomy))) { WP_CLI::error(sprintf("The taxonomy '%s' doesn't exist", $taxonomy)); } $defaults = array('post_type' => $taxonomy_object->object_type, 'posts_per_page' => -1, 'post_status' => 'any'); $query_args = array_merge($defaults, $assoc_args); $query = new WP_Query($query_args); // summary WP_CLI::log(sprintf("---\nPer page: %d \nPage: %d \nTotal pages: %d\n---", $query_args['posts_per_page'], isset($query_args['paged']) ? $query_args['paged'] : 1, $query->max_num_pages)); while ($query->have_posts()) { $query->the_post(); $id = get_the_id(); // get meta $metas = get_post_meta($id, $meta_key); // create term if (!$metas) { WP_CLI::log(WP_CLI::colorize("%c[{$id}]%n No meta, skipped")); } else { if (!is_wp_error(wp_set_object_terms($id, $metas, $taxonomy, true))) { WP_CLI::log(WP_CLI::colorize("%g[{$id}]%n Migrated: " . implode(', ', $metas))); // clean meta delete_post_meta($id, $meta_key); } else { WP_CLI::log(WP_CLI::colorize("%r[{$id}]%n Error: Could not set terms for post")); } } } }
/** * Like get(), but calls WP_CLI::error() instead of returning false. * * @param string $arg The raw CLI argument */ public function get_check($arg) { $item = $this->get($arg); if (!$item) { \WP_CLI::error(sprintf($this->msg, $arg)); } return $item; }
/** * Load and execute a PHP file after loading WordPress. * * ## OPTIONS * * <file> * : The path to the PHP file to execute. * * [<arg>...] * : One or more arguments to pass to the file. They are placed in the $args variable. * * ## EXAMPLES * * wp eval-file my-code.php value1 value2 */ public function __invoke($args) { $file = array_shift($args); if (!file_exists($file)) { WP_CLI::error("'{$file}' does not exist."); } self::_eval($file, $args); }
/** * Loop through all posts, setting the first attached image as the featured images * * ## OPTIONS * * ## EXAMPLES * * wp auto-thumbnail * */ public function __invoke($args, $assoc_args) { set_time_limit(0); // Get all public post types $get_post_types = get_post_types(array('public' => true)); // Post types array that will be used by default $post_types = array(); foreach ($get_post_types as $post_type) { // Only add post types that support if (post_type_supports($post_type, 'thumbnail')) { $post_types[] = $post_type; } } // Default values for wp query $defaults = array('post_type' => $post_types, 'posts_per_page' => -1, 'post_status' => 'any'); // Merge user args with defaults $assoc_args = wp_parse_args($assoc_args, $defaults); // The Query $the_query = new WP_Query($assoc_args); // Number of posts returned by query $found_posts = $the_query->found_posts; // Generate progess bar $progress = new \cli\progress\Bar('Progress', $found_posts); // Counter for number of post successfully processed $counter_success = 0; // Counter for number of post processed $counter_processed = 0; // The Loop while ($the_query->have_posts()) { $the_query->the_post(); // Move the processbar on $progress->tick(); $has_thumb = has_post_thumbnail(get_the_ID()); if (!$has_thumb) { $attached_image = get_children("post_parent=" . get_the_ID() . "&post_type=attachment&post_mime_type=image&numberposts=1"); if ($attached_image) { foreach ($attached_image as $attachment_id => $attachment) { set_post_thumbnail(get_the_ID(), $attachment_id); $counter_success++; } } $counter_processed++; } } $progress->finish(); /* Restore original Post Data * NB: Because we are using new WP_Query we aren't stomping on the * original $wp_query and it does not need to be reset. */ wp_reset_postdata(); if ($found_posts == 0) { WP_CLI::error("No posts found"); } elseif ($counter_processed == 0) { WP_CLI::error("No posts processed"); } elseif ($counter_success == 0) { WP_CLI::success("Unable to processed any posts"); } else { WP_CLI::success("Processing compelete. {$counter_success} of {$counter_processed} where processed successfully."); } }