Skip to content

KunalPareek21/safeupdate

Repository files navigation

SafeUpdate AI

A WordPress-native plugin update orchestration and recovery platform. Provides deterministic risk analysis, pre-update restore points, rollback execution, conflict detection, and a two-layer crash recovery system — all without requiring any external service or API key.

Optional AI provider integration adds human-readable explanations layered on top of native diagnostics. The core system is fully self-contained.


Philosophy

WordPress plugin failures are predictable at the infrastructure level. Most production incidents — white screens, broken admin panels, plugin conflicts — follow recognizable patterns that don't require AI to detect or respond to.

SafeUpdate AI is built on the premise that:

  • Deterministic diagnostics should come first. Conflict detection and risk scoring use rule-based analysis that produces consistent, auditable results with no external dependencies.
  • Recovery must be reachable when the site is broken. A plugin that only works when WordPress is healthy cannot help you when it isn't. The recovery layer is designed to operate before the main application stack initializes.
  • AI is additive, not foundational. Optional AI providers can produce additional plain-English explanations, but removing API access changes nothing about core behavior.
  • PHP-native architecture over frontend complexity. Admin pages are PHP templates. There is no JavaScript build step, no React SPA, no Node dependency at runtime. This keeps the plugin auditable, hostable on shared infrastructure, and maintainable long-term.
  • Honesty about what recovery can and cannot do. Some failures happen at layers this plugin cannot reach. The documentation says so clearly.

Core Capabilities

Update Risk Analysis

Before executing an update, SafeUpdate AI calculates a risk score (0–100) based on:

  • Version delta magnitude (patch vs minor vs major)
  • Plugin criticality inferred from active integrations
  • Update frequency and maintenance history
  • Active conflicts with currently installed plugins
  • Historical failure rate for this plugin on this site

Updates above a configurable risk threshold require explicit confirmation. The score is deterministic and recalculated on every request — no caching of stale risk data.

Restore Points and Rollback

Pre-update restore points capture plugin version state and relevant options before any change is applied. If an update fails, or if post-update validation detects degraded behavior, the rollback engine can restore the pre-update state.

Rollback uses WordPress's own plugin management mechanisms. It does not perform filesystem-level file restoration. Sites that require full filesystem rollback should pair this with a filesystem backup tool.

A dry-run preview endpoint is available before committing to any rollback, showing what will be changed.

Conflict Detection

Eight conflict categories are scanned deterministically, without requiring an AI provider:

Category Description
Hook conflicts Duplicate add_action / add_filter registrations on the same tag
JS asset version conflicts Conflicting versions of enqueued scripts
Duplicate library loading Multiple copies of Bootstrap, jQuery UI, Select2, Font Awesome
Memory risk Combined plugin memory footprint approaching PHP limit
WooCommerce compatibility Known incompatible hook and filter patterns
Elementor compatibility Template hook interference patterns
Abandoned plugins No release in 24+ months
PHP version incompatibility Plugin declares higher minimum PHP than server provides

Conflict records are stored locally and associated with the scan timestamp. Historical conflict data is preserved for trend analysis.

Site Health Scoring

Three composite scores updated on each cron-triggered scan:

  • Stability Score — weighted combination of update success rate, active conflict count, and recent error frequency
  • Update Risk Score — aggregate risk across all currently pending updates
  • Plugin Trust Score — maintenance health of the installed plugin set (last-updated dates, active install counts, abandonment indicators)

Score history is persisted in a local database table for trend visualization.


Recovery Architecture

The plugin uses a two-layer architecture. The separation exists because a plugin that depends on a healthy WordPress environment cannot reliably help when that environment has failed.

Layer 1 — Recovery Bootstrap

A lightweight recovery loader (src/Recovery/RecoveryBootstrap.php) initializes during the earliest practical plugin bootstrap phase, hooking into muplugins_loaded at priority 1. It has no Composer autoloader dependency and no custom database table dependency.

Responsibilities:

  • Incrementing a crash detection counter on each admin page load
  • Resetting that counter on a confirmed successful admin load
  • Triggering Safe Mode automatically after repeated detection of admin load failures
  • Intercepting ?safeupdate_recovery=1 requests early in admin_init
  • Rendering an emergency recovery interface if the main application cannot load

The recovery loader is intentionally minimal. It reads and writes only WordPress options and transients. It does not call any class from the main application stack.

Layer 2 — Main Application

The full plugin stack (service container, REST API, conflict scanner, rollback engine, AI layer) initializes on plugins_loaded. If Layer 2 throws a fatal error, Layer 1 remains operational on the next request.

This design means the emergency recovery interface remains accessible even when the main plugin has crashed. It does not mean recovery is guaranteed — see Limitations.


Safe Mode

Safe Mode is a temporary isolation state entered either manually or automatically after crash loop detection.

Crash loop detection counts consecutive admin page loads that do not reach a successful admin_init completion. The threshold is three consecutive failures within a one-hour window, tracked via WordPress transients with an options-based fallback in case the object cache is unavailable.

When the threshold is reached:

  1. Safe Mode is activated (a flag is written to wp_options)
  2. The most recently updated plugin is identified from the pre-update record
  3. That plugin is temporarily deactivated by directly modifying the active_plugins option, bypassing the normal deactivation hook flow to avoid triggering additional failures
  4. An admin notice is shown on every admin page while Safe Mode is active
  5. The emergency recovery URL (wp-admin/?safeupdate_recovery=1) is surfaced prominently

Exiting Safe Mode reactivates the isolated plugin and clears the crash counter. This is done manually from the Recovery Center or via the emergency endpoint.

Safe Mode attempts to restore dashboard access after update-related failures. Recovery success depends on the hosting environment, the nature of the failure, and whether the failure occurred at a layer this plugin can reach.


Limitations

These are real constraints, not edge cases.

  • Filesystem-level failures are outside scope. If a plugin update leaves corrupted files on disk, this plugin's rollback restores the database state but does not restore files. A filesystem-level backup solution is required for complete file recovery.
  • Failures before WordPress initializes cannot be intercepted. PHP fatal errors that occur before WordPress's own bootstrap phase — including syntax errors in wp-config.php or missing core files — are unreachable by any plugin.
  • Crash loop detection requires at least one admin page load to trigger. If the first request after a failed update causes an immediate fatal error, the crash counter increments. Recovery activates on the third such failure, not the first.
  • Plugin isolation assumes active_plugins manipulation is sufficient. Some plugins with MU-plugin companions or server-level configurations may not be fully isolated by deactivating from active_plugins alone.
  • Rollback restores plugin state, not data. Database changes made by a plugin during its activation or operation are not reversed by rollback. If a plugin ran a database migration during update, rollback removes the new plugin files but leaves the migrated database schema.
  • Hosting restrictions may limit behavior. Some managed hosting environments restrict wp_options writes, transient storage, or outgoing HTTP requests in ways that can interfere with recovery operations.
  • AI provider availability is not monitored. If a configured AI provider is unreachable or returns errors, all core functionality continues normally. AI-generated explanations are silently unavailable. There is no alerting for AI provider outages.

Privacy

SafeUpdate AI collects no telemetry, usage analytics, or behavioral data. No data is transmitted to any remote server by default.

The only outgoing HTTP requests the plugin makes are:

  1. Requests to a configured AI provider API, if you have explicitly entered an API key and enabled AI features. These requests contain only the text prompt constructed from local plugin data — no site identity, user data, or WordPress configuration is included beyond what is relevant to the analysis.
  2. Requests to the WordPress.org plugin API for update availability checking — this is standard WordPress core behavior, not specific to this plugin.

All logs, conflict records, restore points, health scores, and AI usage data are stored in your WordPress database. No data ever leaves your server unless you explicitly configure an AI provider.

