* @author Maximum Software Inc * @license GPL-3.0-only * @link https://agenistrator.com/ * * SPDX-FileCopyrightText: 2025-2026 Alex Ruban * SPDX-FileCopyrightText: 2025-2026 Maximum Software Inc * SPDX-License-Identifier: GPL-3.0-only */ namespace Agenistrator; // Direct access prevention if ( ! defined( 'ABSPATH' ) ) { exit; } /** * Install_Plugin_Tool class. */ class Install_Plugin_Tool extends Tool { /** * Get the tool ID. * * @return string The tool ID. * @since 1.0.0 */ public function get_id() { return 'install_plugin'; } /** * Get the tool name. * * @return string The tool name. * @since 1.0.0 */ public function get_name() { return __( 'Install Plugin', 'agenistrator' ); } /** * Get the tool description. * * @return string The tool description. * @since 1.0.0 */ public function get_description() { return 'Install a plugin from WordPress.org by slug.'; } /** * Get the parameters schema for this tool. * * @return array Parameters schema in JSON Schema format. * @since 1.0.0 */ public function get_parameters() { return array( 'type' => 'object', 'properties' => array( 'slug' => array( 'type' => 'string', 'description' => 'The plugin slug from WordPress.org (e.g., "akismet")', ), 'activate' => array( 'type' => 'boolean', 'description' => 'Whether to activate the plugin after installation', 'default' => false, ), ), 'required' => array( 'slug' ), ); } /** * Check if the current user can execute this tool. * * @return bool True if the current user has permission. * @since 1.0.0 */ public function current_user_can_execute() { return current_user_can( 'install_plugins' ); } /** * Check if this tool is read-only. * * @return bool True if the tool only reads data. * @since 1.0.0 */ public function is_read_only() { return false; } /** * Execute the tool with the given arguments. * * @param array $args The tool arguments. * * @return array The tool execution result. * @since 1.0.0 */ protected function execute( $args ) { // Check if file modifications are disabled if ( ! wp_is_file_mod_allowed( 'plugin_install' ) ) { return $this->error_response( 'File modifications are disabled' ); } if ( ! isset( $args['slug'] ) || empty( $args['slug'] ) ) { return $this->error_response( 'Plugin slug is required' ); } // Sanitize slug for safe use in API calls $slug = sanitize_text_field( $args['slug'] ); if ( ! function_exists( 'plugins_api' ) ) { require_once ABSPATH . 'wp-admin/includes/plugin-install.php'; } require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php'; require_once ABSPATH . 'wp-admin/includes/plugin.php'; // Get plugin info from WordPress.org $api = plugins_api( 'plugin_information', array( 'slug' => $slug ) ); if ( is_wp_error( $api ) ) { return $this->error_response( 'Plugin not found: ' . $api->get_error_message() ); } // Check if already installed using the find_plugin helper // This properly handles all plugin identification formats $existing = WordPress_Utils::find_plugin( $slug ); if ( $existing ) { return $this->error_response( 'Plugin is already installed' ); } // Install the plugin $upgrader = new \Plugin_Upgrader( new \WP_Ajax_Upgrader_Skin() ); $result = $upgrader->install( $api->download_link ); if ( is_wp_error( $result ) ) { return $this->error_response( 'Installation failed: ' . $result->get_error_message() ); } if ( false === $result ) { return $this->error_response( 'Installation failed' ); } $plugin_file = $upgrader->plugin_info(); $response = array( 'slug' => $slug, 'name' => $api->name, 'version' => $api->version, 'plugin_file' => $plugin_file, 'activated' => false, ); // Activate if requested if ( isset( $args['activate'] ) && true === $args['activate'] && $plugin_file ) { $activate_result = activate_plugin( $plugin_file ); if ( ! is_wp_error( $activate_result ) ) { $response['activated'] = true; } } return $this->success_response( 'Plugin installed successfully', $response ); } }