appa dn plugin udpates for integrationa dn final touches

This commit is contained in:
IGNY8 VPS (Salman)
2026-01-13 09:23:54 +00:00
parent e053655962
commit d2b733640c
13 changed files with 236 additions and 337 deletions

View File

@@ -85,6 +85,10 @@ The Integrations module manages:
## Data Models ## Data Models
### Authentication Note
**⚠️ Important:** For WordPress integrations, `Site.wp_api_key` is the **SINGLE source of truth** for API authentication, NOT SiteIntegration fields. The SiteIntegration model is used for sync tracking and multi-platform support (future: Shopify).
### SiteIntegration ### SiteIntegration
| Field | Type | Purpose | | Field | Type | Purpose |
@@ -92,14 +96,15 @@ The Integrations module manages:
| account | FK | Owner account | | account | FK | Owner account |
| site | FK | IGNY8 site | | site | FK | IGNY8 site |
| platform | CharField | wordpress/shopify | | platform | CharField | wordpress/shopify |
| site_url | URLField | External site URL | | external_site_url | URLField | External site URL |
| api_key | CharField | WordPress Application Password |
| username | CharField | WordPress username |
| is_active | Boolean | Enable/disable | | is_active | Boolean | Enable/disable |
| sync_enabled | Boolean | Enable auto-sync | | sync_enabled | Boolean | Enable auto-sync |
| last_sync_at | DateTime | Last sync time | | last_sync_at | DateTime | Last sync time |
| sync_status | CharField | idle/syncing/error | | sync_status | CharField | pending/syncing/completed/error |
| metadata | JSON | Platform-specific data | | sync_error | TextField | Sync error message |
| connection_status | CharField | connected/error |
| config_json | JSON | Platform-specific configuration |
| credentials_json | JSON | (Reserved for future platforms, NOT used for WordPress) |
| created_at | DateTime | Creation date | | created_at | DateTime | Creation date |
### SyncEvent ### SyncEvent

View File

@@ -48,10 +48,18 @@ The IGNY8 plugin distribution system provides a comprehensive infrastructure for
| Platform | Plugin Name | Current Version | Status | | Platform | Plugin Name | Current Version | Status |
|----------|-------------|-----------------|--------| |----------|-------------|-----------------|--------|
| WordPress | IGNY8 WP Bridge | 1.3.3 | Production | | WordPress | IGNY8 WP Bridge | 1.5.1 | Production |
| Shopify | IGNY8 Shopify | - | Infrastructure Ready | | Shopify | IGNY8 Shopify | - | Infrastructure Ready |
| Custom | IGNY8 Bridge | - | Infrastructure Ready | | Custom | IGNY8 Bridge | - | Infrastructure Ready |
### WordPress Plugin Admin Pages (v1.5.1)
| Page | Purpose |
|------|---------|
| Dashboard | Connection status, Site ID, masked API key, content stats |
| Settings | Post types, default post status, taxonomies, sync toggle |
| Logs | Webhook activity with timestamps, event types, status |
## System Features ## System Features
### Distribution System ### Distribution System
@@ -96,6 +104,8 @@ Install/Update → Register Installation → Health Check
## Version Progression (Last 20 Commits) ## Version Progression (Last 20 Commits)
**WordPress Plugin Versions:** **WordPress Plugin Versions:**
- v1.5.1 - Admin UI consolidation (6→3 pages), header fixes
- v1.5.0 - Authentication simplification (Site.wp_api_key as single source)
- v1.3.3 - Template design improvements, image layout fixes - v1.3.3 - Template design improvements, image layout fixes
- v1.3.2 - Template fixes in app and plugin - v1.3.2 - Template fixes in app and plugin
- v1.3.1 - WordPress plugin updates - v1.3.1 - WordPress plugin updates
@@ -103,6 +113,8 @@ Install/Update → Register Installation → Health Check
**Infrastructure Updates:** **Infrastructure Updates:**
- Plugin distribution system implemented (v1.7.0) - Plugin distribution system implemented (v1.7.0)
- Authentication simplified to Site.wp_api_key (single source of truth)
- SiteIntegration model retained for sync tracking (not auth)
- Database models for multi-platform support - Database models for multi-platform support
- API endpoints for lifecycle management - API endpoints for lifecycle management
- Automated packaging and versioning - Automated packaging and versioning

View File

@@ -33,6 +33,8 @@ Django Admin → Add Plugin Version → Enter 3 fields → Save → Change statu
| Version | Date | Type | Key Changes | | Version | Date | Type | Key Changes |
|---------|------|------|-------------| |---------|------|------|-------------|
| 1.5.1 | Jan 10, 2026 | Minor | Admin UI consolidation: 6→3 pages (Dashboard, Settings, Logs), header alignment fixes |
| 1.5.0 | Jan 10, 2026 | Minor | Authentication simplification: Site.wp_api_key as single source of truth |
| 1.3.3 | Jan 10, 2026 | Patch | Template design: Square image grid fixes, landscape image positioning, direct border-radius/shadow on images without captions | | 1.3.3 | Jan 10, 2026 | Patch | Template design: Square image grid fixes, landscape image positioning, direct border-radius/shadow on images without captions |
| 1.3.2 | Jan 9, 2026 | Patch | Template fixes in app and plugin, image layout improvements | | 1.3.2 | Jan 9, 2026 | Patch | Template fixes in app and plugin, image layout improvements |
| 1.3.1 | Jan 9, 2026 | Patch | WordPress plugin versioning updates | | 1.3.1 | Jan 9, 2026 | Patch | WordPress plugin versioning updates |

View File

@@ -122,12 +122,20 @@ This document covers the **app-side** management of WordPress integration:
│ │ ├── igny8-bridge.php # Main plugin file │ │ ├── igny8-bridge.php # Main plugin file
│ │ ├── includes/ # PHP classes │ │ ├── includes/ # PHP classes
│ │ ├── admin/ # Admin interface │ │ ├── admin/ # Admin interface
│ │ │ ├── class-admin.php # Menu registration
│ │ │ ├── layout-header.php # Layout wrapper + sidebar
│ │ │ ├── layout-footer.php # Footer
│ │ │ ├── settings.php # Settings handler
│ │ │ └── pages/ # Admin pages (3 pages)
│ │ │ ├── connection.php # Dashboard (connection + stats)
│ │ │ ├── settings.php # Post types, taxonomies, sync
│ │ │ └── logs.php # Webhook activity logs
│ │ ├── sync/ # Sync functionality │ │ ├── sync/ # Sync functionality
│ │ ├── templates/ # Frontend templates │ │ ├── templates/ # Frontend templates
│ │ └── docs/ # Plugin-internal docs │ │ └── docs/ # Plugin-internal docs
│ └── dist/ # Distribution files │ └── dist/ # Distribution files
│ ├── igny8-wp-bridge-v1.1.1.zip # Version ZIP │ ├── igny8-wp-bridge-v1.x.x.zip # Version ZIP
│ ├── igny8-wp-bridge-v1.1.1.sha256 │ ├── igny8-wp-bridge-v1.x.x.sha256
│ └── igny8-wp-bridge-latest.zip # Symlink to latest │ └── igny8-wp-bridge-latest.zip # Symlink to latest
└── backend/ └── backend/
@@ -141,6 +149,21 @@ This document covers the **app-side** management of WordPress integration:
└── urls.py # URL routing └── urls.py # URL routing
``` ```
### Plugin Admin Pages
The WordPress plugin provides 3 admin pages:
| Page | File | Purpose |
|------|------|---------|
| Dashboard | `connection.php` | Connection status, Site ID, API key, content stats |
| Settings | `settings.php` | Post types, default post status, taxonomies, sync toggle |
| Logs | `logs.php` | Webhook activity with timestamps, event types, status |
**Layout:**
- Dashboard: 2-column grid (Connection Status + Content Stats)
- Settings: 3-column top row (Post Types + Default Post Status + IGNY8 Sync) + dynamic taxonomy cards
- Logs: Full-width table with search
### How ZIP Files Are Created ### How ZIP Files Are Created
#### Automatic Build (Recommended) #### Automatic Build (Recommended)
@@ -523,19 +546,38 @@ The frontend shows:
### Integration Data Model ### Integration Data Model
**Authentication (Source of Truth):**
```python ```python
# SiteIntegration model (in auth/models.py) # Site model (in auth/models.py) - SINGLE source of truth for API auth
class Site(models.Model):
wp_api_key = models.CharField(max_length=255) # API key for WP authentication
# Used by: PublisherService, test connection, plugin verification
```
**Sync Tracking (SiteIntegration):**
```python
# SiteIntegration model (in auth/models.py) - Tracks sync status, NOT auth
class SiteIntegration(models.Model): class SiteIntegration(models.Model):
site = models.ForeignKey(Site, ...) # IGNY8 site site = models.ForeignKey(Site, ...) # IGNY8 site
platform = models.CharField(...) # "wordpress" platform = models.CharField(...) # "wordpress", "shopify"
external_site_url = models.URLField() # WordPress URL external_site_url = models.URLField() # WordPress URL
api_key = models.CharField(...) # Encrypted key
sync_enabled = models.BooleanField() sync_enabled = models.BooleanField()
last_sync = models.DateTimeField() sync_status = models.CharField(...) # "pending", "syncing", "completed"
last_sync_at = models.DateTimeField()
sync_error = models.TextField(null=True)
connection_status = models.CharField(...) # "connected", "error" connection_status = models.CharField(...) # "connected", "error"
``` ```
**Key Architecture Points:**
- `Site.wp_api_key` is the **SINGLE source of truth** for API authentication
- `SiteIntegration` provides sync tracking but NOT authentication
- Publishing uses `Site.wp_api_key` via `X-IGNY8-API-KEY` header
- SiteIntegration kept for future multi-platform support (Shopify, custom)
--- ---
## 9. Troubleshooting ## 9. Troubleshooting
@@ -638,7 +680,20 @@ unzip -p /data/app/igny8/plugins/wordpress/dist/igny8-wp-bridge-v1.1.1.zip \
- `/register/` - Installation registration - `/register/` - Installation registration
- `/health-check/` - Plugin health monitoring - `/health-check/` - Plugin health monitoring
### WordPress Plugin Updates (v1.3.0 → v1.3.3) ### WordPress Plugin Updates (v1.3.0 → v1.5.1)
**v1.5.1 - Admin UI Consolidation:**
- Reduced admin pages from 6 to 3: Dashboard, Settings, Logs
- Renamed Connection page to Dashboard with content stats
- Removed redundant pages: Data, Sync, old Dashboard
- Settings redesigned with 3-column layout (Post Types + Default Post Status + IGNY8 Sync)
- Fixed header alignment across all pages with proper width styling
- Cleaned up orphaned code and functions
**v1.5.0 - Authentication Simplification:**
- Simplified authentication to use Site.wp_api_key as single source of truth
- Removed redundant access_token handling
- Improved test connection flow using authenticated /verify-key endpoint
**v1.3.3 - Template Design Improvements:** **v1.3.3 - Template Design Improvements:**
- Fixed square images displaying in 2 rows (now side-by-side) - Fixed square images displaying in 2 rows (now side-by-side)
@@ -665,11 +720,12 @@ unzip -p /data/app/igny8/plugins/wordpress/dist/igny8-wp-bridge-v1.1.1.zip \
### Version Progression Timeline ### Version Progression Timeline
``` ```
v1.7.0 (Jan 10, 2026) - App infrastructure + plugin v1.3.3 v1.7.0 (Jan 10, 2026) - App infrastructure + plugin v1.5.1
├── Plugin admin UI consolidation (6→3 pages)
├── Authentication simplification
├── Plugin distribution system complete ├── Plugin distribution system complete
├── Template design overhaul ├── Template design overhaul
── Image layout fixes ── Pre-launch cleanup complete
└── Pre-launch cleanup (Phases 1, 5, 6)
v1.6.2 (Jan 8, 2026) - Design refinements v1.6.2 (Jan 8, 2026) - Design refinements
└── Marketing site updates └── Marketing site updates

View File

@@ -523,28 +523,36 @@ class ContentImage(models.Model):
### SiteIntegration ### SiteIntegration
**⚠️ Note:** For WordPress, `Site.wp_api_key` is the **SINGLE source of truth** for API authentication. SiteIntegration is used for sync tracking and future multi-platform support.
```python ```python
class SiteIntegration(models.Model): class SiteIntegration(models.Model):
id = UUIDField(primary_key=True) id = UUIDField(primary_key=True)
name = CharField(max_length=255) name = CharField(max_length=255)
site = ForeignKey(Site, related_name='integrations') site = ForeignKey(Site, related_name='integrations')
platform = CharField(max_length=50) # wordpress platform = CharField(max_length=50) # wordpress, shopify (future)
# Credentials (encrypted) # Configuration
url = URLField() external_site_url = URLField()
username = CharField(max_length=255) config_json = JSONField(default=dict) # Platform-specific settings
api_key = CharField(max_length=255) # Application password credentials_json = JSONField(default=dict) # Reserved for future platforms (NOT for WordPress)
# Cached structure # Sync Tracking
sync_enabled = BooleanField(default=True)
sync_status = CharField(max_length=50) # pending/syncing/completed/error
last_sync_at = DateTimeField(null=True)
sync_error = TextField(null=True)
# Connection
connection_status = CharField(max_length=50) # connected/error
is_active = BooleanField(default=True)
# Cached WordPress structure (from initial sync)
categories = JSONField(default=list) categories = JSONField(default=list)
tags = JSONField(default=list) tags = JSONField(default=list)
authors = JSONField(default=list) authors = JSONField(default=list)
post_types = JSONField(default=list) post_types = JSONField(default=list)
# Status
is_active = BooleanField(default=True)
last_sync_at = DateTimeField(null=True)
structure_updated_at = DateTimeField(null=True) structure_updated_at = DateTimeField(null=True)
created_at = DateTimeField(auto_now_add=True) created_at = DateTimeField(auto_now_add=True)

View File