Uninstalling the plugin with "Delete data on uninstall" enabled removes all six database tables, all plugin options, and all transients.


Security Model

Capability enforcement: All REST API endpoints require manage_options (admin-level) capability. Read-only endpoints require install_plugins. Capability checks are enforced server-side on every request — the frontend receives no elevated access.

Nonce verification: All REST endpoints use WordPress REST API nonce verification (wp_rest nonce). All recovery endpoint actions that modify state require nonce verification with the safeupdate_recovery nonce action.

API key storage: API keys are encrypted at rest using AES-256-CBC with your WordPress AUTH_KEY and SECURE_AUTH_KEY as encryption context. Keys are write-only from the API perspective — GET responses return only a masked placeholder, never the stored value. If the OpenSSL extension is unavailable, keys fall back to base64 encoding with a warning displayed in the settings UI.

Rate limiting: The emergency recovery endpoint is rate-limited to 10 actions per hour per session via a transient counter. The email notification service rate-limits each event type independently (default: once per hour per event).

Rollback validation: Before executing a rollback, the rollback engine validates the restore point integrity, checks that the target plugin version is accessible, and performs a dry-run diff. Rollback to a corrupted or missing restore point is rejected with a descriptive error.

Input sanitization: All user-supplied values passing through REST endpoints are sanitized using WordPress core functions (sanitize_key, sanitize_text_field, absint, wp_kses_post). No raw user input reaches database queries — all database access uses wpdb::prepare().


Design Principles

PHP-first architecture. Admin pages are rendered as PHP templates (templates/admin/). There is no React component tree, no Vite build, no webpack, no npm dependency at runtime. This is a deliberate choice — it reduces attack surface, eliminates build toolchain failures, and keeps the plugin auditable by anyone familiar with PHP.

Progressive enhancement. JavaScript (assets/js/admin.js) is vanilla JS in an IIFE namespace. It enhances server-rendered pages with AJAX saves and toast notifications. Pages are functional without JavaScript.

Shared-hosting compatibility. The plugin avoids dependencies on PHP extensions beyond what WordPress itself requires, avoids CLI-only tooling, and respects WordPress's own abstractions for database, HTTP, and caching. It should work on any host that runs WordPress.

Strict separation of recovery and application layers. The recovery bootstrap layer never calls code from the main application namespace. This is enforced structurally — the recovery loader uses direct require_once for its own dependencies and makes no assumptions about autoloader availability.

Determinism before AI. Every analysis that produces a result the user acts on (risk scores, conflict records, health scores) uses rule-based, deterministic logic. AI providers produce supplementary explanations — they do not drive any decision logic.


Requirements

  • WordPress 6.0+
  • PHP 8.0+ (tested on 8.0, 8.1, 8.2, 8.3)
  • MySQL 5.7+ or MariaDB 10.3+
  • OpenSSL extension (recommended; required for AES-256 API key encryption)

Tested on: single-site, multisite network, WooCommerce, Elementor.


Installation

From a release ZIP:

  1. Download the latest ZIP from Releases.
  2. WordPress admin → Plugins → Add New → Upload Plugin.
  3. Activate and navigate to SafeUpdate AI in the admin sidebar.

From source:

git clone https://github.com/YOUR_USERNAME/safeupdate.git
cd safeupdate
composer install --no-dev --optimize-autoloader

Copy the directory to wp-content/plugins/ and activate.

AI provider setup (optional):

Go to SafeUpdate AI → AI Settings. Select a provider, enter your API key, and save. The key is tested against the provider's API before being stored — if the connection fails, the key is rejected and an inline error is shown. You can skip this entirely; no core feature requires it.


REST API

All endpoints are under /wp-json/safeupdate/v1/. Full capability and nonce verification applies to every route.

