123
This commit is contained in:
@@ -136,6 +136,7 @@ class WordPressAdapter(BaseAdapter):
|
|||||||
"""
|
"""
|
||||||
import requests
|
import requests
|
||||||
from django.utils.html import strip_tags
|
from django.utils.html import strip_tags
|
||||||
|
import json
|
||||||
|
|
||||||
logger.info(f"[WordPressAdapter._publish_via_api_key] 📦 Preparing payload for {site_url}")
|
logger.info(f"[WordPressAdapter._publish_via_api_key] 📦 Preparing payload for {site_url}")
|
||||||
|
|
||||||
@@ -147,7 +148,7 @@ class WordPressAdapter(BaseAdapter):
|
|||||||
excerpt += '...'
|
excerpt += '...'
|
||||||
logger.info(f"[WordPressAdapter._publish_via_api_key] 📝 Generated excerpt: {excerpt[:50]}...")
|
logger.info(f"[WordPressAdapter._publish_via_api_key] 📝 Generated excerpt: {excerpt[:50]}...")
|
||||||
|
|
||||||
# Prepare payload
|
# Prepare base payload
|
||||||
content_data = {
|
content_data = {
|
||||||
'content_id': content.id if hasattr(content, 'id') else None,
|
'content_id': content.id if hasattr(content, 'id') else None,
|
||||||
'title': title,
|
'title': title,
|
||||||
@@ -177,6 +178,99 @@ class WordPressAdapter(BaseAdapter):
|
|||||||
if hasattr(content, 'sector') and content.sector:
|
if hasattr(content, 'sector') and content.sector:
|
||||||
content_data['sector_id'] = content.sector.id
|
content_data['sector_id'] = content.sector.id
|
||||||
optional_fields.append('sector_id')
|
optional_fields.append('sector_id')
|
||||||
|
|
||||||
|
# STEP: Get categories from taxonomy_terms
|
||||||
|
categories = []
|
||||||
|
if hasattr(content, 'taxonomy_terms'):
|
||||||
|
categories = [
|
||||||
|
term.name
|
||||||
|
for term in content.taxonomy_terms.filter(taxonomy_type='category')
|
||||||
|
]
|
||||||
|
logger.info(f"[WordPressAdapter._publish_via_api_key] 📁 Found {len(categories)} categories from taxonomy_terms")
|
||||||
|
|
||||||
|
# FALLBACK: Use cluster as category if no categories found
|
||||||
|
if not categories and hasattr(content, 'cluster') and content.cluster:
|
||||||
|
categories.append(content.cluster.name)
|
||||||
|
logger.info(f"[WordPressAdapter._publish_via_api_key] 📁 Using cluster as category: {content.cluster.name}")
|
||||||
|
|
||||||
|
content_data['categories'] = categories
|
||||||
|
optional_fields.append(f'categories({len(categories)})')
|
||||||
|
|
||||||
|
# STEP: Get tags from taxonomy_terms + keywords
|
||||||
|
tags = []
|
||||||
|
if hasattr(content, 'taxonomy_terms'):
|
||||||
|
tags = [
|
||||||
|
term.name
|
||||||
|
for term in content.taxonomy_terms.filter(taxonomy_type='tag')
|
||||||
|
]
|
||||||
|
logger.info(f"[WordPressAdapter._publish_via_api_key] 🏷️ Found {len(tags)} tags from taxonomy_terms")
|
||||||
|
|
||||||
|
# Add primary keyword as tag
|
||||||
|
if hasattr(content, 'primary_keyword') and content.primary_keyword:
|
||||||
|
if content.primary_keyword not in tags:
|
||||||
|
tags.append(content.primary_keyword)
|
||||||
|
|
||||||
|
# Add secondary keywords as tags
|
||||||
|
if hasattr(content, 'secondary_keywords') and content.secondary_keywords:
|
||||||
|
if isinstance(content.secondary_keywords, list):
|
||||||
|
for keyword in content.secondary_keywords:
|
||||||
|
if keyword and keyword not in tags:
|
||||||
|
tags.append(keyword)
|
||||||
|
elif isinstance(content.secondary_keywords, str):
|
||||||
|
try:
|
||||||
|
keywords = json.loads(content.secondary_keywords)
|
||||||
|
if isinstance(keywords, list):
|
||||||
|
for keyword in keywords:
|
||||||
|
if keyword and keyword not in tags:
|
||||||
|
tags.append(keyword)
|
||||||
|
except (json.JSONDecodeError, TypeError):
|
||||||
|
pass
|
||||||
|
|
||||||
|
content_data['tags'] = tags
|
||||||
|
optional_fields.append(f'tags({len(tags)})')
|
||||||
|
|
||||||
|
# STEP: Get images (featured + gallery)
|
||||||
|
featured_image_url = None
|
||||||
|
gallery_images = []
|
||||||
|
|
||||||
|
if hasattr(content, 'id'):
|
||||||
|
try:
|
||||||
|
from igny8_core.modules.writer.models import Images
|
||||||
|
images = Images.objects.filter(content=content).order_by('position')
|
||||||
|
logger.info(f"[WordPressAdapter._publish_via_api_key] 🖼️ Found {images.count()} images")
|
||||||
|
|
||||||
|
def convert_image_path_to_url(image_path):
|
||||||
|
"""Convert local image path to public URL"""
|
||||||
|
if not image_path:
|
||||||
|
return None
|
||||||
|
if '/frontend/public/' in image_path:
|
||||||
|
relative_path = image_path.split('/frontend/public/')[-1]
|
||||||
|
return f"https://app.igny8.com/{relative_path}"
|
||||||
|
return image_path
|
||||||
|
|
||||||
|
for image in images:
|
||||||
|
image_url = convert_image_path_to_url(image.image_path) if hasattr(image, 'image_path') and image.image_path else None
|
||||||
|
|
||||||
|
if image.image_type == 'featured' and image_url:
|
||||||
|
featured_image_url = image_url
|
||||||
|
logger.info(f"[WordPressAdapter._publish_via_api_key] 🖼️ Featured image: {image_url[:80]}...")
|
||||||
|
elif image.image_type == 'in_article' and image_url:
|
||||||
|
gallery_images.append({
|
||||||
|
'url': image_url,
|
||||||
|
'alt': getattr(image, 'alt', '') or '',
|
||||||
|
'caption': getattr(image, 'caption', '') or ''
|
||||||
|
})
|
||||||
|
logger.info(f"[WordPressAdapter._publish_via_api_key] 🖼️ Gallery image {len(gallery_images)}")
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning(f"[WordPressAdapter._publish_via_api_key] ⚠️ Could not load images: {e}")
|
||||||
|
|
||||||
|
content_data['featured_image_url'] = featured_image_url
|
||||||
|
content_data['gallery_images'] = gallery_images
|
||||||
|
if featured_image_url:
|
||||||
|
optional_fields.append('featured_image')
|
||||||
|
if gallery_images:
|
||||||
|
optional_fields.append(f'gallery({len(gallery_images)})')
|
||||||
|
|
||||||
logger.info(f"[WordPressAdapter._publish_via_api_key] ➕ Added optional fields: {', '.join(optional_fields)}")
|
logger.info(f"[WordPressAdapter._publish_via_api_key] ➕ Added optional fields: {', '.join(optional_fields)}")
|
||||||
|
|
||||||
# Call WordPress endpoint
|
# Call WordPress endpoint
|
||||||
|
|||||||
@@ -178,6 +178,36 @@ export function createReviewPageConfig(params: {
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
key: 'status',
|
||||||
|
label: 'Status',
|
||||||
|
sortable: true,
|
||||||
|
sortField: 'status',
|
||||||
|
width: '120px',
|
||||||
|
render: (value: string, row: Content) => {
|
||||||
|
const status = value || 'draft';
|
||||||
|
const statusColors: Record<string, 'gray' | 'blue' | 'green' | 'amber' | 'red'> = {
|
||||||
|
draft: 'gray',
|
||||||
|
review: 'blue',
|
||||||
|
published: 'green',
|
||||||
|
scheduled: 'amber',
|
||||||
|
archived: 'red',
|
||||||
|
};
|
||||||
|
const color = statusColors[status] || 'gray';
|
||||||
|
const label = status.charAt(0).toUpperCase() + status.slice(1);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="flex items-center gap-1.5">
|
||||||
|
<Badge color={color} size="xs" variant="soft">
|
||||||
|
<span className="text-[11px] font-normal">{label}</span>
|
||||||
|
</Badge>
|
||||||
|
{row.external_id && (
|
||||||
|
<CheckCircleIcon className="w-3.5 h-3.5 text-green-500" title="Published to WordPress" />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
key: 'word_count',
|
key: 'word_count',
|
||||||
label: 'Words',
|
label: 'Words',
|
||||||
|
|||||||
Reference in New Issue
Block a user