@@ -79,15 +79,6 @@ class Igny8Admin {
array($this, 'render_page') array($this, 'render_page')
); );
add_submenu_page(
'igny8-connection',
__('Data', 'igny8-bridge'),
__('Data', 'igny8-bridge'),
'manage_options',
'igny8-data',
array($this, 'render_page')
);
add_submenu_page( add_submenu_page(
'igny8-connection', 'igny8-connection',
__('Logs', 'igny8-bridge'), __('Logs', 'igny8-bridge'),
@@ -281,9 +272,6 @@ class Igny8Admin {
case 'igny8-settings': case 'igny8-settings':
$template_file = IGNY8_BRIDGE_PLUGIN_DIR . 'admin/pages/settings.php'; $template_file = IGNY8_BRIDGE_PLUGIN_DIR . 'admin/pages/settings.php';
break; break;
case 'igny8-data':
$template_file = IGNY8_BRIDGE_PLUGIN_DIR . 'admin/pages/data.php';
break;
case 'igny8-logs': case 'igny8-logs':
$template_file = IGNY8_BRIDGE_PLUGIN_DIR . 'admin/pages/logs.php'; $template_file = IGNY8_BRIDGE_PLUGIN_DIR . 'admin/pages/logs.php';
break; break;

View File

@@ -64,16 +64,6 @@ $is_connected = !empty($api_key);
</a> </a>
</li> </li>
<li>
<a href="<?php echo esc_url(admin_url('admin.php?page=igny8-data')); ?>"
class="<?php echo ($current_page === 'igny8-data') ? 'active' : ''; ?>">
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 7v10c0 2.21 3.582 4 8 4s8-1.79 8-4V7M4 7c0 2.21 3.582 4 8 4s8-1.79 8-4M4 7c0-2.21 3.582-4 8-4s8 1.79 8 4m0 5c0 2.21-3.582 4-8 4s-8-1.79-8-4"/>
</svg>
<?php _e('Data', 'igny8-bridge'); ?>
</a>
</li>
<li> <li>
<a href="<?php echo esc_url(admin_url('admin.php?page=igny8-logs')); ?>" <a href="<?php echo esc_url(admin_url('admin.php?page=igny8-logs')); ?>"
class="<?php echo ($current_page === 'igny8-logs') ? 'active' : ''; ?>"> class="<?php echo ($current_page === 'igny8-logs') ? 'active' : ''; ?>">

View File

@@ -41,7 +41,7 @@ $show_success = isset($_GET['connected']) && $_GET['connected'] === '1';
?> ?>
<div class="igny8-page-header"> <div class="igny8-page-header">
<div style="display: flex; justify-content: space-between; align-items: flex-start;"> <div style="display: flex; justify-content: space-between; align-items: flex-start; width: 100%;">
<div> <div>
<h1><?php _e('Dashboard', 'igny8-bridge'); ?></h1> <h1><?php _e('Dashboard', 'igny8-bridge'); ?></h1>
<p><?php _e('Manage your IGNY8 connection and monitor content', 'igny8-bridge'); ?></p> <p><?php _e('Manage your IGNY8 connection and monitor content', 'igny8-bridge'); ?></p>

View File

@@ -1,156 +0,0 @@
<?php
/**
* Data Page
*
* @package Igny8Bridge
*/
// Prevent direct access
if (!defined('ABSPATH')) {
exit;
}
// Include layout header
include IGNY8_BRIDGE_PLUGIN_DIR . 'admin/layout-header.php';
// Get data statistics
$link_queue = get_option('igny8_link_queue', array());
$pending_links = array_filter($link_queue, function($item) {
return isset($item['status']) && $item['status'] === 'pending';
});
$total_links = count($link_queue);
$pending_count = count($pending_links);
$processed_count = $total_links - $pending_count;
?>
<div class="igny8-page-header">
<div style="display: flex; justify-content: space-between; align-items: flex-start;">
<div>
<h1><?php _e('Data', 'igny8-bridge'); ?></h1>
<p><?php _e('View synced data, queues, and content status', 'igny8-bridge'); ?></p>
</div>
<div style="text-align: right; font-size: 14px; color: rgba(255,255,255,0.9);">
<span style="display: block; font-weight: 500;">Plugin v<?php echo esc_html(IGNY8_BRIDGE_VERSION); ?></span>
<span style="display: block; opacity: 0.75; font-size: 13px;">PHP <?php echo esc_html(PHP_VERSION); ?></span>
</div>
</div>
</div>
<!-- Statistics -->
<div class="igny8-grid igny8-grid-3">
<div class="igny8-card">
<div class="igny8-card-header">
<h2>
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13.828 10.172a4 4 0 00-5.656 0l-4 4a4 4 0 105.656 5.656l1.102-1.101m-.758-4.899a4 4 0 005.656 0l4-4a4 4 0 00-5.656-5.656l-1.1 1.1"/>
</svg>
<?php _e('Total Links', 'igny8-bridge'); ?>
</h2>
</div>
<div style="padding: 16px 0;">
<p style="font-size: 32px; font-weight: 700; margin: 0; color: var(--igny8-primary);">
<?php echo esc_html($total_links); ?>
</p>
</div>
</div>
<div class="igny8-card">
<div class="igny8-card-header">
<h2>
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z"/>
</svg>
<?php _e('Pending', 'igny8-bridge'); ?>
</h2>
</div>
<div style="padding: 16px 0;">
<p style="font-size: 32px; font-weight: 700; margin: 0; color: var(--igny8-warning);">
<?php echo esc_html($pending_count); ?>
</p>
</div>
</div>
<div class="igny8-card">
<div class="igny8-card-header">
<h2>
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"/>
</svg>
<?php _e('Processed', 'igny8-bridge'); ?>
</h2>
</div>
<div style="padding: 16px 0;">
<p style="font-size: 32px; font-weight: 700; margin: 0; color: var(--igny8-success);">
<?php echo esc_html($processed_count); ?>
</p>
</div>
</div>
</div>
<!-- Link Queue -->
<?php if (!empty($link_queue)): ?>
<div class="igny8-card">
<div class="igny8-card-header">
<h2>
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 10h16M4 14h16M4 18h16"/>
</svg>
<?php _e('Link Queue', 'igny8-bridge'); ?>
</h2>
</div>
<table class="igny8-table">
<thead>
<tr>
<th><?php _e('Post Title', 'igny8-bridge'); ?></th>
<th><?php _e('Target URL', 'igny8-bridge'); ?></th>
<th><?php _e('Anchor', 'igny8-bridge'); ?></th>
<th><?php _e('Status', 'igny8-bridge'); ?></th>
</tr>
</thead>
<tbody>
<?php foreach (array_slice($link_queue, 0, 10) as $item): ?>
<tr>
<td>
<?php
$post = get_post($item['post_id'] ?? 0);
echo $post ? esc_html($post->post_title) : __('Unknown Post', 'igny8-bridge');
?>
</td>
<td>
<a href="<?php echo esc_url($item['target_url'] ?? '#'); ?>" target="_blank" style="color: var(--igny8-primary);">
<?php echo esc_html(isset($item['target_url']) ? parse_url($item['target_url'], PHP_URL_HOST) : '—'); ?>
</a>
</td>
<td><?php echo esc_html($item['anchor'] ?? '—'); ?></td>
<td>
<?php if (($item['status'] ?? '') === 'pending'): ?>
<span class="igny8-status igny8-status-disconnected"><?php _e('Pending', 'igny8-bridge'); ?></span>
<?php else: ?>
<span class="igny8-status igny8-status-connected"><?php _e('Processed', 'igny8-bridge'); ?></span>
<?php endif; ?>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<?php if (count($link_queue) > 10): ?>
<p style="margin-top: 16px; color: var(--igny8-text-dim); font-size: 14px;">
<?php printf(__('Showing 10 of %d total items', 'igny8-bridge'), count($link_queue)); ?>
</p>
<?php endif; ?>
</div>
<?php else: ?>
<div class="igny8-alert igny8-alert-success">
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"/>
</svg>
<span><?php _e('No items in link queue. All links have been processed.', 'igny8-bridge'); ?></span>
</div>
<?php endif; ?>
<?php
// Include layout footer
include IGNY8_BRIDGE_PLUGIN_DIR . 'admin/layout-footer.php';
?>

View File

@@ -18,7 +18,7 @@ $webhook_logs = igny8_get_webhook_logs(array('limit' => 20));
?> ?>
<div class="igny8-page-header"> <div class="igny8-page-header">
<div style="display: flex; justify-content: space-between; align-items: flex-start;"> <div style="display: flex; justify-content: space-between; align-items: flex-start; width: 100%;">
<div> <div>
<h1><?php _e('Logs', 'igny8-bridge'); ?></h1> <h1><?php _e('Logs', 'igny8-bridge'); ?></h1>
<p><?php _e('Review webhook activity and troubleshoot sync issues', 'igny8-bridge'); ?></p> <p><?php _e('Review webhook activity and troubleshoot sync issues', 'igny8-bridge'); ?></p>

View File

@@ -1,7 +1,7 @@
<?php <?php
/** /**
* Settings Page (Renamed from Controls) * Settings Page
* Simplified post type and taxonomy management * Configure post types, taxonomies, and sync settings
* *
* @package Igny8Bridge * @package Igny8Bridge
*/ */
@@ -34,7 +34,7 @@ foreach ($all_post_types as $pt) {
?> ?>
<div class="igny8-page-header"> <div class="igny8-page-header">
<div style="display: flex; justify-content: space-between; align-items: flex-start;"> <div style="display: flex; justify-content: space-between; align-items: flex-start; width: 100%;">
<div> <div>
<h1><?php _e('Settings', 'igny8-bridge'); ?></h1> <h1><?php _e('Settings', 'igny8-bridge'); ?></h1>
<p><?php _e('Configure post types, taxonomies, and sync settings', 'igny8-bridge'); ?></p> <p><?php _e('Configure post types, taxonomies, and sync settings', 'igny8-bridge'); ?></p>
@@ -49,50 +49,130 @@ foreach ($all_post_types as $pt) {
<form method="post" action="options.php" id="igny8-settings-form"> <form method="post" action="options.php" id="igny8-settings-form">
<?php settings_fields('igny8_bridge_controls'); ?> <?php settings_fields('igny8_bridge_controls'); ?>
<!-- Post Types Section --> <!-- Top Row: Post Types (1/3) + Default Settings (1/3) + IGNY8 Sync (1/3) -->
<div class="igny8-card" style="margin-bottom: 24px;"> <div class="igny8-grid igny8-grid-3" style="margin-bottom: 24px;">
<div class="igny8-card-header">
<h2>
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24" style="width: 20px; height: 20px;">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"/>
</svg>
<?php _e('Post Types', 'igny8-bridge'); ?>
</h2>
</div>
<p style="margin-bottom: 16px; color: var(--igny8-text-dim);">
<?php _e('Enable post types to sync with IGNY8. Only enabled post types will show their taxonomy configuration below.', 'igny8-bridge'); ?>
</p>
<div style="display: grid; gap: 12px;"> <!-- Post Types Card (1/3) -->
<?php foreach ($public_post_types as $slug => $pt) : <div class="igny8-card">
$is_posts = ($slug === 'post'); <div class="igny8-card-header">
$is_enabled = in_array($slug, $enabled_post_types, true); <h2>
?> <svg fill="none" stroke="currentColor" viewBox="0 0 24 24" style="width: 20px; height: 20px;">
<label class="igny8-post-type-toggle" style="display: flex; align-items: center; cursor: pointer; padding: 12px 16px; border: 1px solid var(--igny8-stroke); border-radius: var(--igny8-radius-base); background: var(--igny8-surface);"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"/>
<input </svg>
type="checkbox" <?php _e('Post Types', 'igny8-bridge'); ?>
name="igny8_enabled_post_types[]" </h2>
value="<?php echo esc_attr($slug); ?>" </div>
class="igny8-post-type-checkbox" <p style="margin-bottom: 16px; color: var(--igny8-text-dim); font-size: 13px;">
data-post-type="<?php echo esc_attr($slug); ?>" <?php _e('Enable post types to sync with IGNY8.', 'igny8-bridge'); ?>
<?php checked($is_enabled); ?> </p>
style="margin-right: 12px;"
/> <div style="display: grid; gap: 8px;">
<div style="flex: 1;"> <?php foreach ($public_post_types as $slug => $pt) :
<span style="font-weight: 600;"> $is_posts = ($slug === 'post');
$is_enabled = in_array($slug, $enabled_post_types, true);
?>
<label class="igny8-post-type-toggle" style="display: flex; align-items: center; cursor: pointer; padding: 10px 12px; border: 1px solid var(--igny8-stroke); border-radius: var(--igny8-radius-sm); background: var(--igny8-surface);">
<input
type="checkbox"
name="igny8_enabled_post_types[]"
value="<?php echo esc_attr($slug); ?>"
class="igny8-post-type-checkbox"
data-post-type="<?php echo esc_attr($slug); ?>"
<?php checked($is_enabled); ?>
style="margin-right: 10px;"
/>
<span style="flex: 1; font-weight: 500; font-size: 14px;">
<?php echo esc_html($pt->label); ?> <?php echo esc_html($pt->label); ?>
</span> </span>
<?php if (!$is_posts) : ?> <?php if (!$is_posts) : ?>
<span class="igny8-badge igny8-badge-warning" style="margin-left: 8px;"> <span class="igny8-badge igny8-badge-warning">
<?php _e('Coming Soon', 'igny8-bridge'); ?> <?php _e('Coming Soon', 'igny8-bridge'); ?>
</span> </span>
<?php else: ?>
<span style="color: var(--igny8-text-dim); font-size: 12px;"><?php echo esc_html($slug); ?></span>
<?php endif; ?> <?php endif; ?>
</label>
<?php endforeach; ?>
</div>
</div>
<!-- Default Post Status Card (1/3) -->
<div class="igny8-card">
<div class="igny8-card-header">
<h2>
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24" style="width: 20px; height: 20px;">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"/>
</svg>
<?php _e('Default Post Status', 'igny8-bridge'); ?>
</h2>
</div>
<p style="margin-bottom: 16px; color: var(--igny8-text-dim); font-size: 13px;">
<?php _e('Set default status for published content.', 'igny8-bridge'); ?>
</p>
<div style="display: grid; gap: 8px;">
<label style="display: flex; align-items: center; cursor: pointer; padding: 12px; border: 1px solid var(--igny8-stroke); border-radius: var(--igny8-radius-sm); <?php echo $default_post_status === 'draft' ? 'background: var(--igny8-primary-subtle); border-color: var(--igny8-primary);' : ''; ?>">
<input
type="radio"
name="igny8_default_post_status"
value="draft"
<?php checked($default_post_status, 'draft'); ?>
style="margin-right: 10px;"
/>
<div>
<strong style="font-size: 14px;"><?php _e('Draft', 'igny8-bridge'); ?></strong>
<span style="display: block; font-size: 12px; color: var(--igny8-text-dim);">
<?php _e('Review before publishing', 'igny8-bridge'); ?>
</span>
</div> </div>
<span style="color: var(--igny8-text-dim); font-size: 13px;">
<?php echo esc_html($slug); ?>
</span>
</label> </label>
<?php endforeach; ?> <label style="display: flex; align-items: center; cursor: pointer; padding: 12px; border: 1px solid var(--igny8-stroke); border-radius: var(--igny8-radius-sm); <?php echo $default_post_status === 'publish' ? 'background: var(--igny8-primary-subtle); border-color: var(--igny8-primary);' : ''; ?>">
<input
type="radio"
name="igny8_default_post_status"
value="publish"
<?php checked($default_post_status, 'publish'); ?>
style="margin-right: 10px;"
/>
<div>
<strong style="font-size: 14px;"><?php _e('Publish', 'igny8-bridge'); ?></strong>
<span style="display: block; font-size: 12px; color: var(--igny8-text-dim);">
<?php _e('Publish immediately', 'igny8-bridge'); ?>
</span>
</div>
</label>
</div>
</div>
<!-- IGNY8 Sync Card (1/3) -->
<div class="igny8-card">
<div class="igny8-card-header">
<h2>
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24" style="width: 20px; height: 20px;">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"/>
</svg>
<?php _e('IGNY8 Sync', 'igny8-bridge'); ?>
</h2>
</div>
<p style="margin-bottom: 16px; color: var(--igny8-text-dim); font-size: 13px;">
<?php _e('Control content publishing from IGNY8.', 'igny8-bridge'); ?>
</p>
<label style="display: flex; align-items: flex-start; cursor: pointer; padding: 14px; border: 1px solid var(--igny8-stroke); border-radius: var(--igny8-radius-sm); background: var(--igny8-surface);">
<input
type="checkbox"
name="igny8_sync_enabled"
value="1"
<?php checked($sync_enabled, 1); ?>
style="margin-right: 12px; margin-top: 2px; width: 18px; height: 18px;"
/>
<div>
<strong style="font-size: 14px; display: block;"><?php _e('Enable IGNY8 Sync', 'igny8-bridge'); ?></strong>
<span style="display: block; font-size: 12px; color: var(--igny8-text-dim); margin-top: 4px;">
<?php _e('Allow IGNY8 to publish content to this site', 'igny8-bridge'); ?>
</span>
</div>
</label>
</div> </div>
</div> </div>
@@ -133,7 +213,7 @@ foreach ($all_post_types as $pt) {
<?php else : ?> <?php else : ?>
<span style="font-size: 20px;">📁</span> <span style="font-size: 20px;">📁</span>
<?php endif; ?> <?php endif; ?>
<?php echo esc_html(strtoupper($pt->label)); ?> <?php echo esc_html(strtoupper($pt->label)); ?> <?php _e('Taxonomies', 'igny8-bridge'); ?>
</h2> </h2>
<?php if (!$is_posts) : ?> <?php if (!$is_posts) : ?>
<span class="igny8-badge igny8-badge-warning"> <span class="igny8-badge igny8-badge-warning">
@@ -142,14 +222,8 @@ foreach ($all_post_types as $pt) {
<?php endif; ?> <?php endif; ?>
</div> </div>
<p style="margin-bottom: 16px; color: var(--igny8-text-dim); font-size: 14px;"> <div style="display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 8px;">
<?php printf(__('Taxonomies for %s:', 'igny8-bridge'), esc_html($pt->label)); ?>
</p>
<div style="display: grid; gap: 8px;">
<?php foreach ($public_taxonomies as $tax_slug => $tax) : <?php foreach ($public_taxonomies as $tax_slug => $tax) :
// Default enabled: category, post_tag, product_cat, product_tag, igny8_sectors, igny8_clusters
$default_enabled = in_array($tax_slug, array('category', 'post_tag', 'product_cat', 'product_tag', 'igny8_sectors', 'igny8_clusters'), true);
$is_tax_enabled = in_array($tax_slug, $enabled_taxonomies, true); $is_tax_enabled = in_array($tax_slug, $enabled_taxonomies, true);
?> ?>
<label style="display: flex; align-items: center; cursor: pointer; padding: 10px 14px; border: 1px solid var(--igny8-stroke); border-radius: var(--igny8-radius-sm); background: var(--igny8-bg);"> <label style="display: flex; align-items: center; cursor: pointer; padding: 10px 14px; border: 1px solid var(--igny8-stroke); border-radius: var(--igny8-radius-sm); background: var(--igny8-bg);">
@@ -160,90 +234,13 @@ foreach ($all_post_types as $pt) {
<?php checked($is_tax_enabled); ?> <?php checked($is_tax_enabled); ?>
style="margin-right: 10px;" style="margin-right: 10px;"
/> />
<span style="flex: 1;"><?php echo esc_html($tax->label); ?></span> <span style="flex: 1; font-size: 14px;"><?php echo esc_html($tax->label); ?></span>
<span style="color: var(--igny8-text-dim); font-size: 12px;"><?php echo esc_html($tax_slug); ?></span>
</label> </label>
<?php endforeach; ?> <?php endforeach; ?>
</div> </div>
</div> </div>
<?php endforeach; ?> <?php endforeach; ?>
<!-- Default Settings -->
<div class="igny8-card" style="margin-bottom: 24px;">
<div class="igny8-card-header">
<h2>
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24" style="width: 20px; height: 20px;">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z"/>
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"/>
</svg>
<?php _e('Default Settings', 'igny8-bridge'); ?>
</h2>
</div>
<div class="igny8-grid igny8-grid-2" style="gap: 24px;">
<!-- Default Post Status -->
<div>
<label style="display: block; font-weight: 600; margin-bottom: 12px;">
<?php _e('Default Post Status', 'igny8-bridge'); ?>
</label>
<div style="display: grid; gap: 8px;">
<label style="display: flex; align-items: center; cursor: pointer; padding: 12px; border: 1px solid var(--igny8-stroke); border-radius: var(--igny8-radius-sm); <?php echo $default_post_status === 'draft' ? 'background: var(--igny8-primary-subtle); border-color: var(--igny8-primary);' : ''; ?>">
<input
type="radio"
name="igny8_default_post_status"
value="draft"
<?php checked($default_post_status, 'draft'); ?>
style="margin-right: 10px;"
/>
<div>
<strong><?php _e('Draft', 'igny8-bridge'); ?></strong>
<span style="display: block; font-size: 12px; color: var(--igny8-text-dim);">
<?php _e('Review before publishing', 'igny8-bridge'); ?>
</span>
</div>
</label>
<label style="display: flex; align-items: center; cursor: pointer; padding: 12px; border: 1px solid var(--igny8-stroke); border-radius: var(--igny8-radius-sm); <?php echo $default_post_status === 'publish' ? 'background: var(--igny8-primary-subtle); border-color: var(--igny8-primary);' : ''; ?>">
<input
type="radio"
name="igny8_default_post_status"
value="publish"
<?php checked($default_post_status, 'publish'); ?>
style="margin-right: 10px;"
/>
<div>
<strong><?php _e('Publish', 'igny8-bridge'); ?></strong>
<span style="display: block; font-size: 12px; color: var(--igny8-text-dim);">
<?php _e('Publish immediately', 'igny8-bridge'); ?>
</span>
</div>
</label>
</div>
</div>
<!-- Enable Sync -->
<div>
<label style="display: block; font-weight: 600; margin-bottom: 12px;">
<?php _e('IGNY8 Sync', 'igny8-bridge'); ?>
</label>
<label style="display: flex; align-items: center; cursor: pointer; padding: 16px; border: 1px solid var(--igny8-stroke); border-radius: var(--igny8-radius-sm); background: var(--igny8-surface);">
<input
type="checkbox"
name="igny8_sync_enabled"
value="1"
<?php checked($sync_enabled, 1); ?>
style="margin-right: 12px; width: 20px; height: 20px;"
/>
<div>
<strong><?php _e('Enable IGNY8 Sync', 'igny8-bridge'); ?></strong>
<span style="display: block; font-size: 12px; color: var(--igny8-text-dim);">
<?php _e('Allow IGNY8 to publish content to this site', 'igny8-bridge'); ?>
</span>
</div>
</label>
</div>
</div>
</div>
<button type="submit" class="igny8-btn igny8-btn-primary"> <button type="submit" class="igny8-btn igny8-btn-primary">
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24" style="width: 16px; height: 16px;"> <svg fill="none" stroke="currentColor" viewBox="0 0 24 24" style="width: 16px; height: 16px;">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/>
@@ -266,10 +263,6 @@ foreach ($all_post_types as $pt) {
background: #fef3c7; background: #fef3c7;
color: #92400e; color: #92400e;
} }
.igny8-badge-success {
background: #d1fae5;
color: #065f46;
}
.igny8-post-type-toggle:hover { .igny8-post-type-toggle:hover {
border-color: var(--igny8-primary); border-color: var(--igny8-primary);
} }

View File

@@ -745,8 +745,9 @@ function igny8_map_wp_status_to_igny8($wp_status) {
@shared_task(bind=True, max_retries=3) @shared_task(bind=True, max_retries=3)
def publish_content_to_wordpress(self, content_id, ...): def publish_content_to_wordpress(self, content_id, ...):
try: try:
response = requests.post(wordpress_url, json=content_data, timeout=30)
if response.status_code == 201:
# Success # Success
content.wordpress_sync_status = 'success' content.wordpress_sync_status = 'success'
content.save() content.save()

View File

@@ -3,7 +3,7 @@
* Plugin Name: IGNY8 WordPress Bridge * Plugin Name: IGNY8 WordPress Bridge
* Plugin URI: https://igny8.com/igny8-wp-bridge * Plugin URI: https://igny8.com/igny8-wp-bridge
* Description: Lightweight bridge plugin that connects WordPress to IGNY8 API for one-way content publishing. * Description: Lightweight bridge plugin that connects WordPress to IGNY8 API for one-way content publishing.
* Version: 1.5.1 * Version: 1.5.2
* Author: IGNY8 * Author: IGNY8
* Author URI: https://igny8.com/ * Author URI: https://igny8.com/
* License: GPL v2 or later * License: GPL v2 or later
@@ -22,7 +22,7 @@ if (!defined('ABSPATH')) {
} }
// Define plugin constants // Define plugin constants
define('IGNY8_BRIDGE_VERSION', '1.5.1'); define('IGNY8_BRIDGE_VERSION', '1.5.2');
define('IGNY8_BRIDGE_PLUGIN_DIR', plugin_dir_path(__FILE__)); define('IGNY8_BRIDGE_PLUGIN_DIR', plugin_dir_path(__FILE__));
define('IGNY8_BRIDGE_PLUGIN_URL', plugin_dir_url(__FILE__)); define('IGNY8_BRIDGE_PLUGIN_URL', plugin_dir_url(__FILE__));
define('IGNY8_BRIDGE_PLUGIN_FILE', __FILE__); define('IGNY8_BRIDGE_PLUGIN_FILE', __FILE__);