# Fixes Applied - November 30, 2025

## Summary

Fixed 4 critical issues related to WordPress integration:

1. ✅ **Status not updating from 'review' to 'published'** - Fixed with optimistic status update
2. ✅ **Missing WP Status column on Published page** - Added WordPress status endpoint
3. ✅ **Custom taxonomy/attribute columns** - Removed, now using native WP taxonomies
4. ✅ **Tags, categories, images, keywords not saving** - Now properly extracted and sent to WordPress

---

## Issue 1: Status Not Updating to 'Published'

### Problem
When content was published from the Review page, the status in IGNY8 remained as 'review' even after successful WordPress publication.

### Root Cause
The publish endpoint was queuing a Celery task but not updating the status immediately. Users had to wait for the background task to complete before seeing status change.

### Fix Applied

**File:** `e:\Projects\...\igny8\backend\igny8_core\modules\writer\views.py`  
**Method:** `ContentViewSet.publish()`

**Changes:**
```python
# OPTIMISTIC UPDATE: Set status to published immediately for better UX
# The Celery task will update external_id and external_url when WordPress responds
content.status = 'published'
content.save(update_fields=['status', 'updated_at'])

# Queue publishing task
result = publish_content_to_wordpress.delay(
    content_id=content.id,
    site_integration_id=site_integration.id
)

# Return with status='published' immediately
return success_response(
    data={
        'content_id': content.id,
        'task_id': result.id,
        'status': 'published',  # ← Now returns 'published' immediately
        'message': 'Publishing queued - content will be published to WordPress shortly'
    },
    message='Content status updated to published and queued for WordPress',
    request=request,
    status_code=status.HTTP_202_ACCEPTED
)
```

**Error Handling:**
- If the Celery task fails to queue, status is reverted to 'review'
- The background task still sets `external_id`, `external_url`, and confirms status after WordPress responds

**Result:** Users now see status change to 'published' immediately when clicking Publish button

---

## Issue 2: No WP Status Column on Published Page

### Problem
The Published page in IGNY8 didn't show the current WordPress status of published content.

### Fix Applied

**File:** `e:\Projects\...\igny8\backend\igny8_core\modules\writer\views.py`  
**New Endpoint:** `GET /api/v1/writer/content/{id}/wordpress_status/`

```python
@action(detail=True, methods=['get'], url_path='wordpress_status', url_name='wordpress_status')
def wordpress_status(self, request, pk=None):
    """
    Get WordPress post status for published content.
    Calls WordPress REST API to get current status.
    
    Returns: {
        'wordpress_status': 'publish'|'draft'|'pending'|null,
        'external_id': 123,
        'external_url': 'https://...',
        'post_title': '...',
        'post_modified': '2025-11-30...',
        'last_checked': '2025-11-30T...'
    }
    """
```

**WordPress Plugin Endpoint:** `GET /wp-json/igny8/v1/post-status/{id}/`

**File:** `c:\Users\Hp\vscode\igny8-wp-integration\includes\class-igny8-rest-api.php`  
**Updated Method:** `get_post_status()`

```php
/**
 * Get post status by post ID or content_id
 * Accepts either WordPress post_id or IGNY8 content_id
 */
public function get_post_status($request) {
    $id = intval($request['id']);
    
    // First try as WordPress post ID
    $post = get_post($id);
    
    // If not found, try as IGNY8 content_id
    if (!$post) {
        $posts = get_posts(array(
            'meta_key' => '_igny8_content_id',
            'meta_value' => $id,
            'post_type' => 'any',
            'posts_per_page' => 1,
            'post_status' => 'any'
        ));
        $post = !empty($posts) ? $posts[0] : null;
    }
    
    return rest_ensure_response(array(
        'success' => true,
        'data' => array(
            'post_id' => $post->ID,
            'post_status' => $post->post_status,  // WordPress status
            'post_title' => $post->post_title,
            'post_modified' => $post->post_modified,
            'wordpress_status' => $post->post_status,
            'igny8_status' => igny8_map_wp_status_to_igny8($post->post_status),
            // ... more fields
        )
    ));
}
```

