""" 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), }