hosting_deployWordpressPlugin
Upload and deploy a WordPress plugin from a local directory to your hosting server. Specify domain, plugin slug, and file path to trigger automatic deployment.
Instructions
Deploy a WordPress plugin from a directory to a hosting server. This tool uploads all plugin files and triggers plugin deployment.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| domain | Yes | Domain name associated with the hosting account (e.g., example.com) | |
| slug | Yes | WordPress plugin slug (e.g., omnisend) | |
| pluginPath | Yes | Absolute or relative path to the plugin directory containing all plugin files |
Implementation Reference
- src/core/runtime.ts:821-907 (handler)Main handler function for hosting_deployWordpressPlugin. Validates params, resolves username from domain, scans plugin directory, generates random upload directory name, uploads all plugin files via TUS to wp-content/plugins/{slug}-{random}/, then calls the deploy API to trigger plugin deployment.
private async handleWordpressPluginDeploy(params: Record<string, any>): Promise<any> { const { domain, slug, pluginPath } = params; this.hosting_deployWordpressPlugin_validateRequiredParams(params); this.hosting_deployWordpressPlugin_validatePluginDirectory(pluginPath); this.log('info', `Resolving username from domain: ${domain}`); const username = await this.resolveUsername(domain); const randomSuffix = this.hosting_deployWordpressPlugin_generateRandomString(8); const uploadDirName = `${slug}-${randomSuffix}`; this.log('info', `Scanning plugin directory: ${pluginPath}`); const pluginFiles = this.hosting_deployWordpressPlugin_scanDirectory(pluginPath); if (pluginFiles.length === 0) { throw new Error(`No files found in plugin directory: ${pluginPath}`); } this.log('info', `Found ${pluginFiles.length} files to upload`); let uploadCredentials: any; try { uploadCredentials = await this.fetchUploadCredentials(username, domain); } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); throw new Error(`Failed to fetch upload credentials: ${errorMessage}`); } const { url: uploadUrl, auth_key: authToken, rest_auth_key: authRestToken } = uploadCredentials; if (!uploadUrl || !authToken || !authRestToken) { throw new Error('Invalid upload credentials received from API'); } this.log('info', `Starting plugin file upload to ${uploadUrl}`); const results: any[] = []; let successCount = 0; let failureCount = 0; for (const fileInfo of pluginFiles) { try { const normalizedRelativePath = this.normalizePath(fileInfo.relativePath); const uploadPath = `wp-content/plugins/${uploadDirName}/${normalizedRelativePath}`; this.log('info', `Uploading: ${fileInfo.absolutePath} -> ${uploadPath}`); const stats = fs.statSync(fileInfo.absolutePath); const uploadResult = await this.uploadFile( fileInfo.absolutePath, uploadPath, uploadUrl, authRestToken, authToken ); results.push({ file: fileInfo.absolutePath, remotePath: uploadPath, status: 'success', uploadUrl: uploadResult.url, size: stats.size }); successCount++; this.log('info', `Successfully uploaded: ${uploadPath}`); } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); const normalizedRelativePath = this.normalizePath(fileInfo.relativePath); const uploadPath = `wp-content/plugins/${uploadDirName}/${normalizedRelativePath}`; results.push({ file: fileInfo.absolutePath, remotePath: uploadPath, status: 'error', error: errorMessage }); failureCount++; this.log('error', `Failed to upload ${fileInfo.absolutePath}: ${errorMessage}`); } } const overallStatus = failureCount === 0 ? 'success' : (successCount === 0 ? 'failure' : 'partial'); if (failureCount === 0) { - src/core/tools/hosting.ts:48-75 (schema)Schema/definition for the hosting_deployWordpressPlugin tool. Defines name, description, inputSchema with required params (domain, slug, pluginPath), and maps to handlerMethod 'handleWordpressPluginDeploy'.
{ "name": "hosting_deployWordpressPlugin", "topic": "hosting", "description": "Deploy a WordPress plugin from a directory to a hosting server. This tool uploads all plugin files and triggers plugin deployment.", "method": "", "path": "", "inputSchema": { "type": "object", "properties": { "domain": { "type": "string", "description": "Domain name associated with the hosting account (e.g., example.com)" }, "slug": { "type": "string", "description": "WordPress plugin slug (e.g., omnisend)" }, "pluginPath": { "type": "string", "description": "Absolute or relative path to the plugin directory containing all plugin files" } }, "required": [ "domain", "slug", "pluginPath" ] }, - src/core/runtime.ts:197-202 (registration)Registration of the custom tool in executeCustomTool switch statement routing 'hosting_deployWordpressPlugin' to handleWordpressPluginDeploy method.
private async executeCustomTool(tool: OpenApiTool, params: Record<string, any>): Promise<any> { switch (tool.name) { case 'hosting_importWordpressWebsite': return await this.handleWordpressWebsiteImport(params); case 'hosting_deployWordpressPlugin': return await this.handleWordpressPluginDeploy(params); - src/core/runtime.ts:705-712 (helper)Helper that generates a random 8-character alphanumeric string used as a suffix for the upload directory name to avoid collisions.
private hosting_deployWordpressPlugin_generateRandomString(length: number): string { const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; let result = ''; for (let i = 0; i < length; i++) { result += chars.charAt(Math.floor(Math.random() * chars.length)); } return result; } - src/core/runtime.ts:767-819 (helper)Helper that calls the Hostinger API (POST /api/hosting/v1/accounts/{username}/websites/{domain}/wordpress/plugins/deploy) to trigger plugin deployment after files are uploaded.
private async hosting_deployWordpressPlugin_deployPlugin(username: string, domain: string, slug: string, pluginPath: string): Promise<boolean> { const baseUrl = this.baseUrl.endsWith("/") ? this.baseUrl : `${this.baseUrl}/`; const url = new URL(`api/hosting/v1/accounts/${username}/websites/${domain}/wordpress/plugins/deploy`, baseUrl).toString(); try { const bearerToken = process.env['API_TOKEN'] || process.env['APITOKEN']; if (!bearerToken) { throw new Error('API_TOKEN environment variable not found'); } const config: AxiosRequestConfig = { method: 'post', url, headers: { ...this.headers, 'Authorization': `Bearer ${bearerToken}`, 'Content-Type': 'application/json' }, data: { slug, plugin_path: pluginPath }, timeout: 60000, // 60s validateStatus: function (status: number): boolean { return status < 500; } }; const response = await axios(config); if (response.status !== 200) { throw new Error(`API returned status ${response.status}: ${JSON.stringify(response.data)}`); } this.log('info', `Successfully triggered plugin deployment for ${domain}`); return true; } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); this.log('error', `Failed to trigger plugin deployment: ${errorMessage}`); if (axios.isAxiosError(error)) { const responseData = error.response?.data; const responseStatus = error.response?.status; this.log('error', 'API Error Details:', { status: responseStatus, data: typeof responseData === 'object' ? JSON.stringify(responseData) : responseData }); } throw error; } }