xarxaprod-wp-theme/vendor/wp-cli/wp-cli/php/WP_CLI/Runner.php

1934 lines
56 KiB
PHP

<?php
namespace WP_CLI;
use WP_CLI;
use WP_CLI\Dispatcher;
use WP_CLI\Dispatcher\CompositeCommand;
use WP_CLI\Dispatcher\Subcommand;
use WP_CLI\Fetchers;
use WP_CLI\Iterators\Exception;
use WP_CLI\Loggers;
use WP_CLI\Utils;
use WP_Error;
/**
* Performs the execution of a command.
*
* @property-read string $global_config_path
* @property-read string $project_config_path
* @property-read array $config
* @property-read array $extra_config
* @property-read ContextManager $context_manager
* @property-read string $alias
* @property-read array $aliases
* @property-read array $arguments
* @property-read array $assoc_args
* @property-read array $runtime_config
* @property-read bool $colorize
* @property-read array $early_invoke
* @property-read string $global_config_path_debug
* @property-read string $project_config_path_debug
* @property-read array $required_files
*
* @package WP_CLI
*/
class Runner {
/**
* List of byte-order marks (BOMs) to detect.
*
* @var array<string, string>
*/
const BYTE_ORDER_MARKS = [
'UTF-8' => "\xEF\xBB\xBF",
'UTF-16 (BE)' => "\xFE\xFF",
'UTF-16 (LE)' => "\xFF\xFE",
];
private $global_config_path;
private $project_config_path;
private $config;
private $extra_config;
private $context_manager;
private $alias;
private $aliases;
private $arguments;
private $assoc_args;
private $runtime_config;
private $colorize = false;
private $early_invoke = [];
private $global_config_path_debug;
private $project_config_path_debug;
private $required_files;
public function __get( $key ) {
if ( '_' === $key[0] ) {
return null;
}
return $this->$key;
}
public function register_context_manager( ContextManager $context_manager ) {
$this->context_manager = $context_manager;
}
/**
* Register a command for early invocation, generally before WordPress loads.
*
* @param string $when Named execution hook
* @param Subcommand $command
*/
public function register_early_invoke( $when, $command ) {
$this->early_invoke[ $when ][] = array_slice( Dispatcher\get_path( $command ), 1 );
}
/**
* Perform the early invocation of a command.
*
* @param string $when Named execution hook
*/
private function do_early_invoke( $when ) {
if ( ! isset( $this->early_invoke[ $when ] ) ) {
return;
}
// Search the value of @when from the command method.
$real_when = '';
$r = $this->find_command_to_run( $this->arguments );
if ( is_array( $r ) ) {
list( $command, $final_args, $cmd_path ) = $r;
foreach ( $this->early_invoke as $_when => $_path ) {
foreach ( $_path as $cmd ) {
if ( $cmd === $cmd_path ) {
$real_when = $_when;
}
}
}
}
foreach ( $this->early_invoke[ $when ] as $path ) {
if ( $this->cmd_starts_with( $path ) ) {
if ( empty( $real_when ) || ( $real_when && $real_when === $when ) ) {
$this->run_command_and_exit();
}
}
}
}
/**
* Get the path to the global configuration YAML file.
*
* @param bool $create_config_file Optional. If a config file doesn't exist,
* should it be created? Defaults to false.
*
* @return string|false
*/
public function get_global_config_path( $create_config_file = false ) {
if ( getenv( 'WP_CLI_CONFIG_PATH' ) ) {
$config_path = getenv( 'WP_CLI_CONFIG_PATH' );
$this->global_config_path_debug = 'Using global config from WP_CLI_CONFIG_PATH env var: ' . $config_path;
} else {
$config_path = Utils\get_home_dir() . '/.wp-cli/config.yml';
$this->global_config_path_debug = 'Using default global config: ' . $config_path;
}
// If global config doesn't exist create one.
if ( true === $create_config_file && ! file_exists( $config_path ) ) {
$this->global_config_path_debug = "Default global config doesn't exist, creating one in {$config_path}";
Process::create( Utils\esc_cmd( 'touch %s', $config_path ) )->run();
}
if ( is_readable( $config_path ) ) {
return $config_path;
}
$this->global_config_path_debug = 'No readable global config found';
return false;
}
/**
* Get the path to the project-specific configuration
* YAML file.
* wp-cli.local.yml takes priority over wp-cli.yml.
*
* @return string|false
*/
public function get_project_config_path() {
$config_files = [
'wp-cli.local.yml',
'wp-cli.yml',
];
// Stop looking upward when we find we have emerged from a subdirectory
// installation into a parent installation
$project_config_path = Utils\find_file_upward(
$config_files,
getcwd(),
static function ( $dir ) {
static $wp_load_count = 0;
$wp_load_path = $dir . DIRECTORY_SEPARATOR . 'wp-load.php';
if ( file_exists( $wp_load_path ) ) {
++ $wp_load_count;
}
return $wp_load_count > 1;
}
);
$this->project_config_path_debug = 'No project config found';
if ( ! empty( $project_config_path ) ) {
$this->project_config_path_debug = 'Using project config: ' . $project_config_path;
}
return $project_config_path;
}
/**
* Get the path to the packages directory
*
* @return string
*/
public function get_packages_dir_path() {
if ( getenv( 'WP_CLI_PACKAGES_DIR' ) ) {
$packages_dir = Utils\trailingslashit( getenv( 'WP_CLI_PACKAGES_DIR' ) );
} else {
$packages_dir = Utils\get_home_dir() . '/.wp-cli/packages/';
}
return $packages_dir;
}
/**
* Attempts to find the path to the WP installation inside index.php
*
* @param string $index_path
* @return string|false
*/
private static function extract_subdir_path( $index_path ) {
$index_code = file_get_contents( $index_path );
if ( ! preg_match( '|^\s*require\s*\(?\s*(.+?)/wp-blog-header\.php([\'"])|m', $index_code, $matches ) ) {
return false;
}
$wp_path_src = $matches[1] . $matches[2];
$wp_path_src = Utils\replace_path_consts( $wp_path_src, $index_path );
$wp_path = eval( "return $wp_path_src;" ); // phpcs:ignore Squiz.PHP.Eval.Discouraged
if ( ! Utils\is_path_absolute( $wp_path ) ) {
$wp_path = dirname( $index_path ) . "/$wp_path";
}
return $wp_path;
}
/**
* Find the directory that contains the WordPress files.
* Defaults to the current working dir.
*
* @return string An absolute path
*/
private function find_wp_root() {
if ( ! empty( $this->config['path'] ) ) {
$path = $this->config['path'];
if ( ! Utils\is_path_absolute( $path ) ) {
$path = getcwd() . '/' . $path;
}
return $path;
}
if ( $this->cmd_starts_with( [ 'core', 'download' ] ) ) {
return getcwd();
}
$dir = getcwd();
while ( is_readable( $dir ) ) {
if ( file_exists( "$dir/wp-load.php" ) ) {
return $dir;
}
if ( file_exists( "$dir/index.php" ) ) {
$path = self::extract_subdir_path( "$dir/index.php" );
if ( ! empty( $path ) ) {
return $path;
}
}
$parent_dir = dirname( $dir );
if ( empty( $parent_dir ) || $parent_dir === $dir ) {
break;
}
$dir = $parent_dir;
}
return getcwd();
}
/**
* Set WordPress root as a given path.
*
* @param string $path
*/
private static function set_wp_root( $path ) {
if ( ! defined( 'ABSPATH' ) ) {
// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedConstantFound -- Declaring a WP native constant.
define( 'ABSPATH', Utils\normalize_path( Utils\trailingslashit( $path ) ) );
} elseif ( ! is_null( $path ) ) {
WP_CLI::error_multi_line(
[
'The --path parameter cannot be used when ABSPATH is already defined elsewhere',
'ABSPATH is defined as: "' . ABSPATH . '"',
]
);
}
WP_CLI::debug( 'ABSPATH defined: ' . ABSPATH, 'bootstrap' );
$_SERVER['DOCUMENT_ROOT'] = realpath( $path );
}
/**
* Guess which URL context WP-CLI has been invoked under.
*
* @param array $assoc_args
* @return string|false
*/
private static function guess_url( $assoc_args ) {
if ( isset( $assoc_args['blog'] ) ) {
$assoc_args['url'] = $assoc_args['blog'];
}
if ( isset( $assoc_args['url'] ) ) {
$url = $assoc_args['url'];
if ( true === $url ) {
WP_CLI::warning( 'The --url parameter expects a value.' );
}
return $url;
}
return false;
}
private function cmd_starts_with( $prefix ) {
return array_slice( $this->arguments, 0, count( $prefix ) ) === $prefix;
}
/**
* Given positional arguments, find the command to execute.
*
* @param array $args
* @return array|string Command, args, and path on success; error message on failure
*/
public function find_command_to_run( $args ) {
$command = WP_CLI::get_root_command();
WP_CLI::do_hook( 'find_command_to_run_pre' );
$cmd_path = [];
while ( ! empty( $args ) && $command->can_have_subcommands() ) {
$cmd_path[] = $args[0];
$full_name = implode( ' ', $cmd_path );
$subcommand = $command->find_subcommand( $args );
if ( ! $subcommand ) {
if ( count( $cmd_path ) > 1 ) {
$child = array_pop( $cmd_path );
$parent_name = implode( ' ', $cmd_path );
$suggestion = $this->get_subcommand_suggestion( $child, $command );
return sprintf(
"'%s' is not a registered subcommand of '%s'. See 'wp help %s' for available subcommands.%s",
$child,
$parent_name,
$parent_name,
! empty( $suggestion ) ? PHP_EOL . "Did you mean '{$suggestion}'?" : ''
);
}
$suggestion = $this->get_subcommand_suggestion( $full_name, $command );
return sprintf(
"'%s' is not a registered wp command. See 'wp help' for available commands.%s",
$full_name,
! empty( $suggestion ) ? PHP_EOL . "Did you mean '{$suggestion}'?" : ''
);
}
if ( $this->is_command_disabled( $subcommand ) ) {
return sprintf(
"The '%s' command has been disabled from the config file.",
$full_name
);
}
$command = $subcommand;
}
return [ $command, $args, $cmd_path ];
}
/**
* Find the WP-CLI command to run given arguments, and invoke it.
*
* @param array $args Positional arguments including command name
* @param array $assoc_args Associative arguments for the command.
* @param array $options Configuration options for the function.
*/
public function run_command( $args, $assoc_args = [], $options = [] ) {
WP_CLI::do_hook( 'before_run_command', $args, $assoc_args, $options );
if ( ! empty( $options['back_compat_conversions'] ) ) {
list( $args, $assoc_args ) = self::back_compat_conversions( $args, $assoc_args );
}
$r = $this->find_command_to_run( $args );
if ( is_string( $r ) ) {
WP_CLI::error( $r );
}
list( $command, $final_args, $cmd_path ) = $r;
$name = implode( ' ', $cmd_path );
$extra_args = [];
if ( isset( $this->extra_config[ $name ] ) ) {
$extra_args = $this->extra_config[ $name ];
}
WP_CLI::debug( 'Running command: ' . $name, 'bootstrap' );
try {
$command->invoke( $final_args, $assoc_args, $extra_args );
} catch ( Exception $e ) {
WP_CLI::error( $e->getMessage() );
}
}
/**
* Show synopsis if the called command is a composite command
*/
public function show_synopsis_if_composite_command() {
$r = $this->find_command_to_run( $this->arguments );
if ( is_array( $r ) ) {
list( $command ) = $r;
if ( $command->can_have_subcommands() ) {
$command->show_usage();
exit;
}
}
}
private function run_command_and_exit( $help_exit_warning = '' ) {
$this->show_synopsis_if_composite_command();
$this->run_command( $this->arguments, $this->assoc_args );
if ( $this->cmd_starts_with( [ 'help' ] ) ) {
// Help couldn't find the command so exit with suggestion.
$suggestion_or_disabled = $this->find_command_to_run( array_slice( $this->arguments, 1 ) );
if ( is_string( $suggestion_or_disabled ) ) {
if ( $help_exit_warning ) {
WP_CLI::warning( $help_exit_warning );
}
WP_CLI::error( $suggestion_or_disabled );
}
// Should never get here.
}
exit;
}
/**
* Perform a command against a remote server over SSH (or a container using
* scheme of "docker", "docker-compose", or "docker-compose-run").
*
* @param string $connection_string Passed connection string.
* @return void
*/
private function run_ssh_command( $connection_string ) {
WP_CLI::do_hook( 'before_ssh' );
$bits = Utils\parse_ssh_url( $connection_string );
$pre_cmd = getenv( 'WP_CLI_SSH_PRE_CMD' );
if ( $pre_cmd ) {
$message = WP_CLI::warning( "WP_CLI_SSH_PRE_CMD found, executing the following command(s) on the remote machine:\n $pre_cmd" );
WP_CLI::log( $message );
$pre_cmd = rtrim( $pre_cmd, ';' ) . '; ';
}
if ( ! empty( $bits['path'] ) ) {
$pre_cmd .= 'cd ' . escapeshellarg( $bits['path'] ) . '; ';
}
$env_vars = '';
if ( getenv( 'WP_CLI_STRICT_ARGS_MODE' ) ) {
$env_vars .= 'WP_CLI_STRICT_ARGS_MODE=1 ';
}
$wp_binary = 'wp';
$wp_args = array_slice( $GLOBALS['argv'], 1 );
if ( $this->alias && ! empty( $wp_args[0] ) && $this->alias === $wp_args[0] ) {
array_shift( $wp_args );
$runtime_alias = [];
foreach ( $this->aliases[ $this->alias ] as $key => $value ) {
if ( 'ssh' === $key ) {
continue;
}
$runtime_alias[ $key ] = $value;
}
if ( ! empty( $runtime_alias ) ) {
$encoded_alias = json_encode(
[
$this->alias => $runtime_alias,
]
);
$wp_binary = "WP_CLI_RUNTIME_ALIAS='{$encoded_alias}' {$wp_binary} {$this->alias}";
}
}
foreach ( $wp_args as $k => $v ) {
if ( preg_match( '#--ssh=#', $v ) ) {
unset( $wp_args[ $k ] );
}
}
$wp_command = $pre_cmd . $env_vars . $wp_binary . ' ' . implode( ' ', array_map( 'escapeshellarg', $wp_args ) );
if ( isset( $bits['scheme'] ) && 'docker-compose-run' === $bits['scheme'] ) {
$wp_command = implode( ' ', $wp_args );
}
$escaped_command = $this->generate_ssh_command( $bits, $wp_command );
passthru( $escaped_command, $exit_code );
if ( 255 === $exit_code ) {
WP_CLI::error( 'Cannot connect over SSH using provided configuration.', 255 );
} else {
exit( $exit_code );
}
}
/**
* Generate a shell command from the parsed connection string.
*
* @param array $bits Parsed connection string.
* @param string $wp_command WP-CLI command to run.
* @return string
*/
private function generate_ssh_command( $bits, $wp_command ) {
$escaped_command = '';
// Set default values.
foreach ( [ 'scheme', 'user', 'host', 'port', 'path', 'key' ] as $bit ) {
if ( ! isset( $bits[ $bit ] ) ) {
$bits[ $bit ] = null;
}
WP_CLI::debug( 'SSH ' . $bit . ': ' . $bits[ $bit ], 'bootstrap' );
}
$is_tty = function_exists( 'posix_isatty' ) && posix_isatty( STDOUT );
if ( 'docker' === $bits['scheme'] ) {
$command = 'docker exec %s%s%s sh -c %s';
$escaped_command = sprintf(
$command,
$bits['user'] ? '--user ' . escapeshellarg( $bits['user'] ) . ' ' : '',
$is_tty ? '-t ' : '',
escapeshellarg( $bits['host'] ),
escapeshellarg( $wp_command )
);
}
if ( 'docker-compose' === $bits['scheme'] ) {
$command = 'docker-compose exec %s%s%s sh -c %s';
$escaped_command = sprintf(
$command,
$bits['user'] ? '--user ' . escapeshellarg( $bits['user'] ) . ' ' : '',
$is_tty ? '' : '-T ',
escapeshellarg( $bits['host'] ),
escapeshellarg( $wp_command )
);
}
if ( 'docker-compose-run' === $bits['scheme'] ) {
$command = 'docker-compose run %s%s%s %s';
$escaped_command = sprintf(
$command,
$bits['user'] ? '--user ' . escapeshellarg( $bits['user'] ) . ' ' : '',
$is_tty ? '' : '-T ',
escapeshellarg( $bits['host'] ),
$wp_command
);
}
// Vagrant ssh-config.
if ( 'vagrant' === $bits['scheme'] ) {
$cache = WP_CLI::get_cache();
$cache_key = 'vagrant:' . $this->project_config_path;
if ( $cache->has( $cache_key ) ) {
$cached = $cache->read( $cache_key );
$values = json_decode( $cached, true );
} else {
$ssh_config = shell_exec( 'vagrant ssh-config 2>/dev/null' );
if ( preg_match_all( '#\s*(?<NAME>[a-zA-Z]+)\s(?<VALUE>.+)\s*#', $ssh_config, $matches ) ) {
$values = array_combine( $matches['NAME'], $matches['VALUE'] );
$cache->write( $cache_key, json_encode( $values ) );
}
}
if ( empty( $bits['host'] ) || ( isset( $values['Host'] ) && $bits['host'] === $values['Host'] ) ) {
$bits['scheme'] = 'ssh';
$bits['host'] = $values['HostName'];
$bits['port'] = $values['Port'];
$bits['user'] = $values['User'];
$bits['key'] = $values['IdentityFile'];
}
// If we could not resolve the bits still, fallback to just `vagrant ssh`
if ( 'vagrant' === $bits['scheme'] ) {
$command = 'vagrant ssh -c %s %s';
$escaped_command = sprintf(
$command,
escapeshellarg( $wp_command ),
escapeshellarg( $bits['host'] )
);
}
}
// Default scheme is SSH.
if ( 'ssh' === $bits['scheme'] || null === $bits['scheme'] ) {
$command = 'ssh -q %s %s %s';
if ( $bits['user'] ) {
$bits['host'] = $bits['user'] . '@' . $bits['host'];
}
$command_args = [
$bits['port'] ? '-p ' . (int) $bits['port'] . ' ' : '',
$bits['key'] ? sprintf( '-i %s', $bits['key'] ) : '',
$is_tty ? '-t' : '-T',
];
$escaped_command = sprintf(
$command,
implode( ' ', array_filter( $command_args ) ),
escapeshellarg( $bits['host'] ),
escapeshellarg( $wp_command )
);
}
WP_CLI::debug( 'Running SSH command: ' . $escaped_command, 'bootstrap' );
return $escaped_command;
}
/**
* Check whether a given command is disabled by the config.
*
* @return bool
*/
public function is_command_disabled( $command ) {
$path = implode( ' ', array_slice( Dispatcher\get_path( $command ), 1 ) );
return in_array( $path, $this->config['disabled_commands'], true );
}
/**
* Returns wp-config.php code, skipping the loading of wp-settings.php.
*
* @param string $wp_config_path Optional. Config file path. If left empty, it tries to
* locate the wp-config.php file automatically.
*
* @return string
*/
public function get_wp_config_code( $wp_config_path = '' ) {
if ( empty( $wp_config_path ) ) {
$wp_config_path = Utils\locate_wp_config();
}
$wp_config_code = explode( "\n", file_get_contents( $wp_config_path ) );
// Detect and strip byte-order marks (BOMs).
// This code assumes they can only be found on the first line.
foreach ( self::BYTE_ORDER_MARKS as $bom_name => $bom_sequence ) {
WP_CLI::debug( "Looking for {$bom_name} BOM", 'bootstrap' );
$length = strlen( $bom_sequence );
while ( substr( $wp_config_code[0], 0, $length ) === $bom_sequence ) {
WP_CLI::warning(
"{$bom_name} byte-order mark (BOM) detected in wp-config.php file, stripping it for parsing."
);
$wp_config_code[0] = substr( $wp_config_code[0], $length );
}
}
$found_wp_settings = false;
$lines_to_run = [];
foreach ( $wp_config_code as $line ) {
if ( preg_match( '/^\s*require.+wp-settings\.php/', $line ) ) {
$found_wp_settings = true;
continue;
}
$lines_to_run[] = $line;
}
if ( ! $found_wp_settings ) {
WP_CLI::error( 'Strange wp-config.php file: wp-settings.php is not loaded directly.' );
}
$source = implode( "\n", $lines_to_run );
$source = Utils\replace_path_consts( $source, $wp_config_path );
return preg_replace( '|^\s*\<\?php\s*|', '', $source );
}
/**
* Transparently convert deprecated syntaxes
*
* @param array $args
* @param array $assoc_args
* @return array
*/
private static function back_compat_conversions( $args, $assoc_args ) {
$top_level_aliases = [
'sql' => 'db',
'blog' => 'site',
];
if ( count( $args ) > 0 ) {
foreach ( $top_level_aliases as $old => $new ) {
if ( $old === $args[0] ) {
$args[0] = $new;
break;
}
}
}
// *-meta -> * meta
if ( ! empty( $args ) && preg_match( '/(post|comment|user|network)-meta/', $args[0], $matches ) ) {
array_shift( $args );
array_unshift( $args, 'meta' );
array_unshift( $args, $matches[1] );
}
// cli aliases -> cli alias list
if ( [ 'cli', 'aliases' ] === array_slice( $args, 0, 2 ) ) {
list( $args[0], $args[1], $args[2] ) = [ 'cli', 'alias', 'list' ];
}
// core (multsite-)install --admin_name= -> --admin_user=
if ( count( $args ) > 0 && 'core' === $args[0] && isset( $assoc_args['admin_name'] ) ) {
$assoc_args['admin_user'] = $assoc_args['admin_name'];
unset( $assoc_args['admin_name'] );
}
// core config -> config create
if ( [ 'core', 'config' ] === array_slice( $args, 0, 2 ) ) {
list( $args[0], $args[1] ) = [ 'config', 'create' ];
}
// core language -> language core
if ( [ 'core', 'language' ] === array_slice( $args, 0, 2 ) ) {
list( $args[0], $args[1] ) = [ 'language', 'core' ];
}
// checksum core -> core verify-checksums
if ( [ 'checksum', 'core' ] === array_slice( $args, 0, 2 ) ) {
list( $args[0], $args[1] ) = [ 'core', 'verify-checksums' ];
}
// checksum plugin -> plugin verify-checksums
if ( [ 'checksum', 'plugin' ] === array_slice( $args, 0, 2 ) ) {
list( $args[0], $args[1] ) = [ 'plugin', 'verify-checksums' ];
}
// site create --site_id= -> site create --network_id=
if ( count( $args ) >= 2 && 'site' === $args[0] && 'create' === $args[1] && isset( $assoc_args['site_id'] ) ) {
$assoc_args['network_id'] = $assoc_args['site_id'];
unset( $assoc_args['site_id'] );
}
// {plugin|theme} update-all -> {plugin|theme} update --all
if ( count( $args ) > 1 && in_array( $args[0], [ 'plugin', 'theme' ], true )
&& 'update-all' === $args[1]
) {
$args[1] = 'update';
$assoc_args['all'] = true;
}
// transient delete-expired -> transient delete --expired
if ( count( $args ) > 1 && 'transient' === $args[0] && 'delete-expired' === $args[1] ) {
$args[1] = 'delete';
$assoc_args['expired'] = true;
}
// transient delete-all -> transient delete --all
if ( count( $args ) > 1 && 'transient' === $args[0] && 'delete-all' === $args[1] ) {
$args[1] = 'delete';
$assoc_args['all'] = true;
}
// plugin scaffold -> scaffold plugin
if ( [ 'plugin', 'scaffold' ] === array_slice( $args, 0, 2 ) ) {
list( $args[0], $args[1] ) = [ $args[1], $args[0] ];
}
// foo --help -> help foo
if ( isset( $assoc_args['help'] ) ) {
array_unshift( $args, 'help' );
unset( $assoc_args['help'] );
}
// {post|user} list --ids -> {post|user} list --format=ids
if ( count( $args ) > 1 && in_array( $args[0], [ 'post', 'user' ], true )
&& 'list' === $args[1]
&& isset( $assoc_args['ids'] )
) {
$assoc_args['format'] = 'ids';
unset( $assoc_args['ids'] );
}
// --json -> --format=json
if ( isset( $assoc_args['json'] ) ) {
$assoc_args['format'] = 'json';
unset( $assoc_args['json'] );
}
// --{version|info} -> cli {version|info}
if ( empty( $args ) ) {
$special_flags = [ 'version', 'info' ];
foreach ( $special_flags as $key ) {
if ( isset( $assoc_args[ $key ] ) ) {
$args = [ 'cli', $key ];
unset( $assoc_args[ $key ] );
break;
}
}
}
// (post|comment|site|term) url --> (post|comment|site|term) list --*__in --field=url
if ( count( $args ) >= 2 && in_array( $args[0], [ 'post', 'comment', 'site', 'term' ], true ) && 'url' === $args[1] ) {
switch ( $args[0] ) {
case 'post':
$post_ids = array_slice( $args, 2 );
$args = [ 'post', 'list' ];
$assoc_args['post__in'] = implode( ',', $post_ids );
$assoc_args['post_type'] = 'any';
$assoc_args['orderby'] = 'post__in';
$assoc_args['field'] = 'url';
break;
case 'comment':
$comment_ids = array_slice( $args, 2 );
$args = [ 'comment', 'list' ];
$assoc_args['comment__in'] = implode( ',', $comment_ids );
$assoc_args['orderby'] = 'comment__in';
$assoc_args['field'] = 'url';
break;
case 'site':
$site_ids = array_slice( $args, 2 );
$args = [ 'site', 'list' ];
$assoc_args['site__in'] = implode( ',', $site_ids );
$assoc_args['field'] = 'url';
break;
case 'term':
$taxonomy = '';
if ( isset( $args[2] ) ) {
$taxonomy = $args[2];
}
$term_ids = array_slice( $args, 3 );
$args = [ 'term', 'list', $taxonomy ];
$assoc_args['include'] = implode( ',', $term_ids );
$assoc_args['orderby'] = 'include';
$assoc_args['field'] = 'url';
break;
}
}
// config get --[global|constant]=<global|constant> --> config get <name> --type=constant|variable
// config get --> config list
if ( count( $args ) === 2
&& 'config' === $args[0]
&& 'get' === $args[1] ) {
if ( isset( $assoc_args['global'] ) ) {
$name = $assoc_args['global'];
$type = 'variable';
unset( $assoc_args['global'] );
} elseif ( isset( $assoc_args['constant'] ) ) {
$name = $assoc_args['constant'];
$type = 'constant';
unset( $assoc_args['constant'] );
}
if ( ! empty( $name ) && ! empty( $type ) ) {
$args[] = $name;
$assoc_args['type'] = $type;
} else {
// We had a 'config get' without a '<name>', so assume 'list' was wanted.
$args[1] = 'list';
}
}
return [ $args, $assoc_args ];
}
/**
* Whether or not the output should be rendered in color
*
* @return bool
*/
public function in_color() {
return $this->colorize;
}
public function init_colorization() {
if ( 'auto' === $this->config['color'] ) {
$this->colorize = ( ! Utils\isPiped() && ! Utils\is_windows() );
} else {
$this->colorize = $this->config['color'];
}
}
public function init_logger() {
if ( $this->config['quiet'] ) {
$logger = new Loggers\Quiet( $this->in_color() );
} else {
$logger = new Loggers\Regular( $this->in_color() );
}
WP_CLI::set_logger( $logger );
}
public function get_required_files() {
return $this->required_files;
}
/**
* Do WordPress core files exist?
*
* @return bool
*/
private function wp_exists() {
return file_exists( ABSPATH . 'wp-includes/version.php' );
}
/**
* Are WordPress core files readable?
*
* @return bool
*/
private function wp_is_readable() {
return is_readable( ABSPATH . 'wp-includes/version.php' );
}
private function check_wp_version() {
$wp_exists = $this->wp_exists();
$wp_is_readable = $this->wp_is_readable();
if ( ! $wp_exists || ! $wp_is_readable ) {
$this->show_synopsis_if_composite_command();
// If the command doesn't exist use as error.
$args = $this->cmd_starts_with( [ 'help' ] ) ? array_slice( $this->arguments, 1 ) : $this->arguments;
$suggestion_or_disabled = $this->find_command_to_run( $args );
if ( is_string( $suggestion_or_disabled ) ) {
if ( ! preg_match( '/disabled from the config file.$/', $suggestion_or_disabled ) ) {
WP_CLI::warning( "No WordPress installation found. If the command '" . implode( ' ', $args ) . "' is in a plugin or theme, pass --path=`path/to/wordpress`." );
}
WP_CLI::error( $suggestion_or_disabled );
}
if ( $wp_exists && ! $wp_is_readable ) {
WP_CLI::error(
'It seems, the WordPress core files do not have the proper file permissions.'
);
}
WP_CLI::error(
"This does not seem to be a WordPress installation.\n" .
'Pass --path=`path/to/wordpress` or run `wp core download`.'
);
}
global $wp_version;
include ABSPATH . 'wp-includes/version.php';
$minimum_version = '3.7';
if ( version_compare( $wp_version, $minimum_version, '<' ) ) {
WP_CLI::error(
"WP-CLI needs WordPress $minimum_version or later to work properly. " .
"The version currently installed is $wp_version.\n" .
'Try running `wp core download --force`.'
);
}
}
public function init_config() {
$configurator = WP_CLI::get_configurator();
$argv = array_slice( $GLOBALS['argv'], 1 );
$this->alias = null;
if ( ! empty( $argv[0] ) && preg_match( '#' . Configurator::ALIAS_REGEX . '#', $argv[0], $matches ) ) {
$this->alias = array_shift( $argv );
}
// File config
{
$this->global_config_path = $this->get_global_config_path();
$this->project_config_path = $this->get_project_config_path();
$configurator->merge_yml( $this->global_config_path, $this->alias );
$config = $configurator->to_array();
$this->required_files['global'] = $config[0]['require'];
$configurator->merge_yml( $this->project_config_path, $this->alias );
$config = $configurator->to_array();
$this->required_files['project'] = $config[0]['require'];
}
// Runtime config and args
{
list( $args, $assoc_args, $this->runtime_config ) = $configurator->parse_args( $argv );
list( $this->arguments, $this->assoc_args ) = self::back_compat_conversions(
$args,
$assoc_args
);
$configurator->merge_array( $this->runtime_config );
}
list( $this->config, $this->extra_config ) = $configurator->to_array();
$this->aliases = $configurator->get_aliases();
if ( count( $this->aliases ) && ! isset( $this->aliases['@all'] ) ) {
$this->aliases = array_reverse( $this->aliases );
$this->aliases['@all'] = 'Run command against every registered alias.';
$this->aliases = array_reverse( $this->aliases );
}
$this->required_files['runtime'] = $this->config['require'];
}
private function check_root() {
if ( $this->config['allow-root'] || getenv( 'WP_CLI_ALLOW_ROOT' ) ) {
return; # they're aware of the risks!
}
if ( count( $this->arguments ) >= 2 && 'cli' === $this->arguments[0] && in_array( $this->arguments[1], [ 'update', 'info' ], true ) ) {
return; # make it easier to update root-owned copies
}
if ( ! function_exists( 'posix_geteuid' ) ) {
return; # posix functions not available
}
if ( posix_geteuid() !== 0 ) {
return; # not root
}
WP_CLI::error(
"YIKES! It looks like you're running this as root. You probably meant to " .
"run this as the user that your WordPress installation exists under.\n" .
"\n" .
"If you REALLY mean to run this as root, we won't stop you, but just " .
'bear in mind that any code on this site will then have full control of ' .
"your server, making it quite DANGEROUS.\n" .
"\n" .
"If you'd like to continue as root, please run this again, adding this " .
"flag: --allow-root\n" .
"\n" .
"If you'd like to run it as the user that this site is under, you can " .
"run the following to become the respective user:\n" .
"\n" .
" sudo -u USER -i -- wp <command>\n" .
"\n"
);
}
private function run_alias_group( $aliases ) {
Utils\check_proc_available( 'group alias' );
$php_bin = escapeshellarg( Utils\get_php_binary() );
$script_path = $GLOBALS['argv'][0];
if ( getenv( 'WP_CLI_CONFIG_PATH' ) ) {
$config_path = getenv( 'WP_CLI_CONFIG_PATH' );
} else {
$config_path = Utils\get_home_dir() . '/.wp-cli/config.yml';
}
$config_path = escapeshellarg( $config_path );
foreach ( $aliases as $alias ) {
WP_CLI::log( $alias );
$args = implode( ' ', array_map( 'escapeshellarg', $this->arguments ) );
$assoc_args = Utils\assoc_args_to_str( $this->assoc_args );
$runtime_config = Utils\assoc_args_to_str( $this->runtime_config );
$full_command = "WP_CLI_CONFIG_PATH={$config_path} {$php_bin} {$script_path} {$alias} {$args}{$assoc_args}{$runtime_config}";
$pipes = [];
$proc = Utils\proc_open_compat( $full_command, [ STDIN, STDOUT, STDERR ], $pipes );
proc_close( $proc );
}
}
private function set_alias( $alias ) {
$orig_config = $this->config;
$alias_config = $this->aliases[ $alias ];
$this->config = array_merge( $orig_config, $alias_config );
foreach ( $alias_config as $key => $_ ) {
if ( isset( $orig_config[ $key ] ) && ! is_null( $orig_config[ $key ] ) ) {
$this->assoc_args[ $key ] = $orig_config[ $key ];
}
}
}
public function start() {
// Enable PHP error reporting to stderr if testing. Will need to be re-enabled after WP loads.
if ( getenv( 'BEHAT_RUN' ) ) {
$this->enable_error_reporting();
}
WP_CLI::debug( $this->global_config_path_debug, 'bootstrap' );
WP_CLI::debug( $this->project_config_path_debug, 'bootstrap' );
WP_CLI::debug( 'argv: ' . implode( ' ', $GLOBALS['argv'] ), 'bootstrap' );
$this->check_root();
if ( $this->alias ) {
if ( '@all' === $this->alias && ! isset( $this->aliases['@all'] ) ) {
WP_CLI::error( "Cannot use '@all' when no aliases are registered." );
}
if ( '@all' === $this->alias && is_string( $this->aliases['@all'] ) ) {
$aliases = array_keys( $this->aliases );
$k = array_search( '@all', $aliases, true );
unset( $aliases[ $k ] );
$this->run_alias_group( $aliases );
exit;
}
if ( ! array_key_exists( $this->alias, $this->aliases ) ) {
$error_msg = "Alias '{$this->alias}' not found.";
$suggestion = Utils\get_suggestion( $this->alias, array_keys( $this->aliases ), $threshold = 2 );
if ( $suggestion ) {
$error_msg .= PHP_EOL . "Did you mean '{$suggestion}'?";
}
WP_CLI::error( $error_msg );
}
// Numerically indexed means a group of aliases
if ( isset( $this->aliases[ $this->alias ][0] ) ) {
$group_aliases = $this->aliases[ $this->alias ];
$all_aliases = array_keys( $this->aliases );
$diff = array_diff( $group_aliases, $all_aliases );
if ( ! empty( $diff ) ) {
WP_CLI::error( "Group '{$this->alias}' contains one or more invalid aliases: " . implode( ', ', $diff ) );
}
$this->run_alias_group( $group_aliases );
exit;
}
$this->set_alias( $this->alias );
}
if ( empty( $this->arguments ) ) {
$this->arguments[] = 'help';
}
// Protect 'cli info' from most of the runtime,
// except when the command will be run over SSH
if ( 'cli' === $this->arguments[0] && ! empty( $this->arguments[1] ) && 'info' === $this->arguments[1] && ! $this->config['ssh'] ) {
$this->run_command_and_exit();
}
if ( isset( $this->config['http'] ) && ! class_exists( '\WP_REST_CLI\Runner' ) ) {
WP_CLI::error( "RESTful WP-CLI needs to be installed. Try 'wp package install wp-cli/restful'." );
}
if ( $this->config['ssh'] ) {
$this->run_ssh_command( $this->config['ssh'] );
return;
}
// Handle --path parameter
self::set_wp_root( $this->find_wp_root() );
// First try at showing man page - if help command and either haven't found 'version.php' or 'wp-config.php' (so won't be loading WP & adding commands) or help on subcommand.
if ( $this->cmd_starts_with( [ 'help' ] )
&& ( ! $this->wp_exists()
|| ! Utils\locate_wp_config()
|| count( $this->arguments ) > 2
) ) {
$this->auto_check_update();
$this->run_command( $this->arguments, $this->assoc_args );
// Help didn't exit so failed to find the command at this stage.
}
// Handle --url parameter
$url = self::guess_url( $this->config );
if ( $url ) {
WP_CLI::set_url( $url );
}
$this->do_early_invoke( 'before_wp_load' );
$this->check_wp_version();
if ( $this->cmd_starts_with( [ 'config', 'create' ] ) ) {
$this->run_command_and_exit();
}
if ( ! Utils\locate_wp_config() ) {
WP_CLI::error(
"'wp-config.php' not found.\n" .
'Either create one manually or use `wp config create`.'
);
}
/*
* Set the MySQLi error reporting off because WordPress handles its own.
* This is due to the default value change from `MYSQLI_REPORT_OFF`
* to `MYSQLI_REPORT_ERROR|MYSQLI_REPORT_STRICT` in PHP 8.1.
*/
if ( function_exists( 'mysqli_report' ) ) {
mysqli_report( 0 ); // phpcs:ignore WordPress.DB.RestrictedFunctions.mysql_mysqli_report
}
// phpcs:disable WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedConstantFound -- Declaring WP native constants.
if ( $this->cmd_starts_with( [ 'core', 'is-installed' ] )
|| $this->cmd_starts_with( [ 'core', 'update-db' ] ) ) {
define( 'WP_INSTALLING', true );
}
if (
count( $this->arguments ) >= 2 &&
'core' === $this->arguments[0] &&
in_array( $this->arguments[1], [ 'install', 'multisite-install' ], true )
) {
define( 'WP_INSTALLING', true );
// We really need a URL here
if ( ! isset( $_SERVER['HTTP_HOST'] ) ) {
$url = 'https://example.com';
WP_CLI::set_url( $url );
}
if ( 'multisite-install' === $this->arguments[1] ) {
// need to fake some globals to skip the checks in wp-includes/ms-settings.php
$url_parts = Utils\parse_url( $url );
self::fake_current_site_blog( $url_parts );
if ( ! defined( 'COOKIEHASH' ) ) {
define( 'COOKIEHASH', md5( $url_parts['host'] ) );
}
}
}
if ( $this->cmd_starts_with( [ 'import' ] ) ) {
define( 'WP_LOAD_IMPORTERS', true );
define( 'WP_IMPORTING', true );
}
if ( $this->cmd_starts_with( [ 'cron', 'event', 'run' ] ) ) {
define( 'DOING_CRON', true );
}
// phpcs:enable WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedConstantFound
$this->load_wordpress();
$this->run_command_and_exit();
}
/**
* Load WordPress, if it hasn't already been loaded
*/
public function load_wordpress() {
static $wp_cli_is_loaded;
// Globals not explicitly globalized in WordPress
global $site_id, $wpdb, $public, $current_site, $current_blog, $path, $shortcode_tags;
if ( ! empty( $wp_cli_is_loaded ) ) {
return;
}
$wp_cli_is_loaded = true;
// Handle --context flag.
$this->context_manager->switch_context( $this->config );
WP_CLI::debug( 'Begin WordPress load', 'bootstrap' );
WP_CLI::do_hook( 'before_wp_load' );
$this->check_wp_version();
$wp_config_path = Utils\locate_wp_config();
if ( ! $wp_config_path ) {
WP_CLI::error(
"'wp-config.php' not found.\n" .
'Either create one manually or use `wp config create`.'
);
}
WP_CLI::debug( 'wp-config.php path: ' . $wp_config_path, 'bootstrap' );
WP_CLI::do_hook( 'before_wp_config_load' );
// Load wp-config.php code, in the global scope
$wp_cli_original_defined_vars = get_defined_vars();
eval( $this->get_wp_config_code() ); // phpcs:ignore Squiz.PHP.Eval.Discouraged
foreach ( get_defined_vars() as $key => $var ) {
if ( array_key_exists( $key, $wp_cli_original_defined_vars ) || 'wp_cli_original_defined_vars' === $key ) {
continue;
}
// phpcs:ignore PHPCompatibility.Variables.ForbiddenGlobalVariableVariable.NonBareVariableFound
global ${$key};
// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedVariableFound
${$key} = $var;
}
$this->maybe_update_url_from_domain_constant();
WP_CLI::do_hook( 'after_wp_config_load' );
$this->do_early_invoke( 'after_wp_config_load' );
// Prevent error notice from wp_guess_url() when core isn't installed
if ( $this->cmd_starts_with( [ 'core', 'is-installed' ] )
&& ! defined( 'COOKIEHASH' ) ) {
define( 'COOKIEHASH', md5( 'wp-cli' ) );
}
// Load WP-CLI utilities
require WP_CLI_ROOT . '/php/utils-wp.php';
// Set up WordPress bootstrap actions and filters
$this->setup_bootstrap_hooks();
// Load Core, mu-plugins, plugins, themes etc.
if ( Utils\wp_version_compare( '4.6-alpha-37575', '>=' ) ) {
if ( $this->cmd_starts_with( [ 'help' ] ) ) {
// Hack: define `WP_DEBUG` and `WP_DEBUG_DISPLAY` to get `wpdb::bail()` to `wp_die()`.
if ( ! defined( 'WP_DEBUG' ) ) {
define( 'WP_DEBUG', true );
}
if ( ! defined( 'WP_DEBUG_DISPLAY' ) ) {
define( 'WP_DEBUG_DISPLAY', true );
}
}
require ABSPATH . 'wp-settings.php';
} else {
require WP_CLI_ROOT . '/php/wp-settings-cli.php';
}
// Fix memory limit. See https://core.trac.wordpress.org/ticket/14889
// phpcs:ignore WordPress.PHP.IniSet.memory_limit_Blacklisted -- This is perfectly fine for CLI usage.
ini_set( 'memory_limit', -1 );
// Load all the admin APIs, for convenience
require ABSPATH . 'wp-admin/includes/admin.php';
add_filter(
'filesystem_method',
static function () {
return 'direct';
},
99
);
// Re-enable PHP error reporting to stderr if testing.
if ( getenv( 'BEHAT_RUN' ) ) {
$this->enable_error_reporting();
}
WP_CLI::debug( 'Loaded WordPress', 'bootstrap' );
WP_CLI::do_hook( 'after_wp_load' );
}
private static function fake_current_site_blog( $url_parts ) {
global $current_site, $current_blog;
if ( ! isset( $url_parts['path'] ) ) {
$url_parts['path'] = '/';
}
// phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited -- Intentional override.
$current_site = (object) [
'id' => 1,
'blog_id' => 1,
'domain' => $url_parts['host'],
'path' => $url_parts['path'],
'cookie_domain' => $url_parts['host'],
'site_name' => 'WordPress',
];
// phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited -- Intentional override.
$current_blog = (object) [
'blog_id' => 1,
'site_id' => 1,
'domain' => $url_parts['host'],
'path' => $url_parts['path'],
'public' => '1',
'archived' => '0',
'mature' => '0',
'spam' => '0',
'deleted' => '0',
'lang_id' => '0',
];
}
/**
* Called after wp-config.php is eval'd, to potentially reset `--url`
*/
private function maybe_update_url_from_domain_constant() {
if ( ! empty( $this->config['url'] ) || ! empty( $this->config['blog'] ) ) {
return;
}
if ( defined( 'DOMAIN_CURRENT_SITE' ) ) {
$url = DOMAIN_CURRENT_SITE;
if ( defined( 'PATH_CURRENT_SITE' ) ) {
$url .= PATH_CURRENT_SITE;
}
WP_CLI::set_url( $url );
}
}
/**
* Set up hooks meant to run during the WordPress bootstrap process
*/
private function setup_bootstrap_hooks() {
if ( $this->config['skip-plugins'] ) {
$this->setup_skip_plugins_filters();
}
if ( $this->config['skip-themes'] ) {
WP_CLI::add_wp_hook( 'setup_theme', [ $this, 'action_setup_theme_wp_cli_skip_themes' ], 999 );
}
if ( $this->cmd_starts_with( [ 'help' ] ) ) {
// Try to trap errors on help.
$help_handler = [ $this, 'help_wp_die_handler' ]; // Avoid any cross PHP version issues by not using $this in anon function.
WP_CLI::add_wp_hook(
'wp_die_handler',
function () use ( $help_handler ) {
return $help_handler;
}
);
} else {
WP_CLI::add_wp_hook(
'wp_die_handler',
static function () {
return '\WP_CLI\Utils\wp_die_handler';
}
);
}
// Prevent code from performing a redirect
WP_CLI::add_wp_hook( 'wp_redirect', 'WP_CLI\\Utils\\wp_redirect_handler' );
WP_CLI::add_wp_hook(
'nocache_headers',
static function ( $headers ) {
// WordPress might be calling nocache_headers() because of a dead db
global $wpdb;
if ( ! empty( $wpdb->error ) ) {
Utils\wp_die_handler( $wpdb->error );
}
// Otherwise, WP might be calling nocache_headers() because WP isn't installed
Utils\wp_not_installed();
return $headers;
}
);
WP_CLI::add_wp_hook(
'setup_theme',
static function () {
// Polyfill is_customize_preview(), as it is needed by TwentyTwenty to
// check for starter content.
if ( ! function_exists( 'is_customize_preview' ) ) {
function is_customize_preview() {
return false;
}
}
},
0
);
// ALTERNATE_WP_CRON might trigger a redirect, which we can't handle
if ( defined( 'ALTERNATE_WP_CRON' ) && ALTERNATE_WP_CRON ) {
WP_CLI::add_wp_hook(
'muplugins_loaded',
static function () {
remove_action( 'init', 'wp_cron' );
}
);
}
// Get rid of warnings when converting single site to multisite
if ( defined( 'WP_INSTALLING' ) && $this->is_multisite() ) {
$values = [
'ms_files_rewriting' => null,
'active_sitewide_plugins' => [],
'_site_transient_update_core' => null,
'_site_transient_update_themes' => null,
'_site_transient_update_plugins' => null,
'WPLANG' => '',
];
foreach ( $values as $key => $value ) {
WP_CLI::add_wp_hook(
"pre_site_option_$key",
static function () use ( $values, $key ) {
return $values[ $key ];
}
);
}
}
// Always permit operations against sites, regardless of status
WP_CLI::add_wp_hook( 'ms_site_check', '__return_true' );
// Always permit operations against WordPress, regardless of maintenance mode
WP_CLI::add_wp_hook(
'enable_maintenance_mode',
static function () {
return false;
}
);
// Use our own debug mode handling instead of WP core
WP_CLI::add_wp_hook(
'enable_wp_debug_mode_checks',
static function ( $ret ) {
Utils\wp_debug_mode();
return false;
}
);
// Never load advanced-cache.php drop-in when WP-CLI is operating
WP_CLI::add_wp_hook(
'enable_loading_advanced_cache_dropin',
static function () {
return false;
}
);
// In a multisite installation, die if unable to find site given in --url parameter
if ( $this->is_multisite() ) {
$run_on_site_not_found = false;
if ( $this->cmd_starts_with( [ 'cache', 'flush' ] ) ) {
$run_on_site_not_found = 'cache flush';
}
if ( $this->cmd_starts_with( [ 'search-replace' ] ) ) {
// Table-specified
// Bits: search-replace <search> <replace> [<table>...]
// Or not against a specific blog
if ( count( $this->arguments ) > 3
|| ! empty( $this->assoc_args['network'] )
|| ! empty( $this->assoc_args['all-tables'] )
|| ! empty( $this->assoc_args['all-tables-with-prefix'] ) ) {
$run_on_site_not_found = 'search-replace';
}
}
if ( $run_on_site_not_found
&& Utils\wp_version_compare( '4.0', '>=' ) ) {
WP_CLI::add_wp_hook(
'ms_site_not_found',
static function () use ( $run_on_site_not_found ) {
// esc_sql() isn't yet loaded, but needed.
if ( 'search-replace' === $run_on_site_not_found ) {
require_once ABSPATH . WPINC . '/formatting.php';
}
// PHP 5.3 compatible implementation of run_command_and_exit().
$runner = WP_CLI::get_runner();
$runner->run_command( $runner->arguments, $runner->assoc_args );
exit;
},
1
);
}
WP_CLI::add_wp_hook(
'ms_site_not_found',
static function ( $current_site, $domain, $path ) {
$url = $domain . $path;
$message = $url ? "Site '{$url}' not found." : 'Site not found.';
$has_param = isset( WP_CLI::get_runner()->config['url'] );
$has_const = defined( 'DOMAIN_CURRENT_SITE' );
$explanation = '';
if ( $has_param ) {
$explanation = 'Verify `--url=<url>` matches an existing site.';
} else {
$explanation = "Define DOMAIN_CURRENT_SITE in 'wp-config.php' or use `--url=<url>` to override.";
if ( $has_const ) {
$explanation = 'Verify DOMAIN_CURRENT_SITE matches an existing site or use `--url=<url>` to override.';
}
}
if ( $explanation ) {
$message .= ' ' . $explanation;
}
WP_CLI::error( $message );
},
10,
3
);
}
// The APC cache is not available on the command-line, so bail, to prevent cache poisoning
WP_CLI::add_wp_hook(
'muplugins_loaded',
static function () {
if ( $GLOBALS['_wp_using_ext_object_cache'] && class_exists( 'APC_Object_Cache' ) ) {
WP_CLI::warning( 'Running WP-CLI while the APC object cache is activated can result in cache corruption.' );
WP_CLI::confirm( 'Given the consequences, do you wish to continue?' );
}
},
0
);
// Handle --user parameter
if ( ! defined( 'WP_INSTALLING' ) ) {
$config = $this->config;
WP_CLI::add_wp_hook(
'init',
static function () use ( $config ) {
if ( isset( $config['user'] ) ) {
$fetcher = new Fetchers\User();
$user = $fetcher->get_check( $config['user'] );
wp_set_current_user( $user->ID );
} else {
add_action( 'init', 'kses_remove_filters', 11 );
}
},
0
);
}
// Avoid uncaught exception when using wp_mail() without defined $_SERVER['SERVER_NAME']
WP_CLI::add_wp_hook(
'wp_mail_from',
static function ( $from_email ) {
if ( 'wordpress@' === $from_email ) {
$sitename = strtolower( Utils\parse_url( site_url(), PHP_URL_HOST ) );
if ( substr( $sitename, 0, 4 ) === 'www.' ) {
$sitename = substr( $sitename, 4 );
}
$from_email = 'wordpress@' . $sitename;
}
return $from_email;
}
);
// Don't apply set_url_scheme in get_home_url() or get_site_url().
WP_CLI::add_wp_hook(
'home_url',
static function ( $url, $path, $scheme, $blog_id ) {
if ( empty( $blog_id ) || ! is_multisite() ) {
$url = get_option( 'home' );
} else {
switch_to_blog( $blog_id );
$url = get_option( 'home' );
restore_current_blog();
}
if ( $path && is_string( $path ) ) {
$url .= '/' . ltrim( $path, '/' );
}
return $url;
},
0,
4
);
WP_CLI::add_wp_hook(
'site_url',
static function ( $url, $path, $scheme, $blog_id ) {
if ( empty( $blog_id ) || ! is_multisite() ) {
$url = get_option( 'siteurl' );
} else {
switch_to_blog( $blog_id );
$url = get_option( 'siteurl' );
restore_current_blog();
}
if ( $path && is_string( $path ) ) {
$url .= '/' . ltrim( $path, '/' );
}
return $url;
},
0,
4
);
// Set up hook for plugins and themes to conditionally add WP-CLI commands.
WP_CLI::add_wp_hook(
'init',
static function () {
do_action( 'cli_init' );
}
);
}
/**
* Set up the filters to skip the loaded plugins
*/
private function setup_skip_plugins_filters() {
$wp_cli_filter_active_plugins = static function ( $plugins ) {
$skipped_plugins = WP_CLI::get_runner()->config['skip-plugins'];
if ( true === $skipped_plugins ) {
return [];
}
if ( ! is_array( $plugins ) ) {
return $plugins;
}
foreach ( $plugins as $a => $b ) {
// active_sitewide_plugins stores plugin name as the key.
if ( false !== strpos( current_filter(), 'active_sitewide_plugins' ) && Utils\is_plugin_skipped( $a ) ) {
unset( $plugins[ $a ] );
// active_plugins stores plugin name as the value.
} elseif ( false !== strpos( current_filter(), 'active_plugins' ) && Utils\is_plugin_skipped( $b ) ) {
unset( $plugins[ $a ] );
}
}
// Reindex because active_plugins expects a numeric index.
if ( false !== strpos( current_filter(), 'active_plugins' ) ) {
$plugins = array_values( $plugins );
}
return $plugins;
};
$hooks = [
'pre_site_option_active_sitewide_plugins',
'site_option_active_sitewide_plugins',
'pre_option_active_plugins',
'option_active_plugins',
];
foreach ( $hooks as $hook ) {
WP_CLI::add_wp_hook( $hook, $wp_cli_filter_active_plugins, 999 );
}
WP_CLI::add_wp_hook(
'plugins_loaded',
static function () use ( $hooks, $wp_cli_filter_active_plugins ) {
foreach ( $hooks as $hook ) {
remove_filter( $hook, $wp_cli_filter_active_plugins, 999 );
}
},
0
);
}
/**
* Set up the filters to skip the loaded theme
*/
public function action_setup_theme_wp_cli_skip_themes() {
$wp_cli_filter_active_theme = static function ( $value ) {
$skipped_themes = WP_CLI::get_runner()->config['skip-themes'];
if ( true === $skipped_themes ) {
return '';
}
if ( ! is_array( $skipped_themes ) ) {
$skipped_themes = explode( ',', $skipped_themes );
}
$checked_value = $value;
// Always check against the stylesheet value
// This ensures a child theme can be skipped when template differs
if ( false !== stripos( current_filter(), 'option_template' ) ) {
$checked_value = get_option( 'stylesheet' );
}
if ( '' === $checked_value || in_array( $checked_value, $skipped_themes, true ) ) {
return '';
}
return $value;
};
$hooks = [
'pre_option_template',
'option_template',
'pre_option_stylesheet',
'option_stylesheet',
];
foreach ( $hooks as $hook ) {
add_filter( $hook, $wp_cli_filter_active_theme, 999 );
}
// Clean up after the TEMPLATEPATH and STYLESHEETPATH constants are defined
WP_CLI::add_wp_hook(
'after_setup_theme',
static function () use ( $hooks, $wp_cli_filter_active_theme ) {
foreach ( $hooks as $hook ) {
remove_filter( $hook, $wp_cli_filter_active_theme, 999 );
}
},
0
);
}
/**
* Whether or not this WordPress installation is multisite.
*
* For use after wp-config.php has loaded, but before the rest of WordPress
* is loaded.
*/
private function is_multisite() {
if ( defined( 'MULTISITE' ) ) {
return MULTISITE;
}
if ( defined( 'SUBDOMAIN_INSTALL' ) || defined( 'VHOST' ) || defined( 'SUNRISE' ) ) {
return true;
}
return false;
}
/**
* Error handler for `wp_die()` when the command is help to try to trap errors (db connection failure in particular) during WordPress load.
*/
public function help_wp_die_handler( $message ) {
$help_exit_warning = 'Error during WordPress load.';
if ( $message instanceof WP_Error ) {
$help_exit_warning = Utils\wp_clean_error_message( $message->get_error_message() );
} elseif ( is_string( $message ) ) {
$help_exit_warning = Utils\wp_clean_error_message( $message );
}
$this->run_command_and_exit( $help_exit_warning );
}
/**
* Check whether there's a WP-CLI update available, and suggest update if so.
*/
private function auto_check_update() {
// `wp cli update` only works with Phars at this time.
if ( ! Utils\inside_phar() ) {
return;
}
$existing_phar = realpath( $_SERVER['argv'][0] );
// Phar needs to be writable to be easily updateable.
if ( ! is_writable( $existing_phar ) || ! is_writable( dirname( $existing_phar ) ) ) {
return;
}
// Only check for update when a human is operating.
if ( ! function_exists( 'posix_isatty' ) || ! posix_isatty( STDOUT ) ) {
return;
}
// Allow hosts and other providers to disable automatic check update.
if ( getenv( 'WP_CLI_DISABLE_AUTO_CHECK_UPDATE' ) ) {
return;
}
// Permit configuration of number of days between checks.
$days_between_checks = getenv( 'WP_CLI_AUTO_CHECK_UPDATE_DAYS' );
if ( false === $days_between_checks ) {
$days_between_checks = 1;
}
$cache = WP_CLI::get_cache();
$cache_key = 'wp-cli-update-check';
// Bail early on the first check, so we don't always check on an unwritable cache.
if ( ! $cache->has( $cache_key ) ) {
$cache->write( $cache_key, time() );
return;
}
// Bail if last check is still within our update check time period.
$last_check = (int) $cache->read( $cache_key );
if ( ( time() - ( 24 * 60 * 60 * $days_between_checks ) ) < $last_check ) {
return;
}
// In case the operation fails, ensure the timestamp has been updated.
$cache->write( $cache_key, time() );
// Check whether any updates are available.
ob_start();
WP_CLI::run_command(
[ 'cli', 'check-update' ],
[
'format' => 'count',
]
);
$count = ob_get_clean();
if ( ! $count ) {
return;
}
// Looks like an update is available, so let's prompt to update.
WP_CLI::run_command( [ 'cli', 'update' ] );
// If the Phar was replaced, we can't proceed with the original process.
exit;
}
/**
* Get a suggestion on similar (sub)commands when the user entered an
* unknown (sub)command.
*
* @param string $entry User entry that didn't match an
* existing command.
* @param CompositeCommand $root_command Root command to start search for
* suggestions at.
*
* @return string Suggestion that fits the user entry, or an empty string.
*/
private function get_subcommand_suggestion( $entry, CompositeCommand $root_command = null ) {
$commands = [];
$this->enumerate_commands( $root_command ?: WP_CLI::get_root_command(), $commands );
return Utils\get_suggestion( $entry, $commands, $threshold = 2 );
}
/**
* Recursive method to enumerate all known commands.
*
* @param CompositeCommand $command Composite command to recurse over.
* @param array $list Reference to list accumulating results.
* @param string $parent Parent command to use as prefix.
*/
private function enumerate_commands( CompositeCommand $command, array &$list, $parent = '' ) {
foreach ( $command->get_subcommands() as $subcommand ) {
/** @var CompositeCommand $subcommand */
$command_string = empty( $parent )
? $subcommand->get_name()
: "{$parent} {$subcommand->get_name()}";
$list[] = $command_string;
$this->enumerate_commands( $subcommand, $list, $command_string );
}
}
/**
* Enables (almost) full PHP error reporting to stderr.
*/
private function enable_error_reporting() {
if ( E_ALL !== error_reporting() ) {
// Don't enable E_DEPRECATED as old versions of WP use PHP 4 style constructors and the mysql extension.
error_reporting( E_ALL & ~E_DEPRECATED );
}
ini_set( 'display_errors', 'stderr' ); // phpcs:ignore WordPress.PHP.IniSet.display_errors_Blacklisted
}
}