'POST', 'callback' => [__CLASS__, 'check_plugin_status'], 'permission_callback' => function () { return current_user_can('install_plugins'); } ] ]); // Plugin Installation Endpoint register_rest_route('plac/v1', '/plugins/install', [ [ 'methods' => 'POST', 'callback' => [__CLASS__, 'install_plugin'], 'permission_callback' => function () { return current_user_can('install_plugins'); } ] ]); // Plugin Activation Endpoint register_rest_route('plac/v1', '/plugins/activate', [ [ 'methods' => 'POST', 'callback' => [__CLASS__, 'activate_plugin'], 'permission_callback' => function () { return current_user_can('activate_plugins'); } ] ]); } public static function check_plugin_status(WP_REST_Request $request) { // Verify nonce $nonce = $request->get_param('_wpnonce'); if (!isset($nonce) || !wp_verify_nonce($nonce, 'plac_wp_rest')) { return new WP_Error('invalid_nonce', 'Invalid nonce', array('status' => 403)); } $slug = $request->get_param('slug'); if (empty($slug)) { return new WP_Error('missing_slug', 'Plugin slug is required', array('status' => 400)); } require_once ABSPATH . 'wp-admin/includes/plugin.php'; require_once ABSPATH . 'wp-admin/includes/plugin-install.php'; // Get all installed plugins $all_plugins = get_plugins(); $plugin_file = null; $status = 'not_installed'; // Find the plugin by slug foreach ($all_plugins as $file => $plugin) { // Get the folder name from the file path $folder = explode('/', $file)[0]; if ($folder === $slug) { $plugin_file = $file; $status = is_plugin_active($file) ? 'activated' : 'installed'; break; } } return array( 'status' => $status, 'plugin_file' => $plugin_file ); } public static function install_plugin(WP_REST_Request $request) { // Prevent any unexpected output ob_start(); // Required WordPress core files for plugin installation require_once ABSPATH . 'wp-admin/includes/plugin-install.php'; require_once ABSPATH . 'wp-admin/includes/file.php'; require_once ABSPATH . 'wp-admin/includes/misc.php'; require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php'; // Get raw JSON input $data = json_decode($request->get_body(), true); // Check nonce for security if (!isset($data['_wpnonce']) || !wp_verify_nonce($data['_wpnonce'], 'plac_wp_rest')) { ob_end_clean(); // Clean any output before sending response return new WP_REST_Response([ 'success' => false, 'message' => 'Invalid nonce' ], 403); } // Remove nonce from data to avoid saving it unset($data['_wpnonce']); $plugin_name = sanitize_text_field($data['plugin_name']); $download_url = esc_url_raw($data['download_url']); // Validate input if (empty($plugin_name) || empty($download_url)) { ob_end_clean(); // Clean any output before sending response return new WP_REST_Response([ 'success' => false, 'message' => 'Plugin name or download URL is missing' ], 400); } // Initialize the Filesystem API if (!WP_Filesystem()) { ob_end_clean(); // Clean any output before sending response return new WP_REST_Response([ 'success' => false, 'message' => 'Cannot initialize filesystem' ], 500); } // Create a custom skin to capture output instead of displaying it $skin = new \WP_Ajax_Upgrader_Skin(); $upgrader = new \Plugin_Upgrader($skin); // Install plugin $result = $upgrader->install($download_url); // Check for installation errors if (is_wp_error($result)) { ob_end_clean(); // Clean any output before sending response return new WP_REST_Response([ 'success' => false, 'message' => $result->get_error_message() ], 500); } if ($skin->get_errors()->has_errors()) { ob_end_clean(); // Clean any output before sending response return new WP_REST_Response([ 'success' => false, 'message' => $skin->get_error_messages() ], 500); } if (false === $result) { ob_end_clean(); // Clean any output before sending response return new WP_REST_Response([ 'success' => false, 'message' => 'Plugin installation failed for an unknown reason.' ], 500); } // Get installed plugins $installed_plugins = get_plugins(); // Find the newly installed plugin $new_plugin = null; foreach ($installed_plugins as $plugin_path => $plugin_data) { if (stripos($plugin_data['Name'], $plugin_name) !== false) { $new_plugin = $plugin_path; break; } } // Clean any buffer output ob_end_clean(); // Return plugin file for activation if ($new_plugin) { return new WP_REST_Response([ 'success' => true, 'plugin_file' => $new_plugin, 'message' => 'Plugin installed successfully.' ], 200); } return new WP_REST_Response([ 'success' => false, 'message' => 'Installed plugin could not be identified' ], 404); } public static function activate_plugin(WP_REST_Request $request) { // Decode JSON body manually $data = json_decode($request->get_body(), true); // Check nonce for security if (!isset($data['_wpnonce']) || !wp_verify_nonce($data['_wpnonce'], 'plac_wp_rest')) { return new WP_REST_Response([ 'message' => 'Invalid nonce' ], 403); } // Remove nonce from data to avoid saving it unset($data['_wpnonce']); $plugin_file = sanitize_text_field($data['plugin_file']); // Validate input if (empty($plugin_file)) { return new WP_Error('invalid_input', 'Plugin file is missing', ['status' => 400]); } // Activate the plugin $result = activate_plugin($plugin_file); if (is_wp_error($result)) { return $result; } return new WP_REST_Response([ 'success' => true, 'message' => 'Plugin activated successfully.' ], 200); } }