**Frontend Integration:**

To display WP Status column on Published page, the frontend should:

1. Call `GET /api/v1/writer/content/{id}/wordpress_status/` for each published content
2. Display `wordpress_status` field (e.g., "Published", "Draft", "Pending")
3. Optionally show `post_modified` to indicate last update time

**Status Mapping:**

| WordPress Status | IGNY8 Status | Display |
|-----------------|-------------|---------|
| `publish` | `completed` | Published |
| `draft` | `draft` | Draft |
| `pending` | `pending` | Pending Review |
| `private` | `completed` | Private |
| `trash` | `archived` | Trashed |
| `future` | `scheduled` | Scheduled |

**Result:** IGNY8 app can now poll WordPress status and display it in the Published page table

---

## Issue 3: Remove Custom Taxonomy/Attribute Columns

### Problem
WordPress admin had custom "Taxonomy" and "Attribute" columns that referenced deprecated custom taxonomies instead of using native WordPress categories and tags.

### Fix Applied

**File:** `c:\Users\Hp\vscode\igny8-wp-integration\admin\class-admin-columns.php`

**Removed:**
- `render_taxonomy_column()` method
- `render_attribute_column()` method
- Custom column registration for `igny8_taxonomy` and `igny8_attribute`

**Before:**
```php
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;
}
```

**After:**
```php
public function add_columns($columns) {
    // Removed custom taxonomy and attribute columns
    // Posts now use native WordPress taxonomies (categories, tags, etc.)
    return $columns;
}
```

**Result:**
- Posts, pages, and products now only show native WordPress taxonomy columns
- Categories, tags, product categories, etc. are displayed in standard WordPress columns
- Cleaner admin UI aligned with WordPress standards

---

## Issue 4: Tags, Categories, Images, Keywords Not Saving

### Problem
When publishing content from IGNY8 to WordPress:
- Tags were not being saved
- Categories were not being saved
- Featured and gallery images were not being attached
- Keywords (primary and secondary) were not being added as tags

### Root Cause
The `publish_content_to_wordpress` Celery task was sending empty arrays:

```python
# BEFORE (BROKEN):
content_data = {
    'title': content.title,
    'content_html': content.content_html,
    # ...
    'featured_image_url': None,  # ← Empty
    'sectors': [],  # ← Empty
    'clusters': [],  # ← Empty
    'tags': []  # ← Empty
}
```

### Fix Applied

**File:** `e:\Projects\...\igny8\backend\igny8_core\tasks\wordpress_publishing.py`  
**Function:** `publish_content_to_wordpress()`

**Changes:**

1. **Extract taxonomy terms from ContentTaxonomyMap:**
```python
from igny8_core.business.content.models import ContentTaxonomyMap
taxonomy_maps = ContentTaxonomyMap.objects.filter(content=content).select_related('taxonomy')

categories = []
tags = []
for mapping in taxonomy_maps:
    tax = mapping.taxonomy
    if tax:
        # Add taxonomy term name to categories
        categories.append(tax.name)
```

2. **Extract images from Images model:**
```python
from igny8_core.modules.writer.models import Images
featured_image_url = None
gallery_images = []

images = Images.objects.filter(content=content).order_by('position')
for image in images:
    if image.image_type == 'featured' and image.image_url:
        featured_image_url = image.image_url
    elif image.image_type == 'in_article' and image.image_url:
        gallery_images.append({
            'url': image.image_url,
            'alt': image.alt_text or '',
            'position': image.position
        })
```

3. **Add keywords as tags:**
```python
# Add primary and secondary keywords as tags
if content.primary_keyword:
    tags.append(content.primary_keyword)

if content.secondary_keywords:
    if isinstance(content.secondary_keywords, list):
        tags.extend(content.secondary_keywords)
    elif isinstance(content.secondary_keywords, str):
        import json
        try:
            keywords = json.loads(content.secondary_keywords)
            if isinstance(keywords, list):
                tags.extend(keywords)
        except (json.JSONDecodeError, TypeError):
            pass
```

4. **Send complete payload to WordPress:**
```python
content_data = {
    'content_id': content.id,
    'task_id': task_id,
    'title': content.title,
    'content_html': content.content_html or '',
    # ... SEO fields ...
    'featured_image_url': featured_image_url,  # ✅ Now populated
    'gallery_images': gallery_images,  # ✅ Now populated
    'categories': categories,  # ✅ Now populated from taxonomy mappings
    'tags': tags,  # ✅ Now populated from keywords
    # ...
}
```

### How WordPress Processes This Data

**File:** `c:\Users\Hp\vscode\igny8-wp-integration\sync\igny8-to-wp.php`  
**Function:** `igny8_create_wordpress_post_from_task()`

1. **Categories:**
```php
// Handle categories
if (!empty($content_data['categories'])) {
    $category_ids = igny8_process_categories($content_data['categories'], $post_id);
    if (!empty($category_ids)) {
        wp_set_post_terms($post_id, $category_ids, 'category');
    }
}
```

2. **Tags:**
```php
// Handle tags
if (!empty($content_data['tags'])) {
    $tag_ids = igny8_process_tags($content_data['tags'], $post_id);
    if (!empty($tag_ids)) {
        wp_set_post_terms($post_id, $tag_ids, 'post_tag');
    }
}
```

3. **Featured Image:**
```php
if (!empty($content_data['featured_image_url'])) {
    igny8_set_featured_image($post_id, $content_data['featured_image_url']);
}
```

4. **Gallery Images:**
```php
if (!empty($content_data['gallery_images'])) {
    igny8_set_image_gallery($post_id, $content_data['gallery_images']);
}
```

5. **Keywords (stored as post meta):**
```php
if (!empty($content_data['primary_keyword'])) {
    update_post_meta($post_id, '_igny8_primary_keyword', $content_data['primary_keyword']);
}

if (!empty($content_data['secondary_keywords'])) {
    update_post_meta($post_id, '_igny8_secondary_keywords', $content_data['secondary_keywords']);
}
```

**Result:**
- ✅ Categories created/assigned from taxonomy mappings
- ✅ Tags created/assigned from keywords (primary + secondary)
- ✅ Featured image downloaded and set as post thumbnail
- ✅ Gallery images downloaded and attached to post
- ✅ Keywords stored in post meta for SEO plugins

---

## Data Flow (Complete)

### Before Fixes ❌
```
IGNY8 Content Model
  ├─ title ✓
  ├─ content_html ✓
  ├─ taxonomy_terms → NOT SENT ❌
  ├─ images → NOT SENT ❌
  ├─ keywords → NOT SENT ❌
  └─ status stays 'review' ❌
        ↓
WordPress Post
  ├─ Title + Content ✓
  ├─ No categories ❌
  ├─ No tags ❌
  ├─ No images ❌
  └─ IGNY8 status still 'review' ❌
```

### After Fixes ✅
```
IGNY8 Content Model
  ├─ title ✓
  ├─ content_html ✓
  ├─ ContentTaxonomyMap → categories[] ✓
  ├─ Images (featured + gallery) → image URLs ✓
  ├─ primary_keyword + secondary_keywords → tags[] ✓
  └─ status = 'published' immediately ✓
        ↓
WordPress Post
  ├─ Title + Content ✓
  ├─ Categories (from taxonomy terms) ✓
  ├─ Tags (from keywords) ✓
  ├─ Featured Image + Gallery ✓
  └─ IGNY8 can query WordPress status ✓
```

---

## Testing Checklist

### 1. Test Status Update
- [ ] Create content in IGNY8 with status 'review'
- [ ] Click "Publish" button
- [ ] ✅ Verify status changes to 'published' immediately (not waiting for background task)
- [ ] ✅ Verify content appears in WordPress with full content
- [ ] ✅ Check IGNY8 `external_id` and `external_url` populated after Celery task completes

