Files
igny8/backend/igny8_core/utils/wordpress.py
2025-11-09 10:27:02 +00:00

219 lines
7.1 KiB
Python

"""
WordPress Integration Service
Handles communication with WordPress sites via REST API
"""
import logging
import requests
from typing import Dict, Any, Optional
from django.conf import settings
logger = logging.getLogger(__name__)
class WordPressClient:
"""
WordPress REST API client for content publishing and sync.
"""
def __init__(self, site_url: str, username: str = None, app_password: str = None):
"""
Initialize WordPress client.
Args:
site_url: WordPress site URL (e.g., https://example.com)
username: WordPress username or application password username
app_password: WordPress application password
"""
self.site_url = site_url.rstrip('/')
self.api_base = f"{self.site_url}/wp-json/wp/v2"
self.igny8_api_base = f"{self.site_url}/wp-json/igny8/v1" # Custom IGNY8 endpoints
self.username = username
self.app_password = app_password
self.session = requests.Session()
# Set up authentication if provided
if username and app_password:
self.session.auth = (username, app_password)
def test_connection(self) -> Dict[str, Any]:
"""
Test connection to WordPress site.
Returns:
Dict with 'success', 'message', 'wp_version'
"""
try:
response = self.session.get(f"{self.api_base}/")
if response.status_code == 200:
data = response.json()
return {
'success': True,
'message': 'Connection successful',
'wp_version': data.get('version', 'Unknown'),
}
return {
'success': False,
'message': f"HTTP {response.status_code}",
'wp_version': None,
}
except Exception as e:
logger.error(f"WordPress connection test failed: {e}")
return {
'success': False,
'message': str(e),
'wp_version': None,
}
def create_post(
self,
title: str,
content: str,
status: str = 'draft',
featured_image_url: Optional[str] = None,
**kwargs
) -> Dict[str, Any]:
"""
Create a new WordPress post.
Args:
title: Post title
content: Post content (HTML or blocks)
status: Post status ('draft', 'publish', 'pending')
featured_image_url: URL of featured image (must be uploaded first)
**kwargs: Additional post fields (excerpt, categories, etc.)
Returns:
Dict with 'success', 'post_id', 'url', 'error'
"""
try:
post_data = {
'title': title,
'content': content,
'status': status,
**kwargs
}
if featured_image_url:
# Convert URL to media ID if needed
media_id = self._get_media_id_from_url(featured_image_url)
if media_id:
post_data['featured_media'] = media_id
response = self.session.post(f"{self.api_base}/posts", json=post_data)
if response.status_code in [200, 201]:
data = response.json()
return {
'success': True,
'post_id': data.get('id'),
'url': data.get('link'),
'error': None,
}
return {
'success': False,
'post_id': None,
'url': None,
'error': f"HTTP {response.status_code}: {response.text}",
}
except Exception as e:
logger.error(f"WordPress post creation failed: {e}")
return {
'success': False,
'post_id': None,
'url': None,
'error': str(e),
}
def upload_image(self, image_url: str, filename: str = None) -> Dict[str, Any]:
"""
Upload an image to WordPress media library.
Args:
image_url: URL of image to upload
filename: Optional filename
Returns:
Dict with 'success', 'media_id', 'url', 'error'
"""
try:
# Download image
img_response = requests.get(image_url)
if img_response.status_code != 200:
return {
'success': False,
'media_id': None,
'url': None,
'error': f"Failed to download image: HTTP {img_response.status_code}",
}
# Upload to WordPress
files = {
'file': (filename or 'image.jpg', img_response.content, img_response.headers.get('content-type', 'image/jpeg'))
}
response = self.session.post(f"{self.api_base}/media", files=files)
if response.status_code in [200, 201]:
data = response.json()
return {
'success': True,
'media_id': data.get('id'),
'url': data.get('source_url'),
'error': None,
}
return {
'success': False,
'media_id': None,
'url': None,
'error': f"HTTP {response.status_code}: {response.text}",
}
except Exception as e:
logger.error(f"WordPress image upload failed: {e}")
return {
'success': False,
'media_id': None,
'url': None,
'error': str(e),
}
def _get_media_id_from_url(self, url: str) -> Optional[int]:
"""Helper to get media ID from URL (if already uploaded)."""
# TODO: Implement media lookup by URL
return None
def sync_settings(self, settings_data: Dict[str, Any]) -> Dict[str, Any]:
"""
Sync settings to WordPress via custom IGNY8 endpoint.
Args:
settings_data: Settings dictionary to sync
Returns:
Dict with 'success', 'message', 'error'
"""
try:
response = self.session.post(
f"{self.igny8_api_base}/sync-settings",
json=settings_data
)
if response.status_code == 200:
return {
'success': True,
'message': 'Settings synced successfully',
'error': None,
}
return {
'success': False,
'message': None,
'error': f"HTTP {response.status_code}: {response.text}",
}
except Exception as e:
logger.error(f"WordPress settings sync failed: {e}")
return {
'success': False,
'message': None,
'error': str(e),
}