Files
igny8/docs/WORDPRESS-PUBLISHING-FIELD-MAPPING.md
IGNY8 VPS (Salman) 7357846527 docs
2025-12-01 06:47:13 +00:00

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_idswp_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_idswp_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 ← title
  • post_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 settings
  • post_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_keywords
  • igny8_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 point
  • WordPressAdapter._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 Images model

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/publish endpoint
  • 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 (accepts content_html or legacy content)
    • 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

📈 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_id
  • content.external_url = WordPress post URL
  • content.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

  1. published_at - Allow scheduled publishing
  2. author - Map IGNY8 user to WordPress author
  3. word_count - Store as post_meta for analytics
  4. 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 WordPress
  • external_metadata - Already used for other destinations (Shopify, Sites)
  • metadata - Generic field, may contain IGNY8-specific data