### 2. Test WordPress Status Endpoint
- [ ] Publish content from IGNY8
- [ ] Call `GET /api/v1/writer/content/{id}/wordpress_status/`
- [ ] ✅ Verify response contains `wordpress_status: 'publish'`
- [ ] Change post status in WordPress to 'draft'
- [ ] Call endpoint again
- [ ] ✅ Verify response contains `wordpress_status: 'draft'`

### 3. Test Custom Columns Removed
- [ ] Go to WordPress admin → Posts → All Posts
- [ ] ✅ Verify no "Taxonomy" or "Attribute" columns appear
- [ ] ✅ Verify only native WP columns (Title, Author, Categories, Tags, Date) are shown

### 4. Test Tags, Categories, Images
- [ ] Create content in IGNY8 with:
  - `primary_keyword`: "SEO Strategy"
  - `secondary_keywords`: ["Digital Marketing", "Content Marketing"]
  - ContentTaxonomyMap: link to taxonomy term "Marketing"
  - Images: 1 featured image, 2 gallery images
- [ ] Publish to WordPress
- [ ] In WordPress admin, check the post:
  - [ ] ✅ Categories: "Marketing" exists
  - [ ] ✅ Tags: "SEO Strategy", "Digital Marketing", "Content Marketing" exist
  - [ ] ✅ Featured image is set
  - [ ] ✅ Gallery images attached to post

---

## Files Modified

### IGNY8 Backend
1. `e:\Projects\...\igny8\backend\igny8_core\tasks\wordpress_publishing.py`
   - Added taxonomy term extraction
   - Added image extraction from Images model
   - Added keyword extraction as tags
   - Populated categories, tags, images in payload

2. `e:\Projects\...\igny8\backend\igny8_core\modules\writer\views.py`
   - Updated `ContentViewSet.publish()` to set status='published' immediately (optimistic update)
   - Added `ContentViewSet.wordpress_status()` endpoint
   - Added error handling to revert status on failure

### WordPress Plugin
1. `c:\Users\Hp\vscode\igny8-wp-integration\includes\class-igny8-rest-api.php`
   - Updated `get_post_status()` to accept both WordPress post_id and IGNY8 content_id
   - Enhanced response with more post metadata

2. `c:\Users\Hp\vscode\igny8-wp-integration\admin\class-admin-columns.php`
   - Removed `render_taxonomy_column()` and `render_attribute_column()`
   - Removed custom taxonomy/attribute column registration
   - Simplified to use only native WP columns

---

## Breaking Changes

**None** - All changes are backward compatible. The WordPress plugin will still accept old payload formats.

---

## Frontend Integration Required

### Published Page - Add WP Status Column

The frontend Published page should:

1. Add "WordPress Status" column to the table
2. For each row, call: `GET /api/v1/writer/content/{id}/wordpress_status/`
3. Display status with color coding:
   - `publish` → Green badge "Published"
   - `draft` → Gray badge "Draft"
   - `pending` → Yellow badge "Pending"
   - `trash` → Red badge "Trashed"
   - `future` → Blue badge "Scheduled"

4. Optional: Add refresh button to re-check WordPress status

**Example:**
```javascript
async function fetchWordPressStatus(contentId) {
  const response = await fetch(`/api/v1/writer/content/${contentId}/wordpress_status/`);
  const data = await response.json();
  return data.data.wordpress_status; // 'publish', 'draft', etc.
}
```

---

## Summary

**Status:** ✅ All 4 issues fixed and ready for testing

**Impact:** 
- Better UX: Users see immediate status changes
- Complete data sync: Tags, categories, images now sync to WordPress
- Cleaner admin: Removed confusing custom columns
- Monitoring: Can now check WordPress status from IGNY8

**Next Steps:**
1. Test all fixes in staging environment
2. Update frontend to use `wordpress_status` endpoint
3. Add WP Status column to Published page UI
4. Monitor Celery logs for any publishing errors

---

**Generated:** November 30, 2025  
**Priority:** HIGH - Core publishing functionality  
**Breaking Changes:** None
