fixing issues of integration with wordpress plugin
This commit is contained in:
371
docs/40-WORKFLOWS/SCHEDULED-CONTENT-PUBLISHING.md
Normal file
371
docs/40-WORKFLOWS/SCHEDULED-CONTENT-PUBLISHING.md
Normal file
@@ -0,0 +1,371 @@
|
||||
# Scheduled Content Publishing Workflow
|
||||
|
||||
**Last Updated:** January 12, 2026
|
||||
**Module:** Publishing / Automation
|
||||
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
IGNY8 provides automated content publishing to WordPress sites. Content goes through a scheduling process before being published at the designated time.
|
||||
|
||||
---
|
||||
|
||||
## Content Lifecycle for Publishing
|
||||
|
||||
### Understanding Content.status vs Content.site_status
|
||||
|
||||
Content has **TWO separate status fields**:
|
||||
|
||||
1. **`status`** - Editorial workflow status
|
||||
- `draft` - Being created/edited
|
||||
- `review` - Submitted for review
|
||||
- `approved` - Ready for publishing
|
||||
- `published` - Legacy (not used for external publishing)
|
||||
|
||||
2. **`site_status`** - External site publishing status
|
||||
- `not_published` - Not yet published to WordPress
|
||||
- `scheduled` - Has a scheduled_publish_at time
|
||||
- `publishing` - Currently being published
|
||||
- `published` - Successfully published to WordPress
|
||||
- `failed` - Publishing failed
|
||||
|
||||
### Publishing Flow
|
||||
|
||||
```
|
||||
┌─────────────────┐
|
||||
│ DRAFT │ ← Content is being created/edited
|
||||
│ status: draft │
|
||||
└────────┬────────┘
|
||||
│ User approves content
|
||||
▼
|
||||
┌─────────────────┐
|
||||
│ APPROVED │ ← Content is ready for publishing
|
||||
│ status: approved│ status='approved', site_status='not_published'
|
||||
│ site_status: │
|
||||
│ not_published │
|
||||
└────────┬────────┘
|
||||
│ Hourly: schedule_approved_content task
|
||||
▼
|
||||
┌─────────────────┐
|
||||
│ SCHEDULED │ ← Content has a scheduled_publish_at time
|
||||
│ status: approved│ site_status='scheduled'
|
||||
│ site_status: │ scheduled_publish_at set to future datetime
|
||||
│ scheduled │
|
||||
└────────┬────────┘
|
||||
│ Every 5 min: process_scheduled_publications task
|
||||
│ (when scheduled_publish_at <= now)
|
||||
▼
|
||||
┌─────────────────┐
|
||||
│ PUBLISHING │ ← WordPress API call in progress
|
||||
│ status: approved│ site_status='publishing'
|
||||
│ site_status: │
|
||||
│ publishing │
|
||||
└────────┬────────┘
|
||||
│
|
||||
┌────┴────┐
|
||||
│ │
|
||||
▼ ▼
|
||||
┌────────┐ ┌────────┐
|
||||
│PUBLISHED│ │ FAILED │
|
||||
│status: │ │status: │
|
||||
│approved │ │approved│
|
||||
│site_ │ │site_ │
|
||||
│status: │ │status: │
|
||||
│published│ │failed │
|
||||
└─────────┘ └────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Celery Tasks
|
||||
|
||||
### 1. `schedule_approved_content`
|
||||
|
||||
**Schedule:** Every hour at :00
|
||||
**Task Name:** `publishing.schedule_approved_content`
|
||||
**File:** `backend/igny8_core/tasks/publishing_scheduler.py`
|
||||
|
||||
#### What It Does:
|
||||
1. Finds all sites with `PublishingSettings.auto_publish_enabled = True`
|
||||
2. Gets approved content (`status='approved'`, `site_status='not_published'`, `scheduled_publish_at=null`)
|
||||
3. Calculates available publishing slots based on:
|
||||
- `publish_days` - which days are allowed (e.g., Mon-Fri)
|
||||
- `publish_time_slots` - which times are allowed (e.g., 09:00, 14:00, 18:00)
|
||||
- `daily_publish_limit` - max posts per day
|
||||
- `weekly_publish_limit` - max posts per week
|
||||
- `monthly_publish_limit` - max posts per month
|
||||
4. Assigns `scheduled_publish_at` datetime and sets `site_status='scheduled'`
|
||||
|
||||
#### Configuration Location:
|
||||
`PublishingSettings` model linked to each Site. Configurable via:
|
||||
- Admin: `/admin/integration/publishingsettings/`
|
||||
- API: `/api/v1/sites/{site_id}/publishing-settings/`
|
||||
|
||||
---
|
||||
|
||||
### 2. `process_scheduled_publications`
|
||||
|
||||
**Schedule:** Every 5 minutes
|
||||
**Task Name:** `publishing.process_scheduled_publications`
|
||||
**File:** `backend/igny8_core/tasks/publishing_scheduler.py`
|
||||
|
||||
#### What It Does:
|
||||
1. Finds all content where:
|
||||
- `site_status='scheduled'`
|
||||
- `scheduled_publish_at <= now`
|
||||
2. For each content item:
|
||||
- Updates `site_status='publishing'`
|
||||
- Gets the site's WordPress integration
|
||||
- Queues `publish_content_to_wordpress` Celery task
|
||||
3. Logs results and any errors
|
||||
|
||||
---
|
||||
|
||||
### 3. `publish_content_to_wordpress`
|
||||
|
||||
**Type:** On-demand Celery task (queued by `process_scheduled_publications`)
|
||||
**Task Name:** `publishing.publish_content_to_wordpress`
|
||||
**File:** `backend/igny8_core/tasks/wordpress_publishing.py`
|
||||
|
||||
#### What It Does:
|
||||
1. **Load Content & Integration** - Gets content and WordPress credentials
|
||||
2. **Check Already Published** - Skips if `external_id` exists
|
||||
3. **Generate Excerpt** - Creates excerpt from HTML content
|
||||
4. **Get Taxonomy Terms** - Loads categories and tags from `ContentTaxonomy`
|
||||
5. **Get Images** - Loads featured image and gallery images
|
||||
6. **Build API Payload** - Constructs WordPress REST API payload
|
||||
7. **Call WordPress API** - POSTs to WordPress via IGNY8 Bridge plugin
|
||||
8. **Update Content** - Sets `external_id`, `external_url`, `site_status='published'`
|
||||
9. **Log Sync Event** - Records in `SyncEvent` model
|
||||
|
||||
#### WordPress Connection:
|
||||
- Uses the IGNY8 WordPress Bridge plugin installed on the site
|
||||
- API endpoint: `{site_url}/wp-json/igny8-bridge/v1/publish`
|
||||
- Authentication: API key stored in `Site.wp_api_key`
|
||||
|
||||
---
|
||||
|
||||
## Database Models
|
||||
|
||||
### Content Fields (Publishing Related)
|
||||
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| `status` | CharField | **Editorial workflow**: `draft`, `review`, `approved` |
|
||||
| `site_status` | CharField | **WordPress publishing status**: `not_published`, `scheduled`, `publishing`, `published`, `failed` |
|
||||
| `site_status_updated_at` | DateTimeField | When site_status was last changed |
|
||||
| `scheduled_publish_at` | DateTimeField | When content should be published (null if not scheduled) |
|
||||
| `external_id` | CharField | WordPress post ID after publishing |
|
||||
| `external_url` | URLField | WordPress post URL after publishing |
|
||||
|
||||
**Important:** These are separate concerns:
|
||||
- `status` tracks editorial approval
|
||||
- `site_status` tracks external publishing
|
||||
- Content typically has `status='approved'` AND `site_status='not_published'` before scheduling
|
||||
|
||||
### PublishingSettings Fields
|
||||
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| `site` | ForeignKey | The site these settings apply to |
|
||||
| `auto_publish_enabled` | BooleanField | Whether automatic scheduling is enabled |
|
||||
| `publish_days` | JSONField | List of allowed days: `['mon', 'tue', 'wed', 'thu', 'fri']` |
|
||||
| `publish_time_slots` | JSONField | List of times: `['09:00', '14:00', '18:00']` |
|
||||
| `daily_publish_limit` | IntegerField | Max posts per day (null = unlimited) |
|
||||
| `weekly_publish_limit` | IntegerField | Max posts per week (null = unlimited) |
|
||||
| `monthly_publish_limit` | IntegerField | Max posts per month (null = unlimited) |
|
||||
|
||||
---
|
||||
|
||||
## Celery Beat Schedule
|
||||
|
||||
From `backend/igny8_core/celery.py`:
|
||||
|
||||
```python
|
||||
app.conf.beat_schedule = {
|
||||
# ...
|
||||
'schedule-approved-content': {
|
||||
'task': 'publishing.schedule_approved_content',
|
||||
'schedule': crontab(minute=0), # Every hour at :00
|
||||
},
|
||||
'process-scheduled-publications': {
|
||||
'task': 'publishing.process_scheduled_publications',
|
||||
'schedule': crontab(minute='*/5'), # Every 5 minutes
|
||||
},
|
||||
# ...
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Manual Publishing
|
||||
|
||||
Content can also be published immediately via:
|
||||
|
||||
### API Endpoint
|
||||
```
|
||||
POST /api/v1/content/{content_id}/publish/
|
||||
```
|
||||
|
||||
### Admin Action
|
||||
In Django Admin, select content and use "Publish to WordPress" action.
|
||||
|
||||
---
|
||||
|
||||
## Monitoring & Debugging
|
||||
|
||||
### Log Files
|
||||
- **Publish Logs:** `backend/logs/publish-sync-logs/`
|
||||
- **API Logs:** `backend/logs/wordpress_api.log`
|
||||
|
||||
### Check Celery Status
|
||||
```bash
|
||||
docker compose -f docker-compose.app.yml -p igny8-app logs igny8_celery_worker
|
||||
docker compose -f docker-compose.app.yml -p igny8-app logs igny8_celery_beat
|
||||
```
|
||||
|
||||
### Check Scheduled Content
|
||||
```python
|
||||
# Django shell
|
||||
from igny8_core.business.content.models import Content
|
||||
from django.utils import timezone
|
||||
|
||||
# Past due content (should have been published)
|
||||
Content.objects.filter(
|
||||
site_status='scheduled',
|
||||
scheduled_publish_at__lt=timezone.now()
|
||||
).count()
|
||||
|
||||
# Upcoming scheduled content
|
||||
Content.objects.filter(
|
||||
site_status='scheduled',
|
||||
scheduled_publish_at__gt=timezone.now()
|
||||
).order_by('scheduled_publish_at')[:10]
|
||||
```
|
||||
|
||||
### Manual Task Execution
|
||||
```python
|
||||
# Django shell
|
||||
from igny8_core.tasks.publishing_scheduler import (
|
||||
schedule_approved_content,
|
||||
process_scheduled_publications
|
||||
)
|
||||
|
||||
# Run scheduling task
|
||||
schedule_approved_content()
|
||||
|
||||
# Process due publications
|
||||
process_scheduled_publications()
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Error Handling
|
||||
|
||||
### Common Failure Reasons
|
||||
|
||||
| Error | Cause | Solution |
|
||||
|-------|-------|----------|
|
||||
| No active WordPress integration | Site doesn't have WordPress connected | Configure integration in Site settings |
|
||||
| API key invalid/expired | WordPress API key issue | Regenerate API key in WordPress plugin |
|
||||
| Connection timeout | WordPress site unreachable | Check site availability |
|
||||
| Plugin not active | IGNY8 Bridge plugin disabled | Enable plugin in WordPress |
|
||||
| Content already published | Duplicate publish attempt | Check `external_id` field |
|
||||
|
||||
### Retry Policy
|
||||
- `publish_content_to_wordpress` has `max_retries=3`
|
||||
- Automatic retry on transient failures
|
||||
- Failed content marked with `site_status='failed'`
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Content Not Being Scheduled
|
||||
|
||||
1. Check `PublishingSettings.auto_publish_enabled` is `True`
|
||||
2. Verify content has `status='approved'` and `site_status='not_published'`
|
||||
3. Check `scheduled_publish_at` is null (already scheduled content won't reschedule)
|
||||
4. Verify publish limits haven't been reached
|
||||
|
||||
### Content Not Publishing
|
||||
|
||||
1. Check Celery Beat is running: `docker compose logs igny8_celery_beat`
|
||||
2. Check Celery Worker is running: `docker compose logs igny8_celery_worker`
|
||||
3. Look for errors in worker logs
|
||||
4. Verify WordPress integration is active
|
||||
5. Test WordPress API connectivity
|
||||
|
||||
### Resetting Failed Content
|
||||
|
||||
```python
|
||||
# Reset failed content to try again
|
||||
from igny8_core.business.content.models import Content
|
||||
|
||||
Content.objects.filter(site_status='failed').update(
|
||||
site_status='not_published',
|
||||
scheduled_publish_at=None
|
||||
)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Architecture Diagram
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ IGNY8 Backend │
|
||||
├─────────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ ┌──────────────────┐ ┌──────────────────┐ │
|
||||
│ │ Celery Beat │ │ Celery Worker │ │
|
||||
│ │ │ │ │ │
|
||||
│ │ Sends tasks at │───▶│ Executes tasks │ │
|
||||
│ │ scheduled times │ │ │ │
|
||||
│ └──────────────────┘ └────────┬─────────┘ │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ ┌────────────────────────────────────────────────────────┐ │
|
||||
│ │ Publishing Tasks │ │
|
||||
│ │ │ │
|
||||
│ │ 1. schedule_approved_content (hourly) │ │
|
||||
│ │ - Find approved content │ │
|
||||
│ │ - Calculate publish slots │ │
|
||||
│ │ - Set scheduled_publish_at │ │
|
||||
│ │ │ │
|
||||
│ │ 2. process_scheduled_publications (every 5 min) │ │
|
||||
│ │ - Find due content │ │
|
||||
│ │ - Queue publish_content_to_wordpress │ │
|
||||
│ │ │ │
|
||||
│ │ 3. publish_content_to_wordpress │ │
|
||||
│ │ - Build API payload │ │
|
||||
│ │ - Call WordPress REST API │ │
|
||||
│ │ - Update content status │ │
|
||||
│ └────────────────────────────────────────────────────────┘ │
|
||||
│ │ │
|
||||
└───────────────────────────────────┼─────────────────────────────┘
|
||||
│
|
||||
▼ HTTPS
|
||||
┌───────────────────────────────────────────────────────────────┐
|
||||
│ WordPress Site │
|
||||
├───────────────────────────────────────────────────────────────┤
|
||||
│ ┌─────────────────────────────────────────────────────────┐ │
|
||||
│ │ IGNY8 Bridge Plugin │ │
|
||||
│ │ │ │
|
||||
│ │ /wp-json/igny8-bridge/v1/publish │ │
|
||||
│ │ - Receives content payload │ │
|
||||
│ │ - Creates/updates WordPress post │ │
|
||||
│ │ - Handles images, categories, tags │ │
|
||||
│ │ - Returns post ID and URL │ │
|
||||
│ └─────────────────────────────────────────────────────────┘ │
|
||||
└───────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [Publisher Module](../10-MODULES/PUBLISHER.md)
|
||||
- [WordPress Integration](../60-PLUGINS/WORDPRESS-INTEGRATION.md)
|
||||
- [Content Pipeline](CONTENT-PIPELINE.md)
|
||||
@@ -28,9 +28,10 @@
|
||||
IGNY8 integrates with WordPress sites through a **custom WordPress plugin** (`igny8-wp-bridge`) that:
|
||||
- Receives content from IGNY8 via a custom REST endpoint (`/wp-json/igny8/v1/publish`)
|
||||
- Sends status updates back to IGNY8 via webhooks
|
||||
- Authenticates using API keys stored in both systems
|
||||
- **Authenticates using API key ONLY** (stored in Site.wp_api_key - single source of truth)
|
||||
- Auto-updates via IGNY8 plugin distribution system (v1.7.0+)
|
||||
- Supports advanced template rendering with image layouts
|
||||
- **No WordPress admin credentials required** (username/password authentication deprecated)
|
||||
|
||||
### Communication Pattern
|
||||
|
||||
@@ -108,19 +109,22 @@ IGNY8 App ←→ WordPress Site
|
||||
**Step 2: User clicks "Generate API Key"**
|
||||
- Frontend calls: `POST /v1/integration/integrations/generate-api-key/`
|
||||
- Body: `{ "site_id": 123 }`
|
||||
- Backend creates/updates `SiteIntegration` record with new API key
|
||||
- Backend stores API key in `Site.wp_api_key` field (SINGLE source of truth)
|
||||
- Creates/updates `SiteIntegration` record with empty credentials_json
|
||||
|
||||
**Step 3: User configures WordPress plugin**
|
||||
- Configures plugin with:
|
||||
- IGNY8 API URL: `https://api.igny8.com`
|
||||
- Site API Key: (copied from IGNY8)
|
||||
- Site ID: (shown in IGNY8)
|
||||
- **Note:** No WordPress admin credentials needed
|
||||
|
||||
**Step 4: Test Connection**
|
||||
- User clicks "Test Connection" in either app
|
||||
- IGNY8 calls: `GET {wordpress_url}/wp-json/wp/v2/users/me`
|
||||
- Uses API key in `X-IGNY8-API-KEY` header
|
||||
- Success: Connection verified, `is_active` set to true, plugin registers installation
|
||||
- Plugin calls: `POST https://api.igny8.com/api/v1/integration/integrations/test-connection/`
|
||||
- Headers: `Authorization: Bearer {api_key}`
|
||||
- Body: `{ "site_id": 123, "api_key": "...", "site_url": "https://..." }`
|
||||
- Backend validates API key against `Site.wp_api_key`
|
||||
- Success: SiteIntegration created with empty credentials_json, plugin registers installation
|
||||
- Failure: Error message displayed
|
||||
|
||||
### 2.4 Data Created During Setup
|
||||
@@ -137,14 +141,100 @@ IGNY8 App ←→ WordPress Site
|
||||
"site_url": "https://example.com"
|
||||
},
|
||||
"credentials_json": {
|
||||
"api_key": "igny8_xxxxxxxxxxxxxxxxxxxx"
|
||||
"plugin_version": "1.3.4",
|
||||
"debug_enabled": false
|
||||
},
|
||||
"is_active": true,
|
||||
"sync_enabled": true,
|
||||
"sync_status": "pending"
|
||||
"sync_status": "pending",
|
||||
"_note": "API key stored in Site.wp_api_key, not in credentials_json"
|
||||
}
|
||||
```
|
||||
|
||||
**Site Model (API Key Storage):**
|
||||
```json
|
||||
{
|
||||
"id": 123,
|
||||
"name": "Example Site",
|
||||
"url": "https://example.com",
|
||||
"wp_api_key": "igny8_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
|
||||
"hosting_type": "wordpress"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2.5 Authentication Architecture (v1.3.4+)
|
||||
|
||||
### API Key as Single Source of Truth
|
||||
|
||||
**Storage:**
|
||||
- API key stored in `Site.wp_api_key` field (Django backend)
|
||||
- Plugin stores same API key in WordPress options table: `igny8_api_key`
|
||||
- SiteIntegration.credentials_json does NOT contain API key
|
||||
|
||||
**Authentication Flow (IGNY8 → WordPress):**
|
||||
```python
|
||||
# Backend: publisher_service.py
|
||||
destination_config = {
|
||||
'site_url': integration.config_json.get('site_url'),
|
||||
'api_key': integration.site.wp_api_key # From Site model
|
||||
}
|
||||
|
||||
# WordPress Adapter: wordpress_adapter.py
|
||||
headers = {
|
||||
'Authorization': f'Bearer {api_key}',
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
requests.post(f"{site_url}/wp-json/igny8/v1/publish", headers=headers, json=payload)
|
||||
```
|
||||
|
||||
**Authentication Flow (WordPress → IGNY8):**
|
||||
```php
|
||||
// Plugin: class-igny8-api.php
|
||||
$api_key = get_option('igny8_api_key');
|
||||
$headers = array(
|
||||
'Authorization' => 'Bearer ' . $api_key,
|
||||
'Content-Type' => 'application/json'
|
||||
);
|
||||
wp_remote_post('https://api.igny8.com/api/v1/...', array('headers' => $headers));
|
||||
```
|
||||
|
||||
**Validation (WordPress Side):**
|
||||
```php
|
||||
// Plugin: class-igny8-rest-api.php
|
||||
public function check_permission($request) {
|
||||
// Check X-IGNY8-API-KEY header
|
||||
$header_api_key = $request->get_header('x-igny8-api-key');
|
||||
|
||||
// Check Authorization Bearer header
|
||||
$auth_header = $request->get_header('Authorization');
|
||||
|
||||
$stored_api_key = get_option('igny8_api_key');
|
||||
|
||||
if (hash_equals($stored_api_key, $header_api_key) ||
|
||||
strpos($auth_header, 'Bearer ' . $stored_api_key) !== false) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return new WP_Error('rest_forbidden', 'Invalid API key', array('status' => 401));
|
||||
}
|
||||
```
|
||||
|
||||
### Deprecated Authentication Methods
|
||||
|
||||
**No Longer Supported (removed in v1.3.4):**
|
||||
- ❌ Username/password authentication
|
||||
- ❌ App passwords via WordPress REST API
|
||||
- ❌ OAuth/token exchange
|
||||
- ❌ Webhook signature validation (webhooks deprecated)
|
||||
- ❌ Storing API key in SiteIntegration.credentials_json
|
||||
|
||||
**Legacy Fields (do not use):**
|
||||
- `Site.wp_username` - deprecated
|
||||
- `Site.wp_app_password` - deprecated
|
||||
- `Site.wp_url` - deprecated (use SiteIntegration.config_json.site_url)
|
||||
|
||||
---
|
||||
|
||||
## 3. Manual Publishing Flow
|
||||
@@ -415,18 +505,119 @@ Refreshes understanding of WordPress site:
|
||||
|-------|------|---------|
|
||||
| id | AutoField | Primary key |
|
||||
| account | FK(Account) | Owner account |
|
||||
| site | FK(Site) | IGNY8 site |
|
||||
| site | FK(Site) | IGNY8 site (contains wp_api_key) |
|
||||
| platform | CharField | 'wordpress' |
|
||||
| platform_type | CharField | 'cms' |
|
||||
| config_json | JSONField | `{ "site_url": "https://..." }` |
|
||||
| credentials_json | JSONField | `{ "api_key": "igny8_xxx" }` |
|
||||
| credentials_json | JSONField | `{ "plugin_version": "1.3.4", "debug_enabled": false }` |
|
||||
| is_active | Boolean | Connection enabled |
|
||||
| sync_enabled | Boolean | Two-way sync enabled |
|
||||
| last_sync_at | DateTime | Last successful sync |
|
||||
| sync_status | CharField | pending/success/failed/syncing |
|
||||
| sync_error | TextField | Last error message |
|
||||
|
||||
### 7.2 SyncEvent
|
||||
**Note:** `credentials_json` no longer stores API key. API key is stored in `Site.wp_api_key` (single source of truth).
|
||||
|
||||
### 7.1a Site Model (API Key Storage)
|
||||
|
||||
| Field | Type | Purpose |
|
||||
|-------|------|---------|-------|
|
||||
| id | AutoField | Primary key |
|
||||
| account | FK(Account) | Owner account |
|
||||
| name | CharField | Site display name |
|
||||
| url | URLField | WordPress site URL |
|
||||
| wp_api_key | CharField | **API key for WordPress integration (SINGLE source of truth)** |
|
||||
| wp_url | URLField | Legacy field (deprecated) |
|
||||
| wp_username | CharField | Legacy field (deprecated) |
|
||||
| wp_app_password | CharField | Legacy field (deprecated) |
|
||||
| hosting_type | CharField | 'wordpress', 'shopify', 'igny8_sites', 'multi' |
|
||||
|
||||
### 7.2 Plugin Models
|
||||
|
||||
#### Plugin
|
||||
|
||||
Core plugin registry (platform-agnostic).
|
||||
|
||||
| Field | Type | Purpose |
|
||||
|-------|------|---------|-------|
|
||||
| id | AutoField | Primary key |
|
||||
| name | CharField | Plugin display name (e.g., "IGNY8 WordPress Bridge") |
|
||||
| slug | SlugField | URL-safe identifier (e.g., "igny8-wp-bridge") |
|
||||
| platform | CharField | Target platform ('wordpress', 'shopify', etc.) |
|
||||
| description | TextField | Plugin description |
|
||||
| author | CharField | Plugin author |
|
||||
| author_url | URLField | Author website |
|
||||
| plugin_url | URLField | Plugin homepage |
|
||||
| icon_url | URLField | Plugin icon (256x256) |
|
||||
| banner_url | URLField | Plugin banner (772x250) |
|
||||
| is_active | Boolean | Whether plugin is available for download |
|
||||
| created_at | DateTime | Record creation |
|
||||
| updated_at | DateTime | Last modified |
|
||||
|
||||
**Current WordPress Plugin:**
|
||||
- Name: "IGNY8 WordPress Bridge"
|
||||
- Slug: "igny8-wp-bridge"
|
||||
- Platform: "wordpress"
|
||||
- Description: "Connect your WordPress site to IGNY8 for AI-powered content publishing, SEO optimization, and seamless automation."
|
||||
- Author: "IGNY8 Team"
|
||||
|
||||
#### PluginVersion
|
||||
|
||||
Version tracking with distribution files.
|
||||
|
||||
| Field | Type | Purpose |
|
||||
|-------|------|---------|-------|
|
||||
| id | AutoField | Primary key |
|
||||
| plugin | FK(Plugin) | Parent plugin |
|
||||
| version | CharField | Semantic version (e.g., "1.3.4") |
|
||||
| status | CharField | 'development', 'beta', 'released', 'deprecated' |
|
||||
| release_notes | TextField | Changelog/release notes |
|
||||
| file_path | CharField | Path to ZIP file in /plugins/{platform}/dist/ |
|
||||
| file_size | BigInteger | ZIP file size in bytes |
|
||||
| checksum_md5 | CharField | MD5 hash for verification |
|
||||
| checksum_sha256 | CharField | SHA256 hash for verification |
|
||||
| requires_version | CharField | Minimum platform version (e.g., WP 5.6+) |
|
||||
| tested_version | CharField | Tested up to version |
|
||||
| is_latest | Boolean | Whether this is the latest stable version |
|
||||
| download_count | Integer | Number of downloads |
|
||||
| released_at | DateTime | Public release date |
|
||||
| created_at | DateTime | Record creation |
|
||||
|
||||
**Current Latest Version (1.3.4):**
|
||||
- Status: "released"
|
||||
- File: `/plugins/wordpress/dist/igny8-wp-bridge-1.3.4.zip`
|
||||
- Requires: WordPress 5.6+
|
||||
- Tested: WordPress 6.4
|
||||
- Features: API key authentication only, template improvements, image layout fixes
|
||||
|
||||
#### PluginInstallation
|
||||
|
||||
Tracks plugin installations per site.
|
||||
|
||||
| Field | Type | Purpose |
|
||||
|-------|------|---------|-------|
|
||||
| id | AutoField | Primary key |
|
||||
| site | FK(Site) | Site where plugin is installed |
|
||||
| plugin_version | FK(PluginVersion) | Installed version |
|
||||
| installed_at | DateTime | Installation timestamp |
|
||||
| last_seen | DateTime | Last health check |
|
||||
| status | CharField | 'active', 'inactive', 'error' |
|
||||
| metadata | JSONField | Installation-specific data (PHP version, WP version, etc.) |
|
||||
|
||||
#### PluginDownload
|
||||
|
||||
Download analytics.
|
||||
|
||||
| Field | Type | Purpose |
|
||||
|-------|------|---------|-------|
|
||||
| id | AutoField | Primary key |
|
||||
| plugin_version | FK(PluginVersion) | Downloaded version |
|
||||
| site | FK(Site, null=True) | Site that downloaded (if authenticated) |
|
||||
| ip_address | GenericIPAddressField | Downloader IP |
|
||||
| user_agent | TextField | Browser/client info |
|
||||
| downloaded_at | DateTime | Download timestamp |
|
||||
|
||||
### 7.3 SyncEvent
|
||||
|
||||
| Field | Type | Purpose |
|
||||
|-------|------|---------|
|
||||
@@ -540,8 +731,7 @@ POST /api/plugins/igny8-wp-bridge/health-check/ - Health monitoring
|
||||
### 8.3 Version History (Recent)
|
||||
|
||||
| Version | Date | Changes |
|
||||
|---------|------|---------|
|
||||
| 1.3.3 | Jan 10, 2026 | Template design: Square image grid fixes, landscape positioning, direct styling for images without captions |
|
||||
|---------|------|---------|| 1.3.4 | Jan 12, 2026 | **API key authentication only** (removed username/password support), webhooks deprecated, Bearer token auth, simplified integration || 1.3.3 | Jan 10, 2026 | Template design: Square image grid fixes, landscape positioning, direct styling for images without captions |
|
||||
| 1.3.2 | Jan 9, 2026 | Template rendering improvements, image layout enhancements |
|
||||
| 1.3.1 | Jan 9, 2026 | Plugin versioning updates |
|
||||
| 1.3.0 | Jan 8, 2026 | Distribution system release, auto-update mechanism |
|
||||
@@ -616,42 +806,69 @@ POST /api/plugins/igny8-wp-bridge/health-check/ - Health monitoring
|
||||
|
||||
## 10. Flow Diagrams
|
||||
|
||||
### 9.1 Integration Setup
|
||||
### 10.1 Integration Setup (API Key Authentication)
|
||||
|
||||
```
|
||||
┌──────────┐ ┌──────────────┐ ┌───────────────┐
|
||||
│ User │ │ IGNY8 App │ │ WordPress │
|
||||
└────┬─────┘ └──────┬───────┘ └───────┬───────┘
|
||||
│ │ │
|
||||
│ 1. Open Site Settings │
|
||||
├─────────────────>│ │
|
||||
│ │ │
|
||||
│ 2. Download Plugin │
|
||||
├─────────────────>│ │
|
||||
│ │ │
|
||||
│<─────────────────┤ │
|
||||
│ 3. Plugin ZIP │ │
|
||||
│ │ │
|
||||
│ 4. Install Plugin──────────────────────┼──────────>
|
||||
│ │ │
|
||||
│ 5. Generate API Key │
|
||||
├─────────────────>│ │
|
||||
│<─────────────────┤ │
|
||||
│ 6. Display API Key │
|
||||
│ │ │
|
||||
│ 7. Enter API Key in Plugin─────────────┼──────────>
|
||||
│ │ │
|
||||
│ 8. Test Connection │
|
||||
├─────────────────>│ │
|
||||
│ │ 9. GET /wp-json/... │
|
||||
│ ├────────────────────>│
|
||||
│ │<────────────────────┤
|
||||
│<─────────────────┤ 10. Success │
|
||||
│ │ │
|
||||
│ │ 11. Register Install│
|
||||
│ │<────────────────────┤
|
||||
┌──────────┐ ┌─────────────────┐ ┌───────────────┐
|
||||
│ User │ │ IGNY8 API │ │ WordPress │
|
||||
│ │ │ (Backend) │ │ Site │
|
||||
└────┬─────┘ └────────┬────────┘ └───────┬───────┘
|
||||
│ │ │
|
||||
│ 1. Generate API Key (Site Settings) │
|
||||
├───────────────────>│ │
|
||||
│ │ Store in Site.wp_api_key
|
||||
│<───────────────────┤ (SINGLE source) │
|
||||
│ 2. API Key: igny8_live_xxxxx │
|
||||
│ │ │
|
||||
│ 3. Download Plugin ZIP │
|
||||
├───────────────────>│ │
|
||||
│ │ GET /api/plugins/ │
|
||||
│ │ igny8-wp-bridge/ │
|
||||
│ │ download/ │
|
||||
│<───────────────────┤ │
|
||||
│ 4. igny8-wp-bridge-1.3.4.zip │
|
||||
│ │ │
|
||||
│ 5. Install & Activate Plugin──────────────┼────────>
|
||||
│ │ │
|
||||
│ 6. Enter API Key + Site ID in WP Settings─┼────────>
|
||||
│ │ │
|
||||
│ 7. Click "Test Connection" in Plugin──────┼────────>
|
||||
│ │ │
|
||||
│ │ 8. POST /api/v1/ │
|
||||
│ │ integration/ │
|
||||
│ │ integrations/ │
|
||||
│ │ test-connection/ │
|
||||
│ │<─────────────────────┤
|
||||
│ │ Headers: │
|
||||
│ │ Authorization: │
|
||||
│ │ Bearer {api_key} │
|
||||
│ │ │
|
||||
│ │ Validate against │
|
||||
│ │ Site.wp_api_key │
|
||||
│ │ │
|
||||
│ │ Create/Update │
|
||||
│ │ SiteIntegration │
|
||||
│ │ (credentials_json={})│
|
||||
│ │ │
|
||||
│ │ 9. 200 OK │
|
||||
│ ├─────────────────────>│
|
||||
│ │ {success: true} │
|
||||
│ │ │
|
||||
│ 10. Success Message in Plugin─────────────┼────────>
|
||||
│ │ │
|
||||
│ │ 11. POST /register/ │
|
||||
│ │<─────────────────────┤
|
||||
│ │ Store PluginInstallation
|
||||
│ │ │
|
||||
```
|
||||
|
||||
**Key Changes in v1.3.4:**
|
||||
- ✅ API key stored in `Site.wp_api_key` (not in SiteIntegration)
|
||||
- ✅ `credentials_json` is empty (only stores plugin_version, debug_enabled)
|
||||
- ✅ Authentication via `Authorization: Bearer {api_key}` header
|
||||
- ✅ No WordPress admin username/password needed
|
||||
- ✅ Simplified setup - single API key for all communication
|
||||
|
||||
### 10.2 Manual Publishing
|
||||
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user