升级至 1.1.7

添加批量安装错误通知
This commit is contained in:
文派备案 2025-03-26 11:17:00 +08:00
parent c5bdfeabcb
commit 4b16ef8556
3 changed files with 194 additions and 49 deletions

View file

@ -3,8 +3,8 @@
* Plugin Name: Bulk Plugin Installer * Plugin Name: Bulk Plugin Installer
* Plugin URI: https://wpmultisite.com/plugins/bulk-plugin-installer/ * Plugin URI: https://wpmultisite.com/plugins/bulk-plugin-installer/
* Description: Bulk install WordPress plugins and themes from repository, URL, or ZIP uploads. * Description: Bulk install WordPress plugins and themes from repository, URL, or ZIP uploads.
* Version: 1.1.6 * Version: 1.1.7
* Author: WPMultisite.com * Author: WPMultisite.com
* Author URI: https://wpmultisite.com * Author URI: https://wpmultisite.com
* Network: true * Network: true
* Requires at least: 5.8 * Requires at least: 5.8
@ -18,7 +18,7 @@ if (!defined('WPINC')) {
die; die;
} }
define('BPI_VERSION', '1.1.6'); define('BPI_VERSION', '1.1.7');
define('BPI_PATH', plugin_dir_path(__FILE__)); define('BPI_PATH', plugin_dir_path(__FILE__));
define('BPI_URL', plugin_dir_url(__FILE__)); define('BPI_URL', plugin_dir_url(__FILE__));
@ -26,6 +26,8 @@ require_once BPI_PATH . 'includes/class-installer.php';
require_once BPI_PATH . 'includes/admin-page.php'; require_once BPI_PATH . 'includes/admin-page.php';
function bpi_init() { function bpi_init() {
load_plugin_textdomain('bulk-plugin-installer', false, dirname(plugin_basename(__FILE__)) . '/languages/');
if (is_multisite()) { if (is_multisite()) {
if (is_network_admin()) { if (is_network_admin()) {
add_action('network_admin_menu', 'bpi_add_network_submenu_page'); add_action('network_admin_menu', 'bpi_add_network_submenu_page');
@ -143,7 +145,10 @@ function bpi_handle_install_plugins() {
check_ajax_referer('bpi_installer', 'nonce'); check_ajax_referer('bpi_installer', 'nonce');
if (!current_user_can('install_plugins') && !(is_multisite() && current_user_can('manage_network_plugins'))) { if (!current_user_can('install_plugins') && !(is_multisite() && current_user_can('manage_network_plugins'))) {
wp_send_json_error(__('Insufficient permissions', 'bulk-plugin-installer')); wp_send_json_error([
'message' => __('Insufficient permissions', 'bulk-plugin-installer'),
'error_code' => 403
]);
} }
$installer = new BPI_Installer(); $installer = new BPI_Installer();
@ -153,7 +158,10 @@ function bpi_handle_install_plugins() {
try { try {
if ($type === 'upload') { if ($type === 'upload') {
if (!isset($_FILES['plugin_files']) || empty($_FILES['plugin_files']['name'])) { if (!isset($_FILES['plugin_files']) || empty($_FILES['plugin_files']['name'])) {
wp_send_json_error(__('No files uploaded', 'bulk-plugin-installer')); wp_send_json_error([
'message' => __('No files uploaded', 'bulk-plugin-installer'),
'error_code' => 400
]);
} }
$files = []; $files = [];
if (is_array($_FILES['plugin_files']['name'])) { if (is_array($_FILES['plugin_files']['name'])) {
@ -181,13 +189,19 @@ function bpi_handle_install_plugins() {
} }
} }
if (empty($files)) { if (empty($files)) {
wp_send_json_error(__('No valid files uploaded', 'bulk-plugin-installer')); wp_send_json_error([
'message' => __('No valid files uploaded', 'bulk-plugin-installer'),
'error_code' => 400
]);
} }
$results = $installer->bpi_install_plugins($files, $type); $results = $installer->bpi_install_plugins($files, $type);
} else { } else {
$items = isset($_POST['items']) ? json_decode(stripslashes($_POST['items']), true) : []; $items = isset($_POST['items']) ? json_decode(stripslashes($_POST['items']), true) : [];
if (!is_array($items) || empty($items)) { if (!is_array($items) || empty($items)) {
wp_send_json_error(__('No items provided', 'bulk-plugin-installer')); wp_send_json_error([
'message' => __('No items provided', 'bulk-plugin-installer'),
'error_code' => 400
]);
} }
$results = $installer->bpi_install_plugins($items, $type); $results = $installer->bpi_install_plugins($items, $type);
} }
@ -195,7 +209,10 @@ function bpi_handle_install_plugins() {
wp_send_json_success($results); wp_send_json_success($results);
} catch (Exception $e) { } catch (Exception $e) {
error_log('BPI Plugin Install Error: ' . $e->getMessage()); error_log('BPI Plugin Install Error: ' . $e->getMessage());
wp_send_json_error(__('Installation failed: ', 'bulk-plugin-installer') . $e->getMessage()); wp_send_json_error([
'message' => $installer->get_error_message($e->getCode(), $e->getMessage()),
'error_code' => $e->getCode()
]);
} }
} }
@ -203,7 +220,10 @@ function bpi_handle_install_themes() {
check_ajax_referer('bpi_installer', 'nonce'); check_ajax_referer('bpi_installer', 'nonce');
if (!current_user_can('install_themes') && !(is_multisite() && current_user_can('manage_network_plugins'))) { if (!current_user_can('install_themes') && !(is_multisite() && current_user_can('manage_network_plugins'))) {
wp_send_json_error(__('Insufficient permissions', 'bulk-plugin-installer')); wp_send_json_error([
'message' => __('Insufficient permissions', 'bulk-plugin-installer'),
'error_code' => 403
]);
} }
$installer = new BPI_Installer(); $installer = new BPI_Installer();
@ -213,7 +233,10 @@ function bpi_handle_install_themes() {
try { try {
if ($type === 'upload') { if ($type === 'upload') {
if (!isset($_FILES['theme_files']) || empty($_FILES['theme_files']['name'])) { if (!isset($_FILES['theme_files']) || empty($_FILES['theme_files']['name'])) {
wp_send_json_error(__('No files uploaded', 'bulk-plugin-installer')); wp_send_json_error([
'message' => __('No files uploaded', 'bulk-plugin-installer'),
'error_code' => 400
]);
} }
$files = []; $files = [];
if (is_array($_FILES['theme_files']['name'])) { if (is_array($_FILES['theme_files']['name'])) {
@ -241,13 +264,19 @@ function bpi_handle_install_themes() {
} }
} }
if (empty($files)) { if (empty($files)) {
wp_send_json_error(__('No valid files uploaded', 'bulk-plugin-installer')); wp_send_json_error([
'message' => __('No valid files uploaded', 'bulk-plugin-installer'),
'error_code' => 400
]);
} }
$results = $installer->bpi_install_themes($files, $type); $results = $installer->bpi_install_themes($files, $type);
} else { } else {
$items = isset($_POST['items']) ? json_decode(stripslashes($_POST['items']), true) : []; $items = isset($_POST['items']) ? json_decode(stripslashes($_POST['items']), true) : [];
if (!is_array($items) || empty($items)) { if (!is_array($items) || empty($items)) {
wp_send_json_error(__('No items provided', 'bulk-plugin-installer')); wp_send_json_error([
'message' => __('No items provided', 'bulk-plugin-installer'),
'error_code' => 400
]);
} }
$results = $installer->bpi_install_themes($items, $type); $results = $installer->bpi_install_themes($items, $type);
} }
@ -255,7 +284,10 @@ function bpi_handle_install_themes() {
wp_send_json_success($results); wp_send_json_success($results);
} catch (Exception $e) { } catch (Exception $e) {
error_log('BPI Theme Install Error: ' . $e->getMessage()); error_log('BPI Theme Install Error: ' . $e->getMessage());
wp_send_json_error(__('Installation failed: ', 'bulk-plugin-installer') . $e->getMessage()); wp_send_json_error([
'message' => $installer->get_error_message($e->getCode(), $e->getMessage()),
'error_code' => $e->getCode()
]);
} }
} }
@ -263,7 +295,10 @@ function bpi_handle_save_settings() {
check_ajax_referer('bpi_installer', 'nonce'); check_ajax_referer('bpi_installer', 'nonce');
if (!current_user_can('manage_options') && !(is_multisite() && current_user_can('manage_network_options'))) { if (!current_user_can('manage_options') && !(is_multisite() && current_user_can('manage_network_options'))) {
wp_send_json_error(__('Insufficient permissions', 'bulk-plugin-installer')); wp_send_json_error([
'message' => __('Insufficient permissions', 'bulk-plugin-installer'),
'error_code' => 403
]);
} }
$roles = isset($_POST['bpi_allowed_roles']) ? (array)$_POST['bpi_allowed_roles'] : []; $roles = isset($_POST['bpi_allowed_roles']) ? (array)$_POST['bpi_allowed_roles'] : [];
@ -322,4 +357,4 @@ function bpi_activate() {
'last_install_time' => '' 'last_install_time' => ''
]); ]);
} }
} }

View file

@ -6,9 +6,25 @@ function bpi_render_admin_page() {
wp_enqueue_style('bpi-admin-style', BPI_URL . 'assets/css/admin.css', [], BPI_VERSION); wp_enqueue_style('bpi-admin-style', BPI_URL . 'assets/css/admin.css', [], BPI_VERSION);
wp_enqueue_script('bpi-admin', BPI_URL . 'assets/js/admin.js', ['jquery'], BPI_VERSION, true); wp_enqueue_script('bpi-admin', BPI_URL . 'assets/js/admin.js', ['jquery'], BPI_VERSION, true);
$i18n_strings = [
'go_to_settings' => __('Go to Settings to add domain', 'bulk-plugin-installer'),
'switch_to_themes' => __('Switch to Themes tab', 'bulk-plugin-installer'),
'switch_to_plugins' => __('Switch to Plugins tab', 'bulk-plugin-installer'),
'retry' => __('Retry', 'bulk-plugin-installer'),
'installation_in_progress' => __('Installation in progress... (Large ZIP files may take some time)', 'bulk-plugin-installer'),
'completed' => __('completed', 'bulk-plugin-installer'),
'remaining' => __('remaining', 'bulk-plugin-installer'),
'installation_complete' => __('Installation completed! Check the results below. Failed items can be retried using the "Retry" buttons if applicable.', 'bulk-plugin-installer'),
'no_files' => __('Please select at least one ZIP file.', 'bulk-plugin-installer'),
'no_slugs' => __('Please enter at least one slug.', 'bulk-plugin-installer'),
'no_urls' => __('Please enter at least one URL.', 'bulk-plugin-installer')
];
wp_localize_script('bpi-admin', 'bpiAjax', [ wp_localize_script('bpi-admin', 'bpiAjax', [
'nonce' => wp_create_nonce('bpi_installer'), 'nonce' => wp_create_nonce('bpi_installer'),
'ajaxurl' => admin_url('admin-ajax.php') 'ajaxurl' => admin_url('admin-ajax.php'),
'i18n' => $i18n_strings
]); ]);
?> ?>
<div class="wrap"> <div class="wrap">

View file

@ -1,6 +1,24 @@
<?php <?php
class BPI_Installer { class BPI_Installer {
private $wp_filesystem; private $wp_filesystem;
private $error_messages = [
// Plugin error codes
1001 => 'Invalid plugin slug format. Please use only lowercase letters, numbers and hyphens.',
1004 => 'Invalid URL format. Please provide a complete URL including http:// or https://',
1005 => 'The domain is not in the trusted list. Please add it in settings or use another source.',
1007 => 'Only ZIP files are allowed for plugin uploads.',
1009 => 'This appears to be a theme ZIP file. Please use the Themes tab for installation.',
1010 => 'The uploaded file is not a valid WordPress plugin ZIP.',
// Theme error codes
2001 => 'Invalid theme slug format. Please use only lowercase letters, numbers and hyphens.',
2003 => 'Only ZIP files are allowed for theme uploads.',
2005 => 'This appears to be a plugin ZIP file. Please use the Plugins tab for installation.',
2006 => 'The uploaded file is not a valid WordPress theme ZIP.',
2009 => 'Invalid URL format for theme. Please provide a complete URL including http:// or https://',
2010 => 'The domain is not in the trusted list for themes. Please add it in settings or use another source.'
];
public function __construct() { public function __construct() {
global $wp_filesystem; global $wp_filesystem;
@ -13,6 +31,10 @@ class BPI_Installer {
$this->wp_filesystem = $wp_filesystem; $this->wp_filesystem = $wp_filesystem;
} }
public function get_error_message($code, $default_message) {
return __($this->error_messages[$code] ?? $default_message, 'bulk-plugin-installer');
}
private function is_plugin_zip($zip_path) { private function is_plugin_zip($zip_path) {
$zip = new ZipArchive(); $zip = new ZipArchive();
if ($zip->open($zip_path) === true) { if ($zip->open($zip_path) === true) {
@ -69,7 +91,10 @@ class BPI_Installer {
if ($type === 'repository' || $type === 'wenpai') { if ($type === 'repository' || $type === 'wenpai') {
$item = sanitize_text_field($item); $item = sanitize_text_field($item);
if (!preg_match('/^[a-z0-9-]+$/', $item)) { if (!preg_match('/^[a-z0-9-]+$/', $item)) {
throw new Exception('Invalid plugin slug', 1001); throw new Exception(
$this->get_error_message(1001, 'Invalid plugin slug'),
1001
);
} }
$plugin_key = $item . '/' . $item . '.php'; $plugin_key = $item . '/' . $item . '.php';
} elseif ($type === 'upload') { } elseif ($type === 'upload') {
@ -94,7 +119,10 @@ class BPI_Installer {
'fields' => ['sections' => false] 'fields' => ['sections' => false]
]); ]);
if (is_wp_error($api)) { if (is_wp_error($api)) {
throw new Exception('Failed to fetch plugin info: ' . $api->get_error_message(), 1002); throw new Exception(
$this->get_error_message(1002, 'Failed to fetch plugin info: ' . $api->get_error_message()),
1002
);
} }
$download_link = $api->download_link; $download_link = $api->download_link;
break; break;
@ -103,7 +131,10 @@ class BPI_Installer {
$response = wp_remote_get("https://api.wenpai.net/wp-json/wp/v2/plugins/{$item}"); $response = wp_remote_get("https://api.wenpai.net/wp-json/wp/v2/plugins/{$item}");
if (is_wp_error($response)) { if (is_wp_error($response)) {
$code = wp_remote_retrieve_response_code($response); $code = wp_remote_retrieve_response_code($response);
throw new Exception("Download failed with status code $code: " . $response->get_error_message(), 1003); throw new Exception(
$this->get_error_message(1003, "Download failed with status code $code: " . $response->get_error_message()),
1003
);
} }
$plugin_data = json_decode(wp_remote_retrieve_body($response), true); $plugin_data = json_decode(wp_remote_retrieve_body($response), true);
$download_link = $plugin_data && !empty($plugin_data['download_link']) $download_link = $plugin_data && !empty($plugin_data['download_link'])
@ -114,10 +145,16 @@ class BPI_Installer {
case 'url': case 'url':
$item = sanitize_text_field($item); $item = sanitize_text_field($item);
if (!filter_var($item, FILTER_VALIDATE_URL)) { if (!filter_var($item, FILTER_VALIDATE_URL)) {
throw new Exception('Invalid URL format', 1004); throw new Exception(
$this->get_error_message(1004, 'Invalid URL format'),
1004
);
} }
if (!bpi_is_domain_allowed($item)) { if (!bpi_is_domain_allowed($item)) {
throw new Exception('Untrusted domain', 1005); throw new Exception(
$this->get_error_message(1005, 'Untrusted domain'),
1005
);
} }
$download_link = $item; $download_link = $item;
break; break;
@ -125,27 +162,42 @@ class BPI_Installer {
case 'upload': case 'upload':
$file = $item; $file = $item;
if ($file['error'] !== UPLOAD_ERR_OK) { if ($file['error'] !== UPLOAD_ERR_OK) {
throw new Exception('File upload error: ' . $file['error'], 1006); throw new Exception(
$this->get_error_message(1006, 'File upload error: ' . $file['error']),
1006
);
} }
$file_name = sanitize_file_name($file['name']); $file_name = sanitize_file_name($file['name']);
if (pathinfo($file_name, PATHINFO_EXTENSION) !== 'zip') { if (pathinfo($file_name, PATHINFO_EXTENSION) !== 'zip') {
throw new Exception('Only ZIP files are allowed', 1007); throw new Exception(
$this->get_error_message(1007, 'Only ZIP files are allowed'),
1007
);
} }
$temp_file = $file['tmp_name']; $temp_file = $file['tmp_name'];
$upload_dir = wp_upload_dir(); $upload_dir = wp_upload_dir();
$dest_path = $upload_dir['path'] . '/' . $file_name; $dest_path = $upload_dir['path'] . '/' . $file_name;
if (!move_uploaded_file($temp_file, $dest_path)) { if (!move_uploaded_file($temp_file, $dest_path)) {
throw new Exception('Failed to move uploaded file. Check server permissions.', 1008); throw new Exception(
$this->get_error_message(1008, 'Failed to move uploaded file. Check server permissions.'),
1008
);
} }
if (!$this->is_plugin_zip($dest_path)) { if (!$this->is_plugin_zip($dest_path)) {
if ($this->is_theme_zip($dest_path)) { if ($this->is_theme_zip($dest_path)) {
unlink($dest_path); unlink($dest_path);
throw new Exception('This appears to be a theme ZIP. Please use the Plugins tab to install.', 1009); throw new Exception(
$this->get_error_message(1009, 'Theme ZIP detected'),
1009
);
} }
unlink($dest_path); unlink($dest_path);
throw new Exception('Invalid plugin ZIP file', 1010); throw new Exception(
$this->get_error_message(1010, 'Invalid plugin ZIP'),
1010
);
} }
$download_link = $dest_path; $download_link = $dest_path;
@ -160,20 +212,26 @@ class BPI_Installer {
if (is_wp_error($result)) { if (is_wp_error($result)) {
$error_message = $result->get_error_message(); $error_message = $result->get_error_message();
throw new Exception($error_message ?: 'Unknown installation error', 1011); throw new Exception(
$this->get_error_message(1011, $error_message ?: 'Unknown installation error'),
1011
);
} elseif ($result !== true) { } elseif ($result !== true) {
throw new Exception('Installation failed unexpectedly', 1012); throw new Exception(
$this->get_error_message(1012, 'Installation failed unexpectedly'),
1012
);
} }
$results[$item] = [ $results[$item] = [
'success' => true, 'success' => true,
'message' => 'Successfully installed' 'message' => __('Successfully installed', 'bulk-plugin-installer')
]; ];
} catch (Exception $e) { } catch (Exception $e) {
$no_retry_codes = [1001, 1004, 1005, 1007, 1009, 1010]; // 无需重试的错误代码 $no_retry_codes = [1001, 1004, 1005, 1007, 1009, 1010];
$results[$item] = [ $results[$item] = [
'success' => false, 'success' => false,
'message' => $e->getMessage(), 'message' => $this->get_error_message($e->getCode(), $e->getMessage()),
'error_code' => $e->getCode(), 'error_code' => $e->getCode(),
'retry' => !in_array($e->getCode(), $no_retry_codes) 'retry' => !in_array($e->getCode(), $no_retry_codes)
]; ];
@ -207,24 +265,36 @@ class BPI_Installer {
if ($type === 'repository' || $type === 'wenpai') { if ($type === 'repository' || $type === 'wenpai') {
$item = sanitize_text_field($item); $item = sanitize_text_field($item);
if (!preg_match('/^[a-z0-9-]+$/', $item)) { if (!preg_match('/^[a-z0-9-]+$/', $item)) {
throw new Exception('Invalid theme slug', 2001); throw new Exception(
$this->get_error_message(2001, 'Invalid theme slug'),
2001
);
} }
$theme_key = $item; $theme_key = $item;
} elseif ($type === 'upload') { } elseif ($type === 'upload') {
$file = $item; $file = $item;
if ($file['error'] !== UPLOAD_ERR_OK) { if ($file['error'] !== UPLOAD_ERR_OK) {
throw new Exception('File upload error: ' . $file['error'], 2002); throw new Exception(
$this->get_error_message(2002, 'File upload error: ' . $file['error']),
2002
);
} }
$file_name = sanitize_file_name($file['name']); $file_name = sanitize_file_name($file['name']);
if (pathinfo($file_name, PATHINFO_EXTENSION) !== 'zip') { if (pathinfo($file_name, PATHINFO_EXTENSION) !== 'zip') {
throw new Exception('Only ZIP files are allowed', 2003); throw new Exception(
$this->get_error_message(2003, 'Only ZIP files are allowed'),
2003
);
} }
$temp_file = $file['tmp_name']; $temp_file = $file['tmp_name'];
$upload_dir = wp_upload_dir(); $upload_dir = wp_upload_dir();
$dest_path = $upload_dir['path'] . '/' . $file_name; $dest_path = $upload_dir['path'] . '/' . $file_name;
if (!move_uploaded_file($temp_file, $dest_path)) { if (!move_uploaded_file($temp_file, $dest_path)) {
throw new Exception('Failed to move uploaded file. Check server permissions.', 2004); throw new Exception(
$this->get_error_message(2004, 'Failed to move uploaded file. Check server permissions.'),
2004
);
} }
$zip = new ZipArchive(); $zip = new ZipArchive();
@ -249,7 +319,7 @@ class BPI_Installer {
} }
$results[$file_name] = [ $results[$file_name] = [
'success' => true, 'success' => true,
'message' => 'Theme already installed, skipped', 'message' => __('Theme already installed, skipped', 'bulk-plugin-installer'),
'skipped' => true 'skipped' => true
]; ];
continue; continue;
@ -258,10 +328,16 @@ class BPI_Installer {
if (!$this->is_theme_zip($dest_path)) { if (!$this->is_theme_zip($dest_path)) {
if ($this->is_plugin_zip($dest_path)) { if ($this->is_plugin_zip($dest_path)) {
unlink($dest_path); unlink($dest_path);
throw new Exception('This appears to be a plugin ZIP. Please use the Plugins tab to install.', 2005); throw new Exception(
$this->get_error_message(2005, 'Plugin ZIP detected'),
2005
);
} }
unlink($dest_path); unlink($dest_path);
throw new Exception('Invalid theme ZIP file', 2006); throw new Exception(
$this->get_error_message(2006, 'Invalid theme ZIP'),
2006
);
} }
$download_link = $dest_path; $download_link = $dest_path;
@ -271,7 +347,7 @@ class BPI_Installer {
if ($theme_key && array_key_exists($theme_key, $installed_themes)) { if ($theme_key && array_key_exists($theme_key, $installed_themes)) {
$results[$item] = [ $results[$item] = [
'success' => true, 'success' => true,
'message' => 'Theme already installed, skipped', 'message' => __('Theme already installed, skipped', 'bulk-plugin-installer'),
'skipped' => true 'skipped' => true
]; ];
continue; continue;
@ -285,7 +361,10 @@ class BPI_Installer {
'fields' => ['sections' => false] 'fields' => ['sections' => false]
]); ]);
if (is_wp_error($api)) { if (is_wp_error($api)) {
throw new Exception('Failed to fetch theme info: ' . $api->get_error_message(), 2007); throw new Exception(
$this->get_error_message(2007, 'Failed to fetch theme info: ' . $api->get_error_message()),
2007
);
} }
$download_link = $api->download_link; $download_link = $api->download_link;
break; break;
@ -294,7 +373,10 @@ class BPI_Installer {
$response = wp_remote_get("https://api.wenpai.net/wp-json/wp/v2/themes/{$item}"); $response = wp_remote_get("https://api.wenpai.net/wp-json/wp/v2/themes/{$item}");
if (is_wp_error($response)) { if (is_wp_error($response)) {
$code = wp_remote_retrieve_response_code($response); $code = wp_remote_retrieve_response_code($response);
throw new Exception("Download failed with status code $code: " . $response->get_error_message(), 2008); throw new Exception(
$this->get_error_message(2008, "Download failed with status code $code: " . $response->get_error_message()),
2008
);
} }
$theme_data = json_decode(wp_remote_retrieve_body($response), true); $theme_data = json_decode(wp_remote_retrieve_body($response), true);
$download_link = $theme_data && !empty($theme_data['download_link']) $download_link = $theme_data && !empty($theme_data['download_link'])
@ -305,16 +387,22 @@ class BPI_Installer {
case 'url': case 'url':
$item = sanitize_text_field($item); $item = sanitize_text_field($item);
if (!filter_var($item, FILTER_VALIDATE_URL)) { if (!filter_var($item, FILTER_VALIDATE_URL)) {
throw new Exception('Invalid URL format', 2009); throw new Exception(
$this->get_error_message(2009, 'Invalid URL format'),
2009
);
} }
if (!bpi_is_domain_allowed($item)) { if (!bpi_is_domain_allowed($item)) {
throw new Exception('Untrusted domain', 2010); throw new Exception(
$this->get_error_message(2010, 'Untrusted domain'),
2010
);
} }
$download_link = $item; $download_link = $item;
break; break;
case 'upload': case 'upload':
// 已在上方处理 // Already handled above
break; break;
} }
@ -325,20 +413,26 @@ class BPI_Installer {
if (is_wp_error($result)) { if (is_wp_error($result)) {
$error_message = $result->get_error_message(); $error_message = $result->get_error_message();
throw new Exception($error_message ?: 'Unknown installation error', 2011); throw new Exception(
$this->get_error_message(2011, $error_message ?: 'Unknown installation error'),
2011
);
} elseif ($result !== true) { } elseif ($result !== true) {
throw new Exception('Installation failed unexpectedly', 2012); throw new Exception(
$this->get_error_message(2012, 'Installation failed unexpectedly'),
2012
);
} }
$results[$item] = [ $results[$item] = [
'success' => true, 'success' => true,
'message' => 'Successfully installed' 'message' => __('Successfully installed', 'bulk-plugin-installer')
]; ];
} catch (Exception $e) { } catch (Exception $e) {
$no_retry_codes = [2001, 2003, 2005, 2006, 2009, 2010]; // 无需重试的错误代码 $no_retry_codes = [2001, 2003, 2005, 2006, 2009, 2010];
$results[$item] = [ $results[$item] = [
'success' => false, 'success' => false,
'message' => $e->getMessage(), 'message' => $this->get_error_message($e->getCode(), $e->getMessage()),
'error_code' => $e->getCode(), 'error_code' => $e->getCode(),
'retry' => !in_array($e->getCode(), $no_retry_codes) 'retry' => !in_array($e->getCode(), $no_retry_codes)
]; ];