wordpress_plugin_readiness
Analyzes WordPress plugins for security vulnerabilities, coding standards, performance issues, and WordPress.org submission requirements to ensure compliance and readiness.
Instructions
Comprehensive WordPress plugin readiness check for security, best practices, and WordPress.org submission
WORKFLOW: Perfect for understanding complex code, identifying issues, and technical debt assessment TIP: Use Desktop Commander to read files, then pass content here for analysis SAVES: Claude context for strategic decisions
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| analysisDepth | No | Level of analysis detail | comprehensive |
| includeSteps | No | Specific analysis steps to include | |
| maxDepth | No | Maximum directory depth for file discovery (1-5) | |
| maxFiles | No | Maximum number of PHP files to analyze | |
| phpVersion | No | Target PHP version for compatibility | 8.0 |
| projectPath | Yes | Path to WordPress plugin root directory | |
| wpVersion | No | Target WordPress version for compatibility | 6.4 |
Implementation Reference
- Main handler function that executes the WordPress plugin readiness analysis tool logic, including validation, file discovery, analysis, prompt generation, and LLM execution.async execute(params: any, llmClient: any) { return await withSecurity(this, params, llmClient, async (secureParams) => { try { // 1. Validate parameters ParameterValidator.validateProjectPath(secureParams); ParameterValidator.validateDepth(secureParams); ParameterValidator.validateEnum(secureParams, 'analysisDepth', ['basic', 'detailed', 'comprehensive']); // 2. Setup model const { model, contextLength } = await ModelSetup.getReadyModel(llmClient); // 3. Discover PHP files in the plugin const phpFiles = await this.discoverPHPFiles( secureParams.projectPath, secureParams.maxDepth, secureParams.maxFiles ); // 4. Analyze the plugin structure const analysisResult = await this.performPluginAnalysis( phpFiles, secureParams, model, contextLength ); // 5. Generate comprehensive prompt const promptStages = this.getPromptStages({ ...secureParams, analysisResult, fileCount: phpFiles.length }); // 6. Execute with chunking (always needed for comprehensive analysis) const promptManager = new ThreeStagePromptManager(); const chunkSize = TokenCalculator.calculateOptimalChunkSize(promptStages, contextLength); const dataChunks = promptManager.chunkDataPayload(promptStages.dataPayload, chunkSize); const conversation = promptManager.createChunkedConversation(promptStages, dataChunks); const messages = [ conversation.systemMessage, ...conversation.dataMessages, conversation.analysisMessage ]; return await ResponseProcessor.executeChunked( messages, model, contextLength, 'wordpress_plugin_readiness', 'multifile' ); } catch (error: any) { return ErrorHandler.createExecutionError('wordpress_plugin_readiness', error); } }); }
- Schema definition for the tool's input parameters including project path, analysis depth, WordPress/PHP versions, and file limits.parameters = { // Primary parameter - WordPress plugin directory projectPath: { type: 'string' as const, description: 'Path to WordPress plugin root directory', required: true }, // Analysis configuration analysisDepth: { type: 'string' as const, description: 'Level of analysis detail', enum: ['basic', 'detailed', 'comprehensive'], default: 'comprehensive', required: false }, includeSteps: { type: 'array' as const, description: 'Specific analysis steps to include', required: false, default: ['structure', 'security', 'database', 'quality', 'standards', 'performance'], items: { type: 'string' as const } }, // WordPress configuration wpVersion: { type: 'string' as const, description: 'Target WordPress version for compatibility', required: false, default: '6.4' }, phpVersion: { type: 'string' as const, description: 'Target PHP version for compatibility', required: false, default: '8.0' }, // File analysis limits maxDepth: { type: 'number' as const, description: 'Maximum directory depth for file discovery (1-5)', required: false, default: 3 }, maxFiles: { type: 'number' as const, description: 'Maximum number of PHP files to analyze', required: false, default: 50 } };
- src/prompts/analyze/wordpress-plugin-readiness.ts:28-32 (registration)Tool class registration defining the tool name 'wordpress_plugin_readiness', category 'analyze', and description.export class WordPressPluginReadiness extends BasePlugin implements IPromptPlugin { name = 'wordpress_plugin_readiness'; category = 'analyze' as const; description = 'Comprehensive WordPress plugin readiness check for security, best practices, and WordPress.org submission';
- Helper function to discover PHP files and critical files in the WordPress plugin directory.private async discoverPHPFiles( projectPath: string, maxDepth: number, maxFiles: number ): Promise<string[]> { const phpFiles: string[] = []; const scanDirectory = async (dir: string, depth: number = 0) => { if (depth > maxDepth || phpFiles.length >= maxFiles) return; try { const items = await readdir(dir); for (const item of items) { if (phpFiles.length >= maxFiles) break; const fullPath = join(dir, item); const itemStat = await stat(fullPath); if (itemStat.isDirectory()) { // Skip common non-code directories if (!item.startsWith('.') && item !== 'node_modules' && item !== 'vendor' && item !== 'tests' && item !== '.git') { await scanDirectory(fullPath, depth + 1); } } else if (item.endsWith('.php')) { phpFiles.push(fullPath); } } } catch (error) { // Continue scanning even if one directory fails } }; await scanDirectory(projectPath); // Also check for critical WordPress files in root const criticalFiles = ['readme.txt', 'license.txt', 'LICENSE']; for (const file of criticalFiles) { const fullPath = join(projectPath, file); try { await stat(fullPath); phpFiles.push(fullPath); // Include these for completeness check } catch { // File doesn't exist, will be flagged in analysis } } return phpFiles; }
- Helper function to analyze individual PHP files for security, database, and standards issues.private async analyzeFile(file: string, content: string, params: any): Promise<any> { const analysis: any = { filePath: relative(params.projectPath, file), fileName: basename(file), size: content.length, lines: content.split('\n').length, security: [], database: [], standards: [] }; // Check for plugin header (main plugin file) if (content.includes('Plugin Name:') && content.includes('*/')) { analysis.isMainPluginFile = true; analysis.pluginHeaders = this.extractPluginHeaders(content); } // Security checks if (content.match(/\$_(GET|POST|REQUEST|SERVER|COOKIE)\[/)) { analysis.security.push({ type: 'INPUT_VALIDATION', pattern: 'Direct superglobal usage without sanitization' }); } if (content.includes('$wpdb->query') && !content.includes('$wpdb->prepare')) { analysis.security.push({ type: 'SQL_INJECTION', pattern: 'Database query without prepare statement' }); } if (content.match(/wp_ajax_\w+/) && !content.includes('check_ajax_referer')) { analysis.security.push({ type: 'NONCE_MISSING', pattern: 'AJAX handler without nonce verification' }); } if (content.includes('add_menu_page') && !content.includes('current_user_can')) { analysis.security.push({ type: 'CAPABILITY_CHECK', pattern: 'Admin page without capability check' }); } // Database patterns if (content.includes('$wpdb')) { const queries = content.match(/\$wpdb->(query|get_results|get_var|get_row)/g); if (queries) { analysis.database = queries.map(q => ({ type: q.replace('$wpdb->', ''), hasPrepare: content.includes('$wpdb->prepare') })); } } // Standards checks if (content.match(/function [A-Z]/)) { analysis.standards.push({ type: 'NAMING_CONVENTION', pattern: 'Function name starts with uppercase (should be lowercase)' }); } if (!content.includes('defined') && !content.includes('ABSPATH')) { analysis.standards.push({ type: 'DIRECT_ACCESS', pattern: 'Missing direct file access prevention' }); } return analysis; }