diff --git a/igny8-wp-plugin/.gitattributes b/igny8-wp-plugin/.gitattributes deleted file mode 100644 index dfe07704..00000000 --- a/igny8-wp-plugin/.gitattributes +++ /dev/null @@ -1,2 +0,0 @@ -# Auto detect text files and perform LF normalization -* text=auto diff --git a/igny8-wp-plugin/BACKEND-FIXES-APPLIED.md b/igny8-wp-plugin/BACKEND-FIXES-APPLIED.md deleted file mode 100644 index 8067bc6a..00000000 --- a/igny8-wp-plugin/BACKEND-FIXES-APPLIED.md +++ /dev/null @@ -1,270 +0,0 @@ -# IGNY8 SaaS Backend - API Key Authentication Fixed - -## โœ… Root Cause Identified - -The **405 error was actually an authentication failure**, not a method not allowed error. The real issue was: - -**The SaaS backend had NO API Key authentication support!** - -The backend only supported: -- JWT token authentication (from `/auth/login/` endpoint) -- Session authentication -- Basic authentication - -But the WordPress plugin was sending the API key as a Bearer token, which the backend couldn't recognize. - ---- - -## ๐Ÿ”ง Fixes Applied to SaaS Backend - -### 1. Created API Key Authentication Class โœ… - -**File**: `backend/igny8_core/api/authentication.py` - -Added new `APIKeyAuthentication` class that: -- Validates API keys from `Authorization: Bearer {api_key}` headers -- Looks up the API key in `Site.wp_api_key` database field -- Authenticates as the account owner user -- Sets `request.account` and `request.site` for tenant isolation -- Returns `None` for JWT tokens (lets JWTAuthentication handle them) - -```python -class APIKeyAuthentication(BaseAuthentication): - """ - API Key authentication for WordPress integration. - Validates API keys stored in Site.wp_api_key field. - """ - def authenticate(self, request): - # Validates Bearer token against Site.wp_api_key - # Returns (user, api_key) tuple if valid - ... -``` - ---- - -### 2. Added API Key Auth to Django Settings โœ… - -**File**: `backend/igny8_core/settings.py` - -Updated `REST_FRAMEWORK` authentication classes (added as **first** in the list): - -```python -'DEFAULT_AUTHENTICATION_CLASSES': [ - 'igny8_core.api.authentication.APIKeyAuthentication', # NEW - WordPress API key (check first) - 'igny8_core.api.authentication.JWTAuthentication', - 'igny8_core.api.authentication.CSRFExemptSessionAuthentication', - 'rest_framework.authentication.BasicAuthentication', -], -``` - -**Why first?** API keys are simpler to validate (just a database lookup) vs JWT decoding, so it's more efficient. - ---- - -### 3. Enhanced Site Admin with API Key Management โœ… - -**File**: `backend/igny8_core/auth/admin.py` - -Added to the Site admin interface: - -**Features Added:** -1. **API Key Display** - Shows the full API key with a "Copy" button in the site detail page -2. **API Key Status** - Shows green/gray indicator in the site list view -3. **Generate API Keys Action** - Bulk action to generate API keys for selected sites -4. **WordPress Integration Fieldset** - Organized WP fields including the API key display - -**Admin Actions:** -- Select one or more sites in the admin list -- Choose "Generate WordPress API Keys" from the actions dropdown -- Click "Go" -- API keys are generated with format: `igny8_{40 random characters}` - ---- - -## ๐Ÿ“‹ Testing Instructions - -### Step 1: Generate an API Key for Your Site - -1. Go to Django Admin โ†’ `http://api.igny8.com/admin/` -2. Navigate to **Auth โ†’ Sites** -3. Find your WordPress site (or create one if it doesn't exist) -4. **Option A - Generate via Admin Action:** - - Check the checkbox next to your site - - Select "Generate WordPress API Keys" from the Actions dropdown - - Click "Go" -5. **Option B - View/Copy from Site Detail:** - - Click on the site name to open it - - Scroll to "WordPress Integration" section - - You'll see the API key with a "Copy" button - -### Step 2: Configure WordPress Plugin - -1. Go to WordPress Admin โ†’ Settings โ†’ IGNY8 API -2. Fill in the form: - - **Email**: Your IGNY8 account email (e.g., `dev@igny8.com`) - - **API Key**: Paste the API key you copied from Django admin - - **Password**: Your IGNY8 account password -3. Click **"Connect to IGNY8"** -4. โœ… Should show: "Successfully connected to IGNY8 API and stored API key." - -### Step 3: Test the Connection - -1. After connecting, scroll to "Connection Status" section -2. Make sure "Enable Sync Operations" is checked -3. Click **"Test Connection"** button -4. โœ… Should show: "Connection successful (tested: System ping endpoint)" - ---- - -## ๐Ÿ” How It Works Now - -### Authentication Flow: - -``` -WordPress Plugin โ†’ Sends: Bearer {api_key} - โ†“ -SaaS API Receives Request - โ†“ -APIKeyAuthentication class checks: - 1. Is header "Bearer {token}"? YES - 2. Is token at least 20 chars? YES - 3. Does token start with "ey" (JWT)? NO โ†’ Continue - 4. Query: Site.objects.filter(wp_api_key=token, is_active=True) - 5. Site found? YES - โ†“ - Sets: - - request.user = site.account.owner - - request.account = site.account - - request.site = site - โ†“ -Request is authenticated โœ… -``` - -### Endpoints Now Accessible: - -| Endpoint | Method | Auth Required | Status | -|----------|--------|---------------|--------| -| `/api/v1/system/ping/` | GET | None (Public) | โœ… Works | -| `/api/v1/planner/keywords/` | GET | Yes | โœ… Works with API key | -| `/api/v1/system/sites/` | GET | Yes | โœ… Works with API key | -| All other API endpoints | * | Yes | โœ… Works with API key | - ---- - -## ๐Ÿš€ What's Fixed - -| Issue | Before | After | -|-------|--------|-------| -| API Key Auth | โŒ Not supported | โœ… Fully working | -| Test Connection | โŒ 405/401 errors | โœ… Success | -| WordPress Plugin | โŒ Can't authenticate | โœ… Can authenticate | -| API Key Generation | โŒ Manual SQL | โœ… Django admin action | -| API Key Display | โŒ Not visible | โœ… Copy button in admin | - ---- - -## ๐Ÿ“Š Database Schema - -The API key is stored in the existing `Site` model: - -```python -class Site(models.Model): - # ... other fields ... - - wp_api_key = models.CharField( - max_length=255, - blank=True, - null=True, - help_text="API key for WordPress integration via IGNY8 WP Bridge plugin" - ) -``` - -**Table**: `igny8_sites` -**Column**: `wp_api_key` -**Format**: `igny8_{40 alphanumeric characters}` -**Example**: `igny8_aB3dE7gH9jK2mN4pQ6rS8tU0vW1xY5zA8cD2fG7hJ9` - ---- - -## ๐Ÿ” Security Features - -1. **API Key Length**: Minimum 20 characters enforced -2. **Site Status Check**: Only active sites (`is_active=True`) can authenticate -3. **User Status Check**: Raises `AuthenticationFailed` if user is inactive -4. **Tenant Isolation**: Automatically sets `request.account` for data filtering -5. **No Token Reuse**: API keys are site-specific, not reusable across accounts -6. **Secure Generation**: Uses Python's `secrets` module for cryptographically secure random generation - ---- - -## ๐Ÿ› Debug Mode (If Still Having Issues) - -### Check API Key in Database: - -```sql -SELECT id, name, wp_api_key, is_active -FROM igny8_sites -WHERE wp_url LIKE '%your-wordpress-site%'; -``` - -### Check Backend Logs: - -If authentication fails, check Django logs for: -``` -APIKeyAuthentication error: {error details} -``` - -### Test API Key Directly: - -```bash -# Replace {YOUR_API_KEY} with your actual API key -curl -v -H "Authorization: Bearer {YOUR_API_KEY}" "https://api.igny8.com/api/v1/system/ping/" -``` - -Expected response: -```json -{ - "success": true, - "data": { - "status": "ok" - }, - "request_id": "..." -} -``` - ---- - -## โœ… Verification Checklist - -- [ ] API key generated in Django admin -- [ ] API key copied and pasted into WordPress plugin -- [ ] WordPress connection successful -- [ ] Test connection button shows success -- [ ] WordPress debug log shows successful API requests - ---- - -## ๐Ÿ“ Next Steps - -1. **Restart the backend container** (if needed): - ```bash - docker restart igny8_backend - ``` - -2. **Test the WordPress plugin connection** following Step 2 above - -3. **Monitor the logs** to ensure requests are being authenticated properly - -4. **Start using the plugin!** The sync features should now work correctly. - ---- - -## ๐ŸŽฏ Summary - -**Root Issue**: SaaS backend lacked API Key authentication support -**Solution**: Added complete API Key authentication system -**Impact**: WordPress plugin can now authenticate and use all API endpoints -**Status**: โœ… **FULLY FIXED AND TESTED** - -The WordPress plugin and SaaS backend can now communicate properly via API key authentication! ๐ŸŽ‰ - diff --git a/igny8-wp-plugin/COMPLETE-FIX-SUMMARY.md b/igny8-wp-plugin/COMPLETE-FIX-SUMMARY.md deleted file mode 100644 index ef6f4a5f..00000000 --- a/igny8-wp-plugin/COMPLETE-FIX-SUMMARY.md +++ /dev/null @@ -1,326 +0,0 @@ -# Complete Fix Summary - WordPress Plugin + SaaS Backend - -## ๐ŸŽฏ Overview - -Fixed **3 major issues** preventing the WordPress plugin from connecting to the IGNY8 SaaS API. - ---- - -## โœ… All Issues Fixed - -### Issue #1: Security Check Failed (WordPress Plugin) -- **Component**: WordPress Plugin -- **File**: `admin/settings.php` -- **Problem**: Nested HTML forms broke nonce verification -- **Solution**: Moved "Revoke API Key" form outside main connection form -- **Status**: โœ… **FIXED** - -### Issue #2: API Key Not Displaying (WordPress Plugin) -- **Component**: WordPress Plugin -- **File**: `admin/class-admin.php` -- **Problem**: Form submitted placeholder asterisks instead of real API key -- **Solution**: Detect placeholder values and preserve stored key -- **Status**: โœ… **FIXED** - -### Issue #3: 405 Error / No API Key Auth (SaaS Backend) โญ -- **Component**: SaaS Backend API -- **Files**: - - `backend/igny8_core/api/authentication.py` - - `backend/igny8_core/settings.py` - - `backend/igny8_core/auth/admin.py` -- **Problem**: Backend had NO API Key authentication support -- **Solution**: - - Created `APIKeyAuthentication` class - - Added to Django REST Framework settings - - Added API key generation to Site admin -- **Status**: โœ… **FIXED** - ---- - -## ๐Ÿ“‹ Files Modified - -### WordPress Plugin (5 files) - -1. **`admin/settings.php`** - - Fixed nested forms issue - - Added debug mode indicator - -2. **`admin/class-admin.php`** - - Fixed API key placeholder detection - - Improved test connection to try multiple endpoints - - Enhanced error reporting - -3. **`includes/class-igny8-api.php`** - - Added comprehensive debug logging - - Added HTTP status codes to responses - - Improved error messages - -4. **`admin/assets/js/admin.js`** - - Enhanced error display with HTTP status - - Added console logging for debugging - -5. **Documentation** - - Created `DEBUG-SETUP.md` - - Created `FIXES-APPLIED.md` - - Created `QUICK-FIX-SUMMARY.txt` - -### SaaS Backend (3 files) - -1. **`backend/igny8_core/api/authentication.py`** โญ NEW CLASS - - Added `APIKeyAuthentication` class - - Validates WordPress API keys - - Sets tenant isolation context - -2. **`backend/igny8_core/settings.py`** - - Added API Key authentication to DRF settings - - Placed first in authentication class list - -3. **`backend/igny8_core/auth/admin.py`** - - Added API key generation action - - Added API key display with copy button - - Added API key status indicator - ---- - -## ๐Ÿš€ Complete Setup & Testing Guide - -### Part 1: Backend Setup (Do This First!) - -**Step 1: Restart Backend Container** -```bash -cd /path/to/igny8-app/igny8 -docker-compose restart backend -# Or: docker restart igny8_backend -``` - -**Step 2: Generate API Key** -1. Go to `http://api.igny8.com/admin/` -2. Navigate to **Auth โ†’ Sites** -3. Find your WordPress site -4. Select the site โ†’ Actions โ†’ "Generate WordPress API Keys" โ†’ Go -5. Click on the site name to open it -6. Find "WordPress Integration" section -7. **Copy the API key** (click the Copy button) - ---- - -### Part 2: WordPress Plugin Setup - -**Step 1: Enable Debug Mode** (Optional but Recommended) - -Add to `wp-config.php`: -```php -define('WP_DEBUG', true); -define('WP_DEBUG_LOG', true); -define('WP_DEBUG_DISPLAY', false); -define('IGNY8_DEBUG', true); -``` - -**Step 2: Clear WordPress Cache** -- Clear browser cache (Ctrl+Shift+Delete) -- Or hard refresh (Ctrl+F5) - -**Step 3: Connect the Plugin** -1. Go to WordPress Admin โ†’ Settings โ†’ IGNY8 API -2. Fill in the form: - - **Email**: `dev@igny8.com` (your IGNY8 account email) - - **API Key**: Paste the key from Django admin - - **Password**: Your IGNY8 password -3. Click **"Connect to IGNY8"** -4. โœ… Should show: "Successfully connected to IGNY8 API and stored API key." - -**Step 4: Test Connection** -1. Reload the WordPress settings page -2. Verify the API key shows as `********` -3. Scroll to "Connection Status" -4. Make sure "Enable Sync Operations" is checked -5. Click **"Test Connection"** -6. โœ… Should show: "โœ“ Connection successful (tested: System ping endpoint)" - ---- - -## ๐Ÿ” Troubleshooting - -### If Connection Still Fails: - -**1. Check Debug Logs** - -WordPress: `wp-content/debug.log` -``` -Look for: "IGNY8 DEBUG GET:" and "IGNY8 DEBUG RESPONSE:" -``` - -**2. Verify API Key in Database** - -```sql -SELECT id, name, wp_api_key, is_active -FROM igny8_sites -WHERE name = 'Your Site Name'; -``` - -**3. Test API Key Directly** - -```bash -curl -v -H "Authorization: Bearer YOUR_API_KEY" \ - "https://api.igny8.com/api/v1/system/ping/" -``` - -Expected response: -```json -{ - "success": true, - "data": { - "status": "ok" - } -} -``` - -**4. Check Site Status** - -Ensure in Django admin: -- Site โ†’ `is_active` = โœ“ (checked) -- Site โ†’ `status` = "Active" -- Account โ†’ `status` = "Active" or "Trial" - ---- - -## ๐Ÿ“Š Before vs After - -### Authentication Flow - -**BEFORE (Broken):** -``` -WordPress โ†’ Bearer {api_key} - โ†“ -SaaS API โ†’ JWTAuthentication tries to decode as JWT - โ†“ -ERROR: Invalid JWT token - โ†“ -401 Unauthorized or 405 Method Not Allowed -``` - -**AFTER (Working):** -``` -WordPress โ†’ Bearer {api_key} - โ†“ -SaaS API โ†’ APIKeyAuthentication checks Site.wp_api_key - โ†“ -Site found โ†’ User authenticated - โ†“ -200 OK - Request successful โœ… -``` - -### Test Connection Results - -| Test | Before | After | -|------|--------|-------| -| `/system/ping/` | โŒ 405 | โœ… 200 OK | -| `/planner/keywords/` | โŒ 401 | โœ… 200 OK | -| `/system/sites/` | โŒ 401 | โœ… 200 OK | - ---- - -## ๐ŸŽ‰ What's Now Working - -โœ… WordPress plugin connects successfully -โœ… API key authentication works -โœ… Test connection shows success -โœ… All API endpoints accessible -โœ… Debug logging captures full request/response -โœ… API keys can be generated in Django admin -โœ… API keys are secure and site-specific -โœ… Tenant isolation works properly - ---- - -## ๐Ÿ“ Key Learnings - -1. **Root Cause**: The 405 error was misleading - the real issue was lack of API key authentication support in the backend - -2. **Authentication Order Matters**: API key auth should be checked first (before JWT) for efficiency - -3. **Security**: API keys are: - - Stored in `Site.wp_api_key` field - - Generated with `secrets` module (cryptographically secure) - - Format: `igny8_{40 random characters}` - - Site-specific (not reusable) - - Validated against active sites only - -4. **Debug Logging**: Essential for diagnosing API issues - shows full request/response details - ---- - -## ๐Ÿ” Security Checklist - -- [x] API keys are cryptographically secure (using `secrets` module) -- [x] API keys are site-specific (tied to Site model) -- [x] API keys require site to be active (`is_active=True`) -- [x] API keys require user to be active -- [x] Tenant isolation automatically applied (`request.account`) -- [x] API keys don't expire (but can be regenerated) -- [x] Debug logs mask sensitive parts of Authorization header - ---- - -## ๐Ÿ“š Documentation - -**WordPress Plugin Docs:** -- `DEBUG-SETUP.md` - Complete debugging guide -- `FIXES-APPLIED.md` - WordPress plugin fixes details -- `QUICK-FIX-SUMMARY.txt` - Quick reference checklist - -**SaaS Backend Docs:** -- `BACKEND-FIXES-APPLIED.md` - Backend fixes details -- `COMPLETE-FIX-SUMMARY.md` - This file - ---- - -## ๐ŸŽฏ Final Checklist - -**Backend:** -- [ ] Backend container restarted -- [ ] API key generated in Django admin -- [ ] API key copied to clipboard -- [ ] Site is marked as active - -**WordPress:** -- [ ] WordPress cache cleared -- [ ] Debug mode enabled (optional) -- [ ] Plugin configured with email, API key, password -- [ ] Connection successful message shown -- [ ] API key displays as `********` after reload -- [ ] Test connection shows success -- [ ] Debug logs show successful requests - ---- - -## โœ… Success Criteria - -You know everything is working when: - -1. โœ… WordPress shows: "Successfully connected to IGNY8 API and stored API key." -2. โœ… Test Connection shows: "โœ“ Connection successful (tested: System ping endpoint)" -3. โœ… API key field shows: `********` -4. โœ… Debug logs show: `IGNY8 DEBUG RESPONSE: Status=200` -5. โœ… No errors in browser console or WordPress debug.log - ---- - -## ๐ŸŽŠ Conclusion - -**All issues have been fixed!** - -The WordPress plugin can now: -- โœ… Authenticate via API key -- โœ… Connect to the IGNY8 SaaS API -- โœ… Access all API endpoints -- โœ… Sync data bidirectionally - -**Status**: ๐ŸŸข **FULLY OPERATIONAL** - ---- - -_Last Updated: November 21, 2025_ -_WordPress Plugin Version: Latest_ -_SaaS Backend Version: Latest_ - diff --git a/igny8-wp-plugin/COMPLETE-STATUS.md b/igny8-wp-plugin/COMPLETE-STATUS.md deleted file mode 100644 index ef61e961..00000000 --- a/igny8-wp-plugin/COMPLETE-STATUS.md +++ /dev/null @@ -1,221 +0,0 @@ -# COMPLETE FIX SUMMARY - WordPress Plugin Sync Issue - -## ๐ŸŽฏ STATUS: PARTIALLY FIXED - NEEDS WORDPRESS PLUGIN DEPLOYMENT - ---- - -## โœ… WHAT'S BEEN FIXED - -### 1. Plugin Code (WordPress) - โœ… FIXED -**Location**: `E:\Projects\All Personal Projects\Digital Projects (Ecom Stores & IT Services)\Development\GIT\igny8-wp\igny8-wp-integration\` - -**Files Modified**: -- โœ… `includes/functions.php` - Better sync logic, platform filter, metadata -- โœ… `admin/class-admin.php` - User feedback messages -- โœ… `includes/class-igny8-api.php` - Debug logging for POST requests -- โœ… `tests/test-sync-structure.php` - NEW diagnostic test - -### 2. Backend Code (IGNY8 App) - โœ… FIXED -**Location**: `E:\Projects\All Personal Projects\Digital Projects (Ecom Stores & IT Services)\Development\GIT\igny8-app\igny8\backend\` - -**Files Modified**: -- โœ… `igny8_core/modules/integration/views.py` - Fixed last_structure_fetch path (line 316) - -### 3. Frontend Code - โœ… ALREADY CORRECT -**Location**: `E:\Projects\All Personal Projects\Digital Projects (Ecom Stores & IT Services)\Development\GIT\igny8-app\igny8\frontend\src\pages\Sites\Settings.tsx` - -No changes needed - the code is correct and waiting for data from backend. - ---- - -## โŒ WHAT'S NOT WORKING YET - -### The Frontend Shows Empty Because: -1. WordPress plugin code changes are NOT deployed to actual WordPress site yet -2. WordPress hasn't pushed any structure data to backend yet -3. Backend has no data to show (config_json['content_types'] is empty) -4. Frontend correctly shows "No content types data available" - -**Root Cause**: The modified WordPress plugin files need to be uploaded to the WordPress site. - ---- - -## ๐Ÿ”ง WHAT NEEDS TO HAPPEN NOW - -### Option 1: Deploy WordPress Plugin (RECOMMENDED) - -**Steps**: -1. Upload modified plugin files to WordPress site: - ``` - wp-content/plugins/igny8-bridge/includes/functions.php - wp-content/plugins/igny8-bridge/admin/class-admin.php - wp-content/plugins/igny8-bridge/includes/class-igny8-api.php - wp-content/plugins/igny8-bridge/tests/test-sync-structure.php - ``` - -2. Go to WordPress Admin โ†’ Settings โ†’ IGNY8 API - -3. Click "Connect to IGNY8" (re-enter credentials if needed) - -4. Look for message: "Site structure (post types and taxonomies) synced successfully" - -5. Refresh frontend: https://app.igny8.com/sites/5/settings?tab=content-types - -6. Should now show Post Types and Taxonomies! - -### Option 2: Manually Push Test Data (TESTING ONLY) - -**Purpose**: Verify backend works without WordPress deployment - -**Steps**: -1. Get your API key from Django admin - -2. Edit this file: - ``` - E:\Projects\All Personal Projects\Digital Projects (Ecom Stores & IT Services)\Development\GIT\igny8-app\igny8\backend\test_push_structure.py - ``` - -3. Replace `YOUR_API_KEY_HERE` with actual API key - -4. Run: - ```bash - cd E:\Projects\All Personal Projects\Digital Projects (Ecom Stores & IT Services)\Development\GIT\igny8-app\igny8\backend - python test_push_structure.py - ``` - -5. If successful, refresh frontend page - ---- - -## ๐Ÿ“Š CURRENT PAGE STATE - -**URL**: https://app.igny8.com/sites/5/settings?tab=content-types - -**What Shows Now**: -``` -WordPress Content Types - -Last structure fetch: - [Sync Now] - -(empty - no post types or taxonomies displayed) -``` - -**What SHOULD Show (After Fix)**: -``` -WordPress Content Types - -Last structure fetch: 2 minutes ago [Sync Now] - -Post Types -โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” -โ”‚ Posts 150 total ยท 0 synced โ”‚ -โ”‚ Enabled Limit: 100 โ”‚ -โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค -โ”‚ Pages 25 total ยท 0 synced โ”‚ -โ”‚ Enabled Limit: 100 โ”‚ -โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค -โ”‚ Products 89 total ยท 0 synced โ”‚ -โ”‚ Enabled Limit: 100 โ”‚ -โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ - -Taxonomies -โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” -โ”‚ Categories 15 total ยท 0 synced โ”‚ -โ”‚ Enabled Limit: 100 โ”‚ -โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค -โ”‚ Tags 234 total ยท 0 synced โ”‚ -โ”‚ Enabled Limit: 100 โ”‚ -โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ -``` - ---- - -## ๐Ÿ” VERIFICATION CHECKLIST - -### โœ… Code Fixed -- [x] WordPress plugin functions.php updated -- [x] WordPress plugin class-admin.php updated -- [x] WordPress plugin class-igny8-api.php updated -- [x] Backend views.py fixed (last_structure_fetch path) -- [x] Test script created (test_push_structure.py) - -### โŒ Deployment Pending -- [ ] WordPress plugin files uploaded to live site -- [ ] WordPress plugin reconnected to IGNY8 -- [ ] Structure sync executed -- [ ] Backend received data -- [ ] Frontend displaying content types - ---- - -## ๐Ÿš€ IMMEDIATE ACTION REQUIRED - -**To complete this fix, you MUST do ONE of these**: - -1. **Deploy WordPress Plugin Files** (uploads them to live WordPress site) -2. **Run Test Script** (manually pushes test data to backend) - -**Without one of these actions, the frontend will remain empty because there's no data in the backend.** - ---- - -## ๐Ÿ“ FILES READY FOR GIT COMMIT - -### WordPress Plugin Repo: -```bash -cd "E:\Projects\All Personal Projects\Digital Projects (Ecom Stores & IT Services)\Development\GIT\igny8-wp\igny8-wp-integration" - -git add includes/functions.php -git add admin/class-admin.php -git add includes/class-igny8-api.php -git add tests/test-sync-structure.php -git add *.md # All documentation - -git commit -m "Fix: WordPress structure sync - improved error handling, debug logging, and user feedback" - -git push origin main -``` - -### IGNY8 App Repo: -```bash -cd "E:\Projects\All Personal Projects\Digital Projects (Ecom Stores & IT Services)\Development\GIT\igny8-app\igny8" - -git add backend/igny8_core/modules/integration/views.py -git add backend/test_push_structure.py - -git commit -m "Fix: Integration content types last_structure_fetch path + test script" - -git push origin main -``` - ---- - -## ๐Ÿ’ก WHY FRONTEND IS STILL EMPTY - -1. โœ… Code is correct (plugin, backend, frontend) -2. โœ… API endpoints exist and work -3. โœ… Frontend correctly calls `/content-types/` endpoint -4. โŒ **Backend returns empty data because WordPress never sent any** -5. โŒ **WordPress hasn't sent data because updated plugin code isn't deployed yet** - -**It's like having a working pipeline with no water in it yet!** - ---- - -## ๐ŸŽฏ NEXT STEP - -**CHOOSE ONE**: - -### A) Deploy to WordPress (Production Fix) -Upload the 3 modified plugin files to your WordPress site and reconnect. - -### B) Run Test Script (Verification Only) -Test that backend works by manually pushing data with Python script. - -**Either way, once data is in the backend, the frontend will display it immediately!** - ---- - -_Last Updated: November 22, 2025 04:20 UTC_ -_Status: Code Fixed, Deployment Pending_ - diff --git a/igny8-wp-plugin/DEBUG-SETUP.md b/igny8-wp-plugin/DEBUG-SETUP.md deleted file mode 100644 index c0b74b82..00000000 --- a/igny8-wp-plugin/DEBUG-SETUP.md +++ /dev/null @@ -1,121 +0,0 @@ -# IGNY8 WordPress Bridge - Debug Setup Guide - -## Quick Fix Summary - -### Issue 1: API Key Not Showing After Reload โœ… FIXED -- **Problem**: API key field was empty after reloading the page -- **Fix**: Updated the form handler to detect placeholder asterisks and preserve the stored API key -- **Result**: API key now properly shows as `********` when stored - -### Issue 2: Test Connection Failing with 405 โœ… IMPROVED -- **Problem**: Test connection returns HTTP 405 (Method Not Allowed) -- **Fix**: Added comprehensive debugging and multiple endpoint fallback -- **Result**: Now tests 3 different endpoints and shows detailed error messages - -## Enable Debug Mode - -To see detailed API request/response logs, add these lines to your `wp-config.php` file (before `/* That's all, stop editing! */`): - -```php -// Enable WordPress debugging -define('WP_DEBUG', true); -define('WP_DEBUG_LOG', true); -define('WP_DEBUG_DISPLAY', false); - -// Enable IGNY8-specific debugging -define('IGNY8_DEBUG', true); -``` - -## View Debug Logs - -After enabling debug mode: - -1. **Test the connection** in WordPress admin (Settings โ†’ IGNY8 API โ†’ Test Connection) -2. **Check the debug log** at: `wp-content/debug.log` -3. Look for lines starting with `IGNY8 DEBUG GET:` and `IGNY8 DEBUG RESPONSE:` - -## What the Logs Will Show - -``` -IGNY8 DEBUG GET: https://api.igny8.com/api/v1/system/ping/ | Headers: {...} -IGNY8 DEBUG RESPONSE: Status=405 | Body={"detail":"Method not allowed"} -``` - -## Common 405 Error Causes - -1. **Endpoint doesn't support GET method** - The SaaS API endpoint may only accept POST -2. **API key lacks permissions** - The API key doesn't have access to that endpoint -3. **Endpoint doesn't exist** - The URL path is incorrect or not implemented yet -4. **Firewall/WAF blocking** - Server-side security blocking the request - -## Test Connection Endpoints (Tried in Order) - -The plugin now tests these endpoints automatically: - -1. `/system/ping/` - Basic health check -2. `/planner/keywords/?page_size=1` - Keywords list (limited to 1 result) -3. `/system/sites/` - Sites list - -If **all three fail**, the error message will show the last failure with HTTP status code. - -## Manual Testing with cURL - -Test the API from your server's command line: - -```bash -# Replace YOUR_API_KEY with your actual API key -curl -v -H "Authorization: Bearer YOUR_API_KEY" "https://api.igny8.com/api/v1/system/ping/" -``` - -Expected success response (HTTP 200): -```json -{ - "success": true, - "data": { - "status": "ok" - } -} -``` - -## Next Steps for SaaS Team - -Based on the debug logs, the SaaS team should: - -1. **Check which HTTP methods are allowed** for the tested endpoints -2. **Verify API key permissions** - Ensure the key has access to at least one endpoint -3. **Implement `/system/ping/` endpoint** if it doesn't exist (should return 200 OK) -4. **Check server logs** for incoming requests from the WordPress host -5. **Review WAF/firewall rules** that might be blocking requests - -## Plugin Changes Made - -### 1. `includes/class-igny8-api.php` -- Added debug logging for all GET requests -- Added HTTP status code to all responses -- Improved error messages with status codes - -### 2. `admin/class-admin.php` -- Updated `test_connection()` to try multiple endpoints -- Returns detailed error information including HTTP status -- Detects API key placeholder to prevent overwriting stored key - -### 3. `admin/assets/js/admin.js` -- Shows HTTP status code in error messages -- Logs full error details to browser console - -### 4. `admin/settings.php` -- Shows debug mode indicator when WP_DEBUG is enabled -- Fixed API key field to show asterisks when key is stored - -## Disable Debug Mode - -After troubleshooting, remove or comment out these lines from `wp-config.php`: - -```php -// define('WP_DEBUG', true); -// define('WP_DEBUG_LOG', true); -// define('IGNY8_DEBUG', true); -``` - -Keep `WP_DEBUG_DISPLAY` as `false` to prevent errors showing on the live site. - diff --git a/igny8-wp-plugin/DEPLOYMENT-CHECKLIST.md b/igny8-wp-plugin/DEPLOYMENT-CHECKLIST.md deleted file mode 100644 index 0abdd1f6..00000000 --- a/igny8-wp-plugin/DEPLOYMENT-CHECKLIST.md +++ /dev/null @@ -1,459 +0,0 @@ -# WordPress Plugin Sync Fix - Deployment Checklist - -**Version**: 1.0 -**Date**: November 22, 2025 -**Risk Level**: Low (Non-breaking changes) - ---- - -## Pre-Deployment - -### Code Review -- [ ] Review changes in `includes/functions.php` - - [ ] Enhanced `igny8_sync_site_structure_to_backend()` function - - [ ] Better error handling and response parsing - - [ ] Added platform filter to API query - - [ ] Improved debug logging - -- [ ] Review changes in `admin/class-admin.php` - - [ ] User feedback messages added - - [ ] Non-blocking approach maintained - - [ ] Connection still succeeds even if sync fails - -- [ ] Review changes in `includes/class-igny8-api.php` - - [ ] POST request debug logging added - - [ ] Respects WP_DEBUG and IGNY8_DEBUG flags - - [ ] Token refresh logic preserved - -- [ ] Review new test file `tests/test-sync-structure.php` - - [ ] Diagnostic script for troubleshooting - - [ ] Can be run standalone - -- [ ] Review documentation - - [ ] `SYNC-FIX-REPORT.md` - Technical details - - [ ] `SYNC-FIX-EXECUTIVE-SUMMARY.md` - Overview - - [ ] `SYNC-DATA-FLOW-DIAGRAM.md` - Data flow visual - - [ ] This checklist - Deployment guide - -### Backup -- [ ] Backup WordPress database - - Command: `wp db export backup-$(date +%s).sql` - - Location: Keep in safe place - -- [ ] Backup IGNY8 backend database - - [ ] PostgreSQL: `pg_dump igny8_production > backup-$(date +%s).sql` - - Or Docker: `docker exec igny8_db pg_dump -U postgres igny8_production > backup.sql` - -- [ ] Backup current plugin files - - Command: `tar -czf plugin-backup-$(date +%s).tar.gz includes/ admin/ sync/` - -- [ ] Document current state - - [ ] Note any active integrations - - [ ] Document any custom configurations - -### Testing Environment -- [ ] Set up staging environment - - [ ] Fresh copy of WordPress - - [ ] Fresh copy of IGNY8 backend - - [ ] Sufficient test data - -- [ ] Verify test environment is isolated - - [ ] Different database - - [ ] Different API endpoints (if possible) - - [ ] No production data - ---- - -## Staging Deployment - -### Deploy Code -- [ ] Copy modified files to staging WordPress: - ```bash - cp includes/functions.php staging-wp/wp-content/plugins/igny8-bridge/includes/ - cp admin/class-admin.php staging-wp/wp-content/plugins/igny8-bridge/admin/ - cp includes/class-igny8-api.php staging-wp/wp-content/plugins/igny8-bridge/includes/ - ``` - -- [ ] Copy test file: - ```bash - cp tests/test-sync-structure.php staging-wp/wp-content/plugins/igny8-bridge/tests/ - ``` - -- [ ] Verify plugin is still active: - ```bash - wp plugin list | grep igny8-bridge - ``` - -### Configure Debug Logging (Staging Only) -- [ ] Enable WordPress debug logging in `wp-config.php`: - ```php - define('WP_DEBUG', true); - define('WP_DEBUG_LOG', true); - define('IGNY8_DEBUG', true); - ``` - -- [ ] Verify log file exists: - ```bash - ls -la wp-content/debug.log - ``` - -### Functional Testing -- [ ] **Test 1: Connection** - - [ ] Go to WordPress Admin โ†’ Settings โ†’ IGNY8 API - - [ ] Enter credentials and click "Connect to IGNY8" - - [ ] Verify: Success message appears - - [ ] Verify: "Site structure synced" message appears (or "will be retried") - -- [ ] **Test 2: Debug Logging** - - [ ] Check `wp-content/debug.log`: - ```bash - tail -50 wp-content/debug.log | grep IGNY8 - ``` - - [ ] Should see: - - [ ] "Sending structure sync to endpoint..." - - [ ] "DEBUG POST: .../update-structure/" - - [ ] "DEBUG POST RESPONSE: Status=200" - - [ ] "Site structure synced successfully" - -- [ ] **Test 3: Backend Storage** - - [ ] Run Django shell: - ```bash - docker exec -it igny8_backend python manage.py shell - ``` - - [ ] Check storage: - ```python - from igny8_core.business.integration.models import SiteIntegration - si = SiteIntegration.objects.filter(platform='wordpress').first() - print(si.config_json.get('content_types', {}).keys()) - # Should show: dict_keys(['post_types', 'taxonomies', 'last_structure_fetch']) - ``` - -- [ ] **Test 4: Frontend Display** - - [ ] Navigate to Site Settings โ†’ Content Types tab - - [ ] Verify display shows: - - [ ] Post Types section - - [ ] Taxonomies section - - [ ] Counts for each item - - [ ] "Structure last fetched" timestamp - -- [ ] **Test 5: Diagnostic Script** - - [ ] Run test script: - ```bash - wp eval-file tests/test-sync-structure.php - ``` - - [ ] Verify: All tests pass (6/6 โœ…) - -- [ ] **Test 6: Error Scenarios** - - [ ] Disable backend temporarily - - [ ] Try to connect - - [ ] Verify: Connection fails with clear error - - [ ] Verify: Debug log shows connection error - - [ ] Re-enable backend - - [ ] Try connection again - - [ ] Verify: Works correctly - -- [ ] **Test 7: Cron Job** - - [ ] Check if daily cron is scheduled: - ```bash - wp cron event list | grep igny8_sync_site_structure - ``` - - [ ] Manually trigger it: - ```bash - wp cron test - # or - wp cron event run igny8_sync_site_structure - ``` - - [ ] Verify: Logs show successful sync - -- [ ] **Test 8: Multiple Sites** - - [ ] If applicable, test with multiple WordPress sites connected - - [ ] Verify: Each shows correct post types/taxonomies - - [ ] Verify: No data leakage between sites - -### Performance Testing -- [ ] Load test: Multiple simultaneous sync requests - - [ ] No timeouts - - [ ] No memory issues - - [ ] Database performs well - -- [ ] Monitor resources during sync: - - [ ] CPU usage reasonable - - [ ] Memory stable - - [ ] No database locks - -### Security Review -- [ ] Verify API credentials not logged: - - [ ] Check debug log - - [ ] Authorization headers masked (Bearer ***) - - [ ] API keys not exposed - -- [ ] Verify access control: - - [ ] Only authenticated users can trigger sync - - [ ] Only owners can see their site data - - [ ] Cross-site access denied - -### Regression Testing -- [ ] Verify existing functionality still works: - - [ ] Plugin connection (original method) - - [ ] Manual sync buttons - - [ ] Post sync operations - - [ ] Taxonomy sync operations - - [ ] Webhook handling - -### Staging Sign-Off -- [ ] QA approval: โœ… or โŒ -- [ ] If issues found: - - [ ] Document issue - - [ ] Fix code - - [ ] Re-test - - [ ] Return to staging sign-off - ---- - -## Production Deployment - -### Pre-Deployment Confirmation -- [ ] Staging tests passed -- [ ] QA sign-off obtained -- [ ] Stakeholders notified -- [ ] Maintenance window scheduled (if needed) -- [ ] Rollback plan documented - -### Deploy to Production -- [ ] **Timing**: Deploy during low-traffic period -- [ ] **Method 1: FTP/SFTP** - ```bash - scp -r includes/ admin/ sync/ user@prod-server:wp-content/plugins/igny8-bridge/ - ``` - -- [ ] **Method 2: Git Deploy** - ```bash - cd /var/www/html/wp-content/plugins/igny8-bridge/ - git pull origin main - ``` - -- [ ] **Method 3: WordPress Admin** - - [ ] Upload plugin zip file - - [ ] Click "Install" - - [ ] Activate plugin - -### Verify Deployment -- [ ] Plugin still active: - ```bash - wp plugin list | grep igny8-bridge - ``` - -- [ ] No PHP errors: - ```bash - grep -i "fatal\|error" wp-content/debug.log | tail -20 - ``` - -- [ ] Files in correct locations: - ```bash - ls -la wp-content/plugins/igny8-bridge/includes/class-igny8-api.php - ls -la wp-content/plugins/igny8-bridge/admin/class-admin.php - ls -la wp-content/plugins/igny8-bridge/includes/functions.php - ``` - -### Smoke Tests (Production) -- [ ] Verify connection still works - - [ ] Test with staging IGNY8 account first (if possible) - - [ ] Then test with production account - -- [ ] Check debug logs: - ```bash - tail -30 wp-content/debug.log | grep IGNY8 - ``` - -- [ ] Verify frontend displays content types - - [ ] Check multiple sites if applicable - - [ ] Verify counts are correct - -- [ ] Check that no errors in logs: - ```bash - grep -i "error" wp-content/debug.log | tail -10 - ``` - -### Monitoring (First 24 Hours) -- [ ] **Hour 0-1**: Active monitoring - - [ ] Check debug logs every 10 minutes - - [ ] Monitor error rates - - [ ] Watch for user complaints - -- [ ] **Hour 1-6**: Periodic checks - - [ ] Check logs every 30 minutes - - [ ] Verify syncs completing - - [ ] Monitor performance metrics - -- [ ] **Hour 6-24**: Daily monitoring - - [ ] Check logs at start, middle, end of day - - [ ] Verify cron jobs running - - [ ] Monitor for anomalies - -### Issues During Deployment -If issues arise: -- [ ] **Do not panic** - Changes are non-breaking -- [ ] Collect information: - - [ ] Screenshots of errors - - [ ] Debug log excerpts (last 100 lines) - - [ ] Browser console errors - - [ ] Backend logs -- [ ] Create incident ticket -- [ ] Decide: Fix or rollback? - -### Rollback Plan (If Needed) -- [ ] Restore from backup: - ```bash - cp plugin-backup-*.tar.gz current.tar.gz - tar -xzf current.tar.gz -C wp-content/plugins/igny8-bridge/ - ``` - -- [ ] Clear any caches: - ```bash - wp cache flush - ``` - -- [ ] Test connection again: - - [ ] Should revert to previous behavior - - [ ] May need to re-connect plugin - -- [ ] Notify stakeholders: - - [ ] Rollback was performed - - [ ] Feature postponed - - [ ] New deployment planned - ---- - -## Post-Deployment - -### Documentation -- [ ] Update deployment log: - - [ ] Version deployed - - [ ] Date/time - - [ ] Any issues encountered - - [ ] Resolution steps - -- [ ] Update team documentation: - - [ ] Point to `SYNC-FIX-REPORT.md` - - [ ] Share `SYNC-DATA-FLOW-DIAGRAM.md` - - [ ] Add to internal knowledge base - -- [ ] Create support guide: - - [ ] How to verify sync is working - - [ ] Common issues and solutions - - [ ] Who to contact for support - -### Team Communication -- [ ] Notify development team: - - [ ] Deployment completed successfully - - [ ] Link to documentation - - [ ] Invite questions - -- [ ] Notify product team: - - [ ] Feature is now active - - [ ] Users can see Content Types tab - - [ ] Daily sync is automatic - -- [ ] Notify support team: - - [ ] How to troubleshoot issues - - [ ] Where to find logs - - [ ] Escalation path - -### Cleanup -- [ ] Disable WP_DEBUG if enabled: - ```php - define('WP_DEBUG', false); - define('WP_DEBUG_LOG', false); - define('IGNY8_DEBUG', false); - ``` - -- [ ] Clear debug logs (optional): - ```bash - rm wp-content/debug.log - ``` - -- [ ] Clear cache: - ```bash - wp cache flush - ``` - -- [ ] Archive backup files: - - [ ] Keep backups for 30 days minimum - - [ ] Document backup locations - -### Success Criteria -โœ… Deployment successful if: -- [ ] No PHP errors in logs -- [ ] Plugin connections working -- [ ] Frontend shows Content Types -- [ ] Debug logs show sync messages -- [ ] Users report success -- [ ] No performance degradation -- [ ] Cron jobs running -- [ ] No security issues - ---- - -## Sign-Off - -| Role | Name | Signature | Date | -|------|------|-----------|------| -| Developer | | | | -| QA | | | | -| DevOps | | | | -| Product | | | | - ---- - -## Support Contact - -For issues during/after deployment: -- **Development Team**: [contact info] -- **DevOps Team**: [contact info] -- **Support Team**: [contact info] - ---- - -## Appendix - -### Useful Commands - -**Check plugin status:** -```bash -wp plugin list | grep igny8 -``` - -**View error logs:** -```bash -tail -100 wp-content/debug.log -``` - -**Test connection manually:** -```bash -wp eval-file tests/test-sync-structure.php -``` - -**Force sync:** -```bash -wp cron event run igny8_sync_site_structure -``` - -**Check backend integration:** -```bash -docker exec igny8_backend python manage.py shell -from igny8_core.business.integration.models import SiteIntegration -SiteIntegration.objects.filter(platform='wordpress').count() -``` - -**Restart WordPress (if needed):** -```bash -# Clear caches -wp cache flush -wp rewrite flush -``` - ---- - -_Last Updated: November 22, 2025_ -_Next Review: December 2025_ - diff --git a/igny8-wp-plugin/FIXES-APPLIED.md b/igny8-wp-plugin/FIXES-APPLIED.md deleted file mode 100644 index e20717bf..00000000 --- a/igny8-wp-plugin/FIXES-APPLIED.md +++ /dev/null @@ -1,173 +0,0 @@ -# IGNY8 WordPress Bridge - Fixes Applied - -## โœ… Issues Fixed - -### 1. Security Check Failed (Nonce Verification) โœ… -**Problem**: Form submission failed with "Security check failed. Please refresh the page and try again." - -**Root Cause**: Nested form elements - The "Revoke API Key" button had a `
` tag nested inside the main connection form, which is invalid HTML and broke nonce submission. - -**Fix**: Moved the "Revoke API Key" form outside the main connection form in `admin/settings.php`. - -**Result**: โœ… Connection form now submits properly with valid nonce. - ---- - -### 2. API Key Not Displaying After Reload โœ… -**Problem**: API key field showed empty after successfully connecting and reloading the page. - -**Root Cause**: The form was storing the placeholder asterisks (`********`) as the actual API key value when resubmitting. - -**Fix**: Updated `handle_connection()` in `admin/class-admin.php` to detect placeholder values and preserve the stored API key. - -**Result**: โœ… API key now properly displays as `********` when stored in the database. - ---- - -### 3. Test Connection 405 Error ๐Ÿ”ง IMPROVED + NEEDS SaaS TEAM -**Problem**: Test Connection button returns HTTP 405 (Method Not Allowed) error. - -**Root Cause**: The API endpoint being tested (`/planner/keywords/?page_size=1`) either: -- Doesn't exist yet -- Doesn't support GET method -- API key doesn't have permission to access it - -**Fixes Applied**: -1. โœ… Added comprehensive debug logging to `class-igny8-api.php` -2. โœ… Test connection now tries 3 different endpoints as fallback -3. โœ… Improved error messages to show HTTP status codes -4. โœ… Added browser console logging for detailed debugging - -**What's Still Needed** (SaaS Team): -1. โš ๏ธ Implement `/system/ping/` endpoint (should return `{"success": true, "data": {"status": "ok"}}`) -2. โš ๏ธ Verify the API key has permission to access at least one endpoint -3. โš ๏ธ Check if endpoints require POST instead of GET -4. โš ๏ธ Review server logs to see what's blocking the requests - ---- - -## ๐Ÿ“‹ Files Modified - -### PHP Files -1. โœ… `admin/settings.php` - Fixed nested forms, added debug indicator -2. โœ… `admin/class-admin.php` - Fixed API key handling, improved test connection -3. โœ… `includes/class-igny8-api.php` - Added debug logging, improved error responses - -### JavaScript Files -4. โœ… `admin/assets/js/admin.js` - Enhanced error display with HTTP status codes - -### Documentation -5. โœ… `DEBUG-SETUP.md` - Complete debugging guide -6. โœ… `FIXES-APPLIED.md` - This file - ---- - -## ๐Ÿงช Testing Instructions - -### Step 1: Clear Browser Cache -1. Open DevTools (F12) -2. Right-click the Refresh button โ†’ "Empty Cache and Hard Reload" - -### Step 2: Test Connection Form -1. Go to WordPress Admin โ†’ Settings โ†’ IGNY8 API -2. Fill in your credentials: - - Email: `dev@igny8.com` - - API Key: `[your-api-key]` - - Password: `[your-password]` -3. Click "Connect to IGNY8" -4. โœ… Should show: "Successfully connected to IGNY8 API and stored API key." -5. Reload the page -6. โœ… Verify API key field shows: `********` - -### Step 3: Enable Debug Mode (IMPORTANT!) -Add to `wp-config.php` (before `/* That's all, stop editing! */`): -```php -define('WP_DEBUG', true); -define('WP_DEBUG_LOG', true); -define('WP_DEBUG_DISPLAY', false); -define('IGNY8_DEBUG', true); -``` - -### Step 4: Test Connection -1. Scroll to "Connection Status" section -2. Click "Test Connection" button -3. Check the result message -4. Open `wp-content/debug.log` and look for: - ``` - IGNY8 DEBUG GET: https://api.igny8.com/api/v1/system/ping/ - IGNY8 DEBUG RESPONSE: Status=405 | Body={...} - ``` - -### Step 5: Check Browser Console -1. Open DevTools (F12) โ†’ Console tab -2. Click "Test Connection" again -3. Look for `IGNY8 Connection Test Failed:` error with full details - ---- - -## ๐Ÿ” Expected Test Results - -### If `/system/ping/` endpoint exists and works: -โœ… **Success**: "Connection successful (tested: System ping endpoint)" - -### If endpoint returns 405: -โš ๏ธ **Error**: "Connection failed: HTTP 405 error (HTTP 405)" -- This means the endpoint doesn't support GET method or doesn't exist - -### If endpoint returns 401: -โš ๏ธ **Error**: "Connection failed: Unauthorized (HTTP 401)" -- This means the API key is invalid or doesn't have permission - -### If endpoint returns 404: -โš ๏ธ **Error**: "Connection failed: HTTP 404 error (HTTP 404)" -- This means the endpoint doesn't exist yet - ---- - -## ๐Ÿ“ง Share Debug Info with SaaS Team - -After testing with debug mode enabled, share: - -1. **Full error message** from Test Connection button -2. **Debug log entries** from `wp-content/debug.log` (search for "IGNY8 DEBUG") -3. **Browser console errors** from DevTools -4. **Your API key** (first 8 characters only, for verification) - -### Example Debug Log to Share: -``` -[21-Nov-2025 12:34:56 UTC] IGNY8 DEBUG GET: https://api.igny8.com/api/v1/system/ping/ | Headers: {"Authorization":"Bearer ***","Content-Type":"application\/json"} -[21-Nov-2025 12:34:56 UTC] IGNY8 DEBUG RESPONSE: Status=405 | Body={"detail":"Method \"GET\" not allowed."} -``` - ---- - -## ๐Ÿš€ Next Actions - -### For You (WordPress Admin): -1. โœ… Test the connection form with your credentials -2. โœ… Enable debug mode in wp-config.php -3. โœ… Click Test Connection and capture the error -4. โœ… Share debug logs with the SaaS team - -### For SaaS Team: -1. โš ๏ธ Review the debug logs you provide -2. โš ๏ธ Implement or verify these endpoints accept GET: - - `/system/ping/` - - `/planner/keywords/?page_size=1` - - `/system/sites/` -3. โš ๏ธ Verify API key permissions -4. โš ๏ธ Check server access logs for the WordPress host IP -5. โš ๏ธ Confirm no WAF/firewall is blocking requests - ---- - -## โœ… Summary - -| Issue | Status | Action Required | -|-------|--------|----------------| -| Security check nonce error | โœ… **FIXED** | None - working | -| API key not displaying | โœ… **FIXED** | None - working | -| Test connection 405 error | ๐Ÿ”ง **IMPROVED** | SaaS team needs to implement/fix endpoints | - -**The plugin is now properly configured and logging detailed debug information. The 405 error is a backend API issue that requires the SaaS team to implement or fix the endpoints.** - diff --git a/igny8-wp-plugin/ISSUES-AND-FIXES.md b/igny8-wp-plugin/ISSUES-AND-FIXES.md deleted file mode 100644 index 44bfe213..00000000 --- a/igny8-wp-plugin/ISSUES-AND-FIXES.md +++ /dev/null @@ -1,454 +0,0 @@ -# WordPress Plugin Sync Issues - Detailed Analysis & Fixes - -**Date**: November 22, 2025 -**Reporter**: System Analysis -**Status**: โœ… FIXED - ---- - -## ๐Ÿ“‹ Issue Summary - -The WordPress plugin was **successfully connecting** to IGNY8, but the **initial sync and planned post/taxonomy counts fetching** through the connected connection between app and plugin was **not working correctly**. - -**Symptoms**: -- Content Types tab in frontend remained empty -- No post types or taxonomies were visible -- Counts showed as 0 or undefined -- Users couldn't see site structure - ---- - -## ๐Ÿ” Root Cause Analysis - -### Issue #1: Incomplete Integration Response Handling -**Location**: `includes/functions.php` - `igny8_sync_site_structure_to_backend()` function - -**The Problem**: -```php -// OLD CODE - ISSUE -$response = $api->get('/v1/integration/integrations/?site=' . $site_id); - -if (!$response['success'] || empty($response['data'])) { - error_log('IGNY8: No integrations found for site.'); - return false; -} - -// Tries to extract integration but doesn't handle multiple formats -$integration = null; -if (isset($response['data']['results']) && !empty($response['data']['results'])) { - $integration = $response['data']['results'][0]; -} elseif (is_array($response['data']) && !empty($response['data'])) { - $integration = $response['data'][0]; -} -``` - -**Why It Fails**: -1. API response can be in different formats (paginated vs direct array) -2. No explicit platform filter to find WordPress integration specifically -3. Poor error logging made debugging impossible -4. If integration ID not found, entire sync fails silently - -**Impact**: -- Structure never gets pushed to backend -- Frontend has nothing to display -- User sees empty Content Types tab - -### Issue #2: Insufficient Error Logging -**Location**: Multiple files - -**The Problem**: -- Only GET requests had debug logging -- POST requests were completely silent -- No request/response body logging -- Hard to troubleshoot connection issues - -**Why It Matters**: -- When sync fails, no information in logs -- Admins can't troubleshoot -- Issues go unreported or misdiagnosed - -**Impact**: -- Admin has no visibility into what went wrong -- Support can't help debug issues -- Problems appear random/mysterious - -### Issue #3: No User Feedback on Sync Status -**Location**: `admin/class-admin.php` - `handle_connection()` method - -**The Problem**: -```php -// OLD CODE -// Connection success message shown -add_settings_error(..., 'Successfully connected...'); - -// But sync is called without user feedback -igny8_sync_site_structure_to_backend(); -// If this fails, user doesn't know! -``` - -**Why It's a Problem**: -- User thinks everything is working -- Structure sync might have failed -- Frontend remains empty -- User confused about what went wrong - -**Impact**: -- False sense of successful setup -- Data discrepancies between what user expects and what frontend shows - -### Issue #4: Missing Metadata in Structure Data -**Location**: `includes/functions.php` - `igny8_get_site_structure()` function - -**The Problem**: -```php -// OLD CODE - Missing data -return array( - 'post_types' => $post_types_data, - 'taxonomies' => $taxonomies_data, - 'timestamp' => current_time('c'), - // Missing: site_url, wordpress_version -); -``` - -**Why It Matters**: -- Backend doesn't know which WordPress version -- Backend doesn't know site URL -- Harder to track changes over time -- Less useful for debugging - -**Impact**: -- Incomplete audit trail -- Harder to diagnose version-specific issues - ---- - -## โœ… Fixes Applied - -### Fix #1: Robust Integration Response Handling - -**File**: `includes/functions.php` - -**What Changed**: -```php -// NEW CODE - FIXED -$response = $api->get('/v1/integration/integrations/?site=' . $site_id . '&platform=wordpress'); -// โ†‘ Added platform filter - -if (!$response['success']) { - error_log('IGNY8: Failed to fetch integrations. Error: ' . json_encode($response)); - return false; -} - -// Handle multiple response formats robustly -$integration = null; -$data = isset($response['data']) ? $response['data'] : array(); - -// Handle paginated response (DRF default) -if (isset($data['results']) && is_array($data['results']) && !empty($data['results'])) { - $integration = $data['results'][0]; -} -// Handle direct array response -elseif (is_array($data) && !empty($data)) { - if (isset($data[0]) && is_array($data[0])) { - $integration = $data[0]; - } elseif (isset($data['id'])) { - $integration = $data; - } -} - -if (!$integration || empty($integration['id'])) { - error_log('IGNY8: Could not find valid WordPress integration. Response data: ' . json_encode($data)); - return false; -} - -// ... rest of sync -$integration_id = (int) $integration['id']; -error_log('IGNY8: Sending structure sync to endpoint /v1/integration/integrations/' . $integration_id . '/update-structure/'); -``` - -**Benefits**: -โœ… Handles multiple response formats -โœ… Platform filter ensures WordPress integration -โœ… Better error logging -โœ… Type casting prevents injection - ---- - -### Fix #2: Enhanced Debug Logging for POST Requests - -**File**: `includes/class-igny8-api.php` - -**What Changed**: -```php -// NEW CODE - FIXED -public function post($endpoint, $data) { - $url = $this->base_url . $endpoint; - - // Debug logging before request - $debug_enabled = (defined('WP_DEBUG') && WP_DEBUG) || (defined('IGNY8_DEBUG') && IGNY8_DEBUG); - if ($debug_enabled) { - error_log(sprintf( - 'IGNY8 DEBUG POST: %s | Payload: %s', - $url, - json_encode($data) - )); - } - - $response = wp_remote_post($url, array( - 'headers' => $this->get_headers(), - 'body' => json_encode($data), - 'timeout' => 60 - )); - - // Debug logging after response - if ($debug_enabled) { - $status_code = wp_remote_retrieve_response_code($response); - $response_body = wp_remote_retrieve_body($response); - error_log(sprintf( - 'IGNY8 DEBUG POST RESPONSE: Status=%s | Body=%s', - $status_code, - substr($response_body, 0, 500) - )); - } - - // ... rest of method -} -``` - -**Benefits**: -โœ… Full request logging -โœ… Response status visible -โœ… Respects WP_DEBUG flag -โœ… Limited response body (first 500 chars) to avoid huge logs - ---- - -### Fix #3: User Feedback on Sync Status - -**File**: `admin/class-admin.php` - -**What Changed**: -```php -// NEW CODE - FIXED -add_settings_error( - 'igny8_settings', - 'igny8_connected', - __('Successfully connected to IGNY8 API.', 'igny8-bridge'), - 'updated' -); - -// Sync structure and provide feedback -if (igny8_sync_site_structure_to_backend()) { - add_settings_error( - 'igny8_settings', - 'igny8_structure_synced', - __('Site structure (post types and taxonomies) synced successfully.', 'igny8-bridge'), - 'updated' - ); -} else { - // Non-blocking - connection still succeeded - add_settings_error( - 'igny8_settings', - 'igny8_structure_sync_pending', - __('Connected but structure sync will be retried. Check WordPress debug log for details.', 'igny8-bridge'), - 'notice' - ); -} -``` - -**Benefits**: -โœ… Clear user feedback -โœ… Non-blocking (connection succeeds even if sync fails) -โœ… Guides user to debug log if needed -โœ… Separate messages for different outcomes - ---- - -### Fix #4: Complete Metadata in Structure - -**File**: `includes/functions.php` - -**What Changed**: -```php -// NEW CODE - FIXED -return array( - 'post_types' => $post_types_data, - 'taxonomies' => $taxonomies_data, - 'timestamp' => current_time('c'), - 'site_url' => get_site_url(), // NEW - 'wordpress_version' => get_bloginfo('version'), // NEW -); -``` - -**Benefits**: -โœ… Backend knows WordPress version -โœ… Backend knows site URL -โœ… Better for audit trail -โœ… Helps with debugging - ---- - -### Fix #5: Structure Sync Status Flag - -**File**: `includes/functions.php` - -**What Changed**: -```php -// NEW CODE - FIXED -if ($update_response['success']) { - error_log('IGNY8: Site structure synced successfully to integration ' . $integration_id . '.'); - update_option('igny8_last_structure_sync', current_time('timestamp')); - - // NEW: Track that initial sync was done - update_option('igny8_structure_synced', 1); - - return true; -} -``` - -**Benefits**: -โœ… Can check if sync ever completed -โœ… Timestamp helps track recency -โœ… Useful for status pages/dashboards - ---- - -## ๐Ÿ“Š Before & After Comparison - -| Aspect | Before | After | -|--------|--------|-------| -| **Integration Query** | Single format | Multiple formats handled | -| **Platform Filter** | No filter | Explicit `&platform=wordpress` | -| **Error Logging** | Limited | Detailed with full context | -| **POST Debug** | None | Full request/response logging | -| **User Feedback** | No sync feedback | Clear success/failure messages | -| **Metadata** | Timestamp only | Timestamp + URL + Version | -| **Sync Status Tracking** | None | `igny8_structure_synced` flag | -| **Troubleshooting** | Very difficult | Clear logs + test script | - ---- - -## ๐Ÿงช How To Verify Fixes - -### Test 1: Check Debug Logs -```bash -tail -50 wp-content/debug.log | grep IGNY8 -``` - -**Expected to see**: -``` -IGNY8 DEBUG POST: https://api.igny8.com/api/v1/integration/integrations/{id}/update-structure/ -IGNY8 DEBUG POST RESPONSE: Status=200 -IGNY8: Sending structure sync to endpoint... -IGNY8: Site structure synced successfully to integration {id}. -``` - -### Test 2: Verify Backend Storage -```python -from igny8_core.business.integration.models import SiteIntegration -si = SiteIntegration.objects.filter(platform='wordpress').first() -content_types = si.config_json.get('content_types', {}) - -# Should have all three keys -assert 'post_types' in content_types -assert 'taxonomies' in content_types -assert 'last_structure_fetch' in content_types - -# Should have post types -assert len(content_types['post_types']) > 0 - -# Should have taxonomies -assert len(content_types['taxonomies']) > 0 -``` - -### Test 3: Frontend Display -Navigate to Site Settings โ†’ Content Types tab - -**Expected to see**: -- โœ… Post Types section (not empty) -- โœ… Taxonomies section (not empty) -- โœ… Counts for each -- โœ… "Structure last fetched" timestamp - ---- - -## ๐ŸŽฏ Impact Assessment - -### Positive Impacts -โœ… **Reliability**: Structure sync now works reliably -โœ… **Visibility**: Users and admins can see what's happening -โœ… **Debugging**: Full logs make troubleshooting easy -โœ… **Robustness**: Multiple response formats handled -โœ… **UX**: Clear feedback about operation status - -### Negative Impacts -โŒ **None identified** - All changes are improvements with no breaking changes - -### Risk Level -๐ŸŸข **LOW** - All changes are backward compatible, non-breaking, and improvements only - ---- - -## ๐Ÿ“ˆ Metrics That Will Improve - -After deployment, these metrics should improve: - -1. **Content Types Tab Population Rate**: 0% โ†’ ~95%+ -2. **Structure Sync Success Rate**: Unknown โ†’ Measurable -3. **User Satisfaction**: Unknown โ†’ Improved (with working feature) -4. **Support Tickets**: Might increase initially (as issues surface), then decrease -5. **Debug Log Usefulness**: Low โ†’ High (with new logging) - ---- - -## ๐Ÿ”„ Long-term Improvements - -Based on this fix, future improvements could include: - -1. **Sync Status Dashboard**: Show sync status for all sites -2. **Automatic Retry Logic**: Retry failed syncs automatically -3. **Webhook Notifications**: Notify on sync completion -4. **Bulk Operations**: Sync multiple sites simultaneously -5. **Scheduled Sync Reports**: Daily sync status emails - ---- - -## ๐Ÿ“ž Related Documentation - -- `SYNC-FIX-REPORT.md` - Detailed technical implementation -- `SYNC-FIX-EXECUTIVE-SUMMARY.md` - High-level overview -- `SYNC-DATA-FLOW-DIAGRAM.md` - Visual data flow -- `DEPLOYMENT-CHECKLIST.md` - Deployment instructions -- `tests/test-sync-structure.php` - Automated testing script - ---- - -## โœจ Conclusion - -The WordPress plugin sync issues have been comprehensively identified and fixed: - -โœ… **Root causes addressed** -- Response format handling improved -- Debug logging enhanced -- User feedback added -- Metadata completeness increased - -โœ… **Quality improvements** -- More robust error handling -- Better logging for debugging -- Clearer user communication -- Stronger status tracking - -โœ… **Testing and documentation** -- Comprehensive test script provided -- Multiple documentation files created -- Deployment checklist provided -- No breaking changes - -The fix is **production-ready** and can be deployed with confidence. - ---- - -_Last Updated: November 22, 2025_ -_Status: โœ… COMPLETE_ - diff --git a/igny8-wp-plugin/PHASE1-COMPLETE.md b/igny8-wp-plugin/PHASE1-COMPLETE.md deleted file mode 100644 index 46477bd1..00000000 --- a/igny8-wp-plugin/PHASE1-COMPLETE.md +++ /dev/null @@ -1,62 +0,0 @@ -# Phase 1 Complete: Authentication Simplification โœ… - -## Changes Made - -### 1. API Connection Card (lines 76-149) -**Before:** -- Email field -- Password field -- API key field (optional) - -**After:** -- โœ… API key field ONLY (required) -- โœ… When connected: Shows masked key (โ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ข) in disabled field -- โœ… Revoke button inline below masked key - -### 2. Connection Status Card (lines 152-239) -**Before:** -- "Enable Sync Operations" checkbox -- "Enable Two-Way Sync" checkbox -- Email display -- Site ID display - -**After:** -- โœ… Single toggle: "Enable Communication" -- โœ… Shows "Connected" (green) or "Disconnected" (gray) -- โœ… Description: "Controls whether plugin can communicate with IGNY8. API key stays connected but no data is synced when disabled." - -### 3. Removed Cards -**Deleted:** -- โŒ Webhook Configuration card (lines 454-489) -- โŒ Link Queue card (lines 492-521) -- โŒ Recent Webhook Activity card (lines 523-552) - -## Key Design Decisions - -### Two-Level Control System -1. **API Key** = Authentication layer (connect/disconnect) -2. **Toggle** = Communication layer (enable/disable data flow) - -This means: -- API key connected + toggle ON = Full sync active -- API key connected + toggle OFF = No sync, but API remains authenticated -- No API key = Cannot connect at all - -### Why This Works -- Simpler for users (no email/password confusion) -- Consistent with IGNY8 app authentication -- Toggle provides quick on/off without losing API key -- Matches backend indicator logic - -## Files Modified -1. `/admin/settings.php` - Removed 200+ lines, added new simplified UI - -## Next Steps: Phase 2 -- Enhance Sync Operations UI with counts -- Add detailed statistics -- Match IGNY8 brand colors -- Add progress indicators - -## Status: โœ… COMPLETE -All Phase 1 tasks done. Ready for Phase 2. - diff --git a/igny8-wp-plugin/PHASE2-COMPLETE.md b/igny8-wp-plugin/PHASE2-COMPLETE.md deleted file mode 100644 index af4ec628..00000000 --- a/igny8-wp-plugin/PHASE2-COMPLETE.md +++ /dev/null @@ -1,122 +0,0 @@ -# Phase 2 Complete: UI/UX Enhancement โœ… - -## Changes Made - -### 1. Sync Operations - Enhanced Cards -**Before:** Simple buttons with no context -**After:** Beautiful card grid with: -- โœ… **Icons** for each operation type -- โœ… **Item counts** (e.g., "Send 142 posts, 23 pages, 15 products") -- โœ… **Descriptions** explaining what each does -- โœ… **Last sync time** (e.g., "Last sync: 2 hours ago") -- โœ… **Loading states** with spinner -- โœ… **Hover effects** with elevation - -**Example Card:** -``` -โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” -โ”‚ [๐Ÿ“„] Sync Posts to IGNY8 โ”‚ -โ”‚ โ”‚ -โ”‚ Send 142 posts, 23 pages, 15 โ”‚ -โ”‚ products from WordPress to โ”‚ -โ”‚ IGNY8 โ”‚ -โ”‚ โ”‚ -โ”‚ โฑ Last sync: 2 hours ago โ”‚ -โ”‚ โ”‚ -โ”‚ [ Sync Now ] โ”‚ -โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ -``` - -### 2. Statistics Dashboard - Modern Cards -**Before:** Basic 2-column grid -**After:** 4-card dashboard with: -- โœ… **Color-coded icons** with backgrounds -- โœ… **Real counts** from database -- โœ… **Meta information** below each stat -- โœ… **Semantic summary** (if available) -- โœ… **Hover effects** - -**Cards:** -1. **Synced Posts** (Blue) - Shows post/page counts -2. **Taxonomy Terms** (Green) - Shows total terms -3. **Last Sync** (Orange) - Shows time ago + date -4. **Connection Status** (Purple) - Active/Disabled - -### 3. IGNY8 Brand Colors Applied -```css ---igny8-primary: #3B82F6 (Blue) ---igny8-success: #10B981 (Green) ---igny8-warning: #F59E0B (Orange) ---igny8-error: #EF4444 (Red) ---igny8-purple: #8B5CF6 (Purple) -``` - -**Applied to:** -- Sync operation buttons -- Statistics icons -- Status indicators -- Toggle switch (green when on) -- Hover states - -### 4. Modern CSS Features -- โœ… **Box shadows** on cards -- โœ… **Border radius** (8px, 12px) -- โœ… **Smooth transitions** (0.3s ease) -- โœ… **Gradient backgrounds** for special cards -- โœ… **Transform animations** (translateY on hover) -- โœ… **Consistent spacing** (16px, 20px, 24px) - -### 5. Loading States -- โœ… Spinner in buttons when syncing -- โœ… "Syncing..." text replaces "Sync Now" -- โœ… Button disabled during operation -- โœ… Status messages below cards (success/error/loading) - -## Visual Improvements - -### Sync Grid Layout -``` -โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” -โ”‚ Posts โ”‚Taxonomiesโ”‚From IGNY8โ”‚Site Scan โ”‚ -โ”‚ Card โ”‚ Card โ”‚ Card โ”‚ Card โ”‚ -โ”‚ โ”‚ โ”‚ โ”‚(highlightโ”‚ -โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ -``` - -### Stats Grid Layout -``` -โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” -โ”‚ Synced โ”‚Taxonomy โ”‚ Last โ”‚Connection -โ”‚ Posts โ”‚ Terms โ”‚ Sync โ”‚ Status โ”‚ -โ”‚ (Blue) โ”‚ (Green) โ”‚(Orange) โ”‚(Purple) โ”‚ -โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ -``` - -## Responsive Design -- โœ… Mobile: 1 column grid -- โœ… Tablet: 2 column grid -- โœ… Desktop: 4 column grid -- โœ… Touch-friendly buttons -- โœ… Readable text sizes - -## Files Modified -1. `/admin/settings.php` - Enhanced HTML structure -2. `/admin/assets/css/admin.css` - Complete redesign with IGNY8 colors - -## Key Features -- **Informative:** Shows exactly what each operation does + counts -- **Beautiful:** Modern cards with icons, shadows, animations -- **Consistent:** IGNY8 brand colors throughout -- **Responsive:** Works on all screen sizes -- **Professional:** Matches IGNY8 app design quality - -## Next Steps: Phase 3 -- Update admin class authentication handlers -- Remove webhook backend code -- Add health check endpoint improvements -- Verify bidirectional sync consistency -- Test complete flow: App โ†” Plugin - -## Status: โœ… COMPLETE -All Phase 2 tasks done. Ready for Phase 3! - diff --git a/igny8-wp-plugin/PHASE3-COMPLETE.md b/igny8-wp-plugin/PHASE3-COMPLETE.md deleted file mode 100644 index de1cdb18..00000000 --- a/igny8-wp-plugin/PHASE3-COMPLETE.md +++ /dev/null @@ -1,192 +0,0 @@ -# Phase 3 Complete: Backend Consistency & Health Check โœ… - -## Changes Made - -### 1. API Client - API Key Only โœ… -**File:** `/includes/class-igny8-api.php` - -**Removed:** -- โŒ `login($email, $password)` method -- โŒ `refresh_token()` method -- โŒ Refresh token logic in GET/POST methods -- โŒ Email/password authentication - -**Added:** -- โœ… `connect($api_key)` method - connects using API key only -- โœ… API key stored securely -- โœ… Tests connection by calling `/auth/sites/` endpoint -- โœ… All requests use `Authorization: Bearer {api_key}` header - -**Key Changes:** -```php -// OLD: login() with email/password -public function login($email, $password) { ... } - -// NEW: connect() with API key only -public function connect($api_key) { - // Store API key - // Test connection - // Return success/failure -} -``` - -### 2. REST API Status Endpoint โœ… -**File:** `/includes/class-igny8-rest-api.php` - -**Added:** -- โœ… `GET /wp-json/igny8/v1/status` endpoint -- โœ… Returns plugin connection status -- โœ… Returns API key presence -- โœ… Returns communication enabled state -- โœ… Returns health status - -**Response Format:** -```json -{ - "success": true, - "data": { - "connected": true, - "has_api_key": true, - "communication_enabled": true, - "plugin_version": "1.0.0", - "wordpress_version": "6.4", - "last_health_check": 1234567890, - "health": "healthy" - } -} -``` - -**Updated Permission Checks:** -- โœ… Uses API key only (no email/password) -- โœ… Accepts `Authorization: Bearer {api_key}` header -- โœ… Accepts `X-IGNY8-API-KEY` header -- โœ… Removed token refresh logic - -### 3. Removed Webhook System โœ… -**Files Removed:** -- โŒ `/includes/class-igny8-webhooks.php` (not loaded) -- โŒ `/includes/class-igny8-webhook-logs.php` (not loaded) -- โŒ Webhook secret regeneration handler in admin class - -**Updated:** -- โœ… `igny8-bridge.php` - Removed webhook includes -- โœ… `admin/class-admin.php` - Removed webhook secret regeneration -- โœ… All authentication now uses API key only - -### 4. Admin Class - API Key Only โœ… -**File:** `/admin/class-admin.php` - -**Updated `handle_connection()`:** -- โŒ Removed email/password fields -- โŒ Removed `login()` call -- โœ… Uses `$api->connect($api_key)` only -- โœ… Simplified error messages -- โœ… Updated success message - -**Removed Settings:** -- โŒ `igny8_email` registration -- โŒ Webhook secret regeneration handler - -### 5. Content Model Verification โœ… -**Backend Model:** `backend/igny8_core/business/content/models.py` - -**Verified Support:** -- โœ… `entity_type` field supports: 'post', 'page', 'product', 'service', 'taxonomy_term' -- โœ… `external_type` field stores WordPress post type -- โœ… `source` field can be 'wordpress' -- โœ… `sync_metadata` JSONField stores platform-specific data -- โœ… All WordPress post types can be synced - -**Conclusion:** Backend Content model is fully capable of handling all WordPress post types, products, and taxonomy terms. - -## Authentication Flow - -### Plugin โ†’ IGNY8 API -1. User enters API key in plugin settings -2. Plugin calls `$api->connect($api_key)` -3. API key stored securely -4. All requests use `Authorization: Bearer {api_key}` header -5. No token refresh needed (API keys don't expire) - -### IGNY8 API โ†’ Plugin -1. IGNY8 backend makes request with API key -2. Plugin checks `Authorization: Bearer {api_key}` header -3. Plugin verifies key matches stored key -4. Request allowed if key matches - -## Status Endpoint Usage - -**Backend can check plugin status:** -``` -GET /wp-json/igny8/v1/status -``` - -**Returns:** -- `connected`: true if API key exists -- `has_api_key`: true if key configured -- `communication_enabled`: true if toggle ON -- `health`: "healthy" or "not_configured" - -**This matches backend indicator logic:** -- Plugin `connected=true` + `communication_enabled=true` โ†’ App shows ๐ŸŸข Connected -- Plugin `connected=true` + `communication_enabled=false` โ†’ App shows ๐Ÿ”ต Configured -- Plugin `connected=false` โ†’ App shows โšช Not configured - -## Consistency Achieved - -### Both Sides Now Use: -1. โœ… **API key only** - No email/password -2. โœ… **Bearer token auth** - `Authorization: Bearer {api_key}` -3. โœ… **Status endpoint** - `/wp-json/igny8/v1/status` -4. โœ… **Two-level control:** - - API key = Authentication (connect/disconnect) - - Toggle = Communication (enable/disable sync) - -### Status Synchronization: -- โœ… Plugin status endpoint returns same info backend needs -- โœ… Backend indicator checks plugin status endpoint -- โœ… Both show consistent states - -## Files Modified - -1. `/includes/class-igny8-api.php` - API key only auth -2. `/includes/class-igny8-rest-api.php` - Status endpoint + permission updates -3. `/admin/class-admin.php` - API key only connection handler -4. `/igny8-bridge.php` - Removed webhook includes - -## Testing Checklist - -### โœ… Authentication -- [x] API key connects successfully -- [x] API key stored securely -- [x] All API calls use Bearer token -- [x] Revoke API key works - -### โœ… Status Endpoint -- [x] Returns correct connection status -- [x] Returns API key presence -- [x] Returns communication enabled state -- [x] Backend can read plugin status - -### โœ… Bidirectional Sync -- [x] WordPress โ†’ IGNY8 (write) works with API key -- [x] IGNY8 โ†’ WordPress (read) works with API key -- [x] Toggle ON/OFF controls sync correctly -- [x] Content model handles all post types - -## Next Steps - -1. **Test in production:** - - Connect plugin with API key - - Verify status endpoint works - - Test sync operations - - Verify backend indicator shows correct status - -2. **Monitor:** - - Check logs for authentication errors - - Verify sync operations succeed - - Confirm status consistency - -## Status: โœ… COMPLETE -All Phase 3 tasks done. Plugin and backend are now fully consistent! - diff --git a/igny8-wp-plugin/QUICK-FIX-SUMMARY.txt b/igny8-wp-plugin/QUICK-FIX-SUMMARY.txt deleted file mode 100644 index 6aa7b5aa..00000000 --- a/igny8-wp-plugin/QUICK-FIX-SUMMARY.txt +++ /dev/null @@ -1,82 +0,0 @@ -โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• - IGNY8 WORDPRESS BRIDGE - QUICK FIX SUMMARY -โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• - -โœ… ISSUE #1: Security Check Failed - STATUS: FIXED โœ“ - CAUSE: Nested HTML forms (invalid HTML) - FILE: admin/settings.php - ACTION: None needed - refresh page and test - -โœ… ISSUE #2: API Key Not Showing - STATUS: FIXED โœ“ - CAUSE: Placeholder asterisks overwriting real key - FILE: admin/class-admin.php - ACTION: None needed - reload page and verify - -โš ๏ธ ISSUE #3: Test Connection 405 Error - STATUS: IMPROVED (needs backend fix) - CAUSE: API endpoint doesn't exist or doesn't support GET - FILES: includes/class-igny8-api.php, admin/class-admin.php - ACTION: Enable debug mode & share logs with SaaS team - -โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• - ENABLE DEBUG MODE (Add to wp-config.php) -โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• - -define('WP_DEBUG', true); -define('WP_DEBUG_LOG', true); -define('WP_DEBUG_DISPLAY', false); -define('IGNY8_DEBUG', true); - -โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• - VIEW DEBUG LOGS -โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• - -Location: wp-content/debug.log -Search for: "IGNY8 DEBUG GET:" and "IGNY8 DEBUG RESPONSE:" - -โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• - TESTING CHECKLIST -โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• - -[ ] 1. Clear browser cache (Ctrl+Shift+Delete) -[ ] 2. Go to Settings โ†’ IGNY8 API -[ ] 3. Enter credentials and click "Connect to IGNY8" -[ ] 4. Verify success message appears -[ ] 5. Reload page and verify API key shows "********" -[ ] 6. Enable debug mode in wp-config.php -[ ] 7. Click "Test Connection" button -[ ] 8. Check wp-content/debug.log for error details -[ ] 9. Check browser console (F12) for error info -[ ] 10. Share logs with SaaS team - -โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• - ENDPOINTS TESTED (in order) -โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• - -1. /system/ping/ (Primary health check) -2. /planner/keywords/?page_size=1 (Fallback #1) -3. /system/sites/ (Fallback #2) - -If all 3 fail โ†’ Backend API issue (needs SaaS team) - -โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• - SAAS TEAM ACTIONS NEEDED -โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• - -1. Implement GET /system/ping/ endpoint -2. Verify API key has permissions -3. Check if endpoints require POST instead of GET -4. Review server logs for WordPress requests -5. Check WAF/firewall rules - -โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• - MORE INFO -โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• - -See: DEBUG-SETUP.md (Complete debugging guide) -See: FIXES-APPLIED.md (Detailed fix documentation) - -โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• - diff --git a/igny8-wp-plugin/README-SYNC-FIX.md b/igny8-wp-plugin/README-SYNC-FIX.md deleted file mode 100644 index 9e928b00..00000000 --- a/igny8-wp-plugin/README-SYNC-FIX.md +++ /dev/null @@ -1,366 +0,0 @@ -# WordPress Plugin Sync Fix - Complete Documentation - -**Version**: 1.0 -**Date**: November 22, 2025 -**Status**: โœ… Ready for Production - ---- - -## ๐ŸŽฏ Quick Start - -If you just want to understand what was fixed and how to test it: - -1. **Start here**: [`SYNC-FIX-EXECUTIVE-SUMMARY.md`](./SYNC-FIX-EXECUTIVE-SUMMARY.md) - - 5-minute overview of the issue and fix - - Quick test steps - - Success criteria - -2. **Then test**: Run the diagnostic script - ```bash - wp eval-file tests/test-sync-structure.php - ``` - -3. **Deploy**: Follow [`DEPLOYMENT-CHECKLIST.md`](./DEPLOYMENT-CHECKLIST.md) - ---- - -## ๐Ÿ“š Complete Documentation - -### For Different Audiences - -#### ๐Ÿ‘จโ€๐Ÿ’ผ **For Managers/Product** -Read first: [`SYNC-FIX-EXECUTIVE-SUMMARY.md`](./SYNC-FIX-EXECUTIVE-SUMMARY.md) -- What was broken -- What was fixed -- Business impact -- Testing status - -#### ๐Ÿ‘จโ€๐Ÿ’ป **For Developers** -Read in order: -1. [`ISSUES-AND-FIXES.md`](./ISSUES-AND-FIXES.md) - Root cause analysis -2. [`SYNC-FIX-REPORT.md`](./SYNC-FIX-REPORT.md) - Technical details -3. [`SYNC-DATA-FLOW-DIAGRAM.md`](./SYNC-DATA-FLOW-DIAGRAM.md) - Visual flow -4. Code files: - - `includes/functions.php` - Main sync logic - - `admin/class-admin.php` - Connection handling - - `includes/class-igny8-api.php` - API client - -#### ๐Ÿ”ง **For DevOps/System Admins** -Read: [`DEPLOYMENT-CHECKLIST.md`](./DEPLOYMENT-CHECKLIST.md) -- Pre-deployment checks -- Backup procedures -- Deployment steps -- Monitoring checklist -- Rollback procedures - -#### ๐Ÿ› **For Support/QA** -Read: -1. [`SYNC-FIX-EXECUTIVE-SUMMARY.md`](./SYNC-FIX-EXECUTIVE-SUMMARY.md) - Overview -2. [`tests/test-sync-structure.php`](./tests/test-sync-structure.php) - Run tests -3. [`DEPLOYMENT-CHECKLIST.md`](./DEPLOYMENT-CHECKLIST.md) - Troubleshooting section - ---- - -## ๐Ÿ“– Document Descriptions - -### [`SYNC-FIX-EXECUTIVE-SUMMARY.md`](./SYNC-FIX-EXECUTIVE-SUMMARY.md) -**Best for**: Quick understanding -**Length**: ~3 pages -**Contents**: -- What was broken (before/after) -- How to test (5-10 minutes) -- Expected results -- Quick deployment steps - -### [`ISSUES-AND-FIXES.md`](./ISSUES-AND-FIXES.md) -**Best for**: Understanding root causes -**Length**: ~4 pages -**Contents**: -- Each issue with detailed explanation -- Why it matters -- Impact assessment -- The fix applied -- Before/after comparison - -### [`SYNC-FIX-REPORT.md`](./SYNC-FIX-REPORT.md) -**Best for**: Comprehensive technical reference -**Length**: ~10 pages -**Contents**: -- Issues found & fixed -- Data flow after fix -- Testing procedures (detailed) -- Manual API testing -- Troubleshooting guide -- Files modified - -### [`SYNC-DATA-FLOW-DIAGRAM.md`](./SYNC-DATA-FLOW-DIAGRAM.md) -**Best for**: Visual understanding -**Length**: ~3 pages -**Contents**: -- Complete sync journey diagram -- Data structures at each step -- Error handling flow -- Daily cron job flow -- Response format handling - -### [`DEPLOYMENT-CHECKLIST.md`](./DEPLOYMENT-CHECKLIST.md) -**Best for**: Safe deployment -**Length**: ~8 pages -**Contents**: -- Pre-deployment checklist -- Staging deployment steps -- Production deployment -- Monitoring (first 24h) -- Rollback procedures -- Sign-off process - -### [`tests/test-sync-structure.php`](./tests/test-sync-structure.php) -**Best for**: Automated testing -**Purpose**: Run diagnostic tests -**Usage**: -```bash -wp eval-file tests/test-sync-structure.php -``` - ---- - -## ๐Ÿ”— Quick Links by Task - -### "I want to understand what happened" -1. [`SYNC-FIX-EXECUTIVE-SUMMARY.md`](./SYNC-FIX-EXECUTIVE-SUMMARY.md) - Overview -2. [`ISSUES-AND-FIXES.md`](./ISSUES-AND-FIXES.md) - Detailed analysis - -### "I want to test if it works" -1. [`SYNC-FIX-EXECUTIVE-SUMMARY.md#-testing`](./SYNC-FIX-EXECUTIVE-SUMMARY.md) - Quick test -2. [`SYNC-FIX-REPORT.md#-testing-the-fix`](./SYNC-FIX-REPORT.md) - Detailed testing -3. [`tests/test-sync-structure.php`](./tests/test-sync-structure.php) - Automated test - -### "I want to deploy this" -1. [`DEPLOYMENT-CHECKLIST.md#pre-deployment`](./DEPLOYMENT-CHECKLIST.md) - Preparation -2. [`DEPLOYMENT-CHECKLIST.md#staging-deployment`](./DEPLOYMENT-CHECKLIST.md) - Staging -3. [`DEPLOYMENT-CHECKLIST.md#production-deployment`](./DEPLOYMENT-CHECKLIST.md) - Production - -### "Something is broken, how do I fix it?" -1. [`SYNC-FIX-REPORT.md#-troubleshooting`](./SYNC-FIX-REPORT.md) - Common issues -2. Run: `wp eval-file tests/test-sync-structure.php` -3. [`DEPLOYMENT-CHECKLIST.md#rollback-plan`](./DEPLOYMENT-CHECKLIST.md) - Rollback if needed - -### "I want to understand the data flow" -1. [`SYNC-DATA-FLOW-DIAGRAM.md`](./SYNC-DATA-FLOW-DIAGRAM.md) - Visual diagrams -2. [`SYNC-FIX-REPORT.md#-data-flow-complete`](./SYNC-FIX-REPORT.md) - Text description - -### "I want technical details" -1. [`ISSUES-AND-FIXES.md`](./ISSUES-AND-FIXES.md) - Root causes -2. [`SYNC-FIX-REPORT.md#-implementation-details`](./SYNC-FIX-REPORT.md) - Implementation -3. View code files directly - ---- - -## ๐Ÿ“‹ Quick Reference - -### Files Modified -| File | Changes | Impact | -|------|---------|--------| -| `includes/functions.php` | Better sync logic + error handling | Core functionality fixed | -| `admin/class-admin.php` | User feedback on sync status | Better UX | -| `includes/class-igny8-api.php` | Debug logging for POST | Troubleshooting improved | - -### New Files Created -| File | Purpose | Use Case | -|------|---------|----------| -| `tests/test-sync-structure.php` | Diagnostic script | Automated testing | -| `SYNC-FIX-EXECUTIVE-SUMMARY.md` | High-level overview | Executive briefing | -| `ISSUES-AND-FIXES.md` | Root cause analysis | Technical understanding | -| `SYNC-FIX-REPORT.md` | Comprehensive guide | Implementation reference | -| `SYNC-DATA-FLOW-DIAGRAM.md` | Visual diagrams | Understanding flow | -| `DEPLOYMENT-CHECKLIST.md` | Deployment guide | Safe deployment | -| `README-SYNC-FIX.md` | This file | Documentation index | - ---- - -## โœ… Verification Steps - -### Step 1: Code Review -```bash -# View the changes made -git diff includes/functions.php -git diff admin/class-admin.php -git diff includes/class-igny8-api.php -``` - -### Step 2: Functional Testing -```bash -# Run automated diagnostics -wp eval-file tests/test-sync-structure.php -``` - -### Step 3: Log Verification -```bash -# Check debug logs show proper sync -tail -30 wp-content/debug.log | grep IGNY8 -``` - -### Step 4: Frontend Verification -- Go to: WordPress Admin โ†’ Site Settings โ†’ Content Types tab -- Should see: Post Types, Taxonomies, Counts, Last Fetch Time - ---- - -## ๐ŸŽ“ Learning Path - -If you want to understand the entire system: - -1. **Start**: [`SYNC-FIX-EXECUTIVE-SUMMARY.md`](./SYNC-FIX-EXECUTIVE-SUMMARY.md) - - 5 minutes - High-level overview - -2. **Understand the problem**: [`ISSUES-AND-FIXES.md`](./ISSUES-AND-FIXES.md) - - 10 minutes - Root cause analysis - -3. **See the flow**: [`SYNC-DATA-FLOW-DIAGRAM.md`](./SYNC-DATA-FLOW-DIAGRAM.md) - - 10 minutes - Visual understanding - -4. **Learn implementation**: [`SYNC-FIX-REPORT.md`](./SYNC-FIX-REPORT.md) - - 15 minutes - Technical details - -5. **Review code**: Source code files - - 20 minutes - Line-by-line review - -6. **Test it**: Run automated tests - - 5 minutes - Verify working - -7. **Deploy it**: [`DEPLOYMENT-CHECKLIST.md`](./DEPLOYMENT-CHECKLIST.md) - - 30-60 minutes - Full deployment - -**Total Time**: ~1.5-2 hours for complete understanding - ---- - -## ๐Ÿ†˜ Support Resources - -### Quick Answers -| Question | Answer | Doc | -|----------|--------|-----| -| What was broken? | Post type/taxonomy sync | EXECUTIVE-SUMMARY | -| How do I test? | Run test-sync-structure.php | SYNC-FIX-REPORT | -| How do I deploy? | Follow DEPLOYMENT-CHECKLIST | DEPLOYMENT-CHECKLIST | -| What if it fails? | Check TROUBLESHOOTING section | SYNC-FIX-REPORT | -| How do I rollback? | Follow ROLLBACK-PLAN section | DEPLOYMENT-CHECKLIST | - -### Debugging -If something doesn't work: - -1. **Enable debug logging**: - ```php - define('WP_DEBUG', true); - define('WP_DEBUG_LOG', true); - define('IGNY8_DEBUG', true); - ``` - -2. **Check logs**: - ```bash - tail -100 wp-content/debug.log | grep IGNY8 - ``` - -3. **Run tests**: - ```bash - wp eval-file tests/test-sync-structure.php - ``` - -4. **Check backend**: - ```python - docker exec igny8_backend python manage.py shell - from igny8_core.business.integration.models import SiteIntegration - si = SiteIntegration.objects.filter(platform='wordpress').first() - print(si.config_json.get('content_types')) - ``` - -5. **Consult troubleshooting**: - See [`SYNC-FIX-REPORT.md#-troubleshooting`](./SYNC-FIX-REPORT.md) - ---- - -## ๐Ÿ“Š Status Dashboard - -| Component | Before | After | Status | -|-----------|--------|-------|--------| -| Plugin Connection | โœ… Works | โœ… Works | No change | -| Structure Sync | โŒ Fails | โœ… Works | **FIXED** | -| Error Logging | โŒ Missing | โœ… Complete | **FIXED** | -| User Feedback | โŒ None | โœ… Clear | **FIXED** | -| Frontend Display | โŒ Empty | โœ… Shows data | **FIXED** | -| Debug Info | โŒ Limited | โœ… Detailed | **FIXED** | - ---- - -## ๐Ÿš€ Next Steps - -### Immediate (Today) -- [ ] Review documentation -- [ ] Run automated tests -- [ ] Verify code changes - -### Short-term (This week) -- [ ] Stage deployment -- [ ] QA testing -- [ ] Get sign-offs - -### Medium-term (This month) -- [ ] Production deployment -- [ ] Monitor results -- [ ] Gather feedback - -### Long-term (Next quarter) -- [ ] Enhancement ideas -- [ ] Performance optimization -- [ ] Additional features - ---- - -## ๐Ÿ“ž Getting Help - -### Documentation -- ๐Ÿ“– Complete docs: Read the files listed above -- ๐Ÿ” Searching: All docs are plain markdown (.md files) -- ๐ŸŽฏ Quick reference: This file (README-SYNC-FIX.md) - -### Automated Help -- ๐Ÿงช Testing: `wp eval-file tests/test-sync-structure.php` -- ๐Ÿ“‹ Logs: `tail wp-content/debug.log | grep IGNY8` -- ๐Ÿ”ง Debugging: Enable `IGNY8_DEBUG` in wp-config.php - -### Manual Help -- ๐Ÿ“ง Contact: [Your support email] -- ๐Ÿ’ฌ Chat: [Your chat channel] -- ๐Ÿ“ž Call: [Your phone number] - ---- - -## ๐Ÿ“œ Version History - -| Version | Date | Changes | -|---------|------|---------| -| 1.0 | Nov 22, 2025 | Initial release | -| | | - Fixed structure sync | -| | | - Enhanced debug logging | -| | | - Added user feedback | -| | | - Comprehensive documentation | - ---- - -## โœจ Thank You - -This fix was made possible by: -- Careful analysis of the integration flow -- Comprehensive debugging -- Robust error handling -- Clear documentation -- Automated testing - -Thank you for using the IGNY8 WordPress integration! - ---- - -**Last Updated**: November 22, 2025 -**Status**: โœ… Production Ready -**Questions?** See the documentation files above or contact support. - diff --git a/igny8-wp-plugin/README.md b/igny8-wp-plugin/README.md deleted file mode 100644 index fa7604b8..00000000 --- a/igny8-wp-plugin/README.md +++ /dev/null @@ -1,396 +0,0 @@ -# IGNY8 WordPress Bridge Plugin - -**Version**: 1.0.0 -**Last Updated**: 2025-10-17 -**Requires**: WordPress 5.0+, PHP 7.4+ - ---- - -## Overview - -The IGNY8 WordPress Bridge Plugin is a **lightweight synchronization interface** that connects WordPress sites to the IGNY8 API. This plugin acts as a bridge, not a content management system, using WordPress native structures (taxonomies, post meta) to sync data bidirectionally with IGNY8. - -### Key Principles - -- โœ… **No Custom Database Tables** - Uses WordPress native taxonomies and post meta -- โœ… **Lightweight Bridge** - Minimal code, maximum efficiency -- โœ… **Two-Way Sync** - WordPress โ†” IGNY8 API synchronization -- โœ… **WordPress Native** - Leverages existing WordPress structures -- โœ… **API-First** - IGNY8 API is the source of truth - ---- - -## Features - -### Core Functionality - -1. **API Authentication** - - Secure token management - - Automatic token refresh - - Encrypted credential storage - -2. **Two-Way Synchronization** - - WordPress โ†’ IGNY8: Post status changes sync to IGNY8 tasks - - IGNY8 โ†’ WordPress: Content published from IGNY8 creates WordPress posts - -3. **Taxonomy Mapping** - - WordPress taxonomies โ†’ IGNY8 Sectors/Clusters - - Hierarchical taxonomies map to IGNY8 Sectors - - Taxonomy terms map to IGNY8 Clusters - -4. **Post Meta Integration** - - `_igny8_task_id` - Links WordPress posts to IGNY8 tasks - - `_igny8_cluster_id` - Links posts to IGNY8 clusters - - `_igny8_sector_id` - Links posts to IGNY8 sectors - - `_igny8_keyword_ids` - Links posts to IGNY8 keywords - -5. **Site Data Collection** - - Automatic collection of WordPress posts, taxonomies, products - - Semantic mapping to IGNY8 structure - - WooCommerce integration support - -6. **Status Mapping** - - WordPress post status โ†’ IGNY8 task status - - Automatic sync on post save/publish/status change - ---- - -## Installation - -### Requirements - -- WordPress 5.0 or higher -- PHP 7.4 or higher -- WordPress REST API enabled -- IGNY8 API account credentials - -### Installation Steps - -1. **Download/Clone Plugin** - ```bash - git clone [repository-url] - cd igny8-ai-os - ``` - -2. **Install in WordPress** - - Copy the `igny8-ai-os` folder to `/wp-content/plugins/` - - Or create a symlink for development - -3. **Activate Plugin** - - Go to WordPress Admin โ†’ Plugins - - Activate "IGNY8 WordPress Bridge" - -4. **Configure API Connection** - - Go to Settings โ†’ IGNY8 API - - Enter your IGNY8 email and password - - Click "Connect to IGNY8" - ---- - -## Configuration - -### API Settings - -Navigate to **Settings โ†’ IGNY8 API** to configure: - -- **Email**: Your IGNY8 account email -- **Password**: Your IGNY8 account password -- **Site ID**: Your IGNY8 site ID (auto-detected after connection) - -### WordPress Integration - -The plugin automatically: - -1. **Registers Taxonomies** (if needed): - - `sectors` - Maps to IGNY8 Sectors - - `clusters` - Maps to IGNY8 Clusters - -2. **Registers Post Meta Fields**: - - `_igny8_task_id` - - `_igny8_cluster_id` - - `_igny8_sector_id` - - `_igny8_keyword_ids` - - `_igny8_content_id` - -3. **Sets Up WordPress Hooks**: - - `save_post` - Syncs post changes to IGNY8 - - `publish_post` - Updates keywords on publish - - `transition_post_status` - Handles status changes - ---- - -## Usage - -### Basic Workflow - -#### 1. Connect to IGNY8 API - -```php -// Automatically handled via Settings page -// Or programmatically: -$api = new Igny8API(); -$api->login('your@email.com', 'password'); -``` - -#### 2. Sync WordPress Site Data - -```php -// Collect and send site data to IGNY8 -$site_id = get_option('igny8_site_id'); -igny8_send_site_data_to_igny8($site_id); -``` - -#### 3. WordPress โ†’ IGNY8 Sync - -When you save/publish a WordPress post: - -1. Plugin checks for `_igny8_task_id` in post meta -2. If found, syncs post status to IGNY8 task -3. If published, updates related keywords to 'mapped' status - -#### 4. IGNY8 โ†’ WordPress Sync - -When content is published from IGNY8: - -1. IGNY8 triggers webhook (or scheduled sync) -2. Plugin creates WordPress post via `wp_insert_post()` -3. Post meta saved with `_igny8_task_id` -4. IGNY8 task updated with WordPress post ID - ---- - -## WordPress Structures Used - -### Taxonomies - -- **`sectors`** (hierarchical) - - Maps to IGNY8 Sectors - - Can be created manually or synced from IGNY8 - -- **`clusters`** (hierarchical) - - Maps to IGNY8 Clusters - - Can be created manually or synced from IGNY8 - -- **Native Taxonomies** - - `category` - Can map to IGNY8 Sectors - - `post_tag` - Can be used for keyword extraction - -### Post Meta Fields - -All stored in WordPress `wp_postmeta` table: - -- `_igny8_task_id` (integer) - IGNY8 task ID -- `_igny8_cluster_id` (integer) - IGNY8 cluster ID -- `_igny8_sector_id` (integer) - IGNY8 sector ID -- `_igny8_keyword_ids` (array) - Array of IGNY8 keyword IDs -- `_igny8_content_id` (integer) - IGNY8 content ID -- `_igny8_last_synced` (datetime) - Last sync timestamp - -### Post Status Mapping - -| WordPress Status | IGNY8 Task Status | -|------------------|-------------------| -| `publish` | `completed` | -| `draft` | `draft` | -| `pending` | `pending` | -| `private` | `completed` | -| `trash` | `archived` | -| `future` | `scheduled` | - ---- - -## API Reference - -### Main Classes - -#### `Igny8API` - -Main API client class for all IGNY8 API interactions. - -```php -$api = new Igny8API(); - -// Login -$api->login('email@example.com', 'password'); - -// Get keywords -$response = $api->get('/planner/keywords/'); - -// Create task -$response = $api->post('/writer/tasks/', $data); - -// Update task -$response = $api->put('/writer/tasks/123/', $data); -``` - -#### `Igny8WordPressSync` - -Handles two-way synchronization between WordPress and IGNY8. - -```php -$sync = new Igny8WordPressSync(); -// Automatically hooks into WordPress post actions -``` - -#### `Igny8SiteIntegration` - -Manages site data collection and semantic mapping. - -```php -$integration = new Igny8SiteIntegration($site_id); -$result = $integration->full_site_scan(); -``` - -### Main Functions - -- `igny8_login($email, $password)` - Authenticate with IGNY8 -- `igny8_sync_post_status_to_igny8($post_id, $post, $update)` - Sync post to IGNY8 -- `igny8_collect_site_data()` - Collect all WordPress site data -- `igny8_send_site_data_to_igny8($site_id)` - Send site data to IGNY8 -- `igny8_map_site_to_semantic_strategy($site_id, $site_data)` - Map to semantic structure - -### Site Metadata Endpoint (Plugin) - -The plugin exposes a discovery endpoint that your IGNY8 app can call to learn which WordPress post types and taxonomies exist and how many items each contains. - -- Endpoint: `GET /wp-json/igny8/v1/site-metadata/` -- Auth: Plugin-level connection must be enabled and authenticated (plugin accepts stored API key or access token) -- Response: IGNY8 unified response format (`success`, `data`, `message`, `request_id`) - -Example response: - -```json -{ - "success": true, - "data": { - "post_types": { - "post": { "label": "Posts", "count": 123 }, - "page": { "label": "Pages", "count": 12 } - }, - "taxonomies": { - "category": { "label": "Categories", "count": 25 }, - "post_tag": { "label": "Tags", "count": 102 } - }, - "generated_at": 1700553600 - }, - "message": "Site metadata retrieved", - "request_id": "550e8400-e29b-41d4-a716-446655440000" -} -``` - ---- - -## File Structure - -``` -igny8-ai-os/ -โ”œโ”€โ”€ igny8-bridge.php # Main plugin file -โ”œโ”€โ”€ README.md # This file -โ”œโ”€โ”€ docs/ # Documentation hub -โ”‚ โ”œโ”€โ”€ README.md # Index of available docs -โ”‚ โ”œโ”€โ”€ WORDPRESS-PLUGIN-INTEGRATION.md -โ”‚ โ”œโ”€โ”€ wp-bridge-implementation-plan.md -โ”‚ โ”œโ”€โ”€ missing-saas-api-endpoints.md -โ”‚ โ”œโ”€โ”€ STATUS_SYNC_DOCUMENTATION.md -โ”‚ โ””โ”€โ”€ STYLE_GUIDE.md -โ”œโ”€โ”€ includes/ -โ”‚ โ”œโ”€โ”€ class-igny8-api.php # API client class -โ”‚ โ”œโ”€โ”€ class-igny8-sync.php # Sync handler class -โ”‚ โ”œโ”€โ”€ class-igny8-site.php # Site integration class -โ”‚ โ””โ”€โ”€ functions.php # Helper functions -โ”œโ”€โ”€ admin/ -โ”‚ โ”œโ”€โ”€ class-admin.php # Admin interface -โ”‚ โ”œโ”€โ”€ settings.php # Settings page -โ”‚ โ””โ”€โ”€ assets/ -โ”‚ โ”œโ”€โ”€ css/ -โ”‚ โ””โ”€โ”€ js/ -โ”œโ”€โ”€ sync/ -โ”‚ โ”œโ”€โ”€ hooks.php # WordPress hooks -โ”‚ โ”œโ”€โ”€ post-sync.php # Post synchronization -โ”‚ โ””โ”€โ”€ taxonomy-sync.php # Taxonomy synchronization -โ”œโ”€โ”€ data/ -โ”‚ โ”œโ”€โ”€ site-collection.php # Site data collection -โ”‚ โ””โ”€โ”€ semantic-mapping.php # Semantic mapping -โ””โ”€โ”€ uninstall.php # Uninstall handler -``` - ---- - -## Development - -### Code Standards - -- Follow WordPress Coding Standards -- Use WordPress native functions -- No custom database tables -- All data in WordPress native structures - -### Testing - -```bash -# Run WordPress unit tests -phpunit - -# Test API connection -wp eval 'var_dump((new Igny8API())->login("test@example.com", "password"));' -``` - ---- - -## Troubleshooting - -### Authentication Issues - -**Problem**: Cannot connect to IGNY8 API - -**Solutions**: -1. Verify email and password are correct -2. Check API endpoint is accessible -3. Check WordPress REST API is enabled -4. Review error logs in WordPress debug log - -### Sync Issues - -**Problem**: Posts not syncing to IGNY8 - -**Solutions**: -1. Verify `_igny8_task_id` exists in post meta -2. Check API token is valid (not expired) -3. Review WordPress hooks are firing -4. Check error logs - -### Token Expiration - -**Problem**: Token expires frequently - -**Solution**: Plugin automatically refreshes tokens. If issues persist, check token refresh logic. - ---- - -## Support - -- **Documentation**: See `WORDPRESS-PLUGIN-INTEGRATION.md` -- **API Documentation**: https://api.igny8.com/docs -- **Issues**: [GitHub Issues](repository-url/issues) - ---- - -## License - -[Your License Here] - ---- - -## Changelog - -### 1.0.0 - 2025-10-17 -- Initial release -- API authentication -- Two-way sync -- Site data collection -- Semantic mapping - ---- - -**Last Updated**: 2025-10-17 - diff --git a/igny8-wp-plugin/SOLUTION-SUMMARY.txt b/igny8-wp-plugin/SOLUTION-SUMMARY.txt deleted file mode 100644 index 9a729b5f..00000000 --- a/igny8-wp-plugin/SOLUTION-SUMMARY.txt +++ /dev/null @@ -1,332 +0,0 @@ -================================================================================ -WORDPRESS PLUGIN & IGNY8 INTEGRATION - SYNC FIX COMPLETE -================================================================================ - -Date: November 22, 2025 -Status: โœ… READY FOR DEPLOYMENT -Risk Level: ๐ŸŸข LOW (Non-breaking changes) - -================================================================================ -EXECUTIVE SUMMARY -================================================================================ - -PROBLEM: --------- -The WordPress plugin connection to IGNY8 was working, but the initial sync -and fetching of post types and taxonomy counts was NOT working correctly. -Result: Content Types tab remained empty, users couldn't see their site structure. - -ROOT CAUSES: ------------- -1. Integration response handling didn't support multiple API response formats -2. No debug logging for POST requests (only GET was logged) -3. User had no feedback about whether structure sync succeeded -4. Missing metadata (WordPress version, site URL) in sync data - -SOLUTION: ---------- -4 files modified with comprehensive fixes: -1. includes/functions.php - Better sync logic + response handling -2. admin/class-admin.php - User feedback messages added -3. includes/class-igny8-api.php - Debug logging for POST requests -4. tests/test-sync-structure.php - Automated diagnostic test (NEW) - -RESULT: -------- -โœ… Structure sync now works reliably -โœ… Users get clear feedback about status -โœ… Debug logs show exactly what's happening -โœ… Frontend Content Types tab displays correctly -โœ… All changes are backward compatible - -================================================================================ -FILES MODIFIED -================================================================================ - -1. includes/functions.php (MAIN FIX) - - Enhanced igny8_sync_site_structure_to_backend() function - - Handles multiple API response formats - - Added platform filter for integration query - - Improved error logging with full context - - Added WordPress version and site URL to structure data - - Added igny8_structure_synced flag tracking - -2. admin/class-admin.php (UX IMPROVEMENT) - - Added user feedback messages for structure sync status - - Shows success or failure (with guidance to check logs) - - Non-blocking approach maintained - -3. includes/class-igny8-api.php (DEBUG IMPROVEMENT) - - Added full debug logging for POST requests - - Logs request URL, payload, and response - - Respects WP_DEBUG and IGNY8_DEBUG constants - - Maintains security (authorization header masked) - -4. tests/test-sync-structure.php (NEW TEST FILE) - - Automated diagnostic test - - Checks all steps of sync process - - Provides clear pass/fail for each step - - Run with: wp eval-file tests/test-sync-structure.php - -================================================================================ -DOCUMENTATION CREATED -================================================================================ - -New comprehensive documentation suite: - -1. README-SYNC-FIX.md - - Documentation index and quick reference - - Links to all other docs - - Quick start guide - - Support resources - -2. SYNC-FIX-EXECUTIVE-SUMMARY.md - - High-level overview (3 pages) - - What was broken, what was fixed - - Quick test steps (5-10 minutes) - - Deployment overview - - For: Managers, Product, Decision-makers - -3. ISSUES-AND-FIXES.md - - Detailed root cause analysis (4 pages) - - Each issue with explanation - - Why it matters - - The fix applied - - Before/after comparison - - For: Developers, Architects - -4. SYNC-FIX-REPORT.md - - Comprehensive technical reference (10 pages) - - Implementation details - - Data flow explanation - - Testing procedures (detailed) - - Manual API testing examples - - Troubleshooting guide - - For: Developers, Support - -5. SYNC-DATA-FLOW-DIAGRAM.md - - Visual ASCII flow diagrams (3 pages) - - Complete sync journey with data structures - - Error handling flow - - Daily cron job flow - - For: Visual learners, Architects - -6. DEPLOYMENT-CHECKLIST.md - - Complete deployment guide (8 pages) - - Pre-deployment checks - - Backup procedures - - Staging deployment - - Production deployment - - Monitoring checklist - - Rollback procedures - - Sign-off template - - For: DevOps, System Admins - -7. ISSUES-AND-FIXES.md - - Complete issue analysis - - Root cause for each problem - - Fix explanation - - Verification steps - - For: Technical teams - -================================================================================ -TESTING -================================================================================ - -Quick Test (5 minutes): ------------------------ -1. Connect WordPress plugin (WordPress Admin โ†’ Settings โ†’ IGNY8 API) -2. Check for success message about structure sync -3. Navigate to Site Settings โ†’ Content Types tab -4. Verify post types and taxonomies are visible - -Automated Test: ---------------- -wp eval-file tests/test-sync-structure.php -- Runs 6 automated tests -- Shows each step result -- Takes about 1 minute - -Detailed Test: --------------- -Follow SYNC-FIX-REPORT.md testing section for comprehensive testing - -Debug Verification: -------------------- -tail -30 wp-content/debug.log | grep IGNY8 -Should see: "Site structure synced successfully" - -Backend Verification: --------------------- -docker exec ighty8_backend python manage.py shell -> from igny8_core.business.integration.models import SiteIntegration -> si = SiteIntegration.objects.filter(platform='wordpress').first() -> print(si.config_json.get('content_types', {}).keys()) -Should show: dict_keys(['post_types', 'taxonomies', 'last_structure_fetch']) - -================================================================================ -DEPLOYMENT STEPS -================================================================================ - -Pre-Deployment: -- [ ] Backup WordPress database -- [ ] Backup IGNY8 backend database -- [ ] Test in staging environment -- [ ] Run all tests and verify passing -- [ ] Get QA sign-off - -Deployment: -- [ ] Copy modified files to production -- [ ] Verify plugin still active -- [ ] Check no PHP errors -- [ ] Run smoke tests - -Post-Deployment: -- [ ] Monitor logs (first hour) -- [ ] Test new connections -- [ ] Verify Content Types tab displays -- [ ] Check daily cron runs -- [ ] Gather user feedback - -See DEPLOYMENT-CHECKLIST.md for complete details - -================================================================================ -SUCCESS CRITERIA -================================================================================ - -โœ… Content Types tab shows post types and taxonomies (not empty) -โœ… Counts are accurate and display correctly -โœ… "Structure last fetched" timestamp is recent -โœ… Debug logs show "Site structure synced successfully" -โœ… Backend stores content_types in config_json -โœ… User gets feedback message about sync status -โœ… No PHP errors in debug log -โœ… Daily cron job runs automatically -โœ… Multiple sites work correctly -โœ… No performance degradation - -================================================================================ -KEY IMPROVEMENTS -================================================================================ - -Before Fix: ------------ -โŒ Content Types tab empty -โŒ No post types visible -โŒ No taxonomies visible -โŒ No debug information -โŒ User confused about status -โŒ Sync silently failed - -After Fix: ----------- -โœ… Content Types tab populated -โœ… All post types visible -โœ… All taxonomies visible -โœ… Full debug logging -โœ… Clear user feedback -โœ… Sync status trackable -โœ… Easy troubleshooting - -================================================================================ -BACKWARD COMPATIBILITY -================================================================================ - -โœ… ALL CHANGES ARE BACKWARD COMPATIBLE -โœ… No breaking changes -โœ… Existing connections continue to work -โœ… Existing data not affected -โœ… Plugin can be rolled back if needed -โœ… Database structure unchanged - -Risk Level: ๐ŸŸข LOW - -================================================================================ -DEPLOYMENT RECOMMENDATION -================================================================================ - -STATUS: โœ… READY FOR PRODUCTION - -Recommendation: DEPLOY IMMEDIATELY -- Low risk (non-breaking, backward compatible) -- High benefit (fixes broken functionality) -- Extensive testing provided -- Complete documentation provided -- Easy to rollback if needed - -Deployment Window: Any time (no downtime required) - -================================================================================ -NEXT STEPS -================================================================================ - -Immediate (Today): -1. Review this summary -2. Run automated tests -3. Review documentation - -Short-term (This week): -1. Deploy to staging -2. QA testing -3. Deploy to production - -Ongoing: -1. Monitor logs (first 24 hours) -2. Gather user feedback -3. Document any issues found -4. Plan future enhancements - -================================================================================ -DOCUMENTATION LOCATION -================================================================================ - -All documentation is in: -/igny8-wp-integration/ - -Main files: -- README-SYNC-FIX.md (START HERE) -- SYNC-FIX-EXECUTIVE-SUMMARY.md (Overview) -- ISSUES-AND-FIXES.md (Root cause analysis) -- SYNC-FIX-REPORT.md (Technical details) -- DEPLOYMENT-CHECKLIST.md (Deployment guide) - -Source code changes: -- includes/functions.php -- admin/class-admin.php -- includes/class-igny8-api.php - -Tests: -- tests/test-sync-structure.php - -================================================================================ -QUESTIONS & SUPPORT -================================================================================ - -For detailed information, see: -- README-SYNC-FIX.md - Documentation index -- SYNC-FIX-EXECUTIVE-SUMMARY.md - Quick overview -- DEPLOYMENT-CHECKLIST.md - Deployment guide - -To verify working: -- Run: wp eval-file tests/test-sync-structure.php -- Check: wp-content/debug.log -- View: Site Settings โ†’ Content Types tab - -================================================================================ -COMPLETION STATUS -================================================================================ - -โœ… Issue identified and analyzed -โœ… Root causes determined -โœ… Fixes implemented -โœ… Code tested -โœ… Documentation written -โœ… Deployment procedures documented -โœ… Rollback procedures documented -โœ… Automated tests created -โœ… Ready for production - -STATUS: ๐ŸŸข COMPLETE - READY FOR DEPLOYMENT - -================================================================================ - diff --git a/igny8-wp-plugin/SYNC-DATA-FLOW-DIAGRAM.md b/igny8-wp-plugin/SYNC-DATA-FLOW-DIAGRAM.md deleted file mode 100644 index 1bf0a778..00000000 --- a/igny8-wp-plugin/SYNC-DATA-FLOW-DIAGRAM.md +++ /dev/null @@ -1,356 +0,0 @@ -# WordPress Plugin โ†” IGNY8 Backend Sync - Data Flow Diagram - -## Complete Sync Journey - -``` -โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” -โ”‚ WORDPRESS ADMIN - Connection Setup โ”‚ -โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค -โ”‚ โ”‚ -โ”‚ User Input: โ”‚ -โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ -โ”‚ โ”‚ Email: dev@igny8.com โ”‚ โ”‚ -โ”‚ โ”‚ Password: **** โ”‚ โ”‚ -โ”‚ โ”‚ API Key: **** โ”‚ โ”‚ -โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ -โ”‚ โ”‚ -โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ - โ†“ -โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” -โ”‚ WORDPRESS PLUGIN - Authentication (class-admin.php handle_connection()) โ”‚ -โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค -โ”‚ โ”‚ -โ”‚ 1. POST /auth/login/ (with email + password) โ”‚ -โ”‚ โ†“ โ”‚ -โ”‚ 2. Store: access_token, refresh_token โ”‚ -โ”‚ โ†“ โ”‚ -โ”‚ 3. GET /system/sites/ (authenticated) โ”‚ -โ”‚ โ†“ โ”‚ -โ”‚ 4. Store: site_id (extracted from first site) โ”‚ -โ”‚ โ†“ โ”‚ -โ”‚ โœ… Connection complete! User sees success message โ”‚ -โ”‚ โ”‚ -โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ - โ†“ -โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” -โ”‚ WORDPRESS PLUGIN - Gather Site Structure (igny8_sync_site_structure_to_backend) -โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค -โ”‚ โ”‚ -โ”‚ Step 1: Query for Integration ID โ”‚ -โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ -โ”‚ โ”‚ GET /v1/integration/integrations/ โ”‚ โ”‚ -โ”‚ โ”‚ ?site={site_id} โ”‚ โ”‚ -โ”‚ โ”‚ &platform=wordpress โ† NEW: Platform filter โ”‚ โ”‚ -โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ -โ”‚ โ†“ โ”‚ -โ”‚ Step 2: Extract Integration ID (handle multiple response formats) โ”‚ -โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ -โ”‚ โ”‚ Response Format Handling: โ”‚ โ”‚ -โ”‚ โ”‚ โ€ข Paginated: data.results[0] โ† Django REST Framework โ”‚ โ”‚ -โ”‚ โ”‚ โ€ข Array: data[0] โ† Alternative format โ”‚ โ”‚ -โ”‚ โ”‚ โ€ข Object: data โ† Direct single object โ”‚ โ”‚ -โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ -โ”‚ โ†“ โ”‚ -โ”‚ Step 3: Gather WordPress Content Structure โ”‚ -โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ -โ”‚ โ”‚ Post Types (igny8_get_site_structure): โ”‚ โ”‚ -โ”‚ โ”‚ โ”œโ”€ post โ†’ "Posts" (count: 50) โ”‚ โ”‚ -โ”‚ โ”‚ โ”œโ”€ page โ†’ "Pages" (count: 10) โ”‚ โ”‚ -โ”‚ โ”‚ โ””โ”€ product โ†’ "Products" (count: 100) โ”‚ โ”‚ -โ”‚ โ”‚ โ”‚ โ”‚ -โ”‚ โ”‚ Taxonomies: โ”‚ โ”‚ -โ”‚ โ”‚ โ”œโ”€ category โ†’ "Categories" (count: 12) โ”‚ โ”‚ -โ”‚ โ”‚ โ”œโ”€ post_tag โ†’ "Tags" (count: 89) โ”‚ โ”‚ -โ”‚ โ”‚ โ””โ”€ product_cat โ†’ "Product Categories" (count: 15) โ”‚ โ”‚ -โ”‚ โ”‚ โ”‚ โ”‚ -โ”‚ โ”‚ Metadata: โ”‚ โ”‚ -โ”‚ โ”‚ โ”œโ”€ timestamp (ISO 8601 format) โ† NEW โ”‚ โ”‚ -โ”‚ โ”‚ โ”œโ”€ site_url (WordPress domain) โ† NEW โ”‚ โ”‚ -โ”‚ โ”‚ โ””โ”€ wordpress_version (e.g., 6.4) โ† NEW โ”‚ โ”‚ -โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ -โ”‚ โ”‚ -โ”‚ With Enhanced Debug Logging (if WP_DEBUG or IGNY8_DEBUG enabled): โ”‚ -โ”‚ โ€ข Log: Integration ID retrieved โ”‚ -โ”‚ โ€ข Log: Structure gathered successfully โ”‚ -โ”‚ โ€ข Log: Ready to sync โ”‚ -โ”‚ โ”‚ -โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ - โ†“ -โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” -โ”‚ WORDPRESS โ†’ IGNY8 BACKEND - Push Structure (class-igny8-api.php post()) โ”‚ -โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค -โ”‚ โ”‚ -โ”‚ POST /v1/integration/integrations/{integration_id}/update-structure/ โ”‚ -โ”‚ โ”‚ -โ”‚ Headers: โ”‚ -โ”‚ โ”œโ”€ Authorization: Bearer {access_token} โ”‚ -โ”‚ โ””โ”€ Content-Type: application/json โ”‚ -โ”‚ โ”‚ -โ”‚ Request Body: โ”‚ -โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ -โ”‚ โ”‚ { โ”‚ โ”‚ -โ”‚ โ”‚ "post_types": { โ”‚ โ”‚ -โ”‚ โ”‚ "post": { โ”‚ โ”‚ -โ”‚ โ”‚ "label": "Posts", โ”‚ โ”‚ -โ”‚ โ”‚ "count": 50, โ”‚ โ”‚ -โ”‚ โ”‚ "enabled": true, โ”‚ โ”‚ -โ”‚ โ”‚ "fetch_limit": 100 โ”‚ โ”‚ -โ”‚ โ”‚ }, โ”‚ โ”‚ -โ”‚ โ”‚ "page": {...}, โ”‚ โ”‚ -โ”‚ โ”‚ "product": {...} โ”‚ โ”‚ -โ”‚ โ”‚ }, โ”‚ โ”‚ -โ”‚ โ”‚ "taxonomies": { โ”‚ โ”‚ -โ”‚ โ”‚ "category": { โ”‚ โ”‚ -โ”‚ โ”‚ "label": "Categories", โ”‚ โ”‚ -โ”‚ โ”‚ "count": 12, โ”‚ โ”‚ -โ”‚ โ”‚ "enabled": true, โ”‚ โ”‚ -โ”‚ โ”‚ "fetch_limit": 100 โ”‚ โ”‚ -โ”‚ โ”‚ }, โ”‚ โ”‚ -โ”‚ โ”‚ "post_tag": {...}, โ”‚ โ”‚ -โ”‚ โ”‚ "product_cat": {...} โ”‚ โ”‚ -โ”‚ โ”‚ }, โ”‚ โ”‚ -โ”‚ โ”‚ "timestamp": "2025-11-22T10:15:30+00:00", โ”‚ โ”‚ -โ”‚ โ”‚ "plugin_connection_enabled": true, โ”‚ โ”‚ -โ”‚ โ”‚ "two_way_sync_enabled": true โ”‚ โ”‚ -โ”‚ โ”‚ } โ”‚ โ”‚ -โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ -โ”‚ โ”‚ -โ”‚ Debug Logging (NEW - Post Request Logging): โ”‚ -โ”‚ โ”œโ”€ Log: Request URL โ”‚ -โ”‚ โ”œโ”€ Log: Request payload (sanitized) โ”‚ -โ”‚ โ”œโ”€ Log: Response status code โ”‚ -โ”‚ โ”œโ”€ Log: Response body (first 500 chars) โ”‚ -โ”‚ โ””โ”€ Log: Success/error with integration ID โ”‚ -โ”‚ โ”‚ -โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ - โ†“ -โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” -โ”‚ IGNY8 BACKEND - Store Structure (modules/integration/views.py โ”‚ -โ”‚ update_site_structure action) โ”‚ -โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค -โ”‚ โ”‚ -โ”‚ 1. Authenticate request โ”‚ -โ”‚ โ”œโ”€ Check Bearer token โ”‚ -โ”‚ โ””โ”€ Verify user owns this integration โ”‚ -โ”‚ โ”‚ -โ”‚ 2. Extract payload โ”‚ -โ”‚ โ”œโ”€ post_types โ”‚ -โ”‚ โ”œโ”€ taxonomies โ”‚ -โ”‚ โ”œโ”€ timestamp (optional, defaults to now) โ”‚ -โ”‚ โ”œโ”€ plugin_connection_enabled โ”‚ -โ”‚ โ””โ”€ two_way_sync_enabled โ”‚ -โ”‚ โ”‚ -โ”‚ 3. Store in SiteIntegration.config_json โ”‚ -โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ -โ”‚ โ”‚ config_json = { โ”‚ โ”‚ -โ”‚ โ”‚ "content_types": { โ”‚ โ”‚ -โ”‚ โ”‚ "post_types": {...}, โ”‚ โ”‚ -โ”‚ โ”‚ "taxonomies": {...}, โ”‚ โ”‚ -โ”‚ โ”‚ "last_structure_fetch": "2025-11-22T10:15:30+00:00" โ”‚ โ”‚ -โ”‚ โ”‚ }, โ”‚ โ”‚ -โ”‚ โ”‚ "plugin_connection_enabled": true, โ”‚ โ”‚ -โ”‚ โ”‚ "two_way_sync_enabled": true, โ”‚ โ”‚ -โ”‚ โ”‚ ... other config fields ... โ”‚ โ”‚ -โ”‚ โ”‚ } โ”‚ โ”‚ -โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ -โ”‚ โ”‚ -โ”‚ 4. Return Success Response โ”‚ -โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ -โ”‚ โ”‚ { โ”‚ โ”‚ -โ”‚ โ”‚ "success": true, โ”‚ โ”‚ -โ”‚ โ”‚ "data": { โ”‚ โ”‚ -โ”‚ โ”‚ "message": "Site structure updated successfully", โ”‚ โ”‚ -โ”‚ โ”‚ "post_types_count": 3, โ”‚ โ”‚ -โ”‚ โ”‚ "taxonomies_count": 3, โ”‚ โ”‚ -โ”‚ โ”‚ "last_structure_fetch": "2025-11-22T10:15:30+00:00" โ”‚ โ”‚ -โ”‚ โ”‚ } โ”‚ โ”‚ -โ”‚ โ”‚ } โ”‚ โ”‚ -โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ -โ”‚ โ”‚ -โ”‚ 5. Database save โ”‚ -โ”‚ โ””โ”€ SiteIntegration record updated โ”‚ -โ”‚ โ”‚ -โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ - โ†“ -โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” -โ”‚ WORDPRESS PLUGIN - Confirm Success & Update Options โ”‚ -โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค -โ”‚ โ”‚ -โ”‚ 1. Response Received (success == true) โ”‚ -โ”‚ โ”œโ”€ Show success message to user โ”‚ -โ”‚ โ”œโ”€ Log: "Site structure synced successfully" โ”‚ -โ”‚ โ””โ”€ Update option: igny8_last_structure_sync = timestamp โ”‚ -โ”‚ โ”‚ -โ”‚ 2. New Options Created: โ”‚ -โ”‚ โ”œโ”€ igny8_structure_synced = 1 (flag for status checking) โ”‚ -โ”‚ โ””โ”€ igny8_last_structure_sync = unix timestamp โ”‚ -โ”‚ โ”‚ -โ”‚ 3. User Feedback: โ”‚ -โ”‚ โ”œโ”€ "Successfully connected to IGNY8 API" โ”‚ -โ”‚ โ”œโ”€ "Site structure synced successfully" โ† NEW MESSAGE โ”‚ -โ”‚ โ””โ”€ Or: "Connected but structure sync will be retried" (non-blocking) โ”‚ -โ”‚ โ”‚ -โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ - โ†“ -โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” -โ”‚ IGNY8 FRONTEND - Fetch & Display Content Types โ”‚ -โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค -โ”‚ โ”‚ -โ”‚ 1. User navigates to Site Settings โ†’ Content Types Tab โ”‚ -โ”‚ โ”‚ -โ”‚ 2. Frontend queries backend: โ”‚ -โ”‚ GET /v1/integration/integrations/{integration_id}/content-types/ โ”‚ -โ”‚ โ”‚ -โ”‚ 3. Backend processes request (content_types_summary action): โ”‚ -โ”‚ โ”œโ”€ Get stored content_types from config_json โ”‚ -โ”‚ โ”œโ”€ Count synced items in Content model โ”‚ -โ”‚ โ”œโ”€ Count synced items in ContentTaxonomy model โ”‚ -โ”‚ โ”œโ”€ Compute synced_count for each post type โ”‚ -โ”‚ โ””โ”€ Compute synced_count for each taxonomy โ”‚ -โ”‚ โ”‚ -โ”‚ 4. Backend Response: โ”‚ -โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ -โ”‚ โ”‚ { โ”‚ โ”‚ -โ”‚ โ”‚ "success": true, โ”‚ โ”‚ -โ”‚ โ”‚ "data": { โ”‚ โ”‚ -โ”‚ โ”‚ "post_types": { โ”‚ โ”‚ -โ”‚ โ”‚ "post": { โ”‚ โ”‚ -โ”‚ โ”‚ "label": "Posts", โ”‚ โ”‚ -โ”‚ โ”‚ "count": 50, โ† Total in WordPress โ”‚ โ”‚ -โ”‚ โ”‚ "synced_count": 30, โ† Synced to IGNY8 โ”‚ โ”‚ -โ”‚ โ”‚ "enabled": true, โ”‚ โ”‚ -โ”‚ โ”‚ "fetch_limit": 100 โ”‚ โ”‚ -โ”‚ โ”‚ }, โ”‚ โ”‚ -โ”‚ โ”‚ "page": {...}, โ”‚ โ”‚ -โ”‚ โ”‚ "product": {...} โ”‚ โ”‚ -โ”‚ โ”‚ }, โ”‚ โ”‚ -โ”‚ โ”‚ "taxonomies": { โ”‚ โ”‚ -โ”‚ โ”‚ "category": { โ”‚ โ”‚ -โ”‚ โ”‚ "label": "Categories", โ”‚ โ”‚ -โ”‚ โ”‚ "count": 12, โ† Total in WordPress โ”‚ โ”‚ -โ”‚ โ”‚ "synced_count": 12, โ† Synced to IGNY8 โ”‚ โ”‚ -โ”‚ โ”‚ "enabled": true, โ”‚ โ”‚ -โ”‚ โ”‚ "fetch_limit": 100 โ”‚ โ”‚ -โ”‚ โ”‚ }, โ”‚ โ”‚ -โ”‚ โ”‚ "post_tag": {...}, โ”‚ โ”‚ -โ”‚ โ”‚ "product_cat": {...} โ”‚ โ”‚ -โ”‚ โ”‚ }, โ”‚ โ”‚ -โ”‚ โ”‚ "last_structure_fetch": "2025-11-22T10:15:30+00:00", โ”‚ โ”‚ -โ”‚ โ”‚ "plugin_connection_enabled": true, โ”‚ โ”‚ -โ”‚ โ”‚ "two_way_sync_enabled": true โ”‚ โ”‚ -โ”‚ โ”‚ } โ”‚ โ”‚ -โ”‚ โ”‚ } โ”‚ โ”‚ -โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ -โ”‚ โ”‚ -โ”‚ 5. Frontend Renders: โ”‚ -โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ -โ”‚ โ”‚ Content Types โ”‚ โ”‚ -โ”‚ โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ โ”‚ -โ”‚ โ”‚ โ”‚ Post Types โ”‚ โ”‚ โ”‚ -โ”‚ โ”‚ โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ โ”‚ โ”‚ -โ”‚ โ”‚ โ”‚ โ”‚ Posts 50 total ยท 30 synced โ”‚ โ”‚ โ”‚ โ”‚ -โ”‚ โ”‚ โ”‚ โ”‚ Enabled Limit: 100 โ”‚ โ”‚ โ”‚ โ”‚ -โ”‚ โ”‚ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ โ”‚ โ”‚ -โ”‚ โ”‚ โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ โ”‚ โ”‚ -โ”‚ โ”‚ โ”‚ โ”‚ Pages 10 total ยท 8 synced โ”‚ โ”‚ โ”‚ โ”‚ -โ”‚ โ”‚ โ”‚ โ”‚ Enabled Limit: 100 โ”‚ โ”‚ โ”‚ โ”‚ -โ”‚ โ”‚ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ โ”‚ โ”‚ -โ”‚ โ”‚ โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ โ”‚ โ”‚ -โ”‚ โ”‚ โ”‚ โ”‚ Products 100 total ยท 45 synced โ”‚ โ”‚ โ”‚ โ”‚ -โ”‚ โ”‚ โ”‚ โ”‚ Enabled Limit: 100 โ”‚ โ”‚ โ”‚ โ”‚ -โ”‚ โ”‚ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ โ”‚ โ”‚ -โ”‚ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ โ”‚ -โ”‚ โ”‚ โ”‚ โ”‚ -โ”‚ โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ โ”‚ -โ”‚ โ”‚ โ”‚ Taxonomies โ”‚ โ”‚ โ”‚ -โ”‚ โ”‚ โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ โ”‚ โ”‚ -โ”‚ โ”‚ โ”‚ โ”‚ Categories 12 total ยท 12 synced โ”‚ โ”‚ โ”‚ โ”‚ -โ”‚ โ”‚ โ”‚ โ”‚ Enabled Limit: 100 โ”‚ โ”‚ โ”‚ โ”‚ -โ”‚ โ”‚ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ โ”‚ โ”‚ -โ”‚ โ”‚ โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ โ”‚ โ”‚ -โ”‚ โ”‚ โ”‚ โ”‚ Tags 89 total ยท 60 synced โ”‚ โ”‚ โ”‚ โ”‚ -โ”‚ โ”‚ โ”‚ โ”‚ Enabled Limit: 100 โ”‚ โ”‚ โ”‚ โ”‚ -โ”‚ โ”‚ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ โ”‚ โ”‚ -โ”‚ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ โ”‚ -โ”‚ โ”‚ โ”‚ โ”‚ -โ”‚ โ”‚ Structure last fetched: 2025-11-22 10:15:30 UTC โ”‚ โ”‚ -โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ -โ”‚ โ”‚ -โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ -``` - ---- - -## Daily Cron Job - Automatic Updates - -``` -โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” -โ”‚ WordPress Cron - Daily Schedule (igny8_sync_site_structure) โ”‚ -โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค -โ”‚ โ”‚ -โ”‚ Every 24 hours: โ”‚ -โ”‚ โ”œโ”€ Trigger: do_action('igny8_sync_site_structure') โ”‚ -โ”‚ โ”œโ”€ Call: igny8_sync_site_structure_to_backend() โ”‚ -โ”‚ โ”œโ”€ Same flow as above (Get structure โ†’ Push to backend) โ”‚ -โ”‚ โ”œโ”€ Updates counts and structure if changed โ”‚ -โ”‚ โ””โ”€ Ensures frontend always has current data โ”‚ -โ”‚ โ”‚ -โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ -``` - ---- - -## Error Handling & Logging Flow - -``` -โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” -โ”‚ Error Detection & Logging โ”‚ -โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค -โ”‚ โ”‚ -โ”‚ If query fails: โ”‚ -โ”‚ โ”œโ”€ Log: "Failed to fetch integrations. Error: [details]" โ”‚ -โ”‚ โ””โ”€ Return: false (non-blocking) โ”‚ -โ”‚ โ”‚ -โ”‚ If integration not found: โ”‚ -โ”‚ โ”œโ”€ Log: "Could not find valid WordPress integration for site {id}" โ”‚ -โ”‚ โ”œโ”€ Log: "Response data: [full response]" โ”‚ -โ”‚ โ””โ”€ Return: false (non-blocking) โ”‚ -โ”‚ โ”‚ -โ”‚ If POST fails: โ”‚ -โ”‚ โ”œโ”€ Log: "Failed to sync site structure to integration {id}" โ”‚ -โ”‚ โ”œโ”€ Log: "Error: [error message]" โ”‚ -โ”‚ โ”œโ”€ Log: "Full response: [response JSON]" โ”‚ -โ”‚ โ””โ”€ Return: false (non-blocking) โ”‚ -โ”‚ โ”‚ -โ”‚ If successful: โ”‚ -โ”‚ โ”œโ”€ Log: "Site structure synced successfully to integration {id}" โ”‚ -โ”‚ โ”œโ”€ Update: igny8_structure_synced option โ”‚ -โ”‚ โ”œโ”€ Update: igny8_last_structure_sync timestamp โ”‚ -โ”‚ โ””โ”€ Return: true โ”‚ -โ”‚ โ”‚ -โ”‚ All logs go to: wp-content/debug.log โ”‚ -โ”‚ To enable: define('WP_DEBUG_LOG', true) in wp-config.php โ”‚ -โ”‚ โ”‚ -โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ -``` - ---- - -## Summary - -โœ… **Reliable bidirectional data flow** -- WordPress โ†’ Backend: Structure pushed on connection and daily -- Backend โ†’ Frontend: Structure retrieved and displayed with sync counts -- All steps logged and error-handled -- Non-blocking approach ensures connection always succeeds - -โœ… **User visibility** -- Clear success/failure messages -- Debug logs provide troubleshooting info -- Frontend shows current status and counts - -โœ… **Maintenance** -- Automatic daily updates keep data fresh -- Error handling prevents sync failures from breaking the system -- Complete audit trail in logs - diff --git a/igny8-wp-plugin/SYNC-FIX-EXECUTIVE-SUMMARY.md b/igny8-wp-plugin/SYNC-FIX-EXECUTIVE-SUMMARY.md deleted file mode 100644 index 37deb729..00000000 --- a/igny8-wp-plugin/SYNC-FIX-EXECUTIVE-SUMMARY.md +++ /dev/null @@ -1,240 +0,0 @@ -# WordPress Plugin & IGNY8 Integration Fix - Executive Summary -## November 22, 2025 - ---- - -## ๐ŸŽฏ What Was Broken - -The WordPress plugin was connecting to IGNY8 successfully, but **the Content Types tab remained empty** because: - -1. โŒ Plugin wasn't sending post types/taxonomy counts to backend -2. โŒ Even when sent, error handling was poor -3. โŒ Debug logging was insufficient for troubleshooting -4. โŒ User had no feedback about structure sync status - -**Impact**: -- Frontend couldn't display available WordPress post types -- Backend had no information about site content structure -- Sync operations couldn't proceed without this data - ---- - -## โœ… What Was Fixed - -### 1. **Plugin Structure Sync Function** (`includes/functions.php`) - - โœ… Improved response format handling - - โœ… Added platform filter to find WordPress integration - - โœ… Better error logging with full response inspection - - โœ… Added metadata (site URL, WordPress version) - -### 2. **User Feedback** (`admin/class-admin.php`) - - โœ… Shows success/failure messages for structure sync - - โœ… Non-blocking (doesn't fail connection) - - โœ… Guides user to check debug log if issues occur - -### 3. **Debug Logging** (`includes/class-igny8-api.php`) - - โœ… POST requests now logged (previously only GET) - - โœ… Shows full request payload and response - - โœ… Respects WP_DEBUG and IGNY8_DEBUG flags - - โœ… Helps diagnose connection issues - ---- - -## ๐Ÿ“Š How It Works Now - -``` -WordPress Admin โ†’ Connect button - โ†“ - [Get Credentials] - โ†“ - [Authenticate] - โ†“ - [Query Integration ID] - โ†“ - [Gather Post Types & Taxonomies] - โ†“ - [Push to /update-structure/ endpoint] - โ†“ - [Backend Stores Data] - โ†“ - [Frontend Fetches & Displays Content Types] -``` - ---- - -## ๐Ÿงช Testing (5-10 minutes) - -### Quick Test: -1. **Enable Debug** (optional): - ```php - // In wp-config.php - define('IGNY8_DEBUG', true); - ``` - -2. **Connect Plugin**: - - WordPress Admin โ†’ Settings โ†’ IGNY8 API - - Enter: Email, Password, API Key - - Click: "Connect to IGNY8" - -3. **Verify Success**: - - โœ… Success message appears - - โœ… Check `wp-content/debug.log` for "Site structure synced successfully" - - โœ… Frontend shows Content Types tab with post types and taxonomies - -### Detailed Test: -See `SYNC-FIX-REPORT.md` for comprehensive testing guide - -### Automated Test: -```bash -# Via WP-CLI -wp eval-file tests/test-sync-structure.php - -# Via browser -http://your-site.com/wp-admin/admin-ajax.php?action=igny8_test_structure_sync -``` - ---- - -## ๐Ÿ“ˆ Expected Results - -### Before Fix: -``` -Content Types Tab -โ”œโ”€ Loading... -โ””โ”€ (empty - never populates) -``` - -### After Fix: -``` -Content Types Tab -โ”œโ”€ Post Types -โ”‚ โ”œโ”€ Posts: 50 total ยท 30 synced (Enabled) -โ”‚ โ”œโ”€ Pages: 10 total ยท 8 synced (Enabled) -โ”‚ โ””โ”€ Products: 100 total ยท 45 synced (Enabled) -โ”œโ”€ Taxonomies -โ”‚ โ”œโ”€ Categories: 12 total ยท 12 synced (Enabled) -โ”‚ โ”œโ”€ Tags: 89 total ยท 60 synced (Enabled) -โ”‚ โ””โ”€ Product Categories: 15 total ยท 15 synced (Enabled) -โ””โ”€ Structure last fetched: 2 minutes ago -``` - ---- - -## ๐Ÿ” Key Files Modified - -| File | Changes | Impact | -|------|---------|--------| -| `includes/functions.php` | Better sync logic + error handling | Core functionality fixed | -| `admin/class-admin.php` | User feedback on sync status | Better UX | -| `includes/class-igny8-api.php` | Debug logging for POST | Troubleshooting improved | -| `tests/test-sync-structure.php` | NEW: Diagnostic test | Easy verification | -| `SYNC-FIX-REPORT.md` | NEW: Detailed documentation | Implementation guide | - ---- - -## โœจ Benefits - -โœ… **Reliable Sync**: Post types and taxonomies reliably synced on connection -โœ… **Better Feedback**: Users know what's happening -โœ… **Easier Debugging**: Debug logs show exactly what's happening -โœ… **Automated**: Daily cron job keeps counts up to date -โœ… **Backward Compatible**: No breaking changes to existing code - ---- - -## ๐Ÿš€ Deployment Steps - -1. **Backup**: Backup WordPress and IGNY8 databases -2. **Update Code**: Replace modified files -3. **Test Connection**: Verify sync works in WordPress admin -4. **Monitor**: Check debug log and frontend for 10 minutes -5. **Deploy**: Roll out to production - ---- - -## โšก Quick Start for Developers - -### View Sync Status: -```bash -# Check if structure was synced -tail -20 wp-content/debug.log | grep "IGNY8" - -# Verify backend storage -docker exec igny8_backend python manage.py shell -> from igny8_core.business.integration.models import SiteIntegration -> si = SiteIntegration.objects.filter(platform='wordpress').first() -> print(si.config_json['content_types']) -``` - -### Manual Trigger Sync: -```bash -# In WordPress, execute: -do_action('igny8_sync_site_structure'); - -# Or trigger via WordPress admin: -# Settings โ†’ IGNY8 API โ†’ "Sync Now" button -``` - -### Check Cron Status: -```bash -wp cron event list | grep igny8_sync_site_structure -# Should show: Daily schedule -``` - ---- - -## ๐Ÿ“ž Support & Troubleshooting - -### Common Issues: - -**Q: Content Types tab still empty** -A: Check WordPress debug.log for errors. Ensure backend endpoint is accessible. - -**Q: "No integrations found" error** -A: Backend doesn't have integration record. Verify in Django admin. - -**Q: Structure synced but frontend still empty** -A: Clear browser cache (Ctrl+Shift+Delete) and try refreshing the page. - ---- - -## ๐Ÿ“‹ Success Checklist - -- [ ] Code deployed to all servers -- [ ] WordPress connections tested -- [ ] Content Types tab shows data -- [ ] Debug log shows sync messages -- [ ] Daily cron job is active -- [ ] Frontend displays accurate counts -- [ ] No errors in debug log -- [ ] Performance is acceptable - ---- - -## ๐ŸŽŠ Result - -โœ… **WordPress plugin now successfully syncs site structure with IGNY8 backend** - -- Plugin connects reliably -- Post types and taxonomies are captured -- Frontend Content Types tab displays data -- Counts update daily -- Users have clear feedback - ---- - -## ๐Ÿ“ž Questions? - -Refer to: -- `SYNC-FIX-REPORT.md` - Detailed technical documentation -- `tests/test-sync-structure.php` - Automated testing script -- WordPress debug.log - Real-time sync status - ---- - -_Implementation Date: November 22, 2025_ -_Status: โœ… READY FOR PRODUCTION_ -_Tested: Yes_ -_Breaking Changes: None_ -_Rollback: Simple code revert_ - diff --git a/igny8-wp-plugin/SYNC-FIX-REPORT.md b/igny8-wp-plugin/SYNC-FIX-REPORT.md deleted file mode 100644 index d6520b06..00000000 --- a/igny8-wp-plugin/SYNC-FIX-REPORT.md +++ /dev/null @@ -1,363 +0,0 @@ -# WordPress Plugin Initial Sync Fix - November 22, 2025 - -## ๐Ÿ” Issues Found & Fixed - -### Issue 1: Incomplete Site Structure Sync Integration Response -**Problem**: The `igny8_sync_site_structure_to_backend()` function had poor error handling when retrieving the integration ID from the API. - -**Root Cause**: -- Inconsistent response format handling (paginated vs direct array) -- Poor error logging made debugging difficult -- No platform filter to specifically get WordPress integration - -**Solution Applied**: -- Added explicit `&platform=wordpress` filter to API query -- Implemented robust response format handling for both paginated and direct array responses -- Enhanced error logging with complete response data inspection -- Added data type casting for integration ID -- Added flag option `igny8_structure_synced` to track successful syncs - -**File Modified**: `includes/functions.php` - -### Issue 2: Site Structure Response Missing Metadata -**Problem**: The `igny8_get_site_structure()` function wasn't including WordPress version and site URL. - -**Root Cause**: Incomplete structure data provided to backend - -**Solution Applied**: -- Added `site_url` to structure data -- Added `wordpress_version` to structure data -- These help backend track site configuration changes - -**File Modified**: `includes/functions.php` - -### Issue 3: Missing User Feedback on Sync Status -**Problem**: Connection success didn't indicate whether structure sync completed. - -**Root Cause**: Sync was called but response wasn't shown to user - -**Solution Applied**: -- Added settings error messages for sync success/failure -- Non-blocking approach - connection succeeds even if structure sync fails -- User gets clear feedback about sync status -- Encourages checking debug log if sync fails - -**File Modified**: `admin/class-admin.php` - -### Issue 4: Insufficient Debug Logging for POST Requests -**Problem**: POST requests didn't have debug logging, making it hard to troubleshoot sync failures. - -**Root Cause**: Only GET requests had debug logging enabled - -**Solution Applied**: -- Added full debug logging for POST requests -- Logs include: URL, request payload, response status, response body -- Respects WP_DEBUG and IGNY8_DEBUG constants -- Masks authorization header in logs for security - -**File Modified**: `includes/class-igny8-api.php` - ---- - -## ๐Ÿ“Š Data Flow After Fix - -``` -1. User Connects via WordPress Admin - โ”œโ”€ Email + Password + API Key provided - โ”œโ”€ Login with email/password โ†’ get access/refresh tokens - โ””โ”€ โœ… Tokens stored securely - -2. [NEW] Plugin Queries for Integration ID - โ”œโ”€ Calls: GET /api/v1/integration/integrations/?site={site_id}&platform=wordpress - โ”œโ”€ Handles multiple response formats - โ”œโ”€ Filters specifically for WordPress platform - โ””โ”€ โœ… Integration ID retrieved - -3. [NEW] Plugin Gathers Site Structure - โ”œโ”€ Collects all public post types with counts - โ”œโ”€ Collects all public taxonomies with counts - โ”œโ”€ Includes: site_url, wordpress_version, timestamp - โ””โ”€ โœ… Structure ready - -4. [NEW] Plugin Pushes Structure to Backend - โ”œโ”€ POST /api/v1/integration/integrations/{id}/update-structure/ - โ”œโ”€ Includes: post_types, taxonomies, plugin_connection_enabled, two_way_sync_enabled - โ”œโ”€ With debug logging of payload and response - โ””โ”€ โœ… Stored in backend SiteIntegration.config_json - -5. Backend Stores Structure - โ”œโ”€ Saves to integration.config_json['content_types'] - โ”œโ”€ Includes: post_types, taxonomies, last_structure_fetch timestamp - โ””โ”€ โœ… Ready for frontend consumption - -6. Frontend Requests Content Types - โ”œโ”€ GET /api/v1/integration/integrations/{id}/content-types/ - โ”œโ”€ Backend computes synced_count from Content models - โ”œโ”€ Returns: post_types, taxonomies with all counts - โ””โ”€ โœ… Displays in Content Types tab -``` - ---- - -## ๐Ÿงช Testing the Fix - -### Quick Verification Checklist - -1. **Backend Ready** - ```bash - # Ensure backend is running and migrations are current - docker-compose restart backend - docker exec igny8_backend python manage.py migrate - ``` - -2. **Enable Debug Logging** (Optional but recommended) - ```php - // In wp-config.php, add: - define('WP_DEBUG', true); - define('WP_DEBUG_LOG', true); - define('IGNY8_DEBUG', true); - ``` - -3. **Connect WordPress Plugin** - - Go to: `WordPress Admin โ†’ Settings โ†’ IGNY8 API` - - Enter: Email, Password, API Key - - Click: "Connect to IGNY8" - - Expected: Success message + structure sync message - -4. **Check WordPress Debug Log** - ```bash - tail -30 /path/to/wordpress/wp-content/debug.log | grep "IGNY8" - ``` - - Should see: - ``` - IGNY8 DEBUG POST: https://api.igny8.com/api/v1/integration/integrations/{id}/update-structure/ - IGNY8 DEBUG POST RESPONSE: Status=200 - IGNY8: Site structure synced successfully to integration {id}. - ``` - -5. **Verify Backend Storage** - ```bash - docker exec -it igny8_backend python manage.py shell - ``` - - ```python - from igny8_core.business.integration.models import SiteIntegration - si = SiteIntegration.objects.filter(platform='wordpress').first() - print(si.config_json.get('content_types', {}).keys()) - # Should show: dict_keys(['post_types', 'taxonomies', 'last_structure_fetch']) - - print(si.config_json['content_types']['post_types']) - # Should show: {'post': {...}, 'page': {...}, 'product': {...}, ...} - ``` - -6. **Check Frontend Display** - - Navigate to: `Site Settings โ†’ Content Types` tab - - Expected to see: - - โœ… Post Types section (Posts, Pages, Products, etc.) - - โœ… Taxonomies section (Categories, Tags, Product Categories, etc.) - - โœ… Counts for each (e.g., "123 total ยท 50 synced") - - โœ… "Structure last fetched" timestamp - ---- - -## ๐Ÿ”ง Manual Testing via API - -### Step 1: Get Integration ID -```bash -curl -H "Authorization: Bearer {YOUR_API_KEY}" \ - https://api.igny8.com/api/v1/integration/integrations/?site=5&platform=wordpress -``` - -Response should show integration with structure data. - -### Step 2: Push Structure Manually (Simulate Plugin) -```bash -curl -X POST \ - -H "Authorization: Bearer {YOUR_API_KEY}" \ - -H "Content-Type: application/json" \ - https://api.igny8.com/api/v1/integration/integrations/{INTEGRATION_ID}/update-structure/ \ - -d '{ - "post_types": { - "post": {"label": "Posts", "count": 10, "enabled": true, "fetch_limit": 100}, - "page": {"label": "Pages", "count": 5, "enabled": true, "fetch_limit": 100} - }, - "taxonomies": { - "category": {"label": "Categories", "count": 3, "enabled": true, "fetch_limit": 100} - }, - "timestamp": "2025-11-22T10:00:00Z", - "plugin_connection_enabled": true, - "two_way_sync_enabled": true - }' -``` - -Expected: `200 OK` with success message - -### Step 3: Verify Stored Structure -```bash -curl -H "Authorization: Bearer {YOUR_API_KEY}" \ - https://api.igny8.com/api/v1/integration/integrations/{INTEGRATION_ID}/content-types/ -``` - -Expected: Full response with `post_types`, `taxonomies`, and computed `synced_count` - ---- - -## โœ… Success Indicators - -| Indicator | Expected | Status | -|-----------|----------|--------| -| Plugin connects | Success message shown | โœ… | -| Debug log shows structure sync | "Site structure synced successfully" | โœ… | -| Backend config updated | `content_types` in config_json | โœ… | -| Frontend shows content types | Post types & taxonomies visible | โœ… | -| Counts are accurate | Matches WordPress database | โœ… | -| Last fetch timestamp | Recent (within seconds) | โœ… | - ---- - -## ๐Ÿšจ Troubleshooting - -### "Connection failed" Error -**Check**: -- [ ] API key is correct (generate new one if needed) -- [ ] Backend is running (`docker ps`) -- [ ] Credentials are valid in Django admin -- [ ] Backend migrations are current - -**Solution**: -```bash -docker exec igny8_backend python manage.py migrate -docker-compose restart backend -``` - -### "No site ID found" in logs -**Check**: -- [ ] Did the site response include ID? -- [ ] Is the site actually created in backend? - -**Debug**: -```python -from igny8_core.auth.models import Site -Site.objects.filter(account__email='your-email').first() -``` - -### "No integrations found" in logs -**Check**: -- [ ] Did the plugin API query include `&platform=wordpress`? -- [ ] Does integration exist in backend for this site? - -**Debug**: -```python -from igny8_core.business.integration.models import SiteIntegration -SiteIntegration.objects.filter(platform='wordpress', site__id=5) -``` - -### Frontend still shows empty Content Types tab -**Check**: -- [ ] Is integration config populated? (Check backend query above) -- [ ] Did you refresh the browser? (Ctrl+Shift+Delete) -- [ ] Check browser console for JS errors - -**Debug**: -```bash -# Check API response -curl -H "Authorization: Bearer {KEY}" \ - https://api.igny8.com/api/v1/integration/integrations/{ID}/content-types/ -``` - ---- - -## ๐Ÿ“ Files Modified - -1. **`includes/functions.php`** - - Enhanced `igny8_sync_site_structure_to_backend()` with: - - Better response format handling - - Platform filter - - Enhanced error logging - - Added `site_url` and `wordpress_version` to structure - -2. **`admin/class-admin.php`** - - Updated `handle_connection()` to: - - Show success/failure messages for structure sync - - Non-blocking sync (doesn't fail connection) - - Better user feedback - -3. **`includes/class-igny8-api.php`** - - Enhanced `post()` method with: - - Full request/response debug logging - - Respects WP_DEBUG and IGNY8_DEBUG constants - - Better token refresh handling - ---- - -## ๐Ÿ”„ Next Steps for Developers - -### To Enable Cron-based Daily Sync -The daily structure sync is already registered in `sync/hooks.php`: -```php -add_action('igny8_sync_site_structure', 'igny8_sync_site_structure_to_backend'); -``` - -This runs daily automatically. To verify: -```bash -# In WordPress shell_exec or CLI -wp cron event list | grep igny8_sync_site_structure -``` - -### To Add Manual Sync Button -An AJAX handler already exists in admin. Can be triggered via JavaScript: -```javascript -jQuery.post(igny8Admin.ajaxUrl, { - action: 'igny8_sync_site_structure', - nonce: igny8Admin.nonce -}); -``` - -### To Monitor Sync Health -```python -# Backend monitoring query -from igny8_core.business.integration.models import SiteIntegration -from django.utils import timezone -from datetime import timedelta - -recently_synced = SiteIntegration.objects.filter( - config_json__content_types__last_structure_fetch__isnull=False -).filter( - config_json__content_types__last_structure_fetch__gte=timezone.now() - timedelta(days=1) -) - -print(f"Recently synced integrations: {recently_synced.count()}") -``` - ---- - -## ๐Ÿ“‹ Deployment Checklist - -- [ ] Backend code updated and tested -- [ ] WordPress plugin code updated -- [ ] Debug logging enabled (for troubleshooting) -- [ ] Test connection in WordPress admin -- [ ] Verify structure synced in debug log -- [ ] Check backend database for config_json['content_types'] -- [ ] Verify frontend Content Types tab shows data -- [ ] Test cron job runs daily -- [ ] Document any API key format requirements -- [ ] Test with multiple WordPress sites -- [ ] Test with different post type configurations - ---- - -## ๐Ÿ“ž Support - -For issues, check: -1. WordPress debug log: `wp-content/debug.log` -2. Backend logs: `docker logs igny8_backend` -3. Database: `SiteIntegration.config_json` -4. Frontend console: Browser dev tools - ---- - -_Last Updated: November 22, 2025_ -_Status: โœ… READY FOR DEPLOYMENT_ - diff --git a/igny8-wp-plugin/admin/assets/css/admin.css b/igny8-wp-plugin/admin/assets/css/admin.css deleted file mode 100644 index a68b883e..00000000 --- a/igny8-wp-plugin/admin/assets/css/admin.css +++ /dev/null @@ -1,469 +0,0 @@ -/** - * Admin Styles - IGNY8 Bridge - * Updated with IGNY8 brand colors and modern UI - * - * @package Igny8Bridge - */ - -/* ============================================ - IGNY8 Brand Colors - ============================================ */ -:root { - --igny8-primary: #3B82F6; - --igny8-primary-hover: #2563EB; - --igny8-success: #10B981; - --igny8-warning: #F59E0B; - --igny8-error: #EF4444; - --igny8-purple: #8B5CF6; - --igny8-gray: #6B7280; - --igny8-light-gray: #F3F4F6; -} - -/* ============================================ - Container & Layout - ============================================ */ - -.igny8-settings-container { - max-width: 1400px; -} - -.igny8-settings-card { - background: #fff; - border: 1px solid #E5E7EB; - box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06); - padding: 24px; - margin: 24px 0; - border-radius: 8px; -} - -.igny8-settings-card h2 { - margin-top: 0; - padding-bottom: 12px; - border-bottom: 2px solid var(--igny8-light-gray); - color: #111827; - font-size: 20px; - font-weight: 600; -} - -/* ============================================ - Toggle Switch - ============================================ */ - -.igny8-toggle-wrapper { - display: flex; - align-items: center; - gap: 12px; -} - -.igny8-toggle-input { - position: relative; - width: 48px; - height: 24px; - -webkit-appearance: none; - appearance: none; - background: var(--igny8-gray); - outline: none; - border-radius: 24px; - cursor: pointer; - transition: 0.3s; -} - -.igny8-toggle-input:checked { - background: var(--igny8-success); -} - -.igny8-toggle-input::before { - content: ''; - position: absolute; - width: 20px; - height: 20px; - border-radius: 50%; - top: 2px; - left: 2px; - background: #fff; - transition: 0.3s; - box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); -} - -.igny8-toggle-input:checked::before { - left: 26px; -} - -/* ============================================ - Sync Operations Grid - ============================================ */ - -.igny8-sync-grid { - display: grid; - grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); - gap: 20px; - margin-top: 20px; -} - -.igny8-sync-card { - background: #fff; - border: 2px solid #E5E7EB; - border-radius: 12px; - padding: 24px; - transition: all 0.3s ease; -} - -.igny8-sync-card:hover { - border-color: var(--igny8-primary); - box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); - transform: translateY(-2px); -} - -.igny8-sync-card-highlight { - border-color: var(--igny8-primary); - background: linear-gradient(135deg, #EFF6FF 0%, #DBEAFE 100%); -} - -.igny8-sync-icon { - width: 48px; - height: 48px; - background: var(--igny8-primary); - border-radius: 10px; - display: flex; - align-items: center; - justify-content: center; - margin-bottom: 16px; - color: white; -} - -.igny8-sync-card h3 { - margin: 0 0 8px 0; - font-size: 16px; - font-weight: 600; - color: #111827; -} - -.igny8-sync-description { - font-size: 14px; - color: #6B7280; - line-height: 1.5; - margin-bottom: 12px; -} - -.igny8-sync-meta { - font-size: 12px; - color: #9CA3AF; - margin-bottom: 16px; -} - -.igny8-sync-time { - display: inline-flex; - align-items: center; - gap: 4px; -} - -.igny8-sync-button { - width: 100%; - height: 40px; - background: var(--igny8-primary) !important; - border-color: var(--igny8-primary) !important; - color: white !important; - font-weight: 500 !important; - border-radius: 8px !important; - transition: all 0.2s ease !important; -} - -.igny8-sync-button:hover:not(:disabled) { - background: var(--igny8-primary-hover) !important; - border-color: var(--igny8-primary-hover) !important; - transform: translateY(-1px); - box-shadow: 0 4px 6px -1px rgba(59, 130, 246, 0.3); -} - -.igny8-sync-button:disabled { - opacity: 0.5 !important; - cursor: not-allowed !important; -} - -.button-loading { - display: flex; - align-items: center; - justify-content: center; - gap: 8px; -} - -/* ============================================ - Statistics Cards - ============================================ */ - -.igny8-stats-grid { - display: grid; - grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); - gap: 20px; - margin-top: 20px; -} - -.igny8-stat-card { - background: linear-gradient(135deg, #ffffff 0%, #f9fafb 100%); - border: 1px solid #E5E7EB; - border-radius: 12px; - padding: 20px; - display: flex; - align-items: flex-start; - gap: 16px; - transition: all 0.3s ease; -} - -.igny8-stat-card:hover { - box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05); - transform: translateY(-2px); -} - -.igny8-stat-icon { - width: 48px; - height: 48px; - border-radius: 10px; - display: flex; - align-items: center; - justify-content: center; - flex-shrink: 0; -} - -.igny8-stat-content { - flex: 1; -} - -.igny8-stat-label { - font-size: 12px; - color: #6B7280; - text-transform: uppercase; - letter-spacing: 0.05em; - margin-bottom: 4px; - font-weight: 500; -} - -.igny8-stat-value { - font-size: 28px; - font-weight: 700; - color: #111827; - line-height: 1.2; - margin-bottom: 4px; -} - -.igny8-stat-meta { - font-size: 12px; - color: #9CA3AF; -} - -/* ============================================ - Semantic Summary - ============================================ */ - -.igny8-semantic-summary { - margin-top: 24px; - padding: 20px; - background: linear-gradient(135deg, #F3E8FF 0%, #E9D5FF 100%); - border-radius: 12px; - border: 1px solid #D8B4FE; -} - -.igny8-semantic-summary h3 { - margin: 0 0 16px 0; - font-size: 16px; - font-weight: 600; - color: #6B21A8; -} - -.igny8-semantic-stats { - display: flex; - gap: 32px; - flex-wrap: wrap; -} - -.igny8-semantic-stat { - display: flex; - flex-direction: column; - gap: 4px; -} - -.igny8-semantic-stat .value { - font-size: 24px; - font-weight: 700; - color: #7C3AED; -} - -.igny8-semantic-stat .label { - font-size: 12px; - color: #8B5CF6; - text-transform: uppercase; - letter-spacing: 0.05em; -} - -/* ============================================ - Status Indicators - ============================================ */ - -.igny8-status-connected { - color: var(--igny8-success); - font-weight: 600; -} - -.igny8-status-disconnected { - color: var(--igny8-error); - font-weight: 600; -} - -/* ============================================ - Diagnostics - ============================================ */ - -.igny8-diagnostics-grid { - display: grid; - grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); - gap: 16px; - margin-top: 20px; -} - -.igny8-diagnostic-item { - padding: 16px; - background: linear-gradient(135deg, #F9FAFB 0%, #F3F4F6 100%); - border: 1px solid #E5E7EB; - border-radius: 8px; - transition: all 0.2s ease; -} - -.igny8-diagnostic-item:hover { - border-color: var(--igny8-primary); - box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05); -} - -.igny8-diagnostic-label { - font-size: 11px; - text-transform: uppercase; - letter-spacing: 0.05em; - color: #6B7280; - margin-bottom: 8px; - font-weight: 500; -} - -.igny8-diagnostic-value { - font-size: 16px; - font-weight: 600; - color: #111827; -} - -.igny8-diagnostic-item .description { - margin: 6px 0 0; - color: #9CA3AF; - font-size: 12px; -} - -/* ============================================ - Sync Status Messages - ============================================ */ - -.igny8-sync-status { - margin-top: 20px; - padding: 16px; - border-radius: 8px; - display: none; - font-size: 14px; -} - -.igny8-sync-status.igny8-sync-status-success { - background-color: #D1FAE5; - border: 1px solid #6EE7B7; - color: #065F46; - display: block; -} - -.igny8-sync-status.igny8-sync-status-error { - background-color: #FEE2E2; - border: 1px solid #FCA5A5; - color: #991B1B; - display: block; -} - -.igny8-sync-status.igny8-sync-status-loading { - background-color: #DBEAFE; - border: 1px solid #93C5FD; - color: #1E40AF; - display: block; -} - -/* ============================================ - Loading States - ============================================ */ - -.igny8-loading { - opacity: 0.6; - pointer-events: none; -} - -@keyframes igny8-spin { - 0% { transform: rotate(0deg); } - 100% { transform: rotate(360deg); } -} - -/* ============================================ - Messages & Notifications - ============================================ */ - -.igny8-message { - padding: 16px; - margin: 15px 0; - border-left: 4px solid; - background: #fff; - border-radius: 4px; -} - -.igny8-message.igny8-message-success { - border-color: var(--igny8-success); - background-color: #F0FDF4; - color: #065F46; -} - -.igny8-message.igny8-message-error { - border-color: var(--igny8-error); - background-color: #FEF2F2; - color: #991B1B; -} - -.igny8-message.igny8-message-info { - border-color: var(--igny8-primary); - background-color: #EFF6FF; - color: #1E40AF; -} - -.igny8-message.igny8-message-warning { - border-color: var(--igny8-warning); - background-color: #FFFBEB; - color: #92400E; -} - -/* ============================================ - Responsive - ============================================ */ - -@media (max-width: 782px) { - .igny8-sync-grid { - grid-template-columns: 1fr; - } - - .igny8-stats-grid { - grid-template-columns: 1fr; - } - - .igny8-diagnostics-grid { - grid-template-columns: 1fr; - } -} - -@media (max-width: 600px) { - .igny8-settings-card { - padding: 16px; - } - - .igny8-sync-card { - padding: 16px; - } - - .igny8-stat-card { - flex-direction: column; - } -} diff --git a/igny8-wp-plugin/admin/assets/js/admin.js b/igny8-wp-plugin/admin/assets/js/admin.js deleted file mode 100644 index fe4fe4f7..00000000 --- a/igny8-wp-plugin/admin/assets/js/admin.js +++ /dev/null @@ -1,188 +0,0 @@ -/** - * Admin JavaScript - * - * @package Igny8Bridge - */ - -(function($) { - 'use strict'; - - $(document).ready(function() { - // Test connection button - $('#igny8-test-connection').on('click', function() { - var $button = $(this); - var $result = $('#igny8-test-result'); - - $button.prop('disabled', true).addClass('igny8-loading'); - $result.html('Testing...'); - - $.ajax({ - url: igny8Admin.ajaxUrl, - type: 'POST', - data: { - action: 'igny8_test_connection', - nonce: igny8Admin.nonce - }, - success: function(response) { - if (response.success) { - $result.html('โœ“ ' + (response.data.message || 'Connection successful') + ''); - } else { - var errorMsg = response.data.message || 'Connection failed'; - var httpStatus = response.data.http_status || ''; - var fullMsg = errorMsg; - if (httpStatus) { - fullMsg += ' (HTTP ' + httpStatus + ')'; - } - $result.html('โœ— ' + fullMsg + ''); - - // Log full error to console for debugging - console.error('IGNY8 Connection Test Failed:', response.data); - } - }, - error: function(xhr, status, error) { - $result.html('โœ— Request failed: ' + error + ''); - console.error('IGNY8 AJAX Error:', xhr, status, error); - }, - complete: function() { - $button.prop('disabled', false).removeClass('igny8-loading'); - } - }); - }); - - // Sync posts to IGNY8 - $('#igny8-sync-posts').on('click', function() { - igny8TriggerSync('igny8_sync_posts', 'Syncing posts to IGNY8...'); - }); - - // Sync taxonomies - $('#igny8-sync-taxonomies').on('click', function() { - igny8TriggerSync('igny8_sync_taxonomies', 'Syncing taxonomies...'); - }); - - // Sync from IGNY8 - $('#igny8-sync-from-igny8').on('click', function() { - igny8TriggerSync('igny8_sync_from_igny8', 'Syncing from IGNY8...'); - }); - - // Collect and send site data - $('#igny8-collect-site-data').on('click', function() { - igny8TriggerSync('igny8_collect_site_data', 'Collecting and sending site data...'); - }); - - // Load sync statistics - igny8LoadStats(); - - // Handle row action links - $(document).on('click', '.igny8-action-link', function(e) { - e.preventDefault(); - - var $link = $(this); - var postId = $link.data('post-id'); - var action = $link.data('action'); - - if (!postId) { - return; - } - - if (!confirm('Are you sure you want to ' + (action === 'send' ? 'send' : 'update') + ' this post to IGNY8?')) { - return; - } - - $link.text('Processing...').prop('disabled', true); - - $.ajax({ - url: igny8Admin.ajaxUrl, - type: 'POST', - data: { - action: 'igny8_send_to_igny8', - post_id: postId, - action_type: action, - nonce: igny8Admin.nonce - }, - success: function(response) { - if (response.success) { - alert(response.data.message || 'Success!'); - location.reload(); - } else { - alert(response.data.message || 'Failed to send to IGNY8'); - $link.text(action === 'send' ? 'Send to IGNY8' : 'Update in IGNY8').prop('disabled', false); - } - }, - error: function() { - alert('Request failed'); - $link.text(action === 'send' ? 'Send to IGNY8' : 'Update in IGNY8').prop('disabled', false); - } - }); - }); - }); - - /** - * Trigger sync operation - */ - function igny8TriggerSync(action, message) { - var $status = $('#igny8-sync-status'); - var $button = $('#' + action.replace('igny8_', 'igny8-')); - - $status.removeClass('igny8-sync-status-success igny8-sync-status-error') - .addClass('igny8-sync-status-loading') - .html('' + message); - - $button.prop('disabled', true).addClass('igny8-loading'); - - $.ajax({ - url: igny8Admin.ajaxUrl, - type: 'POST', - data: { - action: action, - nonce: igny8Admin.nonce - }, - success: function(response) { - if (response.success) { - $status.removeClass('igny8-sync-status-loading') - .addClass('igny8-sync-status-success') - .html('โœ“ ' + (response.data.message || 'Operation completed successfully')); - - // Reload stats - igny8LoadStats(); - } else { - $status.removeClass('igny8-sync-status-loading') - .addClass('igny8-sync-status-error') - .html('โœ— ' + (response.data.message || 'Operation failed')); - } - }, - error: function() { - $status.removeClass('igny8-sync-status-loading') - .addClass('igny8-sync-status-error') - .html('โœ— Request failed'); - }, - complete: function() { - $button.prop('disabled', false).removeClass('igny8-loading'); - } - }); - } - - /** - * Load sync statistics - */ - function igny8LoadStats() { - $.ajax({ - url: igny8Admin.ajaxUrl, - type: 'POST', - data: { - action: 'igny8_get_stats', - nonce: igny8Admin.nonce - }, - success: function(response) { - if (response.success && response.data) { - if (response.data.synced_posts !== undefined) { - $('#igny8-stat-posts').text(response.data.synced_posts); - } - if (response.data.last_sync) { - $('#igny8-stat-last-sync').text(response.data.last_sync); - } - } - } - }); - } -})(jQuery); - diff --git a/igny8-wp-plugin/admin/assets/js/post-editor.js b/igny8-wp-plugin/admin/assets/js/post-editor.js deleted file mode 100644 index 2be154c1..00000000 --- a/igny8-wp-plugin/admin/assets/js/post-editor.js +++ /dev/null @@ -1,200 +0,0 @@ -/** - * Post Editor JavaScript - * - * Handles AJAX interactions for Planner and Optimizer meta boxes - * - * @package Igny8Bridge - */ - -(function($) { - 'use strict'; - - $(document).ready(function() { - // Fetch Planner Brief - $('#igny8-fetch-brief').on('click', function() { - var $button = $(this); - var $message = $('#igny8-planner-brief-message'); - var postId = $button.data('post-id'); - var taskId = $button.data('task-id'); - - $button.prop('disabled', true).text('Fetching...'); - $message.hide().removeClass('notice-success notice-error'); - - $.ajax({ - url: igny8PostEditor.ajaxUrl, - type: 'POST', - data: { - action: 'igny8_fetch_planner_brief', - nonce: igny8PostEditor.nonce, - post_id: postId, - task_id: taskId - }, - success: function(response) { - if (response.success) { - $message.addClass('notice notice-success inline') - .html('

' + response.data.message + '

') - .show(); - - // Reload page to show updated brief - setTimeout(function() { - location.reload(); - }, 1000); - } else { - $message.addClass('notice notice-error inline') - .html('

' + (response.data.message || 'Failed to fetch brief') + '

') - .show(); - $button.prop('disabled', false).text('Fetch Brief'); - } - }, - error: function() { - $message.addClass('notice notice-error inline') - .html('

Request failed

') - .show(); - $button.prop('disabled', false).text('Fetch Brief'); - } - }); - }); - - // Refresh Planner Task - $('#igny8-refresh-task').on('click', function() { - var $button = $(this); - var $message = $('#igny8-planner-brief-message'); - var postId = $button.data('post-id'); - var taskId = $button.data('task-id'); - - if (!confirm('Are you sure you want to request a refresh of this task from IGNY8 Planner?')) { - return; - } - - $button.prop('disabled', true).text('Requesting...'); - $message.hide().removeClass('notice-success notice-error'); - - $.ajax({ - url: igny8PostEditor.ajaxUrl, - type: 'POST', - data: { - action: 'igny8_refresh_planner_task', - nonce: igny8PostEditor.nonce, - post_id: postId, - task_id: taskId - }, - success: function(response) { - if (response.success) { - $message.addClass('notice notice-success inline') - .html('

' + response.data.message + '

') - .show(); - } else { - $message.addClass('notice notice-error inline') - .html('

' + (response.data.message || 'Failed to request refresh') + '

') - .show(); - } - $button.prop('disabled', false).text('Request Refresh'); - }, - error: function() { - $message.addClass('notice notice-error inline') - .html('

Request failed

') - .show(); - $button.prop('disabled', false).text('Request Refresh'); - } - }); - }); - - // Create Optimizer Job - $('#igny8-create-optimizer-job').on('click', function() { - var $button = $(this); - var $message = $('#igny8-optimizer-message'); - var postId = $button.data('post-id'); - var taskId = $button.data('task-id'); - - if (!confirm('Create a new optimizer job for this post?')) { - return; - } - - $button.prop('disabled', true).text('Creating...'); - $message.hide().removeClass('notice-success notice-error'); - - $.ajax({ - url: igny8PostEditor.ajaxUrl, - type: 'POST', - data: { - action: 'igny8_create_optimizer_job', - nonce: igny8PostEditor.nonce, - post_id: postId, - task_id: taskId, - job_type: 'audit', - priority: 'normal' - }, - success: function(response) { - if (response.success) { - $message.addClass('notice notice-success inline') - .html('

' + response.data.message + '

') - .show(); - - // Reload page to show updated status - setTimeout(function() { - location.reload(); - }, 1000); - } else { - $message.addClass('notice notice-error inline') - .html('

' + (response.data.message || 'Failed to create job') + '

') - .show(); - $button.prop('disabled', false).text('Request Optimization'); - } - }, - error: function() { - $message.addClass('notice notice-error inline') - .html('

Request failed

') - .show(); - $button.prop('disabled', false).text('Request Optimization'); - } - }); - }); - - // Check Optimizer Status - $('#igny8-check-optimizer-status').on('click', function() { - var $button = $(this); - var $message = $('#igny8-optimizer-message'); - var postId = $button.data('post-id'); - var jobId = $button.data('job-id'); - - $button.prop('disabled', true).text('Checking...'); - $message.hide().removeClass('notice-success notice-error'); - - $.ajax({ - url: igny8PostEditor.ajaxUrl, - type: 'POST', - data: { - action: 'igny8_get_optimizer_status', - nonce: igny8PostEditor.nonce, - post_id: postId, - job_id: jobId - }, - success: function(response) { - if (response.success) { - $message.addClass('notice notice-success inline') - .html('

Status: ' + response.data.status + '

') - .show(); - - // Reload page to show updated status - setTimeout(function() { - location.reload(); - }, 1000); - } else { - $message.addClass('notice notice-error inline') - .html('

' + (response.data.message || 'Failed to get status') + '

') - .show(); - } - $button.prop('disabled', false).text('Check Status'); - }, - error: function() { - $message.addClass('notice notice-error inline') - .html('

Request failed

') - .show(); - $button.prop('disabled', false).text('Check Status'); - } - }); - }); - }); - -})(jQuery); - diff --git a/igny8-wp-plugin/admin/class-admin-columns.php b/igny8-wp-plugin/admin/class-admin-columns.php deleted file mode 100644 index 06916a8b..00000000 --- a/igny8-wp-plugin/admin/class-admin-columns.php +++ /dev/null @@ -1,306 +0,0 @@ -'; - echo esc_html($taxonomy); - echo ''; - } else { - echo 'โ€”'; - } - } - - /** - * Render attribute column - * - * @param int $post_id Post ID - */ - private function render_attribute_column($post_id) { - $attribute = get_post_meta($post_id, '_igny8_attribute_id', true); - - if ($attribute) { - echo ''; - echo esc_html($attribute); - echo ''; - } else { - echo 'โ€”'; - } - } - - /** - * Add custom columns - * - * @param array $columns Existing columns - * @return array Modified columns - */ - public function add_columns($columns) { - $new_columns = array(); - - foreach ($columns as $key => $value) { - $new_columns[$key] = $value; - - if ($key === 'title') { - $new_columns['igny8_taxonomy'] = __('Taxonomy', 'igny8-bridge'); - $new_columns['igny8_attribute'] = __('Attribute', 'igny8-bridge'); - } - } - - return $new_columns; - } - - /** - * Render column content - * - * @param string $column_name Column name - * @param int $post_id Post ID - */ - public function render_column_content($column_name, $post_id) { - switch ($column_name) { - case 'igny8_taxonomy': - $this->render_taxonomy_column($post_id); - break; - - case 'igny8_attribute': - $this->render_attribute_column($post_id); - break; - } - } - - /** - * Make columns sortable - * - * @param array $columns Sortable columns - * @return array Modified columns - */ - public function make_columns_sortable($columns) { - $columns['igny8_source'] = 'igny8_source'; - return $columns; - } - - /** - * Add row actions - * - * @param array $actions Existing actions - * @param WP_Post $post Post object - * @return array Modified actions - */ - public function add_row_actions($actions, $post) { - // Only add for published posts - if ($post->post_status !== 'publish') { - return $actions; - } - - // Check if already synced to IGNY8 - $task_id = get_post_meta($post->ID, '_igny8_task_id', true); - - if ($task_id) { - // Already synced - show update action - $actions['igny8_update'] = sprintf( - '%s', - '#', - $post->ID, - __('Update in IGNY8', 'igny8-bridge') - ); - } else { - // Not synced - show send action - $actions['igny8_send'] = sprintf( - '%s', - '#', - $post->ID, - __('Send to IGNY8', 'igny8-bridge') - ); - } - - return $actions; - } - - /** - * Send post to IGNY8 (AJAX handler) - */ - public static function send_to_igny8() { - check_ajax_referer('igny8_admin_nonce', 'nonce'); - - if (!current_user_can('edit_posts')) { - wp_send_json_error(array('message' => 'Unauthorized')); - } - - $post_id = isset($_POST['post_id']) ? intval($_POST['post_id']) : 0; - $action = isset($_POST['action_type']) ? sanitize_text_field($_POST['action_type']) : 'send'; - - if (!$post_id) { - wp_send_json_error(array('message' => 'Invalid post ID')); - } - - $post = get_post($post_id); - if (!$post) { - wp_send_json_error(array('message' => 'Post not found')); - } - - if (!igny8_is_connection_enabled()) { - wp_send_json_error(array('message' => 'Connection is disabled. Enable sync operations first.')); - } - - $api = new Igny8API(); - - if (!$api->is_authenticated()) { - wp_send_json_error(array('message' => 'Not authenticated with IGNY8')); - } - - $site_id = get_option('igny8_site_id'); - if (!$site_id) { - wp_send_json_error(array('message' => 'Site ID not set')); - } - - // Prepare post data for IGNY8 - $post_data = array( - 'title' => $post->post_title, - 'content' => $post->post_content, - 'excerpt' => $post->post_excerpt, - 'status' => $post->post_status === 'publish' ? 'completed' : 'draft', - 'post_type' => $post->post_type, - 'url' => get_permalink($post_id), - 'wordpress_post_id' => $post_id - ); - - // Get categories - $categories = wp_get_post_categories($post_id, array('fields' => 'names')); - if (!empty($categories)) { - $post_data['categories'] = $categories; - } - - // Get tags - $tags = wp_get_post_tags($post_id, array('fields' => 'names')); - if (!empty($tags)) { - $post_data['tags'] = $tags; - } - - // Get featured image - $featured_image_id = get_post_thumbnail_id($post_id); - if ($featured_image_id) { - $post_data['featured_image'] = wp_get_attachment_image_url($featured_image_id, 'full'); - } - - // Get sectors and clusters - $sectors = wp_get_post_terms($post_id, 'igny8_sectors', array('fields' => 'ids')); - $clusters = wp_get_post_terms($post_id, 'igny8_clusters', array('fields' => 'ids')); - - if (!empty($sectors)) { - // Get IGNY8 sector IDs from term meta - $igny8_sector_ids = array(); - foreach ($sectors as $term_id) { - $igny8_sector_id = get_term_meta($term_id, '_igny8_sector_id', true); - if ($igny8_sector_id) { - $igny8_sector_ids[] = $igny8_sector_id; - } - } - if (!empty($igny8_sector_ids)) { - $post_data['sector_id'] = $igny8_sector_ids[0]; // Use first sector - } - } - - if (!empty($clusters)) { - // Get IGNY8 cluster IDs from term meta - $igny8_cluster_ids = array(); - foreach ($clusters as $term_id) { - $igny8_cluster_id = get_term_meta($term_id, '_igny8_cluster_id', true); - if ($igny8_cluster_id) { - $igny8_cluster_ids[] = $igny8_cluster_id; - } - } - if (!empty($igny8_cluster_ids)) { - $post_data['cluster_id'] = $igny8_cluster_ids[0]; // Use first cluster - } - } - - // Check if post already has task ID - $existing_task_id = get_post_meta($post_id, '_igny8_task_id', true); - - if ($existing_task_id && $action === 'update') { - // Update existing task - $response = $api->put("/writer/tasks/{$existing_task_id}/", $post_data); - } else { - // Create new task - $response = $api->post("/writer/tasks/", $post_data); - } - - if ($response['success']) { - $task_id = $response['data']['id'] ?? $existing_task_id; - - // Store task ID - update_post_meta($post_id, '_igny8_task_id', $task_id); - update_post_meta($post_id, '_igny8_last_synced', current_time('mysql')); - - wp_send_json_success(array( - 'message' => $action === 'update' ? 'Post updated in IGNY8' : 'Post sent to IGNY8', - 'task_id' => $task_id - )); - } else { - wp_send_json_error(array( - 'message' => 'Failed to send to IGNY8: ' . ($response['error'] ?? 'Unknown error') - )); - } - } -} - -// Initialize -new Igny8AdminColumns(); - -// Register AJAX handler -add_action('wp_ajax_igny8_send_to_igny8', array('Igny8AdminColumns', 'send_to_igny8')); - diff --git a/igny8-wp-plugin/admin/class-admin.php b/igny8-wp-plugin/admin/class-admin.php deleted file mode 100644 index 1406baba..00000000 --- a/igny8-wp-plugin/admin/class-admin.php +++ /dev/null @@ -1,598 +0,0 @@ - 'boolean', - 'sanitize_callback' => array($this, 'sanitize_boolean'), - 'default' => 1 - )); - - register_setting('igny8_bridge_connection', 'igny8_connection_enabled', array( - 'type' => 'boolean', - 'sanitize_callback' => array($this, 'sanitize_boolean'), - 'default' => 1 - )); - - register_setting('igny8_bridge_controls', 'igny8_enabled_post_types', array( - 'type' => 'array', - 'sanitize_callback' => array($this, 'sanitize_post_types'), - 'default' => array_keys(igny8_get_supported_post_types()) - )); - - register_setting('igny8_bridge_controls', 'igny8_enabled_taxonomies', array( - 'type' => 'array', - 'sanitize_callback' => array($this, 'sanitize_taxonomies'), - 'default' => array('category', 'post_tag', 'product_cat', 'igny8_sectors', 'igny8_clusters') - )); - - register_setting('igny8_bridge_controls', 'igny8_enable_woocommerce', array( - 'type' => 'boolean', - 'sanitize_callback' => array($this, 'sanitize_boolean'), - 'default' => class_exists('WooCommerce') ? 1 : 0 - )); - - register_setting('igny8_bridge_controls', 'igny8_control_mode', array( - 'type' => 'string', - 'sanitize_callback' => array($this, 'sanitize_control_mode'), - 'default' => 'mirror' - )); - - register_setting('igny8_bridge_controls', 'igny8_enabled_modules', array( - 'type' => 'array', - 'sanitize_callback' => array($this, 'sanitize_modules'), - 'default' => array_keys(igny8_get_available_modules()) - )); - } - - /** - * Enqueue admin scripts and styles - * - * @param string $hook Current admin page hook - */ - public function enqueue_scripts($hook) { - // Enqueue on settings page - if ($hook === 'settings_page_igny8-settings') { - wp_enqueue_style( - 'igny8-admin-style', - IGNY8_BRIDGE_PLUGIN_URL . 'admin/assets/css/admin.css', - array(), - IGNY8_BRIDGE_VERSION - ); - - wp_enqueue_script( - 'igny8-admin-script', - IGNY8_BRIDGE_PLUGIN_URL . 'admin/assets/js/admin.js', - array('jquery'), - IGNY8_BRIDGE_VERSION, - true - ); - - wp_localize_script('igny8-admin-script', 'igny8Admin', array( - 'ajaxUrl' => admin_url('admin-ajax.php'), - 'nonce' => wp_create_nonce('igny8_admin_nonce'), - )); - } - - // Enqueue on post/page/product list pages - if (strpos($hook, 'edit.php') !== false) { - $screen = get_current_screen(); - if ($screen && in_array($screen->post_type, array('post', 'page', 'product', ''))) { - wp_enqueue_style( - 'igny8-admin-style', - IGNY8_BRIDGE_PLUGIN_URL . 'admin/assets/css/admin.css', - array(), - IGNY8_BRIDGE_VERSION - ); - - wp_enqueue_script( - 'igny8-admin-script', - IGNY8_BRIDGE_PLUGIN_URL . 'admin/assets/js/admin.js', - array('jquery'), - IGNY8_BRIDGE_VERSION, - true - ); - - wp_localize_script('igny8-admin-script', 'igny8Admin', array( - 'ajaxUrl' => admin_url('admin-ajax.php'), - 'nonce' => wp_create_nonce('igny8_admin_nonce'), - )); - } - } - } - - /** - * Render settings page - */ - public function render_settings_page() { - // Handle form submission (use wp_verify_nonce to avoid wp_die on failure) - if (isset($_POST['igny8_connect'])) { - if (empty($_POST['_wpnonce']) || !wp_verify_nonce($_POST['_wpnonce'], 'igny8_settings_nonce')) { - add_settings_error( - 'igny8_settings', - 'igny8_nonce', - __('Security check failed. Please refresh the page and try again.', 'igny8-bridge'), - 'error' - ); - } else { - $this->handle_connection(); - } - } - - // Handle revoke API key (use wp_verify_nonce) - if (isset($_POST['igny8_revoke_api_key'])) { - if (empty($_POST['_wpnonce']) || !wp_verify_nonce($_POST['_wpnonce'], 'igny8_revoke_api_key')) { - add_settings_error( - 'igny8_settings', - 'igny8_nonce_revoke', - __('Security check failed. Could not revoke API key.', 'igny8-bridge'), - 'error' - ); - } else { - self::revoke_api_key(); - add_settings_error( - 'igny8_settings', - 'igny8_api_key_revoked', - __('API key revoked and removed from this site.', 'igny8-bridge'), - 'updated' - ); - } - } - - // Webhook secret regeneration removed - using API key only - - // Include settings template - include IGNY8_BRIDGE_PLUGIN_DIR . 'admin/settings.php'; - } - - /** - * Handle API connection - API key only - */ - private function handle_connection() { - $api_key = sanitize_text_field($_POST['igny8_api_key'] ?? ''); - - // API key is required - if (empty($api_key)) { - add_settings_error( - 'igny8_settings', - 'igny8_error', - __('API key is required to connect to IGNY8.', 'igny8-bridge'), - 'error' - ); - return; - } - - // Connect using API key only - $api = new Igny8API(); - - if (!$api->connect($api_key)) { - add_settings_error( - 'igny8_settings', - 'igny8_error', - __('Failed to connect to IGNY8 API. Please verify your API key is correct.', 'igny8-bridge'), - 'error' - ); - return; - } - - // Store API key securely and also set access token to the API key for subsequent calls - // Only store if it's not the placeholder - if (!$is_placeholder) { - if (function_exists('igny8_store_secure_option')) { - igny8_store_secure_option('igny8_api_key', $api_key); - igny8_store_secure_option('igny8_access_token', $api_key); - } else { - update_option('igny8_api_key', $api_key); - update_option('igny8_access_token', $api_key); - } - } - - // Try to get site ID (if available) using the authenticated client - $site_response = $api->get('/system/sites/'); - if ($site_response['success'] && !empty($site_response['results'])) { - $site = $site_response['results'][0]; - update_option('igny8_site_id', $site['id']); - } - - add_settings_error( - 'igny8_settings', - 'igny8_connected', - __('Successfully connected to IGNY8 API and stored API key.', 'igny8-bridge'), - 'updated' - ); - - // Sync site structure to backend (post types, taxonomies, etc.) - igny8_sync_site_structure_to_backend(); - } - - /** - * Revoke stored API key (secure delete) - * - * Public so tests can call it directly. - */ - public static function revoke_api_key() { - if (function_exists('igny8_delete_secure_option')) { - igny8_delete_secure_option('igny8_api_key'); - igny8_delete_secure_option('igny8_access_token'); - igny8_delete_secure_option('igny8_refresh_token'); - } else { - delete_option('igny8_api_key'); - delete_option('igny8_access_token'); - delete_option('igny8_refresh_token'); - } - - // Also clear token-issued timestamps - delete_option('igny8_token_refreshed_at'); - delete_option('igny8_access_token_issued'); - } - - /** - * Test API connection (AJAX handler) - */ - public static function test_connection() { - check_ajax_referer('igny8_admin_nonce', 'nonce'); - - if (!current_user_can('manage_options')) { - wp_send_json_error(array('message' => 'Unauthorized')); - } - - if (!igny8_is_connection_enabled()) { - wp_send_json_error(array('message' => 'Connection is disabled. Enable sync operations to test.')); - } - - $api = new Igny8API(); - - if (!$api->is_authenticated()) { - wp_send_json_error(array('message' => 'Not authenticated')); - } - - // Try multiple endpoints to find one that works - $test_endpoints = array( - '/system/ping/' => 'System ping endpoint', - '/planner/keywords/?page_size=1' => 'Planner keywords list', - '/system/sites/' => 'Sites list' - ); - - $last_error = ''; - $last_status = 0; - - foreach ($test_endpoints as $endpoint => $description) { - $response = $api->get($endpoint); - - if ($response['success']) { - $checked_at = current_time('timestamp'); - update_option('igny8_last_api_health_check', $checked_at); - wp_send_json_success(array( - 'message' => 'Connection successful (tested: ' . $description . ')', - 'endpoint' => $endpoint, - 'checked_at' => $checked_at - )); - return; - } - - $last_error = $response['error'] ?? 'Unknown error'; - $last_status = $response['http_status'] ?? 0; - } - - // All endpoints failed - wp_send_json_error(array( - 'message' => 'Connection failed: ' . $last_error, - 'http_status' => $last_status, - 'full_error' => $last_error, - 'endpoints_tested' => array_keys($test_endpoints) - )); - } - - /** - * Sync posts to IGNY8 (AJAX handler) - */ - public static function sync_posts() { - check_ajax_referer('igny8_admin_nonce', 'nonce'); - - if (!current_user_can('manage_options')) { - wp_send_json_error(array('message' => 'Unauthorized')); - } - - if (!igny8_is_connection_enabled()) { - wp_send_json_error(array('message' => 'Connection is disabled. Enable sync operations first.')); - } - - $result = igny8_batch_sync_post_statuses(); - - wp_send_json_success(array( - 'message' => sprintf('Synced %d posts, %d failed', $result['synced'], $result['failed']), - 'data' => $result - )); - } - - /** - * Sync taxonomies (AJAX handler) - */ - public static function sync_taxonomies() { - check_ajax_referer('igny8_admin_nonce', 'nonce'); - - if (!current_user_can('manage_options')) { - wp_send_json_error(array('message' => 'Unauthorized')); - } - - if (!igny8_is_connection_enabled()) { - wp_send_json_error(array('message' => 'Connection is disabled. Enable sync operations first.')); - } - - $api = new Igny8API(); - if (!$api->is_authenticated()) { - wp_send_json_error(array('message' => 'Not authenticated')); - } - - // Sync sectors and clusters from IGNY8 - $sectors_result = igny8_sync_igny8_sectors_to_wp(); - $clusters_result = igny8_sync_igny8_clusters_to_wp(); - - wp_send_json_success(array( - 'message' => sprintf('Synced %d sectors, %d clusters', - $sectors_result['synced'] ?? 0, - $clusters_result['synced'] ?? 0 - ), - 'data' => array( - 'sectors' => $sectors_result, - 'clusters' => $clusters_result - ) - )); - } - - /** - * Sync from IGNY8 (AJAX handler) - */ - public static function sync_from_igny8() { - check_ajax_referer('igny8_admin_nonce', 'nonce'); - - if (!current_user_can('manage_options')) { - wp_send_json_error(array('message' => 'Unauthorized')); - } - - if (!igny8_is_connection_enabled()) { - wp_send_json_error(array('message' => 'Connection is disabled. Enable sync operations first.')); - } - - $result = igny8_sync_igny8_tasks_to_wp(); - - if ($result['success']) { - wp_send_json_success(array( - 'message' => sprintf('Created %d posts, updated %d posts', - $result['created'], - $result['updated'] - ), - 'data' => $result - )); - } else { - wp_send_json_error(array( - 'message' => $result['error'] ?? 'Sync failed' - )); - } - } - - /** - * Collect and send site data (AJAX handler) - */ - public static function collect_site_data() { - check_ajax_referer('igny8_admin_nonce', 'nonce'); - - if (!current_user_can('manage_options')) { - wp_send_json_error(array('message' => 'Unauthorized')); - } - - if (!igny8_is_connection_enabled()) { - wp_send_json_error(array('message' => 'Connection is disabled. Enable sync operations first.')); - } - - $site_id = get_option('igny8_site_id'); - if (!$site_id) { - wp_send_json_error(array('message' => 'Site ID not set')); - } - - $result = igny8_send_site_data_to_igny8($site_id); - - if ($result) { - wp_send_json_success(array( - 'message' => 'Site data collected and sent successfully', - 'data' => $result - )); - } else { - wp_send_json_error(array('message' => 'Failed to send site data')); - } - } - - /** - * Get sync statistics (AJAX handler) - */ - public static function get_stats() { - check_ajax_referer('igny8_admin_nonce', 'nonce'); - - if (!current_user_can('manage_options')) { - wp_send_json_error(array('message' => 'Unauthorized')); - } - - global $wpdb; - - // Count synced posts - $synced_posts = $wpdb->get_var(" - SELECT COUNT(DISTINCT post_id) - FROM {$wpdb->postmeta} - WHERE meta_key = '_igny8_task_id' - "); - - // Get last sync time - $last_sync = get_option('igny8_last_site_sync', 0); - $last_sync_formatted = $last_sync ? date_i18n(get_option('date_format') . ' ' . get_option('time_format'), $last_sync) : 'Never'; - - wp_send_json_success(array( - 'synced_posts' => intval($synced_posts), - 'last_sync' => $last_sync_formatted - )); - } - - /** - * Sanitize post types option - * - * @param mixed $value Raw value - * @return array - */ - public function sanitize_post_types($value) { - $supported = array_keys(igny8_get_supported_post_types()); - - if (!is_array($value)) { - return $supported; - } - - $clean = array(); - foreach ($value as $post_type) { - $post_type = sanitize_key($post_type); - if (in_array($post_type, $supported, true)) { - $clean[] = $post_type; - } - } - - return !empty($clean) ? $clean : $supported; - } - - /** - * Sanitize taxonomies option - * - * @param mixed $value Raw value - * @return array - */ - public function sanitize_taxonomies($value) { - $supported = array_keys(igny8_get_supported_taxonomies()); - - if (!is_array($value)) { - return array('category', 'post_tag', 'product_cat', 'igny8_sectors', 'igny8_clusters'); - } - - $clean = array(); - foreach ($value as $taxonomy) { - $taxonomy = sanitize_key($taxonomy); - if (in_array($taxonomy, $supported, true)) { - $clean[] = $taxonomy; - } - } - - // Return defaults if nothing selected - return !empty($clean) ? $clean : array('category', 'post_tag'); - } - - /** - * Sanitize boolean option - * - * @param mixed $value Raw value - * @return int - */ - public function sanitize_boolean($value) { - return $value ? 1 : 0; - } - - /** - * Sanitize control mode - * - * @param mixed $value Raw value - * @return string - */ - public function sanitize_control_mode($value) { - $value = is_string($value) ? strtolower($value) : 'mirror'; - return in_array($value, array('mirror', 'hybrid'), true) ? $value : 'mirror'; - } - - /** - * Sanitize module toggles - * - * @param mixed $value Raw value - * @return array - */ - public function sanitize_modules($value) { - $supported = array_keys(igny8_get_available_modules()); - - if (!is_array($value)) { - return $supported; - } - - $clean = array(); - foreach ($value as $module) { - $module = sanitize_key($module); - if (in_array($module, $supported, true)) { - $clean[] = $module; - } - } - - return !empty($clean) ? $clean : $supported; - } -} - -// Register AJAX handlers -add_action('wp_ajax_igny8_test_connection', array('Igny8Admin', 'test_connection')); -add_action('wp_ajax_igny8_sync_posts', array('Igny8Admin', 'sync_posts')); -add_action('wp_ajax_igny8_sync_taxonomies', array('Igny8Admin', 'sync_taxonomies')); -add_action('wp_ajax_igny8_sync_from_igny8', array('Igny8Admin', 'sync_from_igny8')); -add_action('wp_ajax_igny8_collect_site_data', array('Igny8Admin', 'collect_site_data')); -add_action('wp_ajax_igny8_get_stats', array('Igny8Admin', 'get_stats')); - diff --git a/igny8-wp-plugin/admin/class-post-meta-boxes.php b/igny8-wp-plugin/admin/class-post-meta-boxes.php deleted file mode 100644 index d0d6ebcb..00000000 --- a/igny8-wp-plugin/admin/class-post-meta-boxes.php +++ /dev/null @@ -1,469 +0,0 @@ - admin_url('admin-ajax.php'), - 'nonce' => wp_create_nonce('igny8_post_editor_nonce'), - )); - } - - /** - * Render Planner Brief meta box - */ - public function render_planner_brief_box($post) { - $task_id = get_post_meta($post->ID, '_igny8_task_id', true); - $brief = get_post_meta($post->ID, '_igny8_task_brief', true); - $brief_cached_at = get_post_meta($post->ID, '_igny8_brief_cached_at', true); - $cluster_id = get_post_meta($post->ID, '_igny8_cluster_id', true); - - if (!$task_id && !$cluster_id) { - echo '

'; - _e('This post is not linked to an IGNY8 task or cluster.', 'igny8-bridge'); - echo '

'; - return; - } - - wp_nonce_field('igny8_post_editor_nonce', 'igny8_post_editor_nonce'); - ?> -
- -
- - -

- - - -
- -
- - - -
- - -
    - -
  • - -
- -

- -
- - - -
- - '; - foreach ($keywords as $keyword) { - echo '' . esc_html(trim($keyword)) . ''; - } - echo ''; - ?> -
- - - -
- - -
- - -

- - - -

- -

- -
- -

- -

- -
- -

- - - - - -

- - - ID, '_igny8_task_id', true); - $optimizer_job_id = get_post_meta($post->ID, '_igny8_optimizer_job_id', true); - $optimizer_status = get_post_meta($post->ID, '_igny8_optimizer_status', true); - - if (!$task_id) { - echo '

'; - _e('This post is not linked to an IGNY8 task.', 'igny8-bridge'); - echo '

'; - return; - } - - wp_nonce_field('igny8_post_editor_nonce', 'igny8_post_editor_nonce'); - ?> -
- -
-

- - -

- - -

- - - - -

- - -

- -

-
- -

- -

- -
- -

- -

- - - 'Unauthorized')); - } - - if (!igny8_is_connection_enabled()) { - wp_send_json_error(array('message' => 'Connection is disabled. Enable sync operations first.')); - } - - $post_id = isset($_POST['post_id']) ? intval($_POST['post_id']) : 0; - $task_id = isset($_POST['task_id']) ? intval($_POST['task_id']) : 0; - - if (!$post_id || !$task_id) { - wp_send_json_error(array('message' => 'Invalid post ID or task ID')); - } - - $api = new Igny8API(); - - if (!$api->is_authenticated()) { - wp_send_json_error(array('message' => 'Not authenticated')); - } - - // Try to fetch from Planner first - $response = $api->get("/planner/tasks/{$task_id}/brief/"); - - if (!$response['success']) { - // Fallback to Writer brief - $response = $api->get("/writer/tasks/{$task_id}/brief/"); - } - - if ($response['success'] && !empty($response['data'])) { - update_post_meta($post_id, '_igny8_task_brief', $response['data']); - update_post_meta($post_id, '_igny8_brief_cached_at', current_time('mysql')); - - wp_send_json_success(array( - 'message' => 'Brief fetched successfully', - 'brief' => $response['data'] - )); - } else { - wp_send_json_error(array( - 'message' => 'Failed to fetch brief: ' . ($response['error'] ?? 'Unknown error') - )); - } - } - - /** - * Refresh Planner task (AJAX handler) - */ - public static function refresh_planner_task() { - check_ajax_referer('igny8_post_editor_nonce', 'nonce'); - - if (!current_user_can('edit_posts')) { - wp_send_json_error(array('message' => 'Unauthorized')); - } - - if (!igny8_is_connection_enabled()) { - wp_send_json_error(array('message' => 'Connection is disabled. Enable sync operations first.')); - } - - $post_id = isset($_POST['post_id']) ? intval($_POST['post_id']) : 0; - $task_id = isset($_POST['task_id']) ? intval($_POST['task_id']) : 0; - - if (!$post_id || !$task_id) { - wp_send_json_error(array('message' => 'Invalid post ID or task ID')); - } - - $api = new Igny8API(); - - if (!$api->is_authenticated()) { - wp_send_json_error(array('message' => 'Not authenticated')); - } - - $response = $api->post("/planner/tasks/{$task_id}/refresh/", array( - 'wordpress_post_id' => $post_id, - 'reason' => 'reoptimize', - 'notes' => 'Requested refresh from WordPress editor' - )); - - if ($response['success']) { - wp_send_json_success(array( - 'message' => 'Refresh requested successfully', - 'data' => $response['data'] - )); - } else { - wp_send_json_error(array( - 'message' => 'Failed to request refresh: ' . ($response['error'] ?? 'Unknown error') - )); - } - } - - /** - * Create Optimizer job (AJAX handler) - */ - public static function create_optimizer_job() { - check_ajax_referer('igny8_post_editor_nonce', 'nonce'); - - if (!current_user_can('edit_posts')) { - wp_send_json_error(array('message' => 'Unauthorized')); - } - - if (!igny8_is_connection_enabled()) { - wp_send_json_error(array('message' => 'Connection is disabled. Enable sync operations first.')); - } - - $post_id = isset($_POST['post_id']) ? intval($_POST['post_id']) : 0; - $task_id = isset($_POST['task_id']) ? intval($_POST['task_id']) : 0; - $job_type = isset($_POST['job_type']) ? sanitize_text_field($_POST['job_type']) : 'audit'; - $priority = isset($_POST['priority']) ? sanitize_text_field($_POST['priority']) : 'normal'; - - if (!$post_id || !$task_id) { - wp_send_json_error(array('message' => 'Invalid post ID or task ID')); - } - - $api = new Igny8API(); - - if (!$api->is_authenticated()) { - wp_send_json_error(array('message' => 'Not authenticated')); - } - - $response = $api->post("/optimizer/jobs/", array( - 'post_id' => $post_id, - 'task_id' => $task_id, - 'job_type' => $job_type, - 'priority' => $priority - )); - - if ($response['success'] && !empty($response['data'])) { - $job_id = $response['data']['id'] ?? $response['data']['job_id'] ?? null; - - if ($job_id) { - update_post_meta($post_id, '_igny8_optimizer_job_id', $job_id); - update_post_meta($post_id, '_igny8_optimizer_status', $response['data']['status'] ?? 'pending'); - update_post_meta($post_id, '_igny8_optimizer_job_created_at', current_time('mysql')); - } - - wp_send_json_success(array( - 'message' => 'Optimizer job created successfully', - 'job_id' => $job_id, - 'data' => $response['data'] - )); - } else { - wp_send_json_error(array( - 'message' => 'Failed to create optimizer job: ' . ($response['error'] ?? 'Unknown error') - )); - } - } - - /** - * Get Optimizer job status (AJAX handler) - */ - public static function get_optimizer_status() { - check_ajax_referer('igny8_post_editor_nonce', 'nonce'); - - if (!current_user_can('edit_posts')) { - wp_send_json_error(array('message' => 'Unauthorized')); - } - - if (!igny8_is_connection_enabled()) { - wp_send_json_error(array('message' => 'Connection is disabled. Enable sync operations first.')); - } - - $post_id = isset($_POST['post_id']) ? intval($_POST['post_id']) : 0; - $job_id = isset($_POST['job_id']) ? intval($_POST['job_id']) : 0; - - if (!$post_id || !$job_id) { - wp_send_json_error(array('message' => 'Invalid post ID or job ID')); - } - - $api = new Igny8API(); - - if (!$api->is_authenticated()) { - wp_send_json_error(array('message' => 'Not authenticated')); - } - - $response = $api->get("/optimizer/jobs/{$job_id}/"); - - if ($response['success'] && !empty($response['data'])) { - $status = $response['data']['status'] ?? 'unknown'; - update_post_meta($post_id, '_igny8_optimizer_status', $status); - - if (!empty($response['data']['score_changes'])) { - update_post_meta($post_id, '_igny8_optimizer_score_changes', $response['data']['score_changes']); - } - - if (!empty($response['data']['recommendations'])) { - update_post_meta($post_id, '_igny8_optimizer_recommendations', $response['data']['recommendations']); - } - - wp_send_json_success(array( - 'message' => 'Status retrieved successfully', - 'status' => $status, - 'data' => $response['data'] - )); - } else { - wp_send_json_error(array( - 'message' => 'Failed to get status: ' . ($response['error'] ?? 'Unknown error') - )); - } - } -} - -// Initialize -new Igny8PostMetaBoxes(); - diff --git a/igny8-wp-plugin/admin/settings.php b/igny8-wp-plugin/admin/settings.php deleted file mode 100644 index 5966a944..00000000 --- a/igny8-wp-plugin/admin/settings.php +++ /dev/null @@ -1,701 +0,0 @@ - 10)); - $two_way_sync = (int) get_option('igny8_enable_two_way_sync', 1); - -?> - -
-

- - -
-

-
-
- -

-
- -
-
-

- - - - - - - - - - -
- - - -

- -

-
- - - - - - - - - -
- - - -

- -

-
- -
-
- - -
-
- -
- - -
-

- -
- - - - - - - -
- - - -

- -

-
- - -
- -

- - -

- -

- : - -

- -
-
-

-
-
-
-
-

- -

-
-
-
-
-

- -

-
-
-
-
-

- -

-
-
-
-
-

- -

-
-
-
-
-

- -

-
-
-
-
-

- -

-
-
-
-
-

- -

-
-
-
-
-

- -

-
-
-
-
-
-
-
- -
-

-

- - - -

-

- -

-
- - -
-

- -
- - - - - - - - - - - - - - - - - - - - - - - -
- $label) : ?> - -
- -

- -

-
- $module_label) : ?> - -
- -

- -

-
- -
- -
- - -

- -

- -
- $taxonomy_label) : ?> - -
- -

- -

-
- - -
- -

- -

-
- - -
-

- - - - - - - - - - -
- - -

- -

-
- - -
- - -
-

- -

-
-
- - -
-

-

- -

-

- -

-
- - -
-

- - -
-

-
- -

-
- - - publish + $page_count->publish; - if ($product_count) $total_posts += $product_count->publish; - - $taxonomies = get_taxonomies(['public' => true], 'objects'); - $taxonomy_count = 0; - foreach ($taxonomies as $taxonomy) { - $taxonomy_count += wp_count_terms(['taxonomy' => $taxonomy->name, 'hide_empty' => false]); - } - ?> - -
-
-
- - - -
-

-

- publish, - $page_count->publish, - $product_count ? sprintf(', %d products', $product_count->publish) : '' - ); ?> -

-

- - โฑ - - โฑ - -

- -
- -
-
- - - -
-

-

- -

-

- - โฑ - - โฑ - -

- -
- -
-
- - - -
-

-

- -

-

- - โฑ - - โฑ - -

- -
- -
-
- - - -
-

-

- -

-

- - โฑ - - โฑ - -

- -
-
- -
-
- -
-

- -
-
-
- - - -
-
-
-
-
publish, $page_count->publish); ?>
-
-
- -
-
- - - -
-
-
-
-
-
-
- -
-
- - - -
-
-
-
- - - - - -
-
- - - - - -
-
-
- -
-
- - - -
-
-
-
- - - - - -
-
- - - - - -
-
-
-
- - -
-

-
-
- - -
-
- - -
-
- - -
-
-
- -
- -
-
- diff --git a/igny8-wp-plugin/data/link-graph.php b/igny8-wp-plugin/data/link-graph.php deleted file mode 100644 index 55011eff..00000000 --- a/igny8-wp-plugin/data/link-graph.php +++ /dev/null @@ -1,192 +0,0 @@ -post_content; - $source_url = get_permalink($post_id); - $site_url = get_site_url(); - $links = array(); - - // Match all anchor tags with href attributes - preg_match_all('/]+href=["\']([^"\']+)["\'][^>]*>(.*?)<\/a>/is', $content, $matches, PREG_SET_ORDER); - - foreach ($matches as $match) { - $href = $match[1]; - $anchor = strip_tags($match[2]); - - // Skip empty anchors - if (empty(trim($anchor))) { - continue; - } - - // Only process internal links - if (strpos($href, $site_url) === 0 || strpos($href, '/') === 0) { - // Convert relative URLs to absolute - if (strpos($href, '/') === 0 && strpos($href, '//') !== 0) { - $href = $site_url . $href; - } - - // Normalize URL (remove trailing slash, fragments, query params for matching) - $target_url = rtrim($href, '/'); - - // Skip if source and target are the same - if ($source_url === $target_url) { - continue; - } - - $links[] = array( - 'source_url' => $source_url, - 'target_url' => $target_url, - 'anchor' => trim($anchor), - 'post_id' => $post_id - ); - } - } - - return $links; -} - -/** - * Extract link graph from all posts - * - * @param array $post_ids Optional array of post IDs to process. If empty, processes all enabled posts. - * @return array Link graph array - */ -function igny8_extract_link_graph($post_ids = array()) { - // Skip if connection is disabled - if (!igny8_is_connection_enabled()) { - return array(); - } - - if (function_exists('igny8_is_module_enabled') && !igny8_is_module_enabled('linker')) { - return array(); - } - - $enabled_post_types = igny8_get_enabled_post_types(); - - if (empty($post_ids)) { - // Get all published posts of enabled types - $query_args = array( - 'post_type' => $enabled_post_types, - 'post_status' => 'publish', - 'posts_per_page' => -1, - 'fields' => 'ids', - 'suppress_filters' => true - ); - - $post_ids = get_posts($query_args); - } - - $link_graph = array(); - $processed = 0; - - foreach ($post_ids as $post_id) { - $links = igny8_extract_post_links($post_id); - - if (!empty($links)) { - $link_graph = array_merge($link_graph, $links); - } - - $processed++; - - // Limit processing to prevent timeout (can be increased or made configurable) - if ($processed >= 1000) { - break; - } - } - - return $link_graph; -} - -/** - * Send link graph to IGNY8 Linker module - * - * @param int $site_id IGNY8 site ID - * @param array $link_graph Link graph array (optional, will extract if not provided) - * @return array|false Response data or false on failure - */ -function igny8_send_link_graph_to_igny8($site_id, $link_graph = null) { - // Skip if connection is disabled - if (!igny8_is_connection_enabled()) { - return false; - } - - if (function_exists('igny8_is_module_enabled') && !igny8_is_module_enabled('linker')) { - return false; - } - - $api = new Igny8API(); - - if (!$api->is_authenticated()) { - return false; - } - - // Extract link graph if not provided - if ($link_graph === null) { - $link_graph = igny8_extract_link_graph(); - } - - if (empty($link_graph)) { - return array('success' => true, 'message' => 'No links found', 'links_count' => 0); - } - - // Send in batches (max 500 links per batch) - $batch_size = 500; - $batches = array_chunk($link_graph, $batch_size); - $total_sent = 0; - $errors = array(); - - foreach ($batches as $batch) { - $response = $api->post("/linker/link-map/", array( - 'site_id' => $site_id, - 'links' => $batch, - 'total_links' => count($link_graph), - 'batch_number' => count($batches) > 1 ? (count($batches) - count($batches) + array_search($batch, $batches) + 1) : 1, - 'total_batches' => count($batches) - )); - - if ($response['success']) { - $total_sent += count($batch); - } else { - $errors[] = $response['error'] ?? 'Unknown error'; - } - } - - if ($total_sent > 0) { - update_option('igny8_last_link_graph_sync', current_time('timestamp')); - update_option('igny8_last_link_graph_count', $total_sent); - - return array( - 'success' => true, - 'links_sent' => $total_sent, - 'total_links' => count($link_graph), - 'batches' => count($batches), - 'errors' => $errors - ); - } - - return false; -} - diff --git a/igny8-wp-plugin/data/semantic-mapping.php b/igny8-wp-plugin/data/semantic-mapping.php deleted file mode 100644 index 1aeb58aa..00000000 --- a/igny8-wp-plugin/data/semantic-mapping.php +++ /dev/null @@ -1,225 +0,0 @@ - false, 'error' => 'Connection disabled'); - } - - $api = new Igny8API(); - - if (!$api->is_authenticated()) { - return array('success' => false, 'error' => 'Not authenticated'); - } - - // Extract semantic structure from site data - $semantic_map = array( - 'sectors' => array(), - 'clusters' => array(), - 'keywords' => array() - ); - - // Map taxonomies to sectors - foreach ($site_data['taxonomies'] as $tax_name => $tax_data) { - if ($tax_data['taxonomy']['hierarchical']) { - // Hierarchical taxonomies (categories) become sectors - $sector = array( - 'name' => $tax_data['taxonomy']['label'], - 'slug' => $tax_data['taxonomy']['name'], - 'description' => $tax_data['taxonomy']['description'], - 'source' => 'wordpress_taxonomy', - 'source_id' => $tax_name - ); - - // Map terms to clusters - $clusters = array(); - foreach ($tax_data['terms'] as $term) { - $clusters[] = array( - 'name' => $term['name'], - 'slug' => $term['slug'], - 'description' => $term['description'], - 'source' => 'wordpress_term', - 'source_id' => $term['id'] - ); - - // Extract keywords from posts in this term - $keywords = igny8_extract_keywords_from_term_posts($term['id'], $tax_name); - $semantic_map['keywords'] = array_merge($semantic_map['keywords'], $keywords); - } - - $sector['clusters'] = $clusters; - $semantic_map['sectors'][] = $sector; - } - } - - // Map WooCommerce product categories to sectors - if (!empty($site_data['product_categories'])) { - $product_sector = array( - 'name' => 'Products', - 'slug' => 'products', - 'description' => 'WooCommerce product categories', - 'source' => 'woocommerce', - 'clusters' => array() - ); - - foreach ($site_data['product_categories'] as $category) { - $product_sector['clusters'][] = array( - 'name' => $category['name'], - 'slug' => $category['slug'], - 'description' => $category['description'], - 'source' => 'woocommerce_category', - 'source_id' => $category['id'] - ); - } - - $semantic_map['sectors'][] = $product_sector; - } - - // Send semantic map to IGNY8 - $response = $api->post("/planner/sites/{$site_id}/semantic-map/", array( - 'semantic_map' => $semantic_map, - 'site_data' => $site_data - )); - - return $response; -} - -/** - * Extract keywords from posts associated with a taxonomy term - * - * @param int $term_id Term ID - * @param string $taxonomy Taxonomy name - * @return array Formatted keywords array - */ -function igny8_extract_keywords_from_term_posts($term_id, $taxonomy) { - $args = array( - 'post_type' => 'any', - 'posts_per_page' => -1, - 'tax_query' => array( - array( - 'taxonomy' => $taxonomy, - 'field' => 'term_id', - 'terms' => $term_id - ) - ) - ); - - $query = new WP_Query($args); - $keywords = array(); - - if ($query->have_posts()) { - while ($query->have_posts()) { - $query->the_post(); - - // Extract keywords from post title and content - $title_words = str_word_count(get_the_title(), 1); - $content_words = str_word_count(strip_tags(get_the_content()), 1); - - // Combine and get unique keywords - $all_words = array_merge($title_words, $content_words); - $unique_words = array_unique(array_map('strtolower', $all_words)); - - // Filter out common words (stop words) - $stop_words = array('the', 'a', 'an', 'and', 'or', 'but', 'in', 'on', 'at', 'to', 'for', 'of', 'with', 'by'); - $keywords = array_merge($keywords, array_diff($unique_words, $stop_words)); - } - wp_reset_postdata(); - } - - // Format keywords - $formatted_keywords = array(); - foreach (array_unique($keywords) as $keyword) { - if (strlen($keyword) > 3) { // Only keywords longer than 3 characters - $formatted_keywords[] = array( - 'keyword' => $keyword, - 'source' => 'wordpress_post', - 'source_term_id' => $term_id - ); - } - } - - return $formatted_keywords; -} - -/** - * Complete workflow: Fetch site data โ†’ Map to semantic strategy โ†’ Restructure content - * - * @param int $site_id IGNY8 site ID - * @return array|false Analysis result or false on failure - */ -function igny8_analyze_and_restructure_site($site_id) { - $api = new Igny8API(); - - if (!$api->is_authenticated()) { - return false; - } - - // Step 1: Collect all site data - $site_data = igny8_collect_site_data(); - - // Step 2: Send to IGNY8 for analysis - $analysis_response = $api->post("/system/sites/{$site_id}/analyze/", array( - 'site_data' => $site_data, - 'analysis_type' => 'full_site_restructure' - )); - - if (!$analysis_response['success']) { - return false; - } - - $analysis_id = $analysis_response['data']['analysis_id'] ?? null; - - // Step 3: Map to semantic strategy - $mapping_response = igny8_map_site_to_semantic_strategy($site_id, $site_data); - - if (!$mapping_response['success']) { - return false; - } - - // Step 4: Get restructuring recommendations - $recommendations_response = $api->get("/system/sites/{$site_id}/recommendations/"); - - if (!$recommendations_response['success']) { - return false; - } - - // Get keywords count from mapping response - $keywords_count = 0; - if (isset($mapping_response['data']['keywords'])) { - $keywords_count = count($mapping_response['data']['keywords']); - } - - return array( - 'analysis_id' => $analysis_id, - 'semantic_map' => $mapping_response['data'] ?? null, - 'recommendations' => $recommendations_response['data'] ?? null, - 'site_data_summary' => array( - 'total_posts' => count($site_data['posts']), - 'total_taxonomies' => count($site_data['taxonomies']), - 'total_products' => count($site_data['products'] ?? array()), - 'total_keywords' => $keywords_count - ) - ); -} - diff --git a/igny8-wp-plugin/data/site-collection.php b/igny8-wp-plugin/data/site-collection.php deleted file mode 100644 index a5469734..00000000 --- a/igny8-wp-plugin/data/site-collection.php +++ /dev/null @@ -1,588 +0,0 @@ - 'publish', - 'after' => null, - 'max_pages' => 5, - ); - $args = wp_parse_args($args, $defaults); - - $post_type_object = get_post_type_object($post_type); - $rest_base = ($post_type_object && !empty($post_type_object->rest_base)) ? $post_type_object->rest_base : $post_type; - - $base_url = sprintf('%s/wp-json/wp/v2/%s', get_site_url(), $rest_base); - - $query_args = array( - 'per_page' => min($per_page, 100), - 'status' => $args['status'], - 'orderby' => 'modified', - 'order' => 'desc', - ); - - if (!empty($args['after'])) { - $query_args['after'] = gmdate('c', $args['after']); - } - - $formatted_posts = array(); - $page = 1; - - do { - $query_args['page'] = $page; - $response = wp_remote_get(add_query_arg($query_args, $base_url)); - - if (is_wp_error($response)) { - break; - } - - $posts = json_decode(wp_remote_retrieve_body($response), true); - - if (!is_array($posts) || empty($posts)) { - break; - } - - foreach ($posts as $post) { - $content = $post['content']['rendered'] ?? ''; - $word_count = str_word_count(strip_tags($content)); - - $formatted_posts[] = array( - 'id' => $post['id'], - 'title' => html_entity_decode($post['title']['rendered'] ?? ''), - 'content' => $content, - 'excerpt' => $post['excerpt']['rendered'] ?? '', - 'status' => $post['status'] ?? 'draft', - 'url' => $post['link'] ?? '', - 'published' => $post['date'] ?? '', - 'modified' => $post['modified'] ?? '', - 'author' => $post['author'] ?? 0, - 'post_type' => $post['type'] ?? $post_type, - 'taxonomies' => array( - 'categories' => $post['categories'] ?? array(), - 'tags' => $post['tags'] ?? array(), - ), - 'meta' => array( - 'word_count' => $word_count, - 'reading_time' => $word_count ? ceil($word_count / 200) : 0, - 'featured_media' => $post['featured_media'] ?? 0, - ) - ); - } - - if (count($posts) < $query_args['per_page']) { - break; - } - - $page++; - } while ($page <= $args['max_pages']); - - return $formatted_posts; -} - -/** - * Fetch all available post types from WordPress - * - * @return array|false Post types array or false on failure - */ -function igny8_fetch_all_post_types() { - $wp_response = wp_remote_get(get_site_url() . '/wp-json/wp/v2/types'); - - if (is_wp_error($wp_response)) { - return false; - } - - $types = json_decode(wp_remote_retrieve_body($wp_response), true); - - if (!is_array($types)) { - return false; - } - - $post_types = array(); - foreach ($types as $type_name => $type_data) { - if ($type_data['public']) { - $post_types[] = array( - 'name' => $type_name, - 'label' => $type_data['name'], - 'description' => $type_data['description'] ?? '', - 'rest_base' => $type_data['rest_base'] ?? $type_name - ); - } - } - - return $post_types; -} - -/** - * Fetch all posts from all post types - * - * @param int $per_page Posts per page - * @return array All posts - */ -function igny8_fetch_all_wordpress_posts($per_page = 100) { - $post_types = igny8_fetch_all_post_types(); - - if (!$post_types) { - return array(); - } - - $all_posts = array(); - foreach ($post_types as $type) { - $posts = igny8_fetch_wordpress_posts($type['name'], $per_page); - if ($posts) { - $all_posts = array_merge($all_posts, $posts); - } - } - - return $all_posts; -} - -/** - * Fetch all taxonomies from WordPress - * - * @return array|false Taxonomies array or false on failure - */ -function igny8_fetch_wordpress_taxonomies() { - $wp_response = wp_remote_get(get_site_url() . '/wp-json/wp/v2/taxonomies'); - - if (is_wp_error($wp_response)) { - return false; - } - - $taxonomies = json_decode(wp_remote_retrieve_body($wp_response), true); - - if (!is_array($taxonomies)) { - return false; - } - - $formatted_taxonomies = array(); - foreach ($taxonomies as $tax_name => $tax_data) { - if ($tax_data['public']) { - $formatted_taxonomies[] = array( - 'name' => $tax_name, - 'label' => $tax_data['name'], - 'description' => $tax_data['description'] ?? '', - 'hierarchical' => $tax_data['hierarchical'], - 'rest_base' => $tax_data['rest_base'] ?? $tax_name, - 'object_types' => $tax_data['types'] ?? array() - ); - } - } - - return $formatted_taxonomies; -} - -/** - * Fetch all terms for a specific taxonomy - * - * @param string $taxonomy Taxonomy name - * @param int $per_page Terms per page - * @return array|false Formatted terms array or false on failure - */ -function igny8_fetch_taxonomy_terms($taxonomy, $per_page = 100) { - $taxonomy_obj = get_taxonomy($taxonomy); - $rest_base = ($taxonomy_obj && !empty($taxonomy_obj->rest_base)) ? $taxonomy_obj->rest_base : $taxonomy; - - $base_url = sprintf('%s/wp-json/wp/v2/%s', get_site_url(), $rest_base); - - $formatted_terms = array(); - $page = 1; - - do { - $response = wp_remote_get(add_query_arg(array( - 'per_page' => min($per_page, 100), - 'page' => $page - ), $base_url)); - - if (is_wp_error($response)) { - break; - } - - $terms = json_decode(wp_remote_retrieve_body($response), true); - - if (!is_array($terms) || empty($terms)) { - break; - } - - foreach ($terms as $term) { - $formatted_terms[] = array( - 'id' => $term['id'], - 'name' => $term['name'], - 'slug' => $term['slug'], - 'description' => $term['description'] ?? '', - 'count' => $term['count'], - 'parent' => $term['parent'] ?? 0, - 'taxonomy' => $taxonomy, - 'url' => $term['link'] ?? '' - ); - } - - if (count($terms) < min($per_page, 100)) { - break; - } - - $page++; - } while (true); - - return $formatted_terms; -} - -/** - * Fetch all terms from all taxonomies - * - * @param int $per_page Terms per page - * @return array All terms organized by taxonomy - */ -function igny8_fetch_all_taxonomy_terms($per_page = 100) { - $taxonomies = igny8_fetch_wordpress_taxonomies(); - - if (!$taxonomies) { - return array(); - } - - $all_terms = array(); - foreach ($taxonomies as $taxonomy) { - $terms = igny8_fetch_taxonomy_terms($taxonomy['rest_base'], $per_page); - if ($terms) { - $all_terms[$taxonomy['name']] = $terms; - } - } - - return $all_terms; -} - -/** - * Collect all WordPress site data for IGNY8 semantic mapping - * - * @return array Complete site data - */ -function igny8_collect_site_data($args = array()) { - // Skip if connection is disabled - if (!igny8_is_connection_enabled()) { - return array('disabled' => true, 'reason' => 'connection_disabled'); - } - - if (function_exists('igny8_is_module_enabled') && !igny8_is_module_enabled('sites')) { - return array('disabled' => true); - } - - $settings = igny8_get_site_scan_settings($args); - - $site_data = array( - 'site_url' => get_site_url(), - 'site_name' => get_bloginfo('name'), - 'site_description' => get_bloginfo('description'), - 'collected_at' => current_time('mysql'), - 'settings' => $settings, - 'posts' => array(), - 'taxonomies' => array(), - 'products' => array(), - 'product_categories' => array(), - 'product_attributes' => array() - ); - - foreach ((array) $settings['post_types'] as $post_type) { - if (!post_type_exists($post_type) || !igny8_is_post_type_enabled($post_type)) { - continue; - } - - $posts = igny8_fetch_wordpress_posts($post_type, $settings['per_page'], array( - 'after' => $settings['since'], - 'status' => 'publish' - )); - - if ($posts) { - $site_data['posts'] = array_merge($site_data['posts'], $posts); - } - } - - $tracked_taxonomies = array('category', 'post_tag', 'igny8_sectors', 'igny8_clusters'); - - // Get enabled taxonomies from settings - if (function_exists('igny8_get_enabled_taxonomies')) { - $enabled_taxonomies = igny8_get_enabled_taxonomies(); - if (!empty($enabled_taxonomies)) { - $tracked_taxonomies = $enabled_taxonomies; - } - } - - foreach ($tracked_taxonomies as $taxonomy) { - if (!taxonomy_exists($taxonomy)) { - continue; - } - - $terms = igny8_fetch_taxonomy_terms($taxonomy, 100); - if ($terms) { - $tax_obj = get_taxonomy($taxonomy); - $site_data['taxonomies'][$taxonomy] = array( - 'taxonomy' => array( - 'name' => $taxonomy, - 'label' => $tax_obj ? $tax_obj->label : $taxonomy, - 'description' => $tax_obj->description ?? '', - 'hierarchical' => $tax_obj ? $tax_obj->hierarchical : false, - ), - 'terms' => $terms - ); - } - } - - if (!empty($settings['include_products']) && function_exists('igny8_is_woocommerce_active') && igny8_is_woocommerce_active()) { - require_once IGNY8_BRIDGE_PLUGIN_DIR . 'data/woocommerce.php'; - - $products = igny8_fetch_woocommerce_products(100); - if ($products) { - $site_data['products'] = $products; - } - - $product_categories = igny8_fetch_product_categories(100); - if ($product_categories) { - $site_data['product_categories'] = $product_categories; - } - - $product_attributes = igny8_fetch_product_attributes(); - if ($product_attributes) { - $site_data['product_attributes'] = $product_attributes; - } - } - - // Extract link graph if Linker module is enabled - if (function_exists('igny8_is_module_enabled') && igny8_is_module_enabled('linker')) { - $post_ids = wp_list_pluck($site_data['posts'], 'id'); - $link_graph = igny8_extract_link_graph($post_ids); - - if (!empty($link_graph)) { - $site_data['link_graph'] = $link_graph; - } - } - - $site_data['summary'] = array( - 'posts' => count($site_data['posts']), - 'taxonomies' => count($site_data['taxonomies']), - 'products' => count($site_data['products']), - 'links' => isset($site_data['link_graph']) ? count($site_data['link_graph']) : 0 - ); - - update_option('igny8_last_site_snapshot', array( - 'timestamp' => current_time('timestamp'), - 'summary' => $site_data['summary'] - )); - - return $site_data; -} - -/** - * Send WordPress site data to IGNY8 for semantic strategy mapping - * - * @param int $site_id IGNY8 site ID - * @return array|false Response data or false on failure - */ -function igny8_send_site_data_to_igny8($site_id, $site_data = null, $args = array()) { - // Skip if connection is disabled - if (!igny8_is_connection_enabled()) { - return false; - } - - $api = new Igny8API(); - - if (!$api->is_authenticated()) { - return false; - } - - // Collect all site data if not provided - if (empty($site_data)) { - $site_data = igny8_collect_site_data($args); - } - - if (empty($site_data) || isset($site_data['disabled'])) { - return false; - } - - // Send to IGNY8 API - $response = $api->post("/system/sites/{$site_id}/import/", array( - 'site_data' => $site_data, - 'import_type' => $args['mode'] ?? 'full_site_scan' - )); - - if ($response['success']) { - // Store import ID for tracking - update_option('igny8_last_site_import_id', $response['data']['import_id'] ?? null); - update_option('igny8_last_site_sync', current_time('timestamp')); - - // Send link graph separately to Linker module if available - if (!empty($site_data['link_graph']) && function_exists('igny8_is_module_enabled') && igny8_is_module_enabled('linker')) { - $link_result = igny8_send_link_graph_to_igny8($site_id, $site_data['link_graph']); - if ($link_result) { - error_log(sprintf('IGNY8: Sent %d links to Linker module', $link_result['links_sent'] ?? 0)); - } - } - - return $response['data']; - } else { - error_log("IGNY8: Failed to send site data: " . ($response['error'] ?? 'Unknown error')); - return false; - } -} - -/** - * Sync only changed posts/taxonomies since last sync - * - * @param int $site_id IGNY8 site ID - * @return array|false Sync result or false on failure - */ -function igny8_sync_incremental_site_data($site_id, $settings = array()) { - // Skip if connection is disabled - if (!igny8_is_connection_enabled()) { - return array('synced' => 0, 'message' => 'Connection disabled'); - } - - $api = new Igny8API(); - - if (!$api->is_authenticated()) { - return false; - } - - $settings = igny8_get_site_scan_settings(wp_parse_args($settings, array('mode' => 'incremental'))); - $since = $settings['since'] ?? intval(get_option('igny8_last_site_sync', 0)); - - $formatted_posts = array(); - - foreach ((array) $settings['post_types'] as $post_type) { - if (!post_type_exists($post_type) || !igny8_is_post_type_enabled($post_type)) { - continue; - } - - $query_args = array( - 'post_type' => $post_type, - 'post_status' => array('publish', 'pending', 'draft', 'future'), - 'posts_per_page' => -1, - 'orderby' => 'modified', - 'order' => 'DESC', - 'suppress_filters' => true, - ); - - if ($since) { - $query_args['date_query'] = array( - array( - 'column' => 'post_modified_gmt', - 'after' => gmdate('Y-m-d H:i:s', $since) - ) - ); - } - - $posts = get_posts($query_args); - - foreach ($posts as $post) { - $word_count = str_word_count(strip_tags($post->post_content)); - - $formatted_posts[] = array( - 'id' => $post->ID, - 'title' => get_the_title($post), - 'content' => $post->post_content, - 'status' => $post->post_status, - 'modified' => $post->post_modified_gmt, - 'post_type' => $post->post_type, - 'url' => get_permalink($post), - 'taxonomies' => array( - 'categories' => wp_get_post_terms($post->ID, 'category', array('fields' => 'ids')), - 'tags' => wp_get_post_terms($post->ID, 'post_tag', array('fields' => 'ids')), - ), - 'meta' => array( - 'task_id' => get_post_meta($post->ID, '_igny8_task_id', true), - 'cluster_id' => get_post_meta($post->ID, '_igny8_cluster_id', true), - 'sector_id' => get_post_meta($post->ID, '_igny8_sector_id', true), - 'word_count' => $word_count, - ) - ); - } - } - - if (empty($formatted_posts)) { - return array('synced' => 0, 'message' => 'No changes since last sync'); - } - - $response = $api->post("/system/sites/{$site_id}/sync/", array( - 'posts' => $formatted_posts, - 'sync_type' => 'incremental', - 'last_sync' => $since, - 'post_types' => $settings['post_types'] - )); - - if ($response['success']) { - update_option('igny8_last_site_sync', current_time('timestamp')); - update_option('igny8_last_incremental_site_sync', array( - 'timestamp' => current_time('timestamp'), - 'count' => count($formatted_posts) - )); - - return array( - 'synced' => count($formatted_posts), - 'message' => 'Incremental sync completed' - ); - } - - return false; -} - -/** - * Run a full site scan and semantic mapping - * - * @param int $site_id IGNY8 site ID - * @param array $settings Scan settings - * @return array|false - */ -function igny8_perform_full_site_scan($site_id, $settings = array()) { - $site_data = igny8_collect_site_data($settings); - - if (empty($site_data) || isset($site_data['disabled'])) { - return false; - } - - $import = igny8_send_site_data_to_igny8($site_id, $site_data, array('mode' => 'full_site_scan')); - - if (!$import) { - return false; - } - - update_option('igny8_last_full_site_scan', current_time('timestamp')); - - // Map to semantic strategy (requires Planner module) - if (!function_exists('igny8_is_module_enabled') || igny8_is_module_enabled('planner')) { - $map_response = igny8_map_site_to_semantic_strategy($site_id, $site_data); - if (!empty($map_response['success'])) { - update_option('igny8_last_semantic_map', current_time('timestamp')); - update_option('igny8_last_semantic_map_summary', array( - 'sectors' => count($map_response['data']['sectors'] ?? array()), - 'keywords' => count($map_response['data']['keywords'] ?? array()) - )); - } - } - - // Send link graph to Linker module if available - if (!empty($site_data['link_graph']) && function_exists('igny8_is_module_enabled') && igny8_is_module_enabled('linker')) { - $link_result = igny8_send_link_graph_to_igny8($site_id, $site_data['link_graph']); - if ($link_result) { - error_log(sprintf('IGNY8: Sent %d links to Linker module during full scan', $link_result['links_sent'] ?? 0)); - } - } - - return $import; -} - diff --git a/igny8-wp-plugin/data/woocommerce.php b/igny8-wp-plugin/data/woocommerce.php deleted file mode 100644 index 7f01218e..00000000 --- a/igny8-wp-plugin/data/woocommerce.php +++ /dev/null @@ -1,226 +0,0 @@ - $headers - )); - - if (is_wp_error($wp_response)) { - return false; - } - - $products = json_decode(wp_remote_retrieve_body($wp_response), true); - - if (!is_array($products)) { - return false; - } - - $formatted_products = array(); - foreach ($products as $product) { - $formatted_products[] = array( - 'id' => $product['id'], - 'name' => $product['name'], - 'slug' => $product['slug'], - 'sku' => $product['sku'], - 'type' => $product['type'], - 'status' => $product['status'], - 'description' => $product['description'], - 'short_description' => $product['short_description'], - 'price' => $product['price'], - 'regular_price' => $product['regular_price'], - 'sale_price' => $product['sale_price'], - 'on_sale' => $product['on_sale'], - 'stock_status' => $product['stock_status'], - 'stock_quantity' => $product['stock_quantity'], - 'categories' => $product['categories'] ?? array(), - 'tags' => $product['tags'] ?? array(), - 'images' => $product['images'] ?? array(), - 'attributes' => $product['attributes'] ?? array(), - 'variations' => $product['variations'] ?? array(), - 'url' => $product['permalink'] - ); - } - - return $formatted_products; -} - -/** - * Fetch WooCommerce product categories - * - * @param int $per_page Categories per page - * @return array|false Formatted categories array or false on failure - */ -function igny8_fetch_product_categories($per_page = 100) { - if (!igny8_is_woocommerce_active()) { - return false; - } - - $consumer_key = get_option('woocommerce_api_consumer_key', ''); - $consumer_secret = get_option('woocommerce_api_consumer_secret', ''); - - $headers = array(); - if ($consumer_key && $consumer_secret) { - $headers['Authorization'] = 'Basic ' . base64_encode($consumer_key . ':' . $consumer_secret); - } - - $wp_response = wp_remote_get(sprintf( - '%s/wp-json/wc/v3/products/categories?per_page=%d', - get_site_url(), - $per_page - ), array( - 'headers' => $headers - )); - - if (is_wp_error($wp_response)) { - return false; - } - - $categories = json_decode(wp_remote_retrieve_body($wp_response), true); - - if (!is_array($categories)) { - return false; - } - - $formatted_categories = array(); - foreach ($categories as $category) { - $formatted_categories[] = array( - 'id' => $category['id'], - 'name' => $category['name'], - 'slug' => $category['slug'], - 'description' => $category['description'] ?? '', - 'count' => $category['count'], - 'parent' => $category['parent'] ?? 0, - 'image' => $category['image']['src'] ?? null - ); - } - - return $formatted_categories; -} - -/** - * Fetch WooCommerce product attributes - * - * @return array|false Formatted attributes array or false on failure - */ -function igny8_fetch_product_attributes() { - if (!igny8_is_woocommerce_active()) { - return false; - } - - $consumer_key = get_option('woocommerce_api_consumer_key', ''); - $consumer_secret = get_option('woocommerce_api_consumer_secret', ''); - - $headers = array(); - if ($consumer_key && $consumer_secret) { - $headers['Authorization'] = 'Basic ' . base64_encode($consumer_key . ':' . $consumer_secret); - } - - $wp_response = wp_remote_get( - get_site_url() . '/wp-json/wc/v3/products/attributes', - array( - 'headers' => $headers - ) - ); - - if (is_wp_error($wp_response)) { - return false; - } - - $attributes = json_decode(wp_remote_retrieve_body($wp_response), true); - - if (!is_array($attributes)) { - return false; - } - - $formatted_attributes = array(); - foreach ($attributes as $attribute) { - // Get attribute terms - $terms_response = wp_remote_get(sprintf( - '%s/wp-json/wc/v3/products/attributes/%d/terms', - get_site_url(), - $attribute['id'] - ), array( - 'headers' => $headers - )); - - $terms = array(); - if (!is_wp_error($terms_response)) { - $terms_data = json_decode(wp_remote_retrieve_body($terms_response), true); - if (is_array($terms_data)) { - foreach ($terms_data as $term) { - $terms[] = array( - 'id' => $term['id'], - 'name' => $term['name'], - 'slug' => $term['slug'] - ); - } - } - } - - $formatted_attributes[] = array( - 'id' => $attribute['id'], - 'name' => $attribute['name'], - 'slug' => $attribute['slug'], - 'type' => $attribute['type'], - 'order_by' => $attribute['order_by'], - 'has_archives' => $attribute['has_archives'], - 'terms' => $terms - ); - } - - return $formatted_attributes; -} - diff --git a/igny8-wp-plugin/docs/PHASE_5_IMPLEMENTATION_SUMMARY.md b/igny8-wp-plugin/docs/PHASE_5_IMPLEMENTATION_SUMMARY.md deleted file mode 100644 index eec33324..00000000 --- a/igny8-wp-plugin/docs/PHASE_5_IMPLEMENTATION_SUMMARY.md +++ /dev/null @@ -1,185 +0,0 @@ -# Phase 5 Implementation Summary - -## Overview -Phase 5 implementation adds Planner, Linker, and Optimizer module hooks to the WordPress bridge plugin. - -## Implemented Features - -### 5.1 Planner Briefs Display & Refresh Actions โœ… - -**Files Created:** -- `admin/class-post-meta-boxes.php` - Meta boxes for post editor -- `admin/assets/js/post-editor.js` - JavaScript for AJAX interactions - -**Features:** -- **Planner Brief Meta Box** in post editor sidebar - - Displays cached brief with title, content, outline, keywords, and tone - - Shows cache timestamp - - "Fetch Brief" button to load from IGNY8 API - - "Request Refresh" button to trigger Planner refresh - -**API Endpoints Used:** -- `GET /planner/tasks/{id}/brief/` - Fetch Planner brief (with fallback to Writer brief) -- `POST /planner/tasks/{id}/refresh/` - Request Planner task refresh - -**Meta Fields Added:** -- `_igny8_task_brief` - Cached brief data -- `_igny8_brief_cached_at` - Brief cache timestamp - -**AJAX Handlers:** -- `igny8_fetch_planner_brief` - Fetches and caches brief -- `igny8_refresh_planner_task` - Requests Planner refresh - ---- - -### 5.2 Link Graph Export โœ… - -**Files Created:** -- `data/link-graph.php` - Link graph extraction and export - -**Features:** -- **Link Extraction** from post content - - Extracts all internal links (anchor tags) - - Captures source URL, target URL, and anchor text - - Filters to only internal links (same domain) - - Normalizes URLs for consistency - -- **Link Graph Collection** - - Processes all enabled post types - - Extracts links from published posts - - Configurable batch processing (max 1000 posts per run) - -- **Automatic Export During Site Scans** - - Integrated into `igny8_collect_site_data()` - - Included in site data payload - - Also sent separately to Linker module endpoint - -**API Endpoints Used:** -- `POST /linker/link-map/` - Send link graph to Linker module - -**Functions:** -- `igny8_extract_post_links($post_id)` - Extract links from single post -- `igny8_extract_link_graph($post_ids)` - Extract links from multiple posts -- `igny8_send_link_graph_to_igny8($site_id, $link_graph)` - Send to IGNY8 API - -**Integration Points:** -- `igny8_collect_site_data()` - Includes link graph in site data -- `igny8_send_site_data_to_igny8()` - Sends link graph after site import -- `igny8_perform_full_site_scan()` - Sends link graph during full scans - -**Options Stored:** -- `igny8_last_link_graph_sync` - Last sync timestamp -- `igny8_last_link_graph_count` - Number of links sent - ---- - -### 5.4 Optimizer Triggers โœ… - -**Features:** -- **Optimizer Meta Box** in post editor sidebar - - Displays current optimizer job ID and status - - "Request Optimization" button to create new job - - "Check Status" button to fetch latest job status - - Shows score changes and recommendations when available - -**API Endpoints Used:** -- `POST /optimizer/jobs/` - Create optimizer job -- `GET /optimizer/jobs/{id}/` - Get optimizer job status - -**Meta Fields Added:** -- `_igny8_optimizer_job_id` - Optimizer job ID -- `_igny8_optimizer_status` - Job status (pending, processing, completed, failed) -- `_igny8_optimizer_score_changes` - Score changes from optimization -- `_igny8_optimizer_recommendations` - Optimization recommendations -- `_igny8_optimizer_job_created_at` - Job creation timestamp - -**AJAX Handlers:** -- `igny8_create_optimizer_job` - Creates new optimizer job -- `igny8_get_optimizer_status` - Fetches job status and updates meta - -**Job Parameters:** -- `post_id` - WordPress post ID -- `task_id` - IGNY8 task ID -- `job_type` - Type of job (default: 'audit') -- `priority` - Job priority (default: 'normal') - ---- - -## Module Toggle Support - -All Phase 5 features respect the module toggle settings: -- **Planner** module must be enabled for brief fetching/refresh -- **Linker** module must be enabled for link graph export -- **Optimizer** module must be enabled for optimizer jobs - -Features also check `igny8_is_connection_enabled()` to ensure sync operations are active. - ---- - -## UI/UX Features - -### Post Editor Meta Boxes -- Clean, organized display in sidebar -- Real-time AJAX updates -- Success/error message display -- Auto-refresh after operations -- Disabled state when connection is off - -### JavaScript Enhancements -- Loading states on buttons -- Confirmation dialogs for destructive actions -- Error handling and user feedback -- Non-blocking AJAX requests - ---- - -## Integration with Existing Code - -### Modified Files: -- `igny8-bridge.php` - Added meta boxes class loading -- `includes/functions.php` - Added optimizer meta field registrations -- `data/site-collection.php` - Integrated link graph extraction - -### New Dependencies: -- None (uses existing Igny8API class) - ---- - -## Testing Checklist - -- [ ] Planner brief displays correctly in post editor -- [ ] Fetch brief button works and caches data -- [ ] Request refresh button triggers Planner refresh -- [ ] Link graph extraction works on posts with links -- [ ] Link graph is included in site scans -- [ ] Link graph is sent to Linker endpoint -- [ ] Optimizer job creation works -- [ ] Optimizer status check works -- [ ] All features respect module toggles -- [ ] All features respect connection enabled toggle -- [ ] Meta boxes only show for posts with task IDs -- [ ] Error handling works correctly - ---- - -## Notes - -1. **Link Graph Processing**: Currently limited to 1000 posts per run to prevent timeouts. Can be increased or made configurable. - -2. **Brief Caching**: Briefs are cached in post meta to reduce API calls. Cache can be refreshed manually. - -3. **Optimizer Jobs**: Jobs are created asynchronously. Status must be checked manually or via webhook (Phase 6). - -4. **Module Dependencies**: All features check module enablement before executing. - -5. **Connection Toggle**: All features respect the master connection toggle added earlier. - ---- - -## Next Steps (Phase 6) - -Phase 5.3 (Accept link recommendations via webhook) is deferred to Phase 6, which will implement: -- REST endpoint `/wp-json/igny8/v1/event` with shared secret -- Webhook handler for link recommendations -- Link insertion queue system - diff --git a/igny8-wp-plugin/docs/PHASE_6_IMPLEMENTATION_SUMMARY.md b/igny8-wp-plugin/docs/PHASE_6_IMPLEMENTATION_SUMMARY.md deleted file mode 100644 index 827c88b9..00000000 --- a/igny8-wp-plugin/docs/PHASE_6_IMPLEMENTATION_SUMMARY.md +++ /dev/null @@ -1,298 +0,0 @@ -# Phase 6 Implementation Summary - -## Overview -Phase 6 implementation adds webhook support and remote control capabilities, allowing IGNY8 SaaS to send events to WordPress. - -## Implemented Features - -### 6.1 REST Route Registration with Shared Secret โœ… - -**Files Created:** -- `includes/class-igny8-webhooks.php` - Main webhook handler class - -**Features:** -- **REST Endpoint**: `/wp-json/igny8/v1/event` (POST) -- **Shared Secret Authentication**: HMAC-SHA256 signature verification -- **Connection Check**: All webhook handlers verify `igny8_is_connection_enabled()` before processing - -**Security:** -- Webhook secret stored in WordPress options (auto-generated on first use) -- Signature verification via `X-IGNY8-Signature` header -- Secret can be regenerated from settings page -- Failed authentication attempts are logged - -**Functions:** -- `igny8_get_webhook_secret()` - Get or generate webhook secret -- `igny8_regenerate_webhook_secret()` - Regenerate secret - ---- - -### 6.2 SaaS Event Handlers โœ… - -**Event Types Supported:** - -#### 1. Task Published (`task_published`, `task_completed`) -- Creates or updates WordPress post from IGNY8 task -- Fetches full task data from Writer API -- Respects enabled post types -- Updates post status if task is completed - -#### 2. Link Recommendation (`link_recommendation`, `insert_link`) -- Queues link insertion for processing -- Validates required parameters (post_id, target_url, anchor) -- Respects Linker module toggle -- Processes links asynchronously via cron - -#### 3. Optimizer Request (`optimizer_request`, `optimizer_job_completed`) -- Updates optimizer job status -- Stores score changes and recommendations -- Updates post meta with optimizer data -- Respects Optimizer module toggle - -**Event Handler Flow:** -1. Verify connection is enabled -2. Verify module is enabled (if applicable) -3. Validate event data -4. Process event -5. Log activity -6. Return unified JSON response - ---- - -### 6.3 Webhook Activity Logging โœ… - -**Files Created:** -- `includes/class-igny8-webhook-logs.php` - Logging functions - -**Features:** -- **Log Storage**: WordPress options (last 500 logs) -- **Log Fields**: - - Event type - - Event data - - IP address - - User agent - - Status (received, processed, failed) - - Response data - - Timestamps (received_at, processed_at) - - Error messages - -**Functions:** -- `igny8_log_webhook_activity()` - Log webhook receipt -- `igny8_update_webhook_log()` - Update log with processing result -- `igny8_get_webhook_logs()` - Retrieve logs with filtering -- `igny8_clear_old_webhook_logs()` - Cleanup old logs - -**UI Display:** -- Recent webhook activity table in settings page -- Shows last 10 webhook events -- Displays event type, status, and timestamp - ---- - -### Link Queue System โœ… - -**Files Created:** -- `includes/class-igny8-link-queue.php` - Link insertion queue - -**Features:** -- **Queue Storage**: WordPress options -- **Queue Processing**: Cron-based (processes 10 items per run) -- **Retry Logic**: Up to 3 attempts per link -- **Status Tracking**: pending, completed, failed - -**Link Insertion Logic:** -1. Finds anchor text in post content -2. Wraps anchor with link tag -3. Avoids duplicate links -4. Falls back to appending link if anchor not found - -**Queue Management:** -- Automatic processing via cron -- Manual trigger available -- Queue size limit (1000 items) -- Status tracking per item - ---- - -## Connection Checks - -**All handlers check connection status:** - -โœ… **Webhook Handler** (`verify_webhook_secret`) -- Checks `igny8_is_connection_enabled()` before allowing webhook - -โœ… **Event Handlers** (`handle_webhook`, `handle_task_published`, etc.) -- Double-checks connection enabled before processing -- Returns error if connection disabled - -โœ… **Link Queue** (`igny8_queue_link_insertion`, `igny8_process_link_queue`) -- Checks connection enabled before queuing/processing - -โœ… **REST API Endpoints** (existing endpoints) -- Updated to check connection enabled -- Returns 403 if connection disabled - ---- - -## Settings UI Enhancements - -**New Sections Added:** - -1. **Webhook Configuration** - - Webhook URL display with copy button - - Webhook secret display with copy button - - Regenerate secret button - -2. **Link Queue** - - Shows pending links count - - Displays queue table (last 10 items) - - Shows post ID, anchor, target URL, status - -3. **Recent Webhook Activity** - - Shows last 10 webhook events - - Displays event type, status, timestamp - - Color-coded status badges - ---- - -## Security Features - -1. **HMAC Signature Verification** - - Uses SHA-256 HMAC - - Compares request body signature - - Prevents replay attacks - -2. **Connection Toggle Protection** - - All endpoints check connection status - - Webhooks rejected if connection disabled - - Clear error messages - -3. **Module Toggle Respect** - - Events only processed if module enabled - - Graceful error responses - -4. **Input Validation** - - All parameters sanitized - - Required fields validated - - Type checking - ---- - -## API Response Format - -All webhook responses follow unified JSON format: - -**Success:** -```json -{ - "success": true, - "message": "Event processed", - "data": { ... } -} -``` - -**Error:** -```json -{ - "success": false, - "error": "Error message", - "code": "error_code" -} -``` - ---- - -## Integration Points - -### Modified Files: -- `igny8-bridge.php` - Added webhook classes loading -- `includes/functions.php` - Added webhook secret functions -- `includes/class-igny8-rest-api.php` - Added connection checks -- `admin/settings.php` - Added webhook UI sections -- `admin/class-admin.php` - Added secret regeneration handler - -### New Dependencies: -- None (uses existing WordPress functions) - ---- - -## Testing Checklist - -- [ ] Webhook endpoint accessible at `/wp-json/igny8/v1/event` -- [ ] Signature verification works correctly -- [ ] Invalid signatures are rejected -- [ ] Connection disabled blocks webhooks -- [ ] Task published event creates/updates posts -- [ ] Link recommendation queues links -- [ ] Link queue processes links correctly -- [ ] Optimizer events update post meta -- [ ] Webhook logs are created and updated -- [ ] Settings UI displays webhook info -- [ ] Secret regeneration works -- [ ] All events respect module toggles -- [ ] All events respect connection toggle - ---- - -## Notes - -1. **Webhook Secret**: Auto-generated on first use. Must be configured in IGNY8 SaaS app. - -2. **Link Queue**: Processes 10 items per cron run to prevent timeouts. Can be adjusted. - -3. **Log Retention**: Keeps last 500 logs. Older logs can be cleared manually. - -4. **Signature Header**: IGNY8 SaaS must send `X-IGNY8-Signature` header with HMAC-SHA256 signature of request body. - -5. **Connection Toggle**: All webhook handlers check connection status before processing. This ensures no data is processed when connection is disabled. - -6. **Module Toggles**: Each event type checks if its module is enabled before processing. - ---- - -## Webhook Payload Examples - -### Task Published -```json -{ - "event": "task_published", - "data": { - "task_id": 123, - "status": "completed" - } -} -``` - -### Link Recommendation -```json -{ - "event": "link_recommendation", - "data": { - "post_id": 456, - "target_url": "https://example.com/page", - "anchor": "example link", - "priority": "normal" - } -} -``` - -### Optimizer Request -```json -{ - "event": "optimizer_job_completed", - "data": { - "post_id": 456, - "job_id": 789, - "status": "completed", - "score_changes": { ... }, - "recommendations": [ ... ] - } -} -``` - ---- - -## Next Steps - -Phase 6 is complete. All webhook functionality is implemented with proper security, logging, and connection checks. - diff --git a/igny8-wp-plugin/docs/STATUS_SYNC_DOCUMENTATION.md b/igny8-wp-plugin/docs/STATUS_SYNC_DOCUMENTATION.md deleted file mode 100644 index 14591a62..00000000 --- a/igny8-wp-plugin/docs/STATUS_SYNC_DOCUMENTATION.md +++ /dev/null @@ -1,249 +0,0 @@ -# Status Sync & Content ID Documentation - -**Last Updated**: 2025-10-17 - ---- - -## Overview - -This document explains how the plugin handles status synchronization and content_id tracking between IGNY8 and WordPress. - ---- - -## Status Mapping - -### IGNY8 โ†’ WordPress - -When content arrives from IGNY8, status is mapped as follows: - -| IGNY8 Status | WordPress Status | Description | -|--------------|------------------|-------------| -| `completed` | `publish` | Content is published | -| `draft` | `draft` | Content is draft | -| `pending` | `pending` | Content pending review | -| `scheduled` | `future` | Content scheduled | -| `archived` | `trash` | Content archived | - -### WordPress โ†’ IGNY8 - -When WordPress post status changes, it's mapped back to IGNY8: - -| WordPress Status | IGNY8 Status | Description | -|------------------|--------------|-------------| -| `publish` | `completed` | Post is published | -| `draft` | `draft` | Post is draft | -| `pending` | `pending` | Post pending review | -| `private` | `completed` | Post is private (published) | -| `trash` | `archived` | Post is deleted | -| `future` | `scheduled` | Post is scheduled | - ---- - -## Content ID Tracking - -### Storage - -The plugin stores IGNY8 `content_id` in post meta: -- **Meta Key**: `_igny8_content_id` -- **Type**: Integer -- **REST API**: Available via `/wp-json/wp/v2/posts?meta_key=_igny8_content_id&meta_value=123` - -### Task ID Tracking - -The plugin also stores IGNY8 `task_id`: -- **Meta Key**: `_igny8_task_id` -- **Type**: Integer -- **REST API**: Available via `/wp-json/wp/v2/posts?meta_key=_igny8_task_id&meta_value=456` - ---- - -## Response to IGNY8 - -When content is created/updated in WordPress, the plugin responds to IGNY8 with: - -```json -{ - "assigned_post_id": 123, - "post_url": "https://example.com/post/", - "wordpress_status": "publish", - "status": "completed", - "synced_at": "2025-10-17 12:00:00", - "post_type": "post", - "content_type": "post", - "content_id": 789 -} -``` - -### Response Fields - -- **`assigned_post_id`**: WordPress post ID -- **`post_url`**: Full URL to the post -- **`wordpress_status`**: Actual WordPress status (publish/pending/draft) -- **`status`**: IGNY8 mapped status (completed/pending/draft) -- **`synced_at`**: Timestamp of sync -- **`post_type`**: WordPress post type -- **`content_type`**: IGNY8 content type -- **`content_id`**: IGNY8 content ID (if provided) - ---- - -## REST API Endpoints - -The plugin provides REST API endpoints for IGNY8 to query WordPress: - -### 1. Get Post by Content ID - -**Endpoint**: `GET /wp-json/igny8/v1/post-by-content-id/{content_id}` - -**Response**: -```json -{ - "success": true, - "data": { - "post_id": 123, - "title": "Post Title", - "status": "publish", - "wordpress_status": "publish", - "igny8_status": "completed", - "url": "https://example.com/post/", - "post_type": "post", - "content_id": 789, - "task_id": 456, - "last_synced": "2025-10-17 12:00:00" - } -} -``` - -### 2. Get Post by Task ID - -**Endpoint**: `GET /wp-json/igny8/v1/post-by-task-id/{task_id}` - -**Response**: Same format as above - -### 3. Get Post Status by Content ID - -**Endpoint**: `GET /wp-json/igny8/v1/post-status/{content_id}` - -**Response**: -```json -{ - "success": true, - "data": { - "post_id": 123, - "wordpress_status": "publish", - "igny8_status": "completed", - "status_mapping": { - "publish": "completed", - "draft": "draft", - "pending": "pending", - "private": "completed", - "trash": "archived", - "future": "scheduled" - }, - "content_id": 789, - "url": "https://example.com/post/", - "last_synced": "2025-10-17 12:00:00" - } -} -``` - ---- - -## Status Flow - -### When Content Arrives from IGNY8 - -1. **Receive** content with `content_type`, `status`, `content_id`, `task_id` -2. **Map** IGNY8 status to WordPress status -3. **Create** WordPress post with mapped status -4. **Store** `content_id` and `task_id` in post meta -5. **Respond** to IGNY8 with: - - WordPress post ID - - WordPress actual status - - IGNY8 mapped status - - Post URL - - Content ID - -### When WordPress Status Changes - -1. **Detect** status change via `save_post` or `transition_post_status` hook -2. **Get** `task_id` and `content_id` from post meta -3. **Map** WordPress status to IGNY8 status -4. **Update** IGNY8 task with: - - WordPress actual status - - IGNY8 mapped status - - Post URL - - Content ID (if available) - - Sync timestamp - ---- - -## Available Meta Fields - -All fields are available for IGNY8 to read via REST API: - -- `_igny8_task_id` - IGNY8 task ID -- `_igny8_content_id` - IGNY8 content ID -- `_igny8_cluster_id` - IGNY8 cluster ID -- `_igny8_sector_id` - IGNY8 sector ID -- `_igny8_keyword_ids` - Array of keyword IDs -- `_igny8_wordpress_status` - WordPress post status -- `_igny8_last_synced` - Last sync timestamp - ---- - -## Query Examples - -### Via WordPress REST API - -```bash -# Get post by content_id -GET /wp-json/wp/v2/posts?meta_key=_igny8_content_id&meta_value=123 - -# Get post by task_id -GET /wp-json/wp/v2/posts?meta_key=_igny8_task_id&meta_value=456 - -# Get all IGNY8 posts -GET /wp-json/wp/v2/posts?meta_key=_igny8_task_id -``` - -### Via IGNY8 REST API Endpoints - -```bash -# Get post by content_id (with status info) -GET /wp-json/igny8/v1/post-by-content-id/123 - -# Get post status only -GET /wp-json/igny8/v1/post-status/123 - -# Get post by task_id -GET /wp-json/igny8/v1/post-by-task-id/456 -``` - ---- - -## Authentication - -REST API endpoints require: -- IGNY8 API authentication (access token) -- Authorization header: `Bearer {access_token}` - -Or internal use when IGNY8 is connected. - ---- - -## Status Flags Available - -โœ… **Task ID** - Stored and queryable -โœ… **Content ID** - Stored and queryable -โœ… **WordPress Status** - Stored and sent to IGNY8 -โœ… **IGNY8 Status** - Mapped and sent to IGNY8 -โœ… **Post Type** - Stored and sent to IGNY8 -โœ… **Content Type** - Stored and sent to IGNY8 -โœ… **Sync Timestamp** - Stored and sent to IGNY8 -โœ… **Post URL** - Sent to IGNY8 - ---- - -**All status information is available for IGNY8 to read and query!** - diff --git a/igny8-wp-plugin/docs/STYLE_GUIDE.md b/igny8-wp-plugin/docs/STYLE_GUIDE.md deleted file mode 100644 index 059cd8ee..00000000 --- a/igny8-wp-plugin/docs/STYLE_GUIDE.md +++ /dev/null @@ -1,186 +0,0 @@ -# Style Guide - IGNY8 WordPress Bridge - -**Last Updated**: 2025-10-17 - ---- - -## CSS Architecture - -### No Inline CSS Policy - -โœ… **All styles are in `admin/assets/css/admin.css`** -โŒ **No inline `style=""` attributes** -โŒ **No `