GET    /dashboard
GET    /updates
POST   /updates/{slug}/safe-update
GET    /restore-points
POST   /restore-points
DELETE /restore-points/{id}
POST   /restore-points/{id}/rollback
POST   /restore-points/{id}/dry-run
GET    /conflicts
POST   /conflicts/scan
GET    /health
GET    /logs
GET    /settings
POST   /settings
GET    /ai/settings
POST   /ai/settings
POST   /ai/test-connection
GET    /ai/providers
GET    /ai/models
GET    /ai/usage
GET    /reports/summary
GET    /reports/updates?days=30
GET    /reports/conflicts
GET    /reports/export?format=csv&limit=1000

Database Schema

Six tables are created on activation, all prefixed with your WordPress table prefix:

Table Purpose
SAFEUPDATE_restore_points Restore point metadata and state snapshots
SAFEUPDATE_update_events Update execution history, risk scores, and outcomes
SAFEUPDATE_conflicts Detected conflict records with severity classification
SAFEUPDATE_health_snapshots Point-in-time health score history
SAFEUPDATE_logs Structured event log (level, context, message, data)
SAFEUPDATE_usage Per-request AI token usage and latency tracking

Schema upgrades use dbDelta(). All tables are removed on uninstall if the option is enabled.


Development

# Install all dependencies including dev tools
composer install

# Run test suite
vendor/bin/phpunit --configuration phpunit.xml

# Check coding standards (WordPress Coding Standards)
vendor/bin/phpcs

# Static analysis (PHPStan)
vendor/bin/phpstan analyse --memory-limit=256M

CI runs PHPUnit, PHPCS, and PHPStan against PHP 8.0, 8.1, 8.2, and 8.3 on every push and pull request. All three must pass before merging.


Development Standards

  • Coding standard: WordPress Coding Standards (PHPCS with WordPress ruleset)
  • Static analysis: PHPStan level 5+
  • Type safety: declare(strict_types=1) on every file; typed properties and return types throughout
  • Autoloading: PSR-4 via Composer (SafeUpdateAI\ namespace maps to src/)
  • Database access: All queries through DatabaseManager using wpdb::prepare() — no raw interpolation
  • No build toolchain: No npm, no Vite, no webpack. CSS and JS are plain files in assets/

Contributing

Pull requests are welcome. Before submitting:

  • Run vendor/bin/phpcs and resolve all violations
  • Run vendor/bin/phpstan analyse and resolve all errors at level 5
  • Add or update PHPUnit tests for any new behavior
  • Keep pull requests focused — one feature or fix per PR
  • Describe the problem being solved in the PR description, not just the implementation

For significant changes, open a discussion or issue first to align on approach before writing code.

Security vulnerabilities should be reported privately via GitHub's security advisory feature, not as public issues. Include a description of the vulnerability, reproduction steps, and the potential impact.


Support

  • Bug reports: GitHub Issues — include WordPress version, PHP version, and steps to reproduce
  • Feature requests: GitHub Discussions
  • Security issues: GitHub private security advisory (never public issues)

This is an open-source project. There is no commercial support tier.


Author

Kunal Pareek

License

GPL v2 or later. See the GNU General Public License.


Changelog

1.0.0

Initial release.

  • Safe update orchestration with deterministic risk scoring
  • Pre-update restore points and rollback engine with dry-run preview
  • Conflict detection across eight categories (no external dependencies required)
  • Two-layer recovery architecture: lightweight bootstrap loader + main application
  • Safe Mode with crash loop detection and plugin isolation
  • Emergency recovery endpoint at wp-admin/?safeupdate_recovery=1
  • Optional AI provider integration: OpenAI, Anthropic Claude, Google Gemini, OpenRouter
  • API key validation on save — keys are tested before being stored
  • AES-256-CBC encrypted API key storage
  • Email notifications with per-event-type rate limiting
  • Site health scoring with history
  • Report generation and CSV/JSON export
  • Full REST API (22 endpoints)
  • PHP-native admin interface — no React, no build system, no Node runtime dependency
  • WordPress Multisite support

About

No description, website, or topics provided.

Resources

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors