# Contributing to WP Agentic Writer Thank you for your interest in contributing to WP Agentic Writer! ## Project Overview WP Agentic Writer is a WordPress plugin that integrates AI-powered writing assistance directly into the Gutenberg editor. It helps writers create better content through plan-first workflows, real-time chat, SEO analysis, and image generation. ## Architecture ### Component Overview ``` ┌─────────────────────────────────────────────────────────────────┐ │ Gutenberg Sidebar │ │ (class-gutenberg-sidebar.php) │ │ │ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │ │ Chat Tab │ │ Plan Tab │ │ Image Tab │ │ │ └──────────────┘ └──────────────┘ └──────────────┘ │ └────────────────────────────┬────────────────────────────────────┘ │ REST API ┌───────────────────────┼───────────────────────┐ │ │ │ ▼ ▼ ▼ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │Controller_ │ │Controller_ │ │Controller_ │ │Chat │ │Session │ │Cost │ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ │ │ │ └────────────────────┼────────────────────┘ ▼ ┌───────────────────────┐ │ Provider Manager │ │ (class-provider- │ │ manager.php) │ └───────────┬───────────┘ │ ┌───────────────────┼───────────────────┐ │ │ │ ▼ ▼ ▼ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ OpenRouter │ │ Local │ │ Codex │ │ Provider │ │ Backend │ │ Provider │ └─────────────┘ └─────────────┘ └─────────────┘ ``` ### Key Classes | Class | File | Purpose | |-------|------|---------| | `Gutenberg_Sidebar` | `class-gutenberg-sidebar.php` | Main plugin class, registers REST routes, enqueues assets | | `Controller_Chat` | `class-controller-chat.php` | Chat messaging, streaming, search, research | | `Controller_Session` | `class-controller-session.php` | Session locking for multi-tab safety | | `Controller_Cost` | `class-controller-cost.php` | Cost tracking data | | `Controller_Models` | `class-controller-models.php` | AI model listing and refresh | | `Provider_Manager` | `class-provider-manager.php` | Provider selection and fallback logic | | `AI_Provider` (interface) | `interface-ai-provider.php` | Contract for AI provider implementations | | `Context_Builder` | `class-context-builder.php` | Builds context for AI requests | | `Conversation_Manager` | `class-conversation-manager.php` | Manages conversation sessions | | `Rate_Limiter` | `class-rate-limiter.php` | Rate limiting for REST endpoints | --- ## Adding a New REST Endpoint ### 1. Add the route registration In `class-gutenberg-sidebar.php`, add to `register_rest_routes()`: ```php register_rest_route('wp-agentic-writer/v1', '/my-endpoint', [ 'methods' => 'POST', 'callback' => [$this, 'handle_my_endpoint'], 'permission_callback' => [$this, 'check_permissions'], ]); ``` ### 2. Add the handler method ```php /** * Handle my custom endpoint. * * @param WP_REST_Request $request REST request. * @return WP_REST_Response|WP_Error */ public function handle_my_endpoint($request) { // Get parameters $params = $request->get_json_params(); $post_id = $request->get_param('post_id'); // Check post permission if post_id is provided if ($post_id > 0 && !$this->check_post_permission($post_id)) { return new WP_Error( 'forbidden', __('You do not have permission to access this post.'), ['status' => 403] ); } // Your logic here... return new WP_REST_Response(['result' => 'success'], 200); } ``` ### 3. Add rate limiting (optional) ```php // Check rate limit $rate_limit = WPAW_Rate_Limiter::check('my_endpoint'); if (is_wp_error($rate_limit)) { return $rate_limit; } ``` ### 4. Document the endpoint Add the endpoint to `docs/architecture/REST_API_ENDPOINTS.md`. --- ## Adding a New AI Provider ### 1. Create the provider class ```php class WP_Agentic_Writer_My_Provider implements WPAW_AI_Provider { // Implement all methods from interface-ai-provider.php } ``` ### 2. Register in Provider Manager In `class-provider-manager.php`, add to `register_providers()`: ```php $this->providers['my_provider'] = new WP_Agentic_Writer_My_Provider(); ``` ### 3. Add to selection logic Update `select_provider()` if your provider needs special handling. --- ## Adding a New Sidebar Tab ### 1. Add tab button in JavaScript In `assets/sidebar.js`, add to the tab navigation: ```javascript const tabButtons = document.querySelectorAll('.wpaw-tab-button'); // Add your tab button ``` ### 2. Add tab content ```html
``` ### 3. Add tab switching logic ```javascript function showTab(tabId) { // Handle your tab } ``` --- ## CSS Token System The plugin uses a three-namespace CSS token system: ### Scope Tokens (lowest priority) ```css .wpaw-sidebar-container { --wpaw-color-primary: #2271b1; } ``` ### State Tokens ```css .wpaw-tab-button.active { --wpaw-color-primary: #135e96; } ``` ### Intent Tokens (highest priority) ```css .wpaw-ai-thinking { --wpaw-color-primary: #d63638; } ``` ### CSS Class Hierarchy ``` .wpaw-sidebar-container → Base container ├── .wpaw-tab-content → Tab panels ├── .wpaw-command-area → Input areas ├── .wpaw-settings-v2-wrap → Settings pages ├── .wpaw-ai-thinking → AI processing state └── .wpaw-error → Error states ``` --- ## Database Schema ### Conversations Table ```sql CREATE TABLE {prefix}wpaw_conversations ( id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, session_id VARCHAR(36) NOT NULL UNIQUE, user_id BIGINT UNSIGNED NOT NULL, post_id BIGINT UNSIGNED DEFAULT NULL, title VARCHAR(255) DEFAULT '', created_at DATETIME DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, INDEX idx_user_id (user_id), INDEX idx_post_id (post_id) ) ``` ### Messages Table ```sql CREATE TABLE {prefix}wpaw_messages ( id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, conversation_id BIGINT UNSIGNED NOT NULL, role VARCHAR(20) NOT NULL, content LONGTEXT NOT NULL, metadata JSON DEFAULT NULL, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (conversation_id) REFERENCES {prefix}wpaw_conversations(id) ON DELETE CASCADE ) ``` ### Cost Tracking Table ```sql CREATE TABLE {prefix}wpaw_cost_tracking ( id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, provider VARCHAR(50) NOT NULL, model VARCHAR(100) NOT NULL, input_tokens INT UNSIGNED DEFAULT 0, output_tokens INT UNSIGNED DEFAULT 0, cost DECIMAL(10,6) DEFAULT 0, session_id VARCHAR(36) DEFAULT NULL, status VARCHAR(20) DEFAULT 'complete', created_at DATETIME DEFAULT CURRENT_TIMESTAMP ) ``` --- ## Testing Locally ### Manual Smoke Tests After making changes, verify: 1. **Sidebar loads**: Open a post in Gutenberg, verify sidebar appears 2. **Chat works**: Send a message, verify response appears 3. **Settings save**: Change settings, refresh, verify persistence 4. **Rate limiting**: Rapid requests should return 429 after limit ### Debug Mode Enable debug logging in browser console: ```javascript window.wpAgenticWriter = { debug: true }; ``` ### Database Queries Use WP-CLI to inspect database: ```bash wp db query "SELECT * FROM wp_wpaw_conversations LIMIT 5" wp db query "SELECT * FROM wp_wpaw_messages LIMIT 5" ``` --- ## Code Style - Follow WordPress PHP Coding Standards - Use `wp_add_inline_style()` for dynamic CSS - Prefix all classes/functions with `wpaw_` or `WP_Agentic_Writer_` - Document all public methods with docblocks --- ## Security Checklist - [ ] All post-scoped endpoints check `edit_post` capability - [ ] Sanitize all input with `sanitize_text_field()`, `absint()`, etc. - [ ] Escape all output with `esc_html()`, `esc_attr()`, etc. - [ ] Use WordPress nonces for form submissions - [ ] Rate limit expensive operations --- ## Useful Commands ```bash # Activate plugin wp plugin activate wp-agentic-writer # Deactivate plugin wp plugin deactivate wp-agentic-writer # View cost tracking wp db query "SELECT * FROM wp_wpaw_cost_tracking ORDER BY created_at DESC LIMIT 10" # Clear session locks wp db query "DELETE FROM wp_wpaw_conversations WHERE 1=1" ``` --- ## Resources - [WordPress REST API Handbook](https://developer.wordpress.org/rest-api/) - [Gutenberg Handbook](https://developer.wordpress.org/block-editor/) - [WP AI Client](https://developer.wordpress.org/rest-api/filters/rest_post_dispatch/)