mirror of
https://ghproxy.net/https://github.com/wp-cli/extension-command.git
synced 2025-08-18 05:21:17 +08:00
Merge pull request #453 from wp-cli/add/phpstan
This commit is contained in:
commit
fa25c5525a
11 changed files with 275 additions and 89 deletions
|
@ -18,14 +18,14 @@
|
|||
],
|
||||
"require": {
|
||||
"composer/semver": "^1.4 || ^2 || ^3",
|
||||
"wp-cli/wp-cli": "^2.12"
|
||||
"wp-cli/wp-cli": "^2.13"
|
||||
},
|
||||
"require-dev": {
|
||||
"wp-cli/cache-command": "^2.0",
|
||||
"wp-cli/entity-command": "^1.3 || ^2",
|
||||
"wp-cli/language-command": "^2.0",
|
||||
"wp-cli/scaffold-command": "^1.2 || ^2",
|
||||
"wp-cli/wp-cli-tests": "^5.0.1"
|
||||
"wp-cli/wp-cli-tests": "^5"
|
||||
},
|
||||
"config": {
|
||||
"process-timeout": 7200,
|
||||
|
|
15
phpstan.neon.dist
Normal file
15
phpstan.neon.dist
Normal file
|
@ -0,0 +1,15 @@
|
|||
parameters:
|
||||
level: 9
|
||||
paths:
|
||||
- src
|
||||
- extension-command.php
|
||||
scanDirectories:
|
||||
- vendor/wp-cli/wp-cli/php
|
||||
scanFiles:
|
||||
- vendor/php-stubs/wordpress-stubs/wordpress-stubs.php
|
||||
treatPhpDocTypesAsCertain: false
|
||||
ignoreErrors:
|
||||
- identifier: missingType.iterableValue
|
||||
- identifier: missingType.property
|
||||
- identifier: missingType.parameter
|
||||
- identifier: missingType.return
|
|
@ -72,6 +72,9 @@ class Plugin_AutoUpdates_Command {
|
|||
* $ wp plugin auto-updates enable hello
|
||||
* Plugin auto-updates for 'hello' enabled.
|
||||
* Success: Enabled 1 of 1 plugin auto-updates.
|
||||
*
|
||||
* @param string[] $args Positional arguments.
|
||||
* @param array{all?: bool, 'disabled-only'?: bool} $assoc_args Associative arguments.
|
||||
*/
|
||||
public function enable( $args, $assoc_args ) {
|
||||
$all = Utils\get_flag_value( $assoc_args, 'all', false );
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
<?php
|
||||
|
||||
use WP_CLI\CommandWithUpgrade;
|
||||
use WP_CLI\ParsePluginNameInput;
|
||||
use WP_CLI\Utils;
|
||||
use WP_CLI\WpOrgApi;
|
||||
|
@ -41,9 +42,11 @@ use function WP_CLI\Utils\normalize_path;
|
|||
* Success: Installed 1 of 1 plugins.
|
||||
*
|
||||
* @package wp-cli
|
||||
*
|
||||
* @phpstan-type PluginInformation object{name: string, slug: non-empty-string, version: string, new_version: string, download_link: string, requires_php?: string, requires?: string, package: string}&\stdClass
|
||||
* @extends CommandWithUpgrade<string,>
|
||||
*/
|
||||
class Plugin_Command extends \WP_CLI\CommandWithUpgrade {
|
||||
|
||||
class Plugin_Command extends CommandWithUpgrade {
|
||||
use ParsePluginNameInput;
|
||||
|
||||
protected $item_type = 'plugin';
|
||||
|
@ -66,13 +69,6 @@ class Plugin_Command extends \WP_CLI\CommandWithUpgrade {
|
|||
'auto_update',
|
||||
);
|
||||
|
||||
/**
|
||||
* Plugin fetcher instance.
|
||||
*
|
||||
* @var \WP_CLI\Fetchers\Plugin
|
||||
*/
|
||||
protected $fetcher;
|
||||
|
||||
public function __construct() {
|
||||
require_once ABSPATH . 'wp-admin/includes/plugin.php';
|
||||
require_once ABSPATH . 'wp-admin/includes/plugin-install.php';
|
||||
|
@ -209,6 +205,9 @@ class Plugin_Command extends \WP_CLI\CommandWithUpgrade {
|
|||
}
|
||||
|
||||
protected function status_single( $args ) {
|
||||
/**
|
||||
* @var object{name: string, file: string} $plugin
|
||||
*/
|
||||
$plugin = $this->fetcher->get_check( $args[0] );
|
||||
$file = $plugin->file;
|
||||
|
||||
|
@ -345,11 +344,18 @@ class Plugin_Command extends \WP_CLI\CommandWithUpgrade {
|
|||
* Plugin 'bbpress' network activated.
|
||||
* Plugin 'buddypress' network activated.
|
||||
* Success: Activated 2 of 2 plugins.
|
||||
*
|
||||
* @param array $args
|
||||
* @param array $assoc_args
|
||||
*/
|
||||
public function activate( $args, $assoc_args = array() ) {
|
||||
public function activate( $args, $assoc_args = [] ) {
|
||||
$network_wide = Utils\get_flag_value( $assoc_args, 'network', false );
|
||||
$all = Utils\get_flag_value( $assoc_args, 'all', false );
|
||||
$all_exclude = Utils\get_flag_value( $assoc_args, 'exclude' );
|
||||
$all_exclude = Utils\get_flag_value( $assoc_args, 'exclude', '' );
|
||||
|
||||
/**
|
||||
* @var string $all_exclude
|
||||
*/
|
||||
|
||||
$args = $this->check_optional_args_and_all( $args, $all, 'activate', $all_exclude );
|
||||
if ( ! $args ) {
|
||||
|
@ -358,7 +364,11 @@ class Plugin_Command extends \WP_CLI\CommandWithUpgrade {
|
|||
|
||||
$successes = 0;
|
||||
$errors = 0;
|
||||
$plugins = $this->fetcher->get_many( $args );
|
||||
|
||||
/**
|
||||
* @var array<object{name: string, file: string}> $plugins
|
||||
*/
|
||||
$plugins = $this->fetcher->get_many( $args );
|
||||
if ( count( $plugins ) < count( $args ) ) {
|
||||
$errors = count( $args ) - count( $plugins );
|
||||
}
|
||||
|
@ -387,7 +397,7 @@ class Plugin_Command extends \WP_CLI\CommandWithUpgrade {
|
|||
|
||||
if ( is_wp_error( $result ) ) {
|
||||
$message = $result->get_error_message();
|
||||
$message = preg_replace( '/<a\s[^>]+>.*<\/a>/im', '', $message );
|
||||
$message = (string) preg_replace( '/<a\s[^>]+>.*<\/a>/im', '', $message );
|
||||
$message = wp_strip_all_tags( $message );
|
||||
$message = str_replace( 'Error: ', '', $message );
|
||||
WP_CLI::warning( "Failed to activate plugin. {$message}" );
|
||||
|
@ -437,10 +447,14 @@ class Plugin_Command extends \WP_CLI\CommandWithUpgrade {
|
|||
* Plugin 'ninja-forms' deactivated.
|
||||
* Success: Deactivated 2 of 2 plugins.
|
||||
*/
|
||||
public function deactivate( $args, $assoc_args = array() ) {
|
||||
public function deactivate( $args, $assoc_args = [] ) {
|
||||
$network_wide = Utils\get_flag_value( $assoc_args, 'network' );
|
||||
$disable_all = Utils\get_flag_value( $assoc_args, 'all' );
|
||||
$disable_all_exclude = Utils\get_flag_value( $assoc_args, 'exclude' );
|
||||
$disable_all_exclude = Utils\get_flag_value( $assoc_args, 'exclude', '' );
|
||||
|
||||
/**
|
||||
* @var string $disable_all_exclude
|
||||
*/
|
||||
|
||||
$args = $this->check_optional_args_and_all( $args, $disable_all, 'deactivate', $disable_all_exclude );
|
||||
if ( ! $args ) {
|
||||
|
@ -530,7 +544,7 @@ class Plugin_Command extends \WP_CLI\CommandWithUpgrade {
|
|||
* Plugin 'akismet' activated.
|
||||
* Success: Toggled 1 of 1 plugins.
|
||||
*/
|
||||
public function toggle( $args, $assoc_args = array() ) {
|
||||
public function toggle( $args, $assoc_args ) {
|
||||
$network_wide = Utils\get_flag_value( $assoc_args, 'network' );
|
||||
|
||||
$successes = 0;
|
||||
|
@ -574,6 +588,9 @@ class Plugin_Command extends \WP_CLI\CommandWithUpgrade {
|
|||
$path = untrailingslashit( WP_PLUGIN_DIR );
|
||||
|
||||
if ( ! empty( $args ) ) {
|
||||
/**
|
||||
* @var object{name: string, file: string} $plugin
|
||||
*/
|
||||
$plugin = $this->fetcher->get_check( $args[0] );
|
||||
$path .= '/' . $plugin->file;
|
||||
|
||||
|
@ -591,6 +608,9 @@ class Plugin_Command extends \WP_CLI\CommandWithUpgrade {
|
|||
list($wp_core_version) = explode( '-', $wp_version );
|
||||
$wp_core_version = implode( '.', array_slice( explode( '.', $wp_core_version ), 0, 2 ) );
|
||||
|
||||
/**
|
||||
* @var \WP_Error|PluginInformation $api
|
||||
*/
|
||||
$api = plugins_api( 'plugin_information', array( 'slug' => $slug ) );
|
||||
|
||||
if ( is_wp_error( $api ) ) {
|
||||
|
@ -755,6 +775,9 @@ class Plugin_Command extends \WP_CLI\CommandWithUpgrade {
|
|||
$auto_updates = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @var string[] $recently_active
|
||||
*/
|
||||
$recently_active = is_network_admin() ? get_site_option( 'recently_activated' ) : get_option( 'recently_activated' );
|
||||
|
||||
if ( false === $recently_active ) {
|
||||
|
@ -763,10 +786,11 @@ class Plugin_Command extends \WP_CLI\CommandWithUpgrade {
|
|||
|
||||
foreach ( $this->get_all_plugins() as $file => $details ) {
|
||||
$all_update_info = $this->get_update_info();
|
||||
$update_info = ( isset( $all_update_info->response[ $file ] ) && null !== $all_update_info->response[ $file ] ) ? (array) $all_update_info->response[ $file ] : null;
|
||||
$name = Utils\get_plugin_name( $file );
|
||||
$wporg_info = $this->get_wporg_data( $name );
|
||||
$plugin_data = get_plugin_data( WP_PLUGIN_DIR . '/' . $file, false, false );
|
||||
// @phpstan-ignore notIdentical.alwaysTrue
|
||||
$update_info = ( isset( $all_update_info->response[ $file ] ) && null !== $all_update_info->response[ $file ] ) ? (array) $all_update_info->response[ $file ] : null;
|
||||
$name = Utils\get_plugin_name( $file );
|
||||
$wporg_info = $this->get_wporg_data( $name );
|
||||
$plugin_data = get_plugin_data( WP_PLUGIN_DIR . '/' . $file, false, false );
|
||||
|
||||
if ( ! isset( $duplicate_names[ $name ] ) ) {
|
||||
$duplicate_names[ $name ] = array();
|
||||
|
@ -875,7 +899,7 @@ class Plugin_Command extends \WP_CLI\CommandWithUpgrade {
|
|||
|
||||
if ( isset( $plugin_update_info->requires ) && version_compare( $wp_version, $requires, '>=' ) ) {
|
||||
$reason = "This update requires WordPress version $plugin_update_info->requires, but the version installed is $wp_version.";
|
||||
} elseif ( ! isset( $update_info['package'] ) ) {
|
||||
} elseif ( ! isset( $plugin_update_info->package ) ) {
|
||||
$reason = 'Update file not provided. Contact author for more details';
|
||||
} else {
|
||||
$reason = 'Update not available';
|
||||
|
@ -904,7 +928,7 @@ class Plugin_Command extends \WP_CLI\CommandWithUpgrade {
|
|||
*
|
||||
* @param string $plugin_name The plugin slug.
|
||||
*
|
||||
* @return string The status of the plugin, includes the last update date.
|
||||
* @return array{status: string, last_updated: string|false, status?: string, last_updated?: string} The status of the plugin, includes the last update date.
|
||||
*/
|
||||
protected function get_wporg_data( $plugin_name ) {
|
||||
$data = [
|
||||
|
@ -947,10 +971,12 @@ class Plugin_Command extends \WP_CLI\CommandWithUpgrade {
|
|||
$r_body = wp_remote_retrieve_body( $request );
|
||||
if ( strpos( $r_body, 'pubDate' ) !== false ) {
|
||||
// Very raw check, not validating the format or anything else.
|
||||
$xml = simplexml_load_string( $r_body );
|
||||
$xml_pub_date = $xml->xpath( '//pubDate' );
|
||||
if ( $xml_pub_date ) {
|
||||
$data['last_updated'] = wp_date( 'Y-m-d', (string) strtotime( $xml_pub_date[0] ) );
|
||||
$xml = simplexml_load_string( $r_body );
|
||||
if ( false !== $xml ) {
|
||||
$xml_pub_date = $xml->xpath( '//pubDate' );
|
||||
if ( $xml_pub_date ) {
|
||||
$data['last_updated'] = wp_date( 'Y-m-d', strtotime( $xml_pub_date[0] ) ?: null );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1115,6 +1141,9 @@ class Plugin_Command extends \WP_CLI\CommandWithUpgrade {
|
|||
'status',
|
||||
);
|
||||
|
||||
/**
|
||||
* @var object{name: string, file: string} $plugin
|
||||
*/
|
||||
$plugin = $this->fetcher->get_check( $args[0] );
|
||||
$file = $plugin->file;
|
||||
|
||||
|
@ -1173,11 +1202,14 @@ class Plugin_Command extends \WP_CLI\CommandWithUpgrade {
|
|||
* Uninstalled and deleted 'tinymce-templates' plugin.
|
||||
* Success: Uninstalled 2 of 2 plugins.
|
||||
*/
|
||||
public function uninstall( $args, $assoc_args = array() ) {
|
||||
|
||||
public function uninstall( $args, $assoc_args = [] ) {
|
||||
$all = Utils\get_flag_value( $assoc_args, 'all', false );
|
||||
$all_exclude = Utils\get_flag_value( $assoc_args, 'exclude', false );
|
||||
|
||||
/**
|
||||
* @var string $all_exclude
|
||||
*/
|
||||
|
||||
// Check if plugin names or --all is passed.
|
||||
$args = $this->check_optional_args_and_all( $args, $all, 'uninstall', $all_exclude );
|
||||
if ( ! $args ) {
|
||||
|
@ -1222,6 +1254,9 @@ class Plugin_Command extends \WP_CLI\CommandWithUpgrade {
|
|||
if ( '.' !== $plugin_slug && ! empty( $plugin_translations[ $plugin_slug ] ) ) {
|
||||
$translations = $plugin_translations[ $plugin_slug ];
|
||||
|
||||
/**
|
||||
* @var \WP_Filesystem_Base $wp_filesystem
|
||||
*/
|
||||
global $wp_filesystem;
|
||||
require_once ABSPATH . '/wp-admin/includes/file.php';
|
||||
WP_Filesystem();
|
||||
|
@ -1233,7 +1268,11 @@ class Plugin_Command extends \WP_CLI\CommandWithUpgrade {
|
|||
|
||||
$json_translation_files = glob( WP_LANG_DIR . '/plugins/' . $plugin_slug . '-' . $translation . '-*.json' );
|
||||
if ( $json_translation_files ) {
|
||||
array_map( array( $wp_filesystem, 'delete' ), $json_translation_files );
|
||||
/**
|
||||
* @var callable $callback
|
||||
*/
|
||||
$callback = [ $wp_filesystem, 'delete' ];
|
||||
array_map( $callback, $json_translation_files );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1257,6 +1296,10 @@ class Plugin_Command extends \WP_CLI\CommandWithUpgrade {
|
|||
// Remove deleted plugins from the plugin updates list.
|
||||
$current = get_site_transient( $this->upgrade_transient );
|
||||
if ( $current ) {
|
||||
/**
|
||||
* @var object{response: array<string, mixed>, checked: array<string, mixed>}&\stdClass $current
|
||||
*/
|
||||
|
||||
// Don't remove the plugins that weren't deleted.
|
||||
$deleted = array_diff( $deleted_plugin_files, $delete_errors );
|
||||
|
||||
|
@ -1292,7 +1335,7 @@ class Plugin_Command extends \WP_CLI\CommandWithUpgrade {
|
|||
*
|
||||
* @subcommand is-installed
|
||||
*/
|
||||
public function is_installed( $args, $assoc_args = array() ) {
|
||||
public function is_installed( $args, $assoc_args ) {
|
||||
if ( $this->fetcher->get( $args[0] ) ) {
|
||||
WP_CLI::halt( 0 );
|
||||
} else {
|
||||
|
@ -1322,7 +1365,7 @@ class Plugin_Command extends \WP_CLI\CommandWithUpgrade {
|
|||
*
|
||||
* @subcommand is-active
|
||||
*/
|
||||
public function is_active( $args, $assoc_args = array() ) {
|
||||
public function is_active( $args, $assoc_args ) {
|
||||
$network_wide = Utils\get_flag_value( $assoc_args, 'network' );
|
||||
|
||||
$plugin = $this->fetcher->get( $args[0] );
|
||||
|
@ -1366,10 +1409,14 @@ class Plugin_Command extends \WP_CLI\CommandWithUpgrade {
|
|||
* Deleted 'tinymce-templates' plugin.
|
||||
* Success: Deleted 2 of 2 plugins.
|
||||
*/
|
||||
public function delete( $args, $assoc_args = array() ) {
|
||||
public function delete( $args, $assoc_args ) {
|
||||
$all = Utils\get_flag_value( $assoc_args, 'all', false );
|
||||
$all_exclude = Utils\get_flag_value( $assoc_args, 'exclude', false );
|
||||
|
||||
/**
|
||||
* @var string $all_exclude
|
||||
*/
|
||||
|
||||
// Check if plugin names or --all is passed.
|
||||
$args = $this->check_optional_args_and_all( $args, $all, 'delete', $all_exclude );
|
||||
if ( ! $args ) {
|
||||
|
@ -1505,7 +1552,11 @@ class Plugin_Command extends \WP_CLI\CommandWithUpgrade {
|
|||
* @subcommand list
|
||||
*/
|
||||
public function list_( $_, $assoc_args ) {
|
||||
/**
|
||||
* @var string $fields
|
||||
*/
|
||||
$fields = Utils\get_flag_value( $assoc_args, 'fields' );
|
||||
|
||||
if ( ! empty( $fields ) ) {
|
||||
$fields = explode( ',', $fields );
|
||||
$this->check_wporg['status'] = in_array( 'wporg_status', $fields, true );
|
||||
|
@ -1578,7 +1629,7 @@ class Plugin_Command extends \WP_CLI\CommandWithUpgrade {
|
|||
/**
|
||||
* Gets the details of a plugin.
|
||||
*
|
||||
* @param object
|
||||
* @param string $file Plugin file name.
|
||||
* @return array
|
||||
*/
|
||||
private function get_details( $file ) {
|
||||
|
@ -1591,8 +1642,8 @@ class Plugin_Command extends \WP_CLI\CommandWithUpgrade {
|
|||
/**
|
||||
* Performs deletion of plugin files
|
||||
*
|
||||
* @param $plugin - Plugin fetcher object (name, file)
|
||||
* @return bool - If plugin was deleted
|
||||
* @param $plugin Plugin fetcher object (name, file)
|
||||
* @return bool Whether plugin was deleted
|
||||
*/
|
||||
private function delete_plugin( $plugin ) {
|
||||
// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound
|
||||
|
|
|
@ -28,6 +28,9 @@ use WP_CLI\Utils;
|
|||
*/
|
||||
class Theme_AutoUpdates_Command {
|
||||
|
||||
/**
|
||||
* @use ParseThemeNameInput<\WP_Theme>
|
||||
*/
|
||||
use ParseThemeNameInput;
|
||||
|
||||
/**
|
||||
|
|
|
@ -41,9 +41,15 @@ use WP_CLI\Utils;
|
|||
* Author: the WordPress team
|
||||
*
|
||||
* @package wp-cli
|
||||
*
|
||||
* @phpstan-type ThemeInformation object{name: string, slug: non-empty-string, version: string, new_version: string, download_link: string, requires_php?: string, requires?: string}&\stdClass
|
||||
* @extends CommandWithUpgrade<\WP_Theme>
|
||||
*/
|
||||
class Theme_Command extends CommandWithUpgrade {
|
||||
|
||||
/**
|
||||
* @use ParseThemeNameInput<\WP_Theme>
|
||||
*/
|
||||
use ParseThemeNameInput;
|
||||
|
||||
protected $item_type = 'theme';
|
||||
|
@ -211,8 +217,11 @@ class Theme_Command extends CommandWithUpgrade {
|
|||
*
|
||||
* $ wp theme activate twentysixteen
|
||||
* Success: Switched to 'Twenty Sixteen' theme.
|
||||
*
|
||||
* @param string[] $args Positional arguments.
|
||||
* @param array $assoc_args Associative arguments. Unused.
|
||||
*/
|
||||
public function activate( $args = array() ) {
|
||||
public function activate( $args, $assoc_args = [] ) {
|
||||
$theme = $this->fetcher->get_check( $args[0] );
|
||||
|
||||
$errors = $theme->errors();
|
||||
|
@ -232,7 +241,7 @@ class Theme_Command extends CommandWithUpgrade {
|
|||
WP_CLI::error( "The '{$theme->get_stylesheet()}' theme cannot be activated without its parent, '{$theme->get_template()}'." );
|
||||
}
|
||||
|
||||
switch_theme( $theme->get_template(), $theme->get_stylesheet() );
|
||||
switch_theme( $theme->get_stylesheet() );
|
||||
|
||||
if ( $this->is_active_theme( $theme ) ) {
|
||||
WP_CLI::success( "Switched to '$name' theme." );
|
||||
|
@ -279,6 +288,9 @@ class Theme_Command extends CommandWithUpgrade {
|
|||
WP_CLI::error( 'This is not a multisite installation.' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @var \WP_Theme $theme
|
||||
*/
|
||||
$theme = $this->fetcher->get_check( $args[0] );
|
||||
$name = $theme->get( 'Name' );
|
||||
|
||||
|
@ -290,6 +302,11 @@ class Theme_Command extends CommandWithUpgrade {
|
|||
if ( empty( $allowed_themes ) ) {
|
||||
$allowed_themes = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* @var array<string, bool> $allowed_themes
|
||||
*/
|
||||
|
||||
$allowed_themes[ $theme->get_stylesheet() ] = true;
|
||||
call_user_func( "update{$_site}_option", 'allowedthemes', $allowed_themes );
|
||||
|
||||
|
@ -344,6 +361,11 @@ class Theme_Command extends CommandWithUpgrade {
|
|||
|
||||
# Add the current theme to the allowed themes option or site option
|
||||
$allowed_themes = call_user_func( "get{$_site}_option", 'allowedthemes' );
|
||||
|
||||
/**
|
||||
* @var array<string, bool> $allowed_themes
|
||||
*/
|
||||
|
||||
if ( ! empty( $allowed_themes[ $theme->get_stylesheet() ] ) ) {
|
||||
unset( $allowed_themes[ $theme->get_stylesheet() ] );
|
||||
}
|
||||
|
@ -400,6 +422,9 @@ class Theme_Command extends CommandWithUpgrade {
|
|||
list($wp_core_version) = explode( '-', $wp_version );
|
||||
$wp_core_version = implode( '.', array_slice( explode( '.', $wp_core_version ), 0, 2 ) );
|
||||
|
||||
/**
|
||||
* @var \WP_Error|ThemeInformation $api
|
||||
*/
|
||||
$api = themes_api( 'theme_information', array( 'slug' => $slug ) );
|
||||
|
||||
if ( is_wp_error( $api ) ) {
|
||||
|
@ -732,7 +757,7 @@ class Theme_Command extends CommandWithUpgrade {
|
|||
*
|
||||
* @subcommand is-installed
|
||||
*/
|
||||
public function is_installed( $args, $assoc_args = array() ) {
|
||||
public function is_installed( $args, $assoc_args ) {
|
||||
$theme = wp_get_theme( $args[0] );
|
||||
|
||||
if ( $theme->exists() ) {
|
||||
|
@ -761,7 +786,7 @@ class Theme_Command extends CommandWithUpgrade {
|
|||
*
|
||||
* @subcommand is-active
|
||||
*/
|
||||
public function is_active( $args, $assoc_args = array() ) {
|
||||
public function is_active( $args, $assoc_args ) {
|
||||
$theme = wp_get_theme( $args[0] );
|
||||
|
||||
if ( ! $theme->exists() ) {
|
||||
|
|
|
@ -74,8 +74,11 @@ class Theme_Mod_Command extends WP_CLI_Command {
|
|||
* | background_color | dd3333 |
|
||||
* | header_textcolor | |
|
||||
* +------------------+--------+
|
||||
*
|
||||
* @param string[] $args Positional arguments.
|
||||
* @param array{field?: string, all?: bool, format: string} $assoc_args Associative arguments.
|
||||
*/
|
||||
public function get( $args = array(), $assoc_args = array() ) {
|
||||
public function get( $args, $assoc_args ) {
|
||||
|
||||
if ( ! \WP_CLI\Utils\get_flag_value( $assoc_args, 'all' ) && empty( $args ) ) {
|
||||
WP_CLI::error( 'You must specify at least one mod or use --all.' );
|
||||
|
@ -162,10 +165,13 @@ class Theme_Mod_Command extends WP_CLI_Command {
|
|||
* +------------------+---------+
|
||||
*
|
||||
* @subcommand list
|
||||
*
|
||||
* @param string[] $args Positional arguments. Unused.
|
||||
* @param array{field?: string, format: string} $assoc_args Associative arguments.
|
||||
*/
|
||||
public function list_( $args = array(), $assoc_args = array() ) {
|
||||
public function list_( $args, $assoc_args ) {
|
||||
|
||||
$assoc_args['all'] = 1;
|
||||
$assoc_args['all'] = true;
|
||||
|
||||
$this->get( $args, $assoc_args );
|
||||
}
|
||||
|
@ -194,8 +200,11 @@ class Theme_Mod_Command extends WP_CLI_Command {
|
|||
* # Remove multiple theme mods.
|
||||
* $ wp theme mod remove background_color header_textcolor
|
||||
* Success: 2 mods removed.
|
||||
*
|
||||
* @param string[] $args Positional arguments.
|
||||
* @param array{all?: bool} $assoc_args Associative arguments.
|
||||
*/
|
||||
public function remove( $args = array(), $assoc_args = array() ) {
|
||||
public function remove( $args, $assoc_args ) {
|
||||
|
||||
if ( ! \WP_CLI\Utils\get_flag_value( $assoc_args, 'all' ) && empty( $args ) ) {
|
||||
WP_CLI::error( 'You must specify at least one mod or use --all.' );
|
||||
|
@ -232,8 +241,11 @@ class Theme_Mod_Command extends WP_CLI_Command {
|
|||
* # Set theme mod
|
||||
* $ wp theme mod set background_color 000000
|
||||
* Success: Theme mod background_color set to 000000.
|
||||
*
|
||||
* @param array{0: string, 1: string} $args Positional arguments.
|
||||
* @param array $assoc_args Associative arguments. Unused.
|
||||
*/
|
||||
public function set( $args = array(), $assoc_args = array() ) {
|
||||
public function set( $args, $assoc_args ) {
|
||||
list( $mod, $value ) = $args;
|
||||
|
||||
set_theme_mod( $mod, $value );
|
||||
|
|
|
@ -11,6 +11,12 @@ use WP_CLI\Loggers;
|
|||
use WP_CLI\Utils;
|
||||
use WP_Error;
|
||||
|
||||
/**
|
||||
* @phpstan-import-type ThemeInformation from \Theme_Command
|
||||
* @phpstan-import-type PluginInformation from \Plugin_Command
|
||||
*
|
||||
* @template T
|
||||
*/
|
||||
abstract class CommandWithUpgrade extends \WP_CLI_Command {
|
||||
|
||||
protected $fetcher;
|
||||
|
@ -61,25 +67,43 @@ abstract class CommandWithUpgrade extends \WP_CLI_Command {
|
|||
$this->fetcher = new Fetchers\Plugin();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return class-string<\WP_Upgrader>
|
||||
*/
|
||||
abstract protected function get_upgrader_class( $force );
|
||||
|
||||
abstract protected function get_item_list();
|
||||
|
||||
/**
|
||||
* @param array List of update candidates
|
||||
* @param array List of item names
|
||||
* @param array $items List of update candidates
|
||||
* @param array $args List of item names
|
||||
* @return array List of update candidates
|
||||
*/
|
||||
abstract protected function filter_item_list( $items, $args );
|
||||
|
||||
abstract protected function get_all_items();
|
||||
|
||||
/**
|
||||
* Get the status for a given extension.
|
||||
*
|
||||
* @param T $file Extension to get the status for.
|
||||
*
|
||||
* @return string Status of the extension.
|
||||
*/
|
||||
abstract protected function get_status( $file );
|
||||
|
||||
abstract protected function status_single( $args );
|
||||
|
||||
abstract protected function install_from_repo( $slug, $assoc_args );
|
||||
|
||||
/**
|
||||
* Activates an extension.
|
||||
*
|
||||
* @param string[] $args Positional arguments.
|
||||
* @param array $assoc_args Associative arguments.
|
||||
*/
|
||||
abstract public function activate( $args, $assoc_args = [] );
|
||||
|
||||
public function status( $args ) {
|
||||
// Force WordPress to check for updates.
|
||||
call_user_func( $this->upgrade_refresh );
|
||||
|
@ -197,13 +221,16 @@ abstract class CommandWithUpgrade extends \WP_CLI_Command {
|
|||
|
||||
$filter = false;
|
||||
// If a GitHub URL, do some guessing as to the correct plugin/theme directory.
|
||||
if ( $is_remote && 'github.com' === $this->parse_url_host_component( $slug, PHP_URL_HOST )
|
||||
if ( $is_remote && 'github.com' === Utils\parse_url( $slug, PHP_URL_HOST )
|
||||
// Don't attempt to rename ZIPs uploaded to the releases page or coming from a raw source.
|
||||
&& ! preg_match( '#github\.com/[^/]+/[^/]+/(?:releases/download|raw)/#', $slug ) ) {
|
||||
|
||||
$filter = function ( $source ) use ( $slug ) {
|
||||
|
||||
$slug_dir = Utils\basename( $this->parse_url_host_component( $slug, PHP_URL_PATH ), '.zip' );
|
||||
/**
|
||||
* @var string $path
|
||||
*/
|
||||
$path = Utils\parse_url( $slug, PHP_URL_PATH );
|
||||
$slug_dir = Utils\basename( $path, '.zip' );
|
||||
|
||||
// Don't use the zip name if archive attached to release, as name likely to contain version tag/branch.
|
||||
if ( preg_match( '#github\.com/[^/]+/([^/]+)/archive/#', $slug, $matches ) ) {
|
||||
|
@ -215,7 +242,7 @@ abstract class CommandWithUpgrade extends \WP_CLI_Command {
|
|||
if ( $source_dir === $slug_dir ) {
|
||||
return $source;
|
||||
}
|
||||
$new_path = substr_replace( $source, $slug_dir, strrpos( $source, $source_dir ), strlen( $source_dir ) );
|
||||
$new_path = substr_replace( $source, $slug_dir, (int) strrpos( $source, $source_dir ), strlen( $source_dir ) );
|
||||
|
||||
if ( $GLOBALS['wp_filesystem']->move( $source, $new_path ) ) {
|
||||
WP_CLI::log( sprintf( "Renamed Github-based project from '%s' to '%s'.", $source_dir, $slug_dir ) );
|
||||
|
@ -294,8 +321,10 @@ abstract class CommandWithUpgrade extends \WP_CLI_Command {
|
|||
/**
|
||||
* Prepare an API response for downloading a particular version of an item.
|
||||
*
|
||||
* @param object $response wordpress.org API response
|
||||
* @param string $version The desired version of the package
|
||||
* @param object $response Wordpress.org API response.
|
||||
* @param string $version The desired version of the package.
|
||||
*
|
||||
* @phpstan-param PluginInformation|ThemeInformation $response
|
||||
*/
|
||||
protected static function alter_api_response( $response, $version ) {
|
||||
if ( $response->version === $version ) {
|
||||
|
@ -346,8 +375,8 @@ abstract class CommandWithUpgrade extends \WP_CLI_Command {
|
|||
}
|
||||
|
||||
protected function get_upgrader( $assoc_args ) {
|
||||
$force = (bool) Utils\get_flag_value( $assoc_args, 'force', false );
|
||||
$insecure = (bool) Utils\get_flag_value( $assoc_args, 'insecure', false );
|
||||
$force = Utils\get_flag_value( $assoc_args, 'force', false );
|
||||
$insecure = Utils\get_flag_value( $assoc_args, 'insecure', false );
|
||||
$upgrader_class = $this->get_upgrader_class( $force );
|
||||
return Utils\get_upgrader( $upgrader_class, $insecure );
|
||||
}
|
||||
|
@ -384,19 +413,22 @@ abstract class CommandWithUpgrade extends \WP_CLI_Command {
|
|||
}
|
||||
);
|
||||
|
||||
$minor = (bool) Utils\get_flag_value( $assoc_args, 'minor', false );
|
||||
$patch = (bool) Utils\get_flag_value( $assoc_args, 'patch', false );
|
||||
$minor = Utils\get_flag_value( $assoc_args, 'minor', false );
|
||||
$patch = Utils\get_flag_value( $assoc_args, 'patch', false );
|
||||
|
||||
if (
|
||||
in_array( $this->item_type, [ 'plugin', 'theme' ], true ) &&
|
||||
( $minor || $patch )
|
||||
) {
|
||||
$type = $minor ? 'minor' : 'patch';
|
||||
$insecure = (bool) Utils\get_flag_value( $assoc_args, 'insecure', false );
|
||||
$insecure = Utils\get_flag_value( $assoc_args, 'insecure', false );
|
||||
|
||||
$items_to_update = self::get_minor_or_patch_updates( $items_to_update, $type, $insecure, true, $this->item_type );
|
||||
}
|
||||
|
||||
/**
|
||||
* @var string|null $exclude
|
||||
*/
|
||||
$exclude = Utils\get_flag_value( $assoc_args, 'exclude' );
|
||||
if ( isset( $exclude ) ) {
|
||||
$exclude_items = explode( ',', trim( $assoc_args['exclude'], ',' ) );
|
||||
|
@ -475,6 +507,9 @@ abstract class CommandWithUpgrade extends \WP_CLI_Command {
|
|||
foreach ( $items_to_update as $name => $item_data ) {
|
||||
if ( isset( $transient->response[ $name ] ) ) {
|
||||
if ( is_object( $transient->response[ $name ] ) ) {
|
||||
/**
|
||||
* @var object{response: array<string, ThemeInformation|PluginInformation>} $transient
|
||||
*/
|
||||
$transient->response[ $name ]->new_version = $item_data['update_version'];
|
||||
$transient->response[ $name ]->package = $item_data['update_package'];
|
||||
} else {
|
||||
|
@ -490,6 +525,10 @@ abstract class CommandWithUpgrade extends \WP_CLI_Command {
|
|||
remove_filter( 'site_transient_' . $this->upgrade_transient, $transient_filter, 999 );
|
||||
}
|
||||
|
||||
/**
|
||||
* @var array $items_to_update
|
||||
*/
|
||||
|
||||
// Let the user know the results.
|
||||
$num_to_update = count( $items_to_update );
|
||||
$num_updated = count(
|
||||
|
@ -545,14 +584,14 @@ abstract class CommandWithUpgrade extends \WP_CLI_Command {
|
|||
protected function _list( $_, $assoc_args ) {
|
||||
|
||||
// Force WordPress to check for updates if `--skip-update-check` is not passed.
|
||||
if ( false === (bool) Utils\get_flag_value( $assoc_args, 'skip-update-check', false ) ) {
|
||||
if ( false === Utils\get_flag_value( $assoc_args, 'skip-update-check', false ) ) {
|
||||
delete_site_transient( $this->upgrade_transient );
|
||||
call_user_func( $this->upgrade_refresh );
|
||||
}
|
||||
|
||||
$all_items = $this->get_all_items();
|
||||
|
||||
if ( false !== (bool) Utils\get_flag_value( $assoc_args, 'recently-active', false ) ) {
|
||||
if ( false !== Utils\get_flag_value( $assoc_args, 'recently-active', false ) ) {
|
||||
$all_items = array_filter(
|
||||
$all_items,
|
||||
function ( $value ) {
|
||||
|
@ -624,6 +663,9 @@ abstract class CommandWithUpgrade extends \WP_CLI_Command {
|
|||
* @return bool
|
||||
*/
|
||||
protected function has_update( $slug ) {
|
||||
/**
|
||||
* @var object{checked: array<string, string>, response: array<string, string>, no_update: array<string, object{new_version: string, package: string, requires: string}&\stdClass>} $update_list
|
||||
*/
|
||||
$update_list = get_site_transient( $this->upgrade_transient );
|
||||
|
||||
return isset( $update_list->response[ $slug ] );
|
||||
|
@ -632,10 +674,15 @@ abstract class CommandWithUpgrade extends \WP_CLI_Command {
|
|||
/**
|
||||
* Get the available update info
|
||||
*
|
||||
* @return mixed
|
||||
* @return object{checked: array<string, string>, response: array<string, array<string, string|null>>, no_update: array<string, object{new_version: string, package: string, requires: string}&\stdClass>} $update_list
|
||||
*/
|
||||
protected function get_update_info() {
|
||||
return get_site_transient( $this->upgrade_transient );
|
||||
/**
|
||||
* @var object{checked: array<string, string>, response: array<string, array<string, string|null>>, no_update: array<string, object{new_version: string, package: string, requires: string}&\stdClass>} $update_list
|
||||
*/
|
||||
$update_list = get_site_transient( $this->upgrade_transient );
|
||||
|
||||
return $update_list;
|
||||
}
|
||||
|
||||
private $map = [
|
||||
|
@ -688,8 +735,12 @@ abstract class CommandWithUpgrade extends \WP_CLI_Command {
|
|||
$wp_org_api = new WpOrgApi( [ 'insecure' => $insecure ] );
|
||||
foreach ( $items as $i => $item ) {
|
||||
try {
|
||||
$data = call_user_func(
|
||||
[ $wp_org_api, "get_{$item_type}_info" ],
|
||||
/**
|
||||
* @var callable $callback
|
||||
*/
|
||||
$callback = [ $wp_org_api, "get_{$item_type}_info" ];
|
||||
$data = call_user_func(
|
||||
$callback,
|
||||
$item['name'],
|
||||
// The default.
|
||||
'en_US',
|
||||
|
@ -780,9 +831,15 @@ abstract class CommandWithUpgrade extends \WP_CLI_Command {
|
|||
if ( 'plugin' === $this->item_type ) {
|
||||
$api = plugins_api( 'query_plugins', $api_args );
|
||||
} else {
|
||||
// fields[screenshot_count] could be an int, not a bool.
|
||||
// @phpstan-ignore argument.type
|
||||
$api = themes_api( 'query_themes', $api_args );
|
||||
}
|
||||
|
||||
/**
|
||||
* @var \WP_Error|object{info: object{page: int, pages: int, results: int}} $api
|
||||
*/
|
||||
|
||||
if ( is_wp_error( $api ) ) {
|
||||
WP_CLI::error( $api->get_error_message() . __( ' Try again' ) );
|
||||
}
|
||||
|
@ -803,7 +860,10 @@ abstract class CommandWithUpgrade extends \WP_CLI_Command {
|
|||
}
|
||||
|
||||
if ( 'table' === $format ) {
|
||||
$count = Utils\get_flag_value( $api->info, 'results', 'unknown' );
|
||||
/**
|
||||
* @var string $count
|
||||
*/
|
||||
$count = Utils\get_flag_value( (array) $api->info, 'results', 'unknown' );
|
||||
WP_CLI::success( sprintf( 'Showing %s of %s %s.', count( $items ), $count, $plural ) );
|
||||
}
|
||||
|
||||
|
@ -832,18 +892,6 @@ abstract class CommandWithUpgrade extends \WP_CLI_Command {
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves PHP_URL_HOST component from URL.
|
||||
*
|
||||
* @param int $component The component to retrieve.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function parse_url_host_component( $url, $component ) {
|
||||
// phpcs:ignore WordPress.WP.AlternativeFunctions.parse_url_parse_url -- parse_url will only be used in absence of wp_parse_url.
|
||||
return function_exists( 'wp_parse_url' ) ? wp_parse_url( $url, $component ) : parse_url( $url, $component );
|
||||
}
|
||||
|
||||
/**
|
||||
* Add versioned GitHub URLs to cache allowlist.
|
||||
*
|
||||
|
@ -895,6 +943,9 @@ abstract class CommandWithUpgrade extends \WP_CLI_Command {
|
|||
}
|
||||
|
||||
if ( 404 === wp_remote_retrieve_response_code( $response ) ) {
|
||||
/**
|
||||
* @var object{status: string, message: string} $decoded_body
|
||||
*/
|
||||
return new \WP_Error(
|
||||
$decoded_body->status,
|
||||
$decoded_body->message
|
||||
|
@ -905,6 +956,10 @@ abstract class CommandWithUpgrade extends \WP_CLI_Command {
|
|||
return new \WP_Error( 500, 'Empty response received from GitHub.com API' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @var array<int, object{name: string}> $decoded_body
|
||||
*/
|
||||
|
||||
if ( ! isset( $decoded_body[0] ) ) {
|
||||
return new \WP_Error( '400', 'The given Github repository does not have any releases' );
|
||||
}
|
||||
|
|
|
@ -4,6 +4,8 @@ namespace WP_CLI\Fetchers;
|
|||
|
||||
/**
|
||||
* Fetch a WordPress plugin based on one of its attributes.
|
||||
*
|
||||
* @extends Base<object{name: string, file: string}>
|
||||
*/
|
||||
class Plugin extends Base {
|
||||
|
||||
|
@ -15,10 +17,12 @@ class Plugin extends Base {
|
|||
/**
|
||||
* Get a plugin object by name
|
||||
*
|
||||
* @param string $name
|
||||
* @return object|false
|
||||
* @param string|int $name Plugin name.
|
||||
* @return object{name: string, file: string}|false
|
||||
*/
|
||||
public function get( $name ) {
|
||||
$name = (string) $name;
|
||||
|
||||
// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- Calling native WordPress hook.
|
||||
foreach ( apply_filters( 'all_plugins', get_plugins() ) as $file => $_ ) {
|
||||
if ( "$name.php" === $file ||
|
||||
|
|
|
@ -6,6 +6,8 @@ use WP_CLI\Utils;
|
|||
|
||||
/**
|
||||
* Fetch a WordPress theme based on one of its attributes.
|
||||
*
|
||||
* @extends Base<\WP_Theme>
|
||||
*/
|
||||
class Theme extends Base {
|
||||
|
||||
|
@ -17,8 +19,8 @@ class Theme extends Base {
|
|||
/**
|
||||
* Get a theme object by name
|
||||
*
|
||||
* @param string $name
|
||||
* @return object|false
|
||||
* @param string|int $name
|
||||
* @return \WP_Theme|false
|
||||
*/
|
||||
public function get( $name ) {
|
||||
// Workaround to equalize folder naming conventions across Win/Mac/Linux.
|
||||
|
@ -26,7 +28,7 @@ class Theme extends Base {
|
|||
$existing_themes = wp_get_themes( array( 'errors' => null ) );
|
||||
$existing_stylesheets = array_keys( $existing_themes );
|
||||
if ( ! in_array( $name, $existing_stylesheets, true ) ) {
|
||||
$inexact_match = $this->find_inexact_match( $name, $existing_themes );
|
||||
$inexact_match = $this->find_inexact_match( (string) $name, $existing_themes );
|
||||
if ( false !== $inexact_match ) {
|
||||
$this->msg .= sprintf( " Did you mean '%s'?", $inexact_match );
|
||||
}
|
||||
|
|
|
@ -5,6 +5,9 @@ namespace WP_CLI;
|
|||
use WP_CLI;
|
||||
use Theme_AutoUpdates_Command;
|
||||
|
||||
/**
|
||||
* @template T of \WP_Theme
|
||||
*/
|
||||
trait ParseThemeNameInput {
|
||||
|
||||
/**
|
||||
|
@ -54,11 +57,17 @@ trait ParseThemeNameInput {
|
|||
$theme_version_info = array();
|
||||
|
||||
if ( is_multisite() ) {
|
||||
/**
|
||||
* @var array<string, array{enabled: string}>} $site_enabled
|
||||
*/
|
||||
$site_enabled = get_option( 'allowedthemes' );
|
||||
if ( empty( $site_enabled ) ) {
|
||||
$site_enabled = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* @var array<string, array{enabled: string}>} $network_enabled
|
||||
*/
|
||||
$network_enabled = get_site_option( 'allowedthemes' );
|
||||
if ( empty( $network_enabled ) ) {
|
||||
$network_enabled = array();
|
||||
|
@ -169,7 +178,9 @@ trait ParseThemeNameInput {
|
|||
* @return bool|string
|
||||
*/
|
||||
protected function is_theme_version_valid( $slug, $version ) {
|
||||
// Get Theme Info.
|
||||
/**
|
||||
* @var \WP_Error|object{name: string, slug: string, version: string, download_link: string} $theme_info
|
||||
*/
|
||||
$theme_info = themes_api( 'theme_information', array( 'slug' => $slug ) );
|
||||
|
||||
// Return empty string for themes not on WP.org.
|
||||
|
@ -184,7 +195,7 @@ trait ParseThemeNameInput {
|
|||
/**
|
||||
* Get the status for a given theme.
|
||||
*
|
||||
* @param WP_Theme $theme Theme to get the status for.
|
||||
* @param T $theme Theme to get the status for.
|
||||
*
|
||||
* @return string Status of the theme.
|
||||
*/
|
||||
|
@ -203,7 +214,7 @@ trait ParseThemeNameInput {
|
|||
/**
|
||||
* Check whether a given theme is the active theme.
|
||||
*
|
||||
* @param WP_Theme $theme Theme to check.
|
||||
* @param \WP_Theme $theme Theme to check.
|
||||
*
|
||||
* @return bool Whether the provided theme is the active theme.
|
||||
*/
|
||||
|
@ -214,7 +225,7 @@ trait ParseThemeNameInput {
|
|||
/**
|
||||
* Check whether a given theme is the active theme parent.
|
||||
*
|
||||
* @param WP_Theme $theme Theme to check.
|
||||
* @param \WP_Theme $theme Theme to check.
|
||||
*
|
||||
* @return bool Whether the provided theme is the active theme.
|
||||
*/
|
||||
|
@ -225,9 +236,14 @@ trait ParseThemeNameInput {
|
|||
/**
|
||||
* Get the available update info.
|
||||
*
|
||||
* @return mixed Available update info.
|
||||
* @return object{checked: array<string, string>, response: array<string, array<string, string|null>>, no_update: array<string, object{new_version: string, package: string, requires: string}&\stdClass>} Available update info.
|
||||
*/
|
||||
protected function get_update_info() {
|
||||
return get_site_transient( 'update_themes' );
|
||||
/**
|
||||
* @var object{checked: array<string, string>, response: array<string, array<string, string|null>>, no_update: array<string, object{new_version: string, package: string, requires: string}&\stdClass>} $result
|
||||
*/
|
||||
$result = get_site_transient( 'update_themes' );
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue