16 KiB
WordPress Publishing Complete Field Mapping
Last Updated: 2025-12-01
Purpose: Complete documentation of IGNY8 → WordPress publishing workflow with all field mappings
🔄 Publishing Workflow Overview
Frontend (Review.tsx)
↓ POST /v1/publisher/publish/
Backend (PublisherViewSet)
↓ PublisherService.publish()
WordPressAdapter._publish_via_api_key()
↓ POST {site_url}/wp-json/igny8/v1/publish
WordPress Plugin (class-igny8-rest-api.php)
↓ publish_content_to_wordpress()
WordPress Plugin (igny8-to-wp.php)
↓ igny8_create_wordpress_post_from_task()
WordPress Core
↓ wp_insert_post() + post_meta
WordPress Database (wp_posts, wp_postmeta, wp_term_relationships)
📊 Complete Field Mapping Table
| # | IGNY8 Field | DB Column | Backend Publisher | WordPress Plugin Endpoint | WordPress Plugin Function | WordPress Field | Status | Notes |
|---|---|---|---|---|---|---|---|---|
| 1 | id | id |
content_id |
content_id (required) |
_igny8_content_id (post_meta) |
wp_postmeta |
✅ Published | Tracking field |
| 2 | title | title |
title |
title (required) |
post_title |
wp_posts.post_title |
✅ Published | Core field |
| 3 | content_html | content_html |
content_html |
content_html (required) |
post_content |
wp_posts.post_content |
✅ Published | Core field, sanitized with wp_kses_post() |
| 4 | meta_title | meta_title |
seo_title |
seo_title OR meta_title |
_yoast_wpseo_title, _seopress_titles_title, _aioseo_title, _igny8_meta_title |
wp_postmeta (SEO plugins) |
✅ Published | SEO title for Yoast/SEOPress/AIOSEO |
| 5 | meta_description | meta_description |
seo_description |
seo_description OR meta_description |
_yoast_wpseo_metadesc, _seopress_titles_desc, _aioseo_description, _igny8_meta_description |
wp_postmeta (SEO plugins) |
✅ Published | SEO description for plugins |
| 6 | primary_keyword | primary_keyword |
primary_keyword |
primary_keyword |
Added to tags | wp_terms (post_tag) |
✅ Published | Auto-added as tag if not exists |
| 7 | secondary_keywords | secondary_keywords |
secondary_keywords (JSON array) |
secondary_keywords (JSON array) |
Added to tags | wp_terms (post_tag) |
✅ Published | Each keyword becomes a tag |
| 8 | taxonomy_terms (category) | taxonomy_terms (M2M) |
categories (array of names) |
categories (array) |
category_ids → wp_set_post_terms() |
wp_term_relationships (category) |
✅ Published | Retrieved via taxonomy_terms.filter(taxonomy_type='category') |
| 9 | taxonomy_terms (tag) | taxonomy_terms (M2M) |
tags (array of names) |
tags (array) |
tag_ids → wp_set_post_terms() |
wp_term_relationships (post_tag) |
✅ Published | Retrieved via taxonomy_terms.filter(taxonomy_type='tag') |
| 10 | cluster | cluster_id (FK) |
cluster_id, categories (fallback) |
cluster_id |
_igny8_cluster_id (post_meta), igny8_clusters (taxonomy) |
wp_postmeta, wp_term_relationships |
✅ Published | Used as category fallback if no taxonomy_terms exist |
| 11 | sector | sector_id (FK) |
sector_id |
sector_id |
_igny8_sector_id (post_meta), igny8_sectors (taxonomy) |
wp_postmeta, wp_term_relationships |
✅ Published | Custom taxonomy |
| 12 | Images (featured) | Images model (FK) |
featured_image_url |
featured_image_url OR featured_image |
_thumbnail_id (post_meta) |
wp_postmeta, wp_posts (attachment) |
✅ Published | Via igny8_set_featured_image() - downloads/attaches image |
| 13 | Images (gallery) | Images model (FK) |
gallery_images (array) |
gallery_images (array) |
Gallery processing | wp_postmeta, wp_posts (attachments) |
✅ Published | Via igny8_set_gallery_images() - downloads/attaches images |
| 14 | status | status |
status |
status |
post_status |
wp_posts.post_status |
✅ Published | Mapped via igny8_map_igny8_status_to_wp() (draft/published/review→publish/draft) |
| 15 | published_at | published_at |
NOT SENT | published_at (optional) |
post_date, post_date_gmt |
wp_posts.post_date, wp_posts.post_date_gmt |
⚠️ Available | Not currently sent by backend |
| 16 | excerpt | N/A | excerpt (generated from content_html) |
excerpt |
post_excerpt |
wp_posts.post_excerpt |
✅ Published | Auto-generated: first 150 chars of stripped HTML |
| 17 | content_type | content_type |
content_type (optional) |
content_type (optional) |
_igny8_content_type (post_meta) |
wp_postmeta |
✅ Published | Tracking field (e.g., "blog_post", "product_page") |
| 18 | content_structure | content_structure |
content_structure (optional) |
content_structure (optional) |
_igny8_content_structure (post_meta) |
wp_postmeta |
✅ Published | Tracking field |
| 19 | source | source |
NOT SENT | source (optional) |
_igny8_source (post_meta) |
wp_postmeta |
⚠️ Available | Not currently sent by backend |
| 20 | author | user_id (FK) |
NOT SENT | author (optional) |
post_author |
wp_posts.post_author |
⚠️ Available | Not sent - WordPress uses fallback author mapping |
| 21 | word_count | word_count |
NOT SENT | N/A | N/A | N/A | ❌ Not Published | Could be sent as post_meta |
| 22 | optimization_scores | optimization_scores |
NOT SENT | N/A | N/A | N/A | ❌ Not Published | JSON field - could be sent as post_meta |
| 23 | metadata | metadata |
NOT SENT | N/A | N/A | N/A | ❌ Not Published | JSON field - could be sent as post_meta |
| 24 | internal_links | internal_links |
NOT SENT | N/A | N/A | N/A | ❌ Not Published | JSON field - could be sent as post_meta |
| 25 | external_id | external_id |
NOT SENT (return value) | N/A | post_id (return) |
wp_posts.ID |
✅ Return Value | WordPress returns this to IGNY8, saved to content.external_id |
| 26 | external_url | external_url |
NOT SENT (return value) | N/A | post_url (return) |
get_permalink() |
✅ Return Value | WordPress returns this to IGNY8, saved to content.external_url |
| 27 | external_metadata | external_metadata |
NOT SENT | N/A | N/A | N/A | ❌ Not Published | JSON field - not sent |
| 28 | task_id | N/A | NOT SENT | task_id (optional) |
_igny8_task_id (post_meta) |
wp_postmeta |
⚠️ Available | Not sent by backend, but WordPress accepts it |
| 29 | brief | brief |
NOT SENT | brief (optional) |
Used for excerpt fallback | wp_posts.post_excerpt |
⚠️ Available | Not sent, but would be used as excerpt if sent |
| 30 | slug | slug |
NOT SENT | N/A | N/A | wp_posts.post_name |
❌ Not Published | WordPress auto-generates slug |
| 31 | ai_content_brief | ai_content_brief |
NOT SENT | N/A | N/A | N/A | ❌ Not Published | IGNY8-internal field |
| 32 | ai_response_raw | ai_response_raw |
NOT SENT | N/A | N/A | N/A | ❌ Not Published | IGNY8-internal field |
📋 Status Legend
- ✅ Published - Field is actively sent and saved to WordPress
- ⚠️ Available - Field is accepted by WordPress but not currently sent by IGNY8 backend
- ❌ Not Published - Field is not sent and not used in publishing workflow
🔑 Authentication & Endpoints
Backend API Endpoint
POST /v1/publisher/publish/
Authorization: Token <user_token>
Request Body:
{
"destination_id": 123,
"content_ids": [456]
}
WordPress Plugin Endpoint
POST {site_url}/wp-json/igny8/v1/publish
Headers:
X-IGNY8-API-KEY: <api_key>
Content-Type: application/json
Request Body:
{
"content_id": 456,
"title": "...",
"content_html": "...",
"seo_title": "...",
"seo_description": "...",
"categories": ["Category 1", "Category 2"],
"tags": ["tag1", "tag2", "keyword"],
"featured_image_url": "https://...",
"gallery_images": [{"url": "...", "alt": "...", "caption": "..."}],
"status": "publish",
"primary_keyword": "...",
"secondary_keywords": ["...", "..."],
"cluster_id": 789,
"sector_id": 101,
"content_type": "blog_post",
"content_structure": "..."
}
🗂️ WordPress Database Mapping
Core Post Data (wp_posts)
post_title← titlepost_content← content_html (sanitized)post_excerpt← excerpt (auto-generated)post_status← status (mapped: draft→draft, published→publish, review→publish)post_type← resolved from content_type (default: "post")post_author← mapped from WordPress author settingspost_date← published_at (if provided)post_date_gmt← published_at (converted to GMT)
Post Meta (wp_postmeta)
_igny8_content_id← content_id_igny8_cluster_id← cluster_id_igny8_sector_id← sector_id_igny8_content_type← content_type_igny8_content_structure← content_structure_igny8_meta_title← meta_title_igny8_meta_description← meta_description_yoast_wpseo_title← meta_title (Yoast SEO)_yoast_wpseo_metadesc← meta_description (Yoast SEO)_seopress_titles_title← meta_title (SEOPress)_seopress_titles_desc← meta_description (SEOPress)_aioseo_title← meta_title (AIOSEO)_aioseo_description← meta_description (AIOSEO)_thumbnail_id← featured image attachment ID
Taxonomies (wp_term_relationships, wp_terms)
category← categories array + cluster.name (fallback)post_tag← tags array + primary_keyword + secondary_keywordsigny8_clusters← cluster_id (custom taxonomy)igny8_sectors← sector_id (custom taxonomy)
Attachments (wp_posts type=attachment)
- Featured image ← downloaded from featured_image_url
- Gallery images ← downloaded from gallery_images[].url
🔧 Backend Code Locations
Publisher Service
File: backend/igny8_core/business/publishing/services/publisher_service.py
PublisherService._publish_to_destination()- Main orchestration- Updates
content.external_id,content.external_url,content.status='published'after success
WordPress Adapter
File: backend/igny8_core/business/publishing/services/adapters/wordpress_adapter.py
WordPressAdapter.publish()- Entry pointWordPressAdapter._publish_via_api_key()- Prepares payload and sends to WordPress- Line 147-160: Extracts optional fields (meta_title, meta_description, keywords, cluster, sector)
- Line 162-178: Gets categories from
taxonomy_terms.filter(taxonomy_type='category') - Line 180-212: Gets tags from
taxonomy_terms.filter(taxonomy_type='tag')+ primary_keyword + secondary_keywords - Line 214-253: Gets images (featured + gallery) from
Imagesmodel
Publisher ViewSet
File: backend/igny8_core/modules/writer/views.py
PublisherViewSet.publish()- API endpoint handler
🎯 WordPress Plugin Code Locations
REST API Endpoint
File: igny8-wp-plugin/includes/class-igny8-rest-api.php
- Line 90: Registers
/wp-json/igny8/v1/publishendpoint - Line 490-631:
publish_content_to_wordpress()- Validates request, logs data, calls creation function
Post Creation Function
File: igny8-wp-plugin/sync/igny8-to-wp.php
- Line 73-300+:
igny8_create_wordpress_post_from_task()- Main creation function- Line 106: Prepares
content_html(acceptscontent_htmlor legacycontent) - Line 112: Maps author via
igny8_map_content_author() - Line 118-131: Creates post data array with title, content, excerpt, status, type, author
- Line 133-138: Sets publication date if provided
- Line 141-175: Adds IGNY8 metadata (_igny8_content_id, _igny8_cluster_id, etc.)
- Line 178: Creates post with
wp_insert_post() - Line 186: Imports SEO metadata via
igny8_import_seo_metadata() - Line 189: Imports featured image via
igny8_import_featured_image() - Line 192: Imports taxonomies via
igny8_import_taxonomies() - Line 195: Imports/processes content images via
igny8_import_content_images() - Line 209-238: Processes and assigns categories via
igny8_process_categories() - Line 241-258: Processes and assigns tags via
igny8_process_tags() - Line 261-273: Sets featured image from URL
- Line 274-299: Sets SEO meta fields for Yoast/SEOPress/AIOSEO
- Line 106: Prepares
📈 Field Usage Statistics
Currently Published: 19 fields
- Core content: title, content_html, excerpt, status
- SEO: meta_title, meta_description, primary_keyword, secondary_keywords
- Taxonomies: categories (via taxonomy_terms), tags (via taxonomy_terms), cluster (fallback), sector
- Images: featured_image_url, gallery_images
- Tracking: content_id, cluster_id, sector_id, content_type, content_structure
Available But Unused: 4 fields
- published_at (WordPress accepts, backend doesn't send)
- source (WordPress accepts, backend doesn't send)
- author (WordPress has fallback mapping, backend doesn't send)
- task_id (WordPress accepts, backend doesn't send)
Not Published: 9 fields
- word_count, optimization_scores, metadata, internal_links
- slug (WordPress auto-generates)
- ai_content_brief, ai_response_raw (IGNY8-internal)
- external_id, external_url (return values from WordPress)
- external_metadata (not sent)
🚀 Recent Enhancements (2025-12-01)
Content Status Update
After successful WordPress publish, IGNY8 backend now updates:
content.status = 'published'
content.save()
File: publisher_service.py line 184
Error Handling Improvements
Frontend now shows proper error messages instead of "undefined":
errorMessage = "Publishing failed"
File: frontend/src/pages/Writer/Review.tsx
Taxonomy Integration Fixed
Categories and tags now properly extracted from ContentTaxonomy M2M relationship:
categories = [term.name for term in content.taxonomy_terms.filter(taxonomy_type='category')]
tags = [term.name for term in content.taxonomy_terms.filter(taxonomy_type='tag')]
File: wordpress_adapter.py lines 162-178, 180-212
🔍 Verification & Testing
Check WordPress Logs
WordPress plugin logs to /wp-content/uploads/igny8-logs/:
tail -f /path/to/wordpress/wp-content/uploads/igny8-logs/igny8-YYYY-MM-DD.log
Check IGNY8 Celery Logs
docker logs -f igny8_celery_worker
Verify Published Post
After publishing, IGNY8 saves:
content.external_id= WordPress post_idcontent.external_url= WordPress post URLcontent.status= 'published'
Database Queries
IGNY8 Backend:
-- Check content with taxonomies
SELECT c.id, c.title, c.status, c.external_id, c.external_url,
COUNT(DISTINCT ctr.id) as taxonomy_count
FROM igny8_content c
LEFT JOIN igny8_content_taxonomy_relations ctr ON c.id = ctr.content_id
WHERE c.id = 456
GROUP BY c.id;
-- Check taxonomy terms for content
SELECT ct.name, ct.taxonomy_type, ct.slug
FROM igny8_content_taxonomy_terms ct
JOIN igny8_content_taxonomy_relations ctr ON ct.id = ctr.taxonomy_id
WHERE ctr.content_id = 456;
WordPress:
-- Check post and meta
SELECT p.ID, p.post_title, p.post_status, pm.meta_key, pm.meta_value
FROM wp_posts p
LEFT JOIN wp_postmeta pm ON p.ID = pm.post_id
WHERE pm.meta_key = '_igny8_content_id' AND pm.meta_value = '456';
-- Check categories and tags
SELECT t.name, tt.taxonomy
FROM wp_terms t
JOIN wp_term_taxonomy tt ON t.term_id = tt.term_id
JOIN wp_term_relationships tr ON tt.term_taxonomy_id = tr.term_taxonomy_id
WHERE tr.object_id = <post_id>;
💡 Recommendations
Potentially Useful Fields to Publish
- published_at - Allow scheduled publishing
- author - Map IGNY8 user to WordPress author
- word_count - Store as post_meta for analytics
- optimization_scores - Store as post_meta for content quality tracking
Fields to Keep Internal
ai_content_brief,ai_response_raw- IGNY8-specific, no value in WordPressexternal_metadata- Already used for other destinations (Shopify, Sites)metadata- Generic field, may contain IGNY8-specific data