PLugin versioning fixes

This commit is contained in:
IGNY8 VPS (Salman)
2026-01-09 23:36:03 +00:00
parent 4343f62140
commit 0ea3a30909
7 changed files with 441 additions and 115 deletions

View File

@@ -1,6 +1,7 @@
""" """
Django Admin Configuration for Plugin Distribution System Django Admin Configuration for Plugin Distribution System
""" """
from django import forms
from django.contrib import admin from django.contrib import admin
from django.utils.html import format_html from django.utils.html import format_html
from django.urls import reverse from django.urls import reverse
@@ -8,6 +9,68 @@ from unfold.admin import ModelAdmin, TabularInline
from .models import Plugin, PluginVersion, PluginInstallation, PluginDownload from .models import Plugin, PluginVersion, PluginInstallation, PluginDownload
class PluginVersionForm(forms.ModelForm):
"""
Simplified form for creating new plugin versions.
Auto-fills most fields from the latest version, only requires:
- Plugin (select)
- Version number
- Changelog
- Status (defaults to 'draft')
All other fields are either:
- Auto-filled from previous version (min_api_version, min_php_version, etc.)
- Auto-generated on release (file_path, file_size, checksum)
- Auto-calculated (version_code)
"""
class Meta:
model = PluginVersion
fields = '__all__'
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# If this is a new version (no instance), auto-fill from latest
if not self.instance.pk:
# Check if plugin is already selected (from initial data or POST data)
plugin_id = None
# Try to get plugin from POST data (when form is submitted)
if self.data:
plugin_id = self.data.get('plugin')
# Try to get plugin from initial data (when form is pre-filled)
elif self.initial:
plugin_id = self.initial.get('plugin')
if plugin_id:
try:
plugin = Plugin.objects.get(pk=plugin_id)
latest = plugin.get_latest_version()
if latest:
# Auto-fill from latest version (only if not POST)
if not self.data:
if 'min_api_version' in self.fields:
self.fields['min_api_version'].initial = latest.min_api_version
if 'min_platform_version' in self.fields:
self.fields['min_platform_version'].initial = latest.min_platform_version
if 'min_php_version' in self.fields:
self.fields['min_php_version'].initial = latest.min_php_version
if 'force_update' in self.fields:
self.fields['force_update'].initial = False
except (Plugin.DoesNotExist, ValueError, TypeError):
pass
# Set helpful help texts for fields that exist in the form
# (some fields may be readonly and not in self.fields)
if 'version' in self.fields:
self.fields['version'].help_text = "Semantic version (e.g., 1.2.0)"
if 'changelog' in self.fields:
self.fields['changelog'].help_text = "What's new in this version"
class PluginVersionInline(TabularInline): class PluginVersionInline(TabularInline):
"""Inline admin for plugin versions.""" """Inline admin for plugin versions."""
model = PluginVersion model = PluginVersion
@@ -66,35 +129,37 @@ class PluginAdmin(ModelAdmin):
class PluginVersionAdmin(ModelAdmin): class PluginVersionAdmin(ModelAdmin):
"""Admin configuration for PluginVersion model.""" """Admin configuration for PluginVersion model."""
form = PluginVersionForm
list_display = ['plugin', 'version', 'status', 'file_size_display', 'download_count', 'released_at'] list_display = ['plugin', 'version', 'status', 'file_size_display', 'download_count', 'released_at']
list_filter = ['plugin', 'status', 'released_at'] list_filter = ['plugin', 'status', 'released_at']
search_fields = ['plugin__name', 'version', 'changelog'] search_fields = ['plugin__name', 'version', 'changelog']
readonly_fields = ['version_code', 'created_at', 'download_count'] readonly_fields = ['version_code', 'file_path', 'file_size', 'checksum', 'created_at', 'released_at', 'download_count']
fieldsets = [ fieldsets = [
('Version Info', { ('Required Fields', {
'fields': ['plugin', 'version', 'version_code', 'status'] 'fields': ['plugin', 'version', 'status', 'changelog'],
'description': 'Only these fields are required. Others are auto-filled from previous version or auto-generated.'
}), }),
('File Info', { ('Requirements (Auto-filled from previous version)', {
'fields': ['file_path', 'file_size', 'checksum'] 'fields': ['min_api_version', 'min_platform_version', 'min_php_version'],
}),
('Requirements', {
'fields': ['min_api_version', 'min_platform_version', 'min_php_version']
}),
('Release', {
'fields': ['changelog', 'force_update', 'released_at']
}),
('Statistics', {
'fields': ['download_count'],
'classes': ['collapse'] 'classes': ['collapse']
}), }),
('Timestamps', { ('File Info (Auto-generated on release)', {
'fields': ['created_at'], 'fields': ['file_path', 'file_size', 'checksum'],
'classes': ['collapse']
}),
('Advanced Options', {
'fields': ['version_code', 'force_update'],
'classes': ['collapse']
}),
('Metadata', {
'fields': ['released_at', 'download_count', 'created_at'],
'classes': ['collapse'] 'classes': ['collapse']
}), }),
] ]
actions = ['release_versions', 'mark_as_update_ready'] actions = ['release_versions', 'mark_as_update_ready', 'mark_as_deprecated']
def file_size_display(self, obj): def file_size_display(self, obj):
if obj.file_size: if obj.file_size:
@@ -109,19 +174,25 @@ class PluginVersionAdmin(ModelAdmin):
return obj.get_download_count() return obj.get_download_count()
download_count.short_description = 'Downloads' download_count.short_description = 'Downloads'
@admin.action(description="Release selected versions") @admin.action(description="Release selected versions (builds ZIP automatically)")
def release_versions(self, request, queryset): def release_versions(self, request, queryset):
from django.utils import timezone from django.utils import timezone
count = queryset.filter(status__in=['draft', 'testing', 'staged']).update( count = 0
status='released', for version in queryset.filter(status__in=['draft', 'testing', 'staged']):
released_at=timezone.now() version.status = 'released'
) version.save() # Triggers signal to build ZIP
self.message_user(request, f"Released {count} version(s)") count += 1
self.message_user(request, f"Released {count} version(s). ZIP files are being built automatically.")
@admin.action(description="Mark as update ready (push to installations)") @admin.action(description="📢 Mark as update ready (notify WordPress sites)")
def mark_as_update_ready(self, request, queryset): def mark_as_update_ready(self, request, queryset):
count = queryset.filter(status='released').update(status='update_ready') count = queryset.filter(status='released').update(status='update_ready')
self.message_user(request, f"Marked {count} version(s) as update ready") self.message_user(request, f"Marked {count} version(s) as update ready. WordPress sites will be notified.")
@admin.action(description="🗑️ Mark as deprecated")
def mark_as_deprecated(self, request, queryset):
count = queryset.update(status='deprecated')
self.message_user(request, f"Marked {count} version(s) as deprecated")
@admin.register(PluginInstallation) @admin.register(PluginInstallation)

View File

@@ -0,0 +1,23 @@
# Generated by Django 5.2.10 on 2026-01-09 23:16
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('plugins', '0001_initial'),
]
operations = [
migrations.AlterField(
model_name='pluginversion',
name='file_path',
field=models.CharField(blank=True, default='', help_text='Relative path to ZIP file in dist/ directory. Auto-generated on release.', max_length=500),
),
migrations.AlterField(
model_name='pluginversion',
name='version_code',
field=models.IntegerField(blank=True, help_text='Numeric version for comparison (1.0.1 -> 10001). Auto-calculated.', null=True),
),
]

View File

@@ -99,7 +99,9 @@ class PluginVersion(models.Model):
help_text="Semantic version string (e.g., '1.0.0', '1.0.1')" help_text="Semantic version string (e.g., '1.0.0', '1.0.1')"
) )
version_code = models.IntegerField( version_code = models.IntegerField(
help_text="Numeric version for comparison (1.0.1 -> 10001)" null=True,
blank=True,
help_text="Numeric version for comparison (1.0.1 -> 10001). Auto-calculated."
) )
status = models.CharField( status = models.CharField(
max_length=20, max_length=20,
@@ -112,7 +114,9 @@ class PluginVersion(models.Model):
# File info # File info
file_path = models.CharField( file_path = models.CharField(
max_length=500, max_length=500,
help_text="Relative path to ZIP file in dist/ directory" blank=True,
default='',
help_text="Relative path to ZIP file in dist/ directory. Auto-generated on release."
) )
file_size = models.IntegerField( file_size = models.IntegerField(
default=0, default=0,

View File

@@ -23,40 +23,47 @@ def auto_build_plugin_on_release(sender, instance, **kwargs):
1. ZIP file is always up-to-date with source code 1. ZIP file is always up-to-date with source code
2. File size and checksum are auto-calculated 2. File size and checksum are auto-calculated
3. No manual intervention needed for releases 3. No manual intervention needed for releases
Triggers on:
- New version created with status 'released' or 'update_ready'
- Existing version status changed to 'released' or 'update_ready'
""" """
# Skip if this is a new instance (no pk yet)
if not instance.pk:
return
try:
# Get the old instance to check for status change
old_instance = PluginVersion.objects.get(pk=instance.pk)
except PluginVersion.DoesNotExist:
return
# Check if status is changing TO 'released' or 'update_ready'
release_statuses = ['released', 'update_ready'] release_statuses = ['released', 'update_ready']
# Check if this version should have a ZIP built
should_build = False
if not instance.pk:
# New instance - build if status is a release status
if instance.status in release_statuses:
should_build = True
logger.info(f"New plugin version {instance.plugin.slug} v{instance.version} created with status '{instance.status}' - building ZIP")
else:
# Existing instance - check if status changed to a release status
try:
old_instance = PluginVersion.objects.get(pk=instance.pk)
old_status = old_instance.status old_status = old_instance.status
new_status = instance.status new_status = instance.status
# Only trigger build if: # Build if moving to a release status from a non-release status
# 1. Status is changing if new_status in release_statuses and old_status not in release_statuses:
# 2. New status is a release status should_build = True
# 3. Old status was not a release status (avoid rebuilding on every save) logger.info(f"Building plugin ZIP for {instance.plugin.slug} v{instance.version} (status: {old_status} -> {new_status})")
if old_status == new_status: elif old_status == new_status and new_status in release_statuses:
# No status change, but already released - no rebuild
return return
elif old_status in release_statuses and new_status in release_statuses:
if new_status not in release_statuses: # Moving between release statuses - no rebuild
return
# If moving from one release status to another, don't rebuild
if old_status in release_statuses:
logger.info(f"Plugin {instance.plugin.slug} v{instance.version}: Status changing from {old_status} to {new_status}, no rebuild needed") logger.info(f"Plugin {instance.plugin.slug} v{instance.version}: Status changing from {old_status} to {new_status}, no rebuild needed")
return return
except PluginVersion.DoesNotExist:
return
logger.info(f"Building plugin ZIP for {instance.plugin.slug} v{instance.version} (status: {old_status} -> {new_status})") if not should_build:
return
# Build the ZIP # Build the ZIP
try:
file_path, checksum, file_size = create_plugin_zip( file_path, checksum, file_size = create_plugin_zip(
platform=instance.plugin.platform, platform=instance.plugin.platform,
plugin_slug=instance.plugin.slug, plugin_slug=instance.plugin.slug,
@@ -73,8 +80,11 @@ def auto_build_plugin_on_release(sender, instance, **kwargs):
instance.checksum = checksum instance.checksum = checksum
instance.file_size = file_size instance.file_size = file_size
# Set released_at if moving to released status and not already set # Set released_at if not already set
if new_status in release_statuses and not instance.released_at: if not instance.released_at:
instance.released_at = timezone.now() instance.released_at = timezone.now()
logger.info(f"Built plugin ZIP: {file_path} ({file_size} bytes, checksum: {checksum[:16]}...)") logger.info(f"Built plugin ZIP: {file_path} ({file_size} bytes, checksum: {checksum[:16]}...)")
except Exception as e:
logger.error(f"Error building ZIP for {instance.plugin.slug} v{instance.version}: {e}")

View File

@@ -6,6 +6,26 @@
--- ---
## 🎯 Quick Start: Simplified Release Process
The plugin release process has been **simplified** to require only 3 fields:
1. **Version** (e.g., 1.2.0)
2. **Changelog** (what's new)
3. **Status** (draft → released)
All other fields are either:
- ✅ Auto-filled from previous version
- ✅ Auto-generated on release (file path, size, checksum)
- ✅ Auto-calculated (version code)
**Release in 3 clicks:**
```
Django Admin → Add Plugin Version → Enter 3 fields → Save → Change status to 'released'
```
---
## Table of Contents ## Table of Contents
1. [Update Workflow Overview](#1-update-workflow-overview) 1. [Update Workflow Overview](#1-update-workflow-overview)
@@ -128,11 +148,12 @@ WordPress will show "Update Available" in:
| Action | When | How | | Action | When | How |
|--------|------|-----| |--------|------|-----|
| **Update Source Version** | Before release | Edit `igny8-bridge.php` header | | **Update Source Version** | Before release | Edit `igny8-bridge.php` header |
| **Create PluginVersion Record** | Each release | Django admin or management command | | **Create PluginVersion Record** | Each release | Django admin: just enter version, changelog, status |
| **Write Changelog** | Each release | Enter in PluginVersion.changelog |
| **Verify After Release** | After status change | Run verification checklist | | **Verify After Release** | After status change | Run verification checklist |
| **Mark Old Version Deprecated** | After successful release | Change old version status | | **Mark Old Version Deprecated** | After successful release | Change old version status |
**Note:** The form is simplified - most fields auto-fill from previous version or are auto-generated.
### Source Version Update Locations ### Source Version Update Locations
When releasing a new version, update these in the source: When releasing a new version, update these in the source:
@@ -154,6 +175,37 @@ define('IGNY8_BRIDGE_VERSION', '1.2.0'); ← AND THIS
## 4. Step-by-Step: Releasing a New Version ## 4. Step-by-Step: Releasing a New Version
### The Simplified Process
```
┌─────────────────────────────────────────────────────────────────────────┐
│ Simplified Version Release (3 Required Fields) │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ Django Admin → Add Plugin Version │
│ │
│ ┌────────────────────────────────────────────────────────────────┐ │
│ │ Plugin: [IGNY8 WordPress Bridge ▼] ← Select plugin │ │
│ │ Version: [1.2.0] ← New version │ │
│ │ Status: [draft ▼] ← Start as draft │ │
│ │ Changelog: [Bug fixes and improvements] ← What's new │ │
│ │ │ │
│ │ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ │ │
│ │ Everything below is AUTO-FILLED or AUTO-GENERATED: │ │
│ │ │ │
│ │ Min API Version: 1.0 (from previous version) │ │
│ │ Min PHP Version: 7.4 (from previous version) │ │
│ │ File Path: (empty) → Auto-generated on release │ │
│ │ File Size: (empty) → Auto-calculated on release │ │
│ │ Checksum: (empty) → Auto-calculated on release │ │
│ │ Version Code: (empty) → Auto-calculated from version │ │
│ └────────────────────────────────────────────────────────────────┘ │
│ │
│ Click [Save] → Status changes to 'released' → ZIP builds automatically │
│ │
└─────────────────────────────────────────────────────────────────────────┘
```
### Step 1: Make Code Changes ### Step 1: Make Code Changes
```bash ```bash
@@ -181,21 +233,35 @@ define('IGNY8_BRIDGE_VERSION', '1.2.0'); ← Match here
1. Go to: `https://api.igny8.com/backend/` 1. Go to: `https://api.igny8.com/backend/`
2. Navigate to: **Plugin Distribution****Plugin Versions** 2. Navigate to: **Plugin Distribution****Plugin Versions**
3. Click **Add Plugin Version** 3. Click **Add Plugin Version**
4. Fill in: 4. Fill in **ONLY** these required fields:
- **Plugin:** IGNY8 WordPress Bridge - **Plugin:** IGNY8 WordPress Bridge
- **Version:** 1.2.0 - **Version:** 1.2.0
- **Status:** draft (initially) - **Status:** draft (initially)
- **Changelog:** Describe changes - **Changelog:** Describe changes
- **Min PHP Version:** 7.4 (or higher if needed)
5. Click **Save** 5. Click **Save**
**Note:** All other fields are auto-filled:
- `min_api_version`, `min_platform_version`, `min_php_version` → Copied from previous version
- `file_path`, `file_size`, `checksum` → Auto-generated when you release
- `version_code` → Auto-calculated from version number
### Step 4: Release the Version ### Step 4: Release the Version
**Option A: Release via Status Change**
1. Edit the PluginVersion you just created 1. Edit the PluginVersion you just created
2. Change **Status** to `released` 2. Change **Status** to `released`
3. Click **Save** 3. Click **Save**
**What happens:** Signal triggers auto-build → ZIP created → database updated **Option B: Release via Bulk Action**
1. Select the version(s) in the list
2. Choose **Actions****✅ Release selected versions**
3. Click **Go**
**What happens:** Signal triggers auto-build → ZIP created → database updated with file info
**Note:** You can also use the action **📢 Mark as update ready** to immediately notify WordPress sites.
### Step 5: Verify Release ### Step 5: Verify Release
@@ -211,32 +277,127 @@ Run the [verification checklist](#5-post-update-verification-checklist) below.
## 5. Post-Update Verification Checklist ## 5. Post-Update Verification Checklist
### Immediate Checks (Do Every Release) ### Quick Verification Script
Run this single command to verify everything:
```bash ```bash
# 1. Verify ZIP exists #!/bin/bash
ls -lh /data/app/igny8/plugins/wordpress/dist/igny8-wp-bridge-v1.2.0.zip # Complete Plugin Release Verification Script
# Usage: Save as verify-plugin.sh and run: bash verify-plugin.sh 1.1.2
# 2. Verify symlink updated VERSION=${1:-"latest"}
ls -la /data/app/igny8/plugins/wordpress/dist/igny8-wp-bridge-latest.zip PLUGIN_SLUG="igny8-wp-bridge"
echo "=========================================="
echo "Plugin Release Verification: v${VERSION}"
echo "=========================================="
echo ""
# 1. Check ZIP file exists
echo "1. Checking ZIP file..."
if [ "$VERSION" = "latest" ]; then
ls -lh /data/app/igny8/plugins/wordpress/dist/${PLUGIN_SLUG}-latest.zip 2>/dev/null && echo " ✓ Latest ZIP exists" || echo " ✗ Latest ZIP not found"
else
ls -lh /data/app/igny8/plugins/wordpress/dist/${PLUGIN_SLUG}-v${VERSION}.zip 2>/dev/null && echo " ✓ ZIP v${VERSION} exists" || echo " ✗ ZIP v${VERSION} not found"
fi
echo ""
# 2. Check symlink
echo "2. Checking symlink..."
ls -la /data/app/igny8/plugins/wordpress/dist/${PLUGIN_SLUG}-latest.zip | grep -q "^l" && echo " ✓ Symlink valid" || echo " ✗ Symlink missing"
echo ""
# 3. Test download endpoint # 3. Test download endpoint
curl -s -o /dev/null -w "%{http_code} - %{size_download} bytes\n" \ echo "3. Testing download endpoint..."
https://api.igny8.com/api/plugins/igny8-wp-bridge/download/ HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" https://api.igny8.com/api/plugins/${PLUGIN_SLUG}/download/)
FILE_SIZE=$(curl -s -o /dev/null -w "%{size_download}" https://api.igny8.com/api/plugins/${PLUGIN_SLUG}/download/)
if [ "$HTTP_CODE" = "200" ]; then
echo " ✓ Download works: ${HTTP_CODE} - ${FILE_SIZE} bytes ($(( FILE_SIZE / 1024 )) KB)"
else
echo " ✗ Download failed: HTTP ${HTTP_CODE}"
fi
echo ""
# 4. Test check-update endpoint # 4. Test check-update endpoint
curl -s "https://api.igny8.com/api/plugins/igny8-wp-bridge/check-update/?current_version=1.0.0" | python3 -m json.tool echo "4. Testing check-update endpoint..."
UPDATE_RESPONSE=$(curl -s "https://api.igny8.com/api/plugins/${PLUGIN_SLUG}/check-update/?current_version=1.0.0")
LATEST_VERSION=$(echo "$UPDATE_RESPONSE" | python3 -c "import sys, json; print(json.load(sys.stdin).get('latest_version', 'N/A'))" 2>/dev/null)
if [ -n "$LATEST_VERSION" ] && [ "$LATEST_VERSION" != "N/A" ]; then
echo " ✓ Check-update works: Latest version = $LATEST_VERSION"
else
echo " ✗ Check-update failed"
fi
echo ""
# 5. Test info endpoint # 5. Test info endpoint
curl -s https://api.igny8.com/api/plugins/igny8-wp-bridge/info/ | python3 -m json.tool echo "5. Testing info endpoint..."
INFO_RESPONSE=$(curl -s "https://api.igny8.com/api/plugins/${PLUGIN_SLUG}/info/")
PLUGIN_NAME=$(echo "$INFO_RESPONSE" | python3 -c "import sys, json; print(json.load(sys.stdin).get('name', 'N/A'))" 2>/dev/null)
if [ -n "$PLUGIN_NAME" ] && [ "$PLUGIN_NAME" != "N/A" ]; then
echo " ✓ Info endpoint works: $PLUGIN_NAME"
else
echo " ✗ Info endpoint failed"
fi
echo ""
# 6. Verify version in ZIP # 6. Verify version in ZIP
unzip -p /data/app/igny8/plugins/wordpress/dist/igny8-wp-bridge-v1.2.0.zip \ echo "6. Verifying version in ZIP..."
igny8-wp-bridge/igny8-bridge.php | grep -E "Version:|IGNY8_BRIDGE_VERSION" if [ "$VERSION" != "latest" ]; then
ZIP_VERSION=$(unzip -p /data/app/igny8/plugins/wordpress/dist/${PLUGIN_SLUG}-v${VERSION}.zip ${PLUGIN_SLUG}/igny8-bridge.php 2>/dev/null | grep -E "Version:" | head -1 | awk '{print $3}')
if [ "$ZIP_VERSION" = "$VERSION" ]; then
echo " ✓ ZIP version matches: $ZIP_VERSION"
else
echo " ✗ ZIP version mismatch: expected $VERSION, got $ZIP_VERSION"
fi
else
echo " - Skipped (use specific version to check)"
fi
echo ""
# 7. Verify API URL in ZIP (must be api.igny8.com) # 7. Verify API URL
unzip -p /data/app/igny8/plugins/wordpress/dist/igny8-wp-bridge-v1.2.0.zip \ echo "7. Verifying API URL in ZIP..."
igny8-wp-bridge/igny8-bridge.php | grep "api.igny8.com" API_COUNT=$(unzip -p /data/app/igny8/plugins/wordpress/dist/${PLUGIN_SLUG}-latest.zip ${PLUGIN_SLUG}/igny8-bridge.php 2>/dev/null | grep -c "api.igny8.com")
if [ "$API_COUNT" -gt 0 ]; then
echo " ✓ API URL correct: api.igny8.com found (${API_COUNT} occurrences)"
else
echo " ✗ API URL incorrect: api.igny8.com not found"
fi
echo ""
# 8. Check database
echo "8. Checking database..."
docker exec igny8_backend python manage.py shell -c "
from igny8_core.plugins.models import Plugin, PluginVersion
try:
p = Plugin.objects.get(slug='${PLUGIN_SLUG}')
v = p.get_latest_version()
if v:
print(f' ✓ Latest version: {v.version}')
print(f' ✓ Status: {v.status}')
print(f' ✓ File: {v.file_path}')
print(f' ✓ Size: {v.file_size:,} bytes ({v.file_size/1024:.1f} KB)')
print(f' ✓ Checksum: {v.checksum[:32]}...')
else:
print(' ✗ No released version found')
except Exception as e:
print(f' ✗ Error: {e}')
" 2>/dev/null | grep -E "✓|✗"
echo ""
echo "=========================================="
echo "Verification Complete"
echo "=========================================="
```
**Quick run (copy-paste):**
```bash
# Verify latest version
curl -s "https://api.igny8.com/api/plugins/igny8-wp-bridge/info/" | python3 -m json.tool && \
curl -s "https://api.igny8.com/api/plugins/igny8-wp-bridge/check-update/?current_version=1.0.0" | python3 -m json.tool && \
ls -lh /data/app/igny8/plugins/wordpress/dist/igny8-wp-bridge-latest.zip && \
echo "✓ All endpoints working"
``` ```
### Database Verification ### Database Verification
@@ -382,17 +543,27 @@ curl https://api.igny8.com/api/plugins/igny8-wp-bridge/check-update/?current_ver
## Quick Reference Card ## Quick Reference Card
### Release New Version ### Release New Version (Simplified)
``` ```
1. Edit source code 1. Edit source code in /plugins/wordpress/source/igny8-wp-bridge/
2. Update version in igny8-bridge.php (header + constant) 2. Update version in igny8-bridge.php (header + constant)
3. Create PluginVersion in Django admin (status: draft) 3. Django Admin → Add Plugin Version:
4. Change status to "released" → Auto-build triggers - Plugin: IGNY8 WordPress Bridge
- Version: 1.2.0
- Changelog: Describe changes
- Status: draft
- (All other fields auto-fill)
4. Change status to "released" (or use bulk action) → Auto-build triggers
5. Run verification checklist 5. Run verification checklist
6. Deprecate old version 6. Optionally: Mark old version as deprecated
``` ```
**Admin Bulk Actions:**
- **✅ Release selected versions** - Builds ZIP and marks as released
- **📢 Mark as update ready** - Notifies WordPress sites
- **🗑️ Mark as deprecated** - Deprecates old versions
### Verification Commands ### Verification Commands
```bash ```bash

View File

@@ -390,23 +390,32 @@ View and manage plugin registry.
Manage versions and trigger releases. Manage versions and trigger releases.
| Field | Description | **Required Fields Only:**
|-------|-------------| - Plugin
| Plugin | Parent plugin | - Version (e.g., 1.2.0)
| Version | Semantic version (e.g., 1.1.1) | - Changelog
| Status | draft, testing, staged, released, update_ready, deprecated | - Status
| File Path | Auto-set on release |
| File Size | Auto-calculated on release | **Auto-Filled Fields:**
| Checksum | Auto-calculated on release | - Min API/Platform/PHP versions (copied from previous version)
| Changelog | What's new (shown to users) | - File path, size, checksum (generated on release)
| Force Update | Set true for critical security fixes | - Version code (calculated from version number)
**To Release a New Version:** **To Release a New Version:**
1. Create new PluginVersion record with status `draft` 1. Click **Add Plugin Version**
2. Enter version number, changelog 2. Select plugin
3. Change status to `released` or `update_ready` 3. Enter version number (e.g., 1.2.0)
4. Save → ZIP is automatically built 4. Write changelog
5. Set status to `draft`
6. Save
7. Change status to `released` (or use bulk action "✅ Release selected versions")
8. ZIP is automatically built with all file info populated
**Bulk Actions:**
- **✅ Release selected versions** - Builds ZIP and releases
- **📢 Mark as update ready** - Notifies WordPress sites
- **🗑️ Mark as deprecated** - Deprecates old versions
#### Plugin Installations #### Plugin Installations

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.1.1 * Version: 1.1.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
@@ -167,6 +167,44 @@ class Igny8Bridge {
if (!get_option('igny8_default_post_status')) { if (!get_option('igny8_default_post_status')) {
add_option('igny8_default_post_status', 'draft'); add_option('igny8_default_post_status', 'draft');
} }
// Register installation with IGNY8 API
$this->register_installation();
}
/**
* Register this plugin installation with IGNY8 API
*/
private function register_installation() {
// Get API key and site ID
$api_key = get_option('igny8_api_key');
$site_id = get_option('igny8_site_id');
// Skip if not configured yet
if (empty($api_key) || empty($site_id)) {
return;
}
// Register installation
$response = wp_remote_post(
'https://api.igny8.com/api/plugins/igny8-wp-bridge/register-installation/',
array(
'headers' => array(
'Authorization' => 'Bearer ' . $api_key,
'Content-Type' => 'application/json',
),
'body' => wp_json_encode(array(
'site_id' => intval($site_id),
'version' => IGNY8_BRIDGE_VERSION,
)),
'timeout' => 15,
)
);
// Log result (don't fail activation if this fails)
if (is_wp_error($response)) {
error_log('IGNY8 Bridge: Failed to register installation - ' . $response->get_error_message());
}
} }
/** /**