mirror of
https://github.com/WenPai-org/bulk-plugin-installer.git
synced 2025-08-03 10:24:21 +08:00
升级至 1.1.7
添加批量安装错误通知
This commit is contained in:
parent
c5bdfeabcb
commit
4b16ef8556
3 changed files with 194 additions and 49 deletions
|
@ -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' => ''
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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">
|
||||||
|
|
|
@ -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)
|
||||||
];
|
];
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue