WP Optimal State Plugin Banner

📘 User Manual - PRO Version 1.3.1

ℹ️ NOTICE: This manual applies to both the PRO and FREE versions. However, some features described in the manual are not available in the free version.
⚠️ WARNING: If your server is running Nginx, you need to add basic security rules to your configuration - Section 7.3.1.

📑 Table of Contents

🔎 Search the Manual

Ctrl + K
Found 0 results
    1. 🚀 Introduction
    2. 🛠️ Getting Started
    3. 🎯 Dashboard Philosophy: The 3-Step Workflow
    4. 💾 The Database Backup & Restore Manager (Section 1)
    5. 🧹 The Database Optimization Suite (Sections 2-9)
    6. ⏰ Automatic Backup & Cleanup (Section 10)
    7. ⚡ Performance Features Manager (Section 11)
    8. 🎯 Optimization Strategies: Putting It All Together
    9. 📥 Settings & Security (Section 12)
    10. 🔧 Troubleshooting & Advanced FAQ
    11. 🏗️ Technical Architecture
    12. 📝 Disclaimer
    13. 📝 Developer API (Hooks & Filters)
    14. 🆘 Technical Support

🚀 1. Introduction

🧠 1.1. The Philosophy of WP Optimal State PRO

WP Optimal State PRO is an advanced, all-in-one WordPress optimization and management suite. It was built on the philosophy that site management should be comprehensive, secure, and powerful. It provides a complete set of tools to clean, optimize, back up, and secure your WordPress database, combined with a robust performance module to make your site exceptionally fast.

This plugin is not just a simple "cleaner." It's a complete toolkit for database management and site performance, giving you both "one-click" simplicity and the granular, advanced control that professionals demand.

👥 1.2. Who is This Manual For?

This manual is for every user of WP Optimal State PRO.

⚠️ 1.3. A CRITICAL First Warning: ALWAYS BACK UP

🚨 WARNING: THIS IS A POWERFUL TOOL

WP Optimal State PRO interacts directly and deeply with your website's database. Operations like cleanup, optimization, and restoration are powerful and, in most cases, irreversible.

While this plugin includes its own robust, best-in-class backup system, we cannot overstate the importance of caution.

💾 Before performing ANY cleanup or restore operation, you MUST create a fresh backup.

The plugin's built-in "Safety Backup" feature during restores provides a strong safety net, but a separate, downloadable backup is your ultimate insurance policy. Use this plugin responsibly. The author and this manual are not responsible for any data loss.

🛠️ 2. Getting Started

💻 2.1. System Requirements

To ensure full compatibility and smooth operation, your server should meet these minimum requirements:

2.1.1. ⏱️ Rate Limiting & Timeout Settings

The plugin implements intelligent rate limiting and timeout configurations to prevent server overload:

💡 For Advanced Users: These timeouts are particularly important for large database operations. If you're working with databases over 1GB, the plugin's connection management prevents timeout errors during long-running operations.

📁 2.2. A Note on File & Directory Permissions

This plugin requires the ability to write files to your wp-content/uploads/ directory. This is a standard WordPress capability, but if your server has non-standard or overly restrictive permissions, you may encounter errors.

The plugin uses the WP_Filesystem API to safely read and write files. If you see an error like "Cannot initialize WP_Filesystem," it means your server is not configured to allow WordPress to manage its own files. You must contact your hosting provider to resolve this.

2.2.1. 🔧 WordPress Filesystem Method (FS_METHOD)

WordPress supports multiple methods for file operations. WP Optimal State PRO adapts its validation logic based on your server's configuration:

Available Filesystem Methods
Method Description Security Level
direct PHP directly reads/writes files. Requires proper file ownership and permissions. Highest - Plugin uses realpath() for canonical path validation
ssh2 Uses SSH/SFTP connection. WordPress prompts for SSH credentials. High
ftpext Uses FTP extension (PHP 7.4+). WordPress prompts for FTP credentials. Medium
ftpsockets Pure PHP FTP implementation (fallback when ftpext unavailable). Medium
How the Plugin Adapts

The plugin's path validation adjusts based on your FS_METHOD setting:

Checking Your Current Method

To see which filesystem method WordPress is using:

  1. Check wp-config.php for: define('FS_METHOD', 'value');
  2. If not defined, WordPress auto-detects based on file permissions
  3. View in "WP Site Health" → "Info" tab → "Filesystem Permissions" section
Recommended Configuration

For best performance and security with this plugin:

// In wp-config.php (if your hosting supports it)
define('FS_METHOD', 'direct');

To enable direct method safely:

⚠️ Common Issue: If WordPress keeps prompting for FTP credentials when you try to update plugins, your FS_METHOD isn't set to 'direct' or your file permissions are incorrect. Fix permissions first, then add define('FS_METHOD', 'direct'); to wp-config.php.
🔐 Security Note: The plugin's path validation works with all filesystem methods, but 'direct' provides the strongest security by allowing canonical path resolution. If you must use SSH/FTP methods, ensure your hosting provider has proper chroot restrictions in place.

2.3. 🚫 CRITICAL: Multisite Not Supported

WP Optimal State PRO cannot be activated on WordPress Multisite (network) installations. If you attempt to activate it on a multisite network, you will see a clear error message and activation will be blocked.

Why Multisite Is Not Supported

This is a deliberate architectural decision, not a limitation to be worked around:

  1. Shared Table Operations: Multisite installations share certain database tables (users, usermeta, sitemeta) across all sites. Cleanup operations on one subsite could delete data needed by other subsites.
  2. Complex Prefix Handling: Multisite uses dynamic table prefixes (wp_, wp_2_, wp_3_, etc.). The plugin's table detection logic is designed for single-site prefixes and could misidentify tables.
  3. Metadata Cascade Risk: Deleting orphaned metadata on a multisite network requires checking relationships across ALL subsites, not just one. This multiplies execution time by the number of sites and risks deadlocks.
  4. Backup/Restore Scope: Should a backup include all subsites? Just one? The network tables? There's no clear answer, and partial restores could break the network.
  5. Performance Feature Conflicts: Browser caching rules, page caching, and bad bot blocking need network-wide coordination on multisite. The single-site implementation would conflict with network-wide plugins.

The Safety Check

During activation, the plugin executes this check:

if (is_multisite()) {
    deactivate_plugins(plugin_basename(__FILE__));
    wp_die(
        'WP Optimal State cannot be activated on WordPress Multisite installations.',
        'Plugin Activation Blocked'
    );
}
⛔ Do Not Attempt to Bypass This Check
Commenting out the multisite check or force-activating through database manipulation will cause data loss. The plugin's operations are not multisite-aware and will:

Alternatives for Multisite Users

If you run a multisite network, consider these alternatives:

⚡ 2.4. Installation & Activation

  1. Navigate to your WordPress Admin Dashboard.
  2. Go to Plugins > Add New.
  3. Click Upload Plugin.
  4. Choose the WP_Optimal_State_PRO_X-X-X.zip file from your computer and click Install Now.
  5. Once installed, click Activate Plugin.
  6. Upon activation, the plugin will immediately check for and create its required directories and default settings files (Section 2.6).
  7. Look for "Optimal State" in you admin menu.

🔄 2.5. Upgrading From FREE Version

The upgrade process is straightforward. Simply replace the free version with the PRO version.

👉 Follow these quick steps:

  1. In the plugin interface, go to section 1 and download your database backups (they will download as compressed .sql.gz files).
  2. Then, go to section 12 (Settings & Security) and click Export Settings to download your .json settings file.
  3. Go to Plugins > Add Plugin, then click Upload Plugin. Choose the zip file WP_Optimal_State_PRO_X-X-X.zip containing the PRO version and click Install Now.
  4. At this point, you will now be asked to either replace the current version with the uploaded one, or cancel and go back. Click Replace current with uploaded.
  5. The update is complete! Visit the plugin admin panel to confirm that your backups and settings are intact.
  6. If your settings have not been properly preserved, go to section 12 and import the .json file you downloaded in step 2.
💡 TROUBLESHOOTING: Functions Not Working After Upgrade

If after upgrading some functions don't work properly (e.g., save buttons not responding), this is usually caused by your browser still using cached versions of old JavaScript and CSS files.

Solution: Clear your browser cache

📊 2.6. Filesystem Footprint (What the Plugin Creates)

On activation, the plugin creates the following directories and database tables to ensure persistent operation and data integrity.

📂 Filesystem (wp-content/uploads)

🗄️ Database Tables

Performance Impact: The three-tier caching system means backup/restore progress checks happen at memory speed rather than hitting the database repeatedly. This is why the dashboard remains responsive even during intensive operations.
⚠️ WARNING - NGINX SERVERS

If your server is running Nginx, your site's sensitive directories are currently unprotected. The .htaccess files this plugin relies on are ignored, leaving your files and settings exposed.

To secure your server, you must manually add the security rules to your Nginx configuration. Read Section 7.3.1 for immediate instructions.

2.6.1. 🗄️ The Process Store: Multi-Layer Caching System

WP Optimal State PRO uses a sophisticated three-tier caching system for process state management:

Cache Layers (Fastest to Slowest)
  1. Runtime Cache (PHP Memory): Static array that persists for the current request only. Fastest possible access with zero overhead.
  2. Object Cache (Memcached/Redis): If available, stores process data in your server's object cache (via wp_cache_set/get). Shared across PHP requests but cleared on server restart.
  3. Database Table (wp_optistate_processes): Permanent storage for process data that survives server restarts. Created during activation with optimized indexes for fast lookups.
How the Fallback Works

When you access process data (like backup/restore status), the system:

  1. First checks runtime cache (instant)
  2. Falls back to object cache if available (microseconds)
  3. Falls back to database query if needed (milliseconds)
  4. Stores result in faster layers for subsequent requests
Automatic Cleanup

The process store automatically purges expired entries in batches of 1,000 to prevent table bloat. Expiration times are set per-operation:

Performance Impact: This multi-tier system means backup/restore status checks, which happen every 2 seconds during operations, cost virtually nothing in server resources even on high-traffic sites.
🔍 Troubleshooting: If the dashboard shows stale backup progress (percentage frozen), your object cache might not be working correctly. The plugin will automatically fall back to database queries, but performance may be slightly slower.

🔔 2.7. Keep the Plugin Updated

Your update process depends on whether you are using the FREE or PRO version. Please read the correct section for your plugin.

✔ UPDATING THE PREVIEW VERSION

If you installed the free preview/demo version of the plugin from the official WordPress plugin repository, you can update it directly from your WordPress dashboard.

⭐ UPDATING THE PRO OR FREE VERSION

Updating the PRO or FREE version (which you received as a .zip file) takes just a couple of minutes. You have two equally valid options.

💡 Option 1: Via the Dashboard

  1. In the plugin interface, go to section 1 and download your database backups (they will download as compressed .sql.gz files).
  2. Then, go to section 12 (Settings & Security) and click Export Settings to download your .json settings file.
  3. Go to Plugins > Add Plugin, then click Upload Plugin. Choose the .zip file containing the latest plugin release and click Install Now.
  4. At this point, you will now be asked to either replace the current version with the uploaded one, or cancel and go back. Click Replace current with uploaded.
  5. The update is complete! Visit the plugin admin panel to confirm that your backups and settings are intact.
  6. If your settings have not been properly preserved, go to section 12 and import the .json file you downloaded in step 2.

👨‍💻 Option 2: Via FTP Client

  1. Unzip the new plugin .zip file on your computer to get a folder named optistate.
  2. Open your FTP client or hosting file explorer and navigate to wp-content/plugins/.
  3. Upload the optistate folder from your computer, choosing to replace or overwrite all existing files in the /wp-content/plugins/optistate/ directory.
  4. Once complete, go to Plugins > Installed Plugins, find WP Optimal State and verify that the new version number is displayed.
  5. The update is complete! Visit the plugin admin panel to confirm that your backups and settings are intact.

📥 How to Get PRO Updates

💡 TROUBLESHOOTING: Functions Not Working After Update

If after updating some functions don't work properly (e.g., save buttons not responding), this is usually caused by your browser still using cached versions of old JavaScript and CSS files.

Solution: Clear your browser cache

2.8. 🛑 What Happens When You Deactivate

Understanding the deactivation cleanup process helps you make informed decisions about plugin management. The steps below reflect the actual execution order in the code.

Automatic Cleanup (Execution Order)

When you deactivate WP Optimal State PRO, the following actions run in this sequence:

  1. Bot Blocking Rules Removed: Bad bot blocking rules are removed from .htaccess.
  2. Deactivation Logged: A 🔌 Plugin Deactivated by {username} entry is written to the activity log before any data is deleted, ensuring the event is always recorded.
  3. Scheduled Hooks Cleared: All four plugin cron hooks are unregistered: optistate_scheduled_cleanup, optistate_daily_cleanup, optistate_background_preload_batch, and optistate_run_rollback_cron.
  4. Browser Caching Rules Removed: Browser caching directives are removed from .htaccess.
  5. Maintenance Mode Cleared: The optistate_maintenance_mode_active option is deleted to prevent the site being left in maintenance mode.
  6. Database Tables Dropped:
    • wp_optistate_processes — the process-store table (dropped via its class method).
    • wp_optistate_login_protect — the login-protection table (name validated against alphanumeric pattern before the drop is executed).
    • Any stray tables matching wp_optistate_old_* or wp_optistate_temp_* — see the Stray Table Cleanup Logic subsection below.
  7. Transients Cleared: All transient keys matching _transient_optistate_* and their corresponding timeout keys _transient_timeout_optistate_* are deleted in a single query.
  8. Options Cleaned: All remaining options whose names start with optistate_ are deleted in batches of 100 to avoid memory issues on large databases.
  9. User Metadata Removed: The optistate_action_timestamps meta key is deleted from all user records.
  10. Filesystem Cleanup: Two directories are deleted entirely:
    • Page cache: wp-content/uploads/optistate/page-cache/
    • Restore temp: wp-content/uploads/optistate/db-restore-temp/

What Is Preserved (Intentionally NOT Deleted)

Two directories survive deactivation on purpose, so that reactivating the plugin restores your previous state without data loss:

💾 Important: If you have a 500 MB database with 3 backups, deactivating leaves approximately 1.5 GB of backup files on disk. These are intentionally preserved, but you may want to delete them manually via FTP to free space if you do not plan to reactivate.

Manual Cleanup (Complete Removal)

To remove all traces of the plugin after deactivation:

  1. Delete via FTP: wp-content/uploads/optistate-settings/ (settings and logs) and wp-content/uploads/optistate/db-backups/ (all backup files).
  2. Delete plugin folder: wp-content/plugins/optistate/

Stray Table Cleanup Logic

The deactivation process includes a dedicated routine to clean up tables left behind by interrupted or failed operations:

  1. Queries information_schema.TABLES for tables in the current database whose names match optistate_old_% or optistate_temp_%.
  2. Each candidate is validated through three checks: the name must be alphanumeric-plus-underscore only (/^[a-zA-Z0-9_]+$/), no longer than 64 characters, and must start with the expected WordPress prefix (e.g. wp_optistate_old_ or wp_optistate_temp_). Tables that fail any check are skipped.
  3. Foreign key checks are disabled (SET FOREIGN_KEY_CHECKS = 0) for the duration of the drops to avoid constraint errors on interdependent tables.
  4. All validated tables are dropped.
  5. Foreign key checks are re-enabled (SET FOREIGN_KEY_CHECKS = 1).
🔒 Safety: Multiple validation layers prevent accidental deletion of unrelated tables. Only tables that pass every check — correct prefix, valid characters, and length within limits — are dropped.

Reactivation

Because the settings and backup directories are preserved, reactivation is designed to be seamless:

🎯 3. Dashboard Philosophy: The 3-Step Workflow

The plugin dashboard is organized to guide you through a logical and safe workflow.

🛡️ Step 1: The Safety Net (Backup)

Section: 1. Create a Database Backup

Before you diagnose or fix anything, you must have an exit strategy. This section is your safety net. You can create a new, verifiable backup in seconds.

🔍 Step 2: The Diagnosis (Analyze)

Sections: 3. Database Health Score, 4. Database Statistics, 6. Database Structure Analysis

You can't fix what you don't understand. These sections are your diagnostic tools.

✨ Step 3: The Solution (Optimize)

Sections: 2. One-Click Optimization, 8. Detailed Cleanup, 9. Advanced Optimization, 10. Automation, 11. Performance

Once you have a backup and have diagnosed the problems, you can apply the solution.

💾 4. The Database Backup & Restore Manager (Section 1)

This is the plugin's most critical feature. It allows you to create, manage, download, and restore your database with a focus on security and integrity.

📥 4.1. Creating a Database Backup

The backup process relies on an asynchronous chunked engine that runs entirely in the background, making it resilient on any hosting environment — including shared hosting with low PHP time limits.

  1. 📊 Maximum Backups to Keep: This setting (1–10) enforces a rolling limit. After a backup completes, the engine sorts all existing backups by last-modified timestamp (oldest first) and deletes the excess. Only .sql and .sql.gz files are counted — internal SAFETY-RESTORE-* backups created during the restore process are explicitly excluded from this limit.
    • 💡 Recommendation: Set this to 3. This keeps recent restore points available while minimizing server storage usage.
  2. 🔄 Create Backup Now Button: Clicking this initializes a secure multi-step background process:
    • 🔒 Collision-Safe Filename: Each backup filename is suffixed with 14 random hex bytes (random_bytes(7)), making filename collisions statistically impossible. If a file at the target path already exists, the process throws an exception rather than overwriting.
    • 🔑 PID Lock File: A .lock file is written with the current PHP process ID before any data is touched. If the lock cannot be created, the backup is aborted immediately. This prevents two concurrent backups from writing to the same file.
    • 📋 Table Discovery: The engine runs SHOW FULL TABLES to enumerate every table, including its type (BASE TABLE vs. VIEW). Internal plugin tables (wp_optistate_processes, wp_optistate_backup_metadata, wp_optistate_login_protect, and any stray optistate_old_* tables) are silently excluded from the backup to avoid self-referential loops.
    • ⚙️ Worker Coordination: Before processing each chunk, the engine atomically registers itself as the active worker in the process store. If another worker process is already active and has sent a heartbeat within the last 45 seconds, the new worker skips its chunk and exits cleanly, preventing parallel writes to the same file.
    • 📦 Streamed gzip Writing: Data is written chunk by chunk directly into a .sql.gz file opened in append mode (ab6f), meaning no full SQL file is ever held in memory. If PHP crashes mid-chunk, the partial gzip file is cleaned up on the next request.
    • 🔒 Metadata Storage: On successful completion, the backup's filename, file size, creation timestamp, and database name are written to the protected wp_optistate_backup_metadata database table. This is intentionally a database table, not a sidecar file — it cannot be tampered with by uploading a file to the backup directory.
    • ✅ SHA-256 Integrity Seal: A SHA-256 checksum of the completed file is generated and stored separately. Every subsequent action on that backup (download, restore) re-verifies this checksum before proceeding. A failed checksum aborts the action entirely.

🔧 4.2. Under the Hood: The Backup & Verification Process

The backup mechanism is server-timeout proof using an asynchronous, chunked process. The plugin executes a series of timed AJAX requests, each running for a fixed window before saving state and yielding — ensuring reliability on any hosting environment including aggressively time-limited shared hosts.

  1. 🔓 Concurrency Lock: When a chunk starts, the engine atomically claims the active_worker slot in the process store with a unique worker ID and a worker_ping timestamp. If another process already holds the slot with a fresh ping (<45 seconds old), the new chunk exits immediately without touching the file. If the existing worker has gone stale, the slot is stolen and processing continues.
  2. 🧠 Adaptive Resource Tiering: Before the first chunk, the engine detects your server's available resources (CPU cores via shell_exec, PHP memory limit) and assigns a performance tier that controls how long each chunk runs and how quickly subsequent chunks are scheduled:
    • High Tier: High RAM/CPU — longer chunk windows with minimal delays between requests.
    • Medium Tier: Standard VPS — balanced chunk windows.
    • Low Tier: Shared hosting — short chunk windows with longer cooldowns to avoid triggering resource abuse limits.
  3. 🏗️ Structure Dump: For each table the engine first emits DROP TABLE IF EXISTS followed by the full SHOW CREATE TABLE output (or SHOW CREATE VIEW for views). The AUTO_INCREMENT value is read from SHOW TABLE STATUS and explicitly written into the CREATE statement, ensuring auto-increment counters are preserved exactly. Generated columns are detected and excluded from the column list to avoid restore errors.
  4. 📐 Pagination Method Selection: After dumping the structure, the engine examines each table's primary key to choose the safest pagination method:
    • Keyset (primary): Single numeric PK → WHERE pk > last_seen LIMIT N. Zero drift, no performance degradation at scale.
    • Unique index fallback: If no PK exists, the engine scans SHOW INDEX … WHERE Non_unique = 0 and uses the first numeric unique column for keyset pagination.
    • OFFSET fallback: Composite PKs, non-numeric PKs, or no PK at all → standard LIMIT N OFFSET M, with batch size reduced to 65% of normal to compensate for offset overhead.
  5. 📦 Adaptive Batch Sizing & Streaming: For each table, AVG_ROW_LENGTH is fetched from information_schema (with SHOW TABLE STATUS as fallback) and cached in memory (up to 160 entries) and as a transient (10-minute TTL). The batch limit is calculated as floor(2MB / avg_row_length), clamped between 10 and 2,000 rows. Rows are buffered in memory up to 2MB, then flushed as a single INSERT INTO … VALUES (…),(…) block directly into the gzip stream. Oversized single rows that exceed the 2MB buffer are flushed individually. Memory usage is monitored every 1,000 rows — if usage exceeds 80% of the PHP memory limit, gc_collect_cycles() is called and the buffer is flushed immediately.
  6. 📄 phpMyAdmin-Compatible Header & Footer: The output SQL begins with a full phpMyAdmin-style header (version, host, generation time, server version, database name, charset/collation) and wraps all data in START TRANSACTION … COMMIT. This ensures the file is importable by phpMyAdmin, MySQL CLI, or any standard SQL tool without modification.
  7. ✅ SHA-256 Checksum: After all tables are written and the file is finalized, a SHA-256 checksum of the completed gzip file is computed and stored in the wp_optistate_backup_metadata table alongside the filename, file size, database name, and creation timestamp.
  8. 🗜️ Compression: Data is written into the gzip stream in real time using PHP's gzopen/gzwrite (level 6 by default). On servers where pigz (parallel gzip) is available and shell_exec is enabled, the decompression step during restore uses pigz for multi-core performance — backup creation always uses the streaming PHP path for safety.
Database Connection Refresh During Long Operations

For large databases (500MB+), backup/restore operations may exceed the standard connection lifecycle limits. The plugin automatically handles this:

When Does Connection Refresh Occur?
What Happens During Refresh?
  1. Old connection is gracefully closed (commits any pending autocommit changes)
  2. New connection is established with fresh timeouts
  3. Session settings are reapplied:
    • SET SESSION time_zone
    • SET SESSION sql_mode='NO_ENGINE_SUBSTITUTION'
    • SET SESSION wait_timeout=300
    • Character set/collation
  4. Operation continues seamlessly from next query
🔄 Technical Detail: Connection refresh is blocked during active transactions. The plugin only refreshes between complete table operations, never mid-transaction, preventing data inconsistency.
⏱️ Why You Might Notice This: If your backup progress seems to pause briefly every few minutes on very large databases, that's the connection refresh. It typically takes 100-300ms and prevents timeout errors that would otherwise abort the entire operation.
Foreign Key Constraint Handling

Database tables with foreign key relationships require special handling during backup and restore operations.

What Are Foreign Keys? Constraints that enforce relationships between tables (e.g., wp_postmeta.post_id must reference existing wp_posts.ID).

The Problem: During restore, you can't drop parent tables if child tables have foreign keys pointing to them, causing "Cannot add or update child row" errors.

The Solution: The plugin temporarily disables foreign key checks during operations:

SET FOREIGN_KEY_CHECKS = 0;
-- ... perform operations ...
SET FOREIGN_KEY_CHECKS = 1;

Safety Mechanisms:

⚠️ Important: If you manually interrupt a restore (kill process), run this in phpMyAdmin to restore safety:
SET FOREIGN_KEY_CHECKS = 1;

Common Plugins Using Foreign Keys: WooCommerce (orders), Advanced Custom Fields, BuddyPress, LearnDash

📋 4.3. Managing Existing Backups (The Action Buttons)

This table lists all available backups.

🛡️ 4.4. The Chunked, 4-Phase Safety Restore

Restoring a database backup is the most critical operation the plugin performs. To guarantee zero data loss against server timeouts, crashes, or corrupted files, the restore is broken into four distinct phases — each resumable, each with its own safety gate.

🔐 Phase 1: Pre-Flight Validation & Safety Backup

  1. 🔒 Global MySQL Advisory Lock: First of all, the engine acquires a MySQL-level advisory lock (GET_LOCK('optistate_master_restore_global', 5)). This prevents two concurrent restore operations from running simultaneously — even across different browser tabs or server requests. If the lock cannot be acquired within 5 seconds, the restore is refused with a clear error message. A PHP shutdown handler is registered to release this lock automatically if the process crashes.
  2. 📄 SQL File Validation: The restore target file is opened and its first 8KB is scanned for a -- Database: dbname header comment. If the database name in the file does not match your current WordPress database name (compared with hash_equals() to prevent timing attacks), the restore is blocked immediately. This prevents accidentally restoring a backup from a different site.
  3. 💾 Automatic Safety Backup: Before the target database is touched, the plugin creates a complete, real-time SAFETY-RESTORE-{date}.sql.gz backup of your current live database using the same chunked engine described in section 4.2. This backup is your guaranteed rollback point — if anything goes wrong during the restore, it will be used to recover your original data automatically.
  4. ✅ Safety Backup Integrity Validation: After the safety backup completes, the engine verifies it is readable and its gzip stream is valid before proceeding. If the safety backup is missing, smaller than 1KB, or its gzip stream is unreadable, the restore is aborted. A restore that begins without a verified safety backup is never allowed to proceed.
  5. 🚧 Maintenance Mode: Only after the safety backup is verified does the site enter a brief maintenance mode (optistate_maintenance_mode_active option set to true). This blocks new front-end database writes while tables are being swapped. Maintenance mode is always deactivated — even if the restore fails — via the same shutdown handler that releases the advisory lock.

⚙️ Phase 2: Staged Import to Temporary Tables

  1. 🗄️ Shadow Table Naming: Every CREATE TABLE statement in the backup is rewritten on-the-fly by the SQL parser to target a shadow table instead of the live table. For example, wp_posts becomes optistate_temp_wp_posts_{hash}. Your live tables are never touched during the import phase.
  2. 📦 Chunked Streaming Import: The backup file is parsed and executed asynchronously. Each AJAX chunk runs for approximately 18 seconds, processes as many SQL statements as possible, commits its transaction, saves the file pointer position, and initiates the next request. If the server times out, the next request resumes from the exact byte offset where the previous one stopped — nothing is lost or re-executed.
  3. 🏗️ Deferred Index Building: When a CREATE TABLE statement is parsed, the engine strips secondary indexes from the CREATE statement and stores the corresponding ALTER TABLE … ADD INDEX queries separately. The table is created with only its primary key, all data is inserted at full speed (no index maintenance overhead), and the indexes are built in a single pass after the data is loaded. This mirrors what professional database import tools like mysqldump --disable-keys achieve.
  4. 🔒 Charset & Collation Safety: Before the first statement executes, the engine reads the current database charset and compares it against the backup's charset (detected from the backup's SET NAMES header). A utf8mb4 backup into a utf8 database is blocked with a clear error: this would cause data corruption (emoji and 4-byte characters would be silently truncated). A utf8 backup into a utf8mb4 database is allowed and handled correctly.
  5. 🛡️ Statement Security Filter: Every SQL statement passes through a whitelist filter before execution. Statements that are blocked regardless of file source include: SET GLOBAL, SET USER, GTID_NEXT/GTID_PURGED, CREATE PROCEDURE/FUNCTION/TRIGGER/EVENT, CREATE DATABASE, USE dbname, and LOCK TABLES/UNLOCK TABLES. This ensures a maliciously crafted backup file cannot escalate privileges or alter server-level settings.
  6. 🔁 Connection Resilience: Every 100 queries the engine sends a SELECT 1 heartbeat. If the connection has gone stale (MySQL wait_timeout disconnection), the engine automatically reconnects, re-applies all session settings, and resumes without loss. If the statement that failed was an INSERT, the transaction is reopened and the statement is retried.

🔍 Phase 3: Staged Table Verification

⚡ Phase 4: Atomic Swap & Instant Rollback Guarantee

  1. 🔄 Atomic RENAME TABLE: The swap is executed as a single RENAME TABLE statement that renames all live tables to optistate_old_* and all temporary tables to the live names simultaneously. MySQL guarantees this operation is atomic — either all renames succeed, or none do. There is no moment when your live tables are missing or partially replaced. Table names longer than 64 characters are automatically handled with a hash-based truncation strategy.
  2. 🔴 Instant Rollback Map: Immediately before executing the RENAME, the engine writes a map of live_table → optistate_old_table pairs to the process store. If anything fails after the swap — including a PHP fatal error, memory exhaustion, or server crash — a subsequent request can call perform_rollback() which executes a reverse atomic RENAME to restore the original tables. This rollback itself is wrapped in a transaction, so it either succeeds completely or leaves the optistate_old_* tables intact for manual recovery.
  3. 🧹 Post-Swap Cleanup: On successful swap, deferred indexes are applied to the now-live tables, the optistate_old_* tables are dropped, the safety backup file is deleted (it's no longer needed), and maintenance mode is deactivated. wp_cache_flush() is called to ensure no stale object cache entries survive the restored data.

This architecture means that at no point during a restore operation is your site left in an undefined state. Either you have your original data, the restored data, or (in the rare event of a catastrophic failure) an automatic revert to the safety backup created in Phase 1.

📤 4.5. How to Restore Database from an Uploaded File

This feature is designed to upload a .sql or .sql.gz file. You can upload a compressed backup downloaded from this plugin or an export from phpMyAdmin.

🚨 WARNING

Only upload .sql or .sql.gz files generated by WP Optimal State or phpMyAdmin. Uploading a random file or a backup from another plugin may damage your database structure. 🧩 phpMyAdmin Compatibility: To ensure 100% compatibility with WP Optimal State, uncheck the Enclose export in a transaction option before performing exports.

🔄 Process:

  1. 📁 Choose SQL File: Click the button to select a .sql or .sql.gz file from your computer.
  2. 🔍 Validation & Upload: The file will be uploaded, and a progress bar will be displayed. During this process, a multi-step security validation occurs (see 4.6).
  3. 🔄 Restore from File: Once the upload is complete and validated, the "Restore from File" button will appear.
  4. ✅ Confirmation: Clicking this button will trigger the same confirmation modal and the exact same 4-Phase Safety Restore process described in section 4.4.
  5. ⏳ Execution: The time required to complete the restore will vary significantly depending on both the size of the database and the available server resources (from a few seconds to 30-60 minutes).

🔒 4.6. Security-First: The Upload Validation Process

When you upload a .sql or .sql.gz file, it undergoes a rigorous multi-step security scan before it is ever used. Every check that fails results in the uploaded file being deleted from the server immediately.

  1. 📄 Extension & MIME Check: The file extension must be .sql or .sql.gz. The MIME type (e.g., text/plain, application/sql, application/gzip, application/x-gzip) is also verified independently to prevent file-type spoofing via renamed extensions.
  2. 📏 File Size Limit: Enforces a 5GB maximum (Free tier: 50MB). Files exceeding this limit are rejected before decompression.
  3. 🛡️ Content Security Scan: If the file is compressed, it is first decompressed into a secure temporary path. The plugin reads the SQL content and scans for:
    • PHP code injection: <?php, <?=
    • Server-side code execution functions: eval(, system(, exec(, base64_decode
    Any match causes immediate rejection and deletion of the upload.
  4. 🗄️ Database Name Verification: During the restore phase, the SQL file's first 8KB is read and searched for a -- Database: dbname comment (the standard phpMyAdmin export header). If found and the name does not match your current WordPress database name, the restore is blocked. The comparison uses hash_equals() (constant-time comparison) to prevent timing-based enumeration of your database name. A random microsleep of 3–18ms is also inserted at this check point to further frustrate automated probing.
  5. 📋 WordPress Table Structure Validation: Beyond the database name check, the validator scans up to 5,000 SQL statements looking for CREATE TABLE or INSERT INTO statements targeting tables with the core WordPress suffixes (_options, _posts, _users). A file that passes the MIME and size checks but contains no recognizable WordPress tables is rejected as "not a valid SQL database backup."

If any of these checks fail, the file is deleted from the server and the restore is aborted with a specific error message identifying which check failed.

🛑 FALSE POSITIVES (security risks detected)
In some cases, the security scan may flag content that is not actually dangerous — for example, a plugin whose settings contain base64-encoded data stored in wp_options.
If you are certain your backup is from a trusted source, you can select Disable Restore Security Checks directly below the upload area in Section 1.1.

🚨 4.6.1. Emergency Recovery: What Happens When Things Go Wrong

WP Optimal State PRO has a sophisticated emergency recovery system that activates during PHP shutdown to prevent database corruption.

What Triggers Emergency Cleanup?

Emergency Recovery Steps (Automatic)

When PHP shuts down unexpectedly, the emergency_cleanup() function executes:

  1. Transaction Detection: Checks if any database transaction is still active
  2. Connection Health Check: Uses $connection->ping() to verify if MySQL connection is still alive
  3. Rollback Active Transactions: If connection is alive, rolls back any uncommitted changes
  4. Restore Safety Settings: Ensures FOREIGN_KEY_CHECKS and AUTOCOMMIT are set back to defaults
  5. Connection Reconnection: If connection was lost, attempts to reconnect and restore settings
  6. Graceful Closure: Properly closes database connection to free server resources

What This Prevents

❌ Without Emergency Cleanup:
✅ With Emergency Cleanup:

Checking Emergency Cleanup Logs

If emergency cleanup runs, you'll find entries in your PHP error log (error_log file):

[03-Feb-2026 14:32:18 UTC] OPTISTATE DB EMERGENCY ERROR: Connection lost during transaction
[03-Feb-2026 14:32:18 UTC] OPTISTATE: Failed to reconnect during emergency cleanup: Too many connections
🔧 Manual Recovery (Rarely Needed): If you see emergency cleanup errors in logs and your database seems unstable:
  1. Run SET FOREIGN_KEY_CHECKS = 1; in phpMyAdmin
  2. Run SET AUTOCOMMIT = 1; in phpMyAdmin
  3. Check for tables starting with optistate_temp_ or optistate_old_ and manually drop them
  4. Deactivate and reactivate the plugin to reset all settings

Preventing Emergency Situations

To minimize the chance of emergency cleanup activation:

🧹 5. The Database Optimization Suite (Sections 2-9)

This is the core optimization suite. These sections work together to help you diagnose and clean your database.

❤️ 5.1. Database Health Score

The Database Health Score is your central diagnostic hub—a comprehensive analysis that gives you a single number (0-100) representing your database's overall condition. This score is calculated by examining multiple aspects of your database and applying weighted penalties for issues that impact performance, cleanliness, and structural efficiency.

🎯 How the Score is Calculated

The plugin analyzes your database across three key categories, each with its own sub-score. These are then combined into a single Overall Score using a weighted formula:

Overall Score = (Performance × 40%) + (Cleanliness × 35%) + (Efficiency × 25%)

A sensitivity factor of 1.3× is then applied to penalties, making the score more responsive to issues that need attention.

📊 Understanding Your Overall Score

📈 The Three Category Scores Explained

⚡ Performance Score (40% weight)

Measures factors that directly impact your site's speed and response time. This category has the highest weight because performance issues directly affect user experience.

What's analyzed:

🧹 Cleanliness Score (35% weight)

Evaluates how much "junk" data is accumulating in your database. Clean databases are faster to query and backup.

What's analyzed:

🎯 Efficiency Score (25% weight)

Analyzes your database's structural health and optimization. This includes indexing efficiency and table management.

What's analyzed:

💡 Actionable Recommendations

The most valuable part of the Health Score interface is the recommendations section. Based on the specific issues detected, the plugin provides prioritized, actionable suggestions with direct links to the tools you need.

Recommendations are prioritized by severity:

💡 PRO TIP: Regular Monitoring

Your Health Score is cached for 12 hours to avoid unnecessary database queries. Click "⟲ Refresh" to force a new calculation after making changes.

Check your score weekly or after major content changes (like importing products, publishing many posts, or installing/uninstalling plugins) to catch issues early.

📈 5.2. Database Statistics (A Detailed Glossary)

This is the raw data used to calculate your Health Score. It shows you exactly what was found in your database.

🚀 5.3. One-Click Optimization (The "Easy Button")

The "One-Click Optimization" is the heart of the plugin's ease-of-use philosophy. It is designed to be a "safe-by-default" maintenance routine that you can run without fear of breaking your site or losing important data.

🛡️ What is "Safe Cleaning"?

Unlike aggressive cleaners that might empty your trash bin or delete comments you haven't reviewed yet, this process selectively targets only useless data that has no effect on your live content.

✅ What It CLEANS (Safe Junk)
  • 🔹 Post Revisions: Excessive history of old edits.
  • 🔹 Auto Drafts: Abandoned, unsaved posts generated by WP.
  • 🔹 Trashed Comments: Comments explicitly moved to trash.
  • 🔹 Expired Transients: Temporary cache data that is no longer valid.
  • 🔹 Duplicate Post Meta: Redundant database entries for posts.
  • 🔹 Duplicate Comment Meta: Redundant database entries for comments.
  • 🔹 Orphaned Data: Metadata left behind after deleting posts, comments, users, or terms.
  • 🔹 Pingbacks & Trackbacks: Automated link notifications from other blogs.
🛡️ What It PROTECTS (Untouched)
  • 🔸 Trashed Posts/Pages: Items in your main Trash bin.
  • 🔸 Spam Comments: Comments marked as spam.
  • 🔸 Unapproved Comments: Comments awaiting moderation.
  • 🔸 Active Transients: Valid cache data currently in use.

To clean these "Protected" items, use the Detailed Database Cleanup (Section 8).

🔄 The 2-Stage Process

When you click "🚀 Optimize Now", the plugin executes two distinct operations in sequence:

  1. Stage 1: Garbage Collection
    It runs the SQL delete commands for all the "Safe Junk" items listed above.
  2. Stage 2: Table Defragmentation
    Immediately after cleaning, it runs OPTIMIZE TABLE on your database. This reclaims the empty space ("overhead") left behind by the deleted data, physically shrinking your database size and speeding up read/write operations.

💡 Result: After completion, you will see a summary report of exactly how many items were removed and how much disk space was reclaimed.

This is the recommended action for most users after creating a backup.

🔍 5.4. Legacy Plugin Data Scanner

The Legacy Plugin Data Scanner helps you find "ghost data" — database entries left behind by plugins and themes you've already removed. Many plugins don't clean up after themselves when uninstalled, leaving behind options, metadata, custom tables, and files that waste space and can slow down your site.

What It Actually Scans:

ℹ️ Important Limitation: This scanner only detects data from its built-in database of 400+ popular plugins and themes. It won't find data from obscure or custom plugins. It doesn't scan usermeta, commentmeta, or termmeta tables — only options, postmeta, custom tables, and filesystem folders.

How Detection Works:

The scanner uses intelligent pattern matching:

  1. First, it builds a "protected list" from your currently active plugins, themes, and must-use plugins
  2. It also identifies all installed (but inactive) plugins and themes
  3. Then it scans your database for option names, meta keys, and custom tables that match known plugin patterns (like yoast_, elementor_, woocommerce_)
  4. If it finds a match that's not in the protected or installed lists, it flags it as potential ghost data
  5. For filesystem scans, it checks wp-content and related directories for orphaned folders (limited to 3000 folders max to prevent timeouts)
  6. Results are shown with the detected plugin name, data type, size/count, and risk level

Risk Levels Explained:

How to Use the Scanner:

  1. Go to the Optimize tab
  2. Scroll down to find the "🔌 5. Legacy Plugin Data Scanner" section
  3. Click "🔎 Scan for Ghost Data"
  4. Wait a few seconds while it scans (rate-limited to once per 5 seconds)
  5. Review the results table showing Data Source, Type, Size/Count, and Risk Level
  6. Click "Delete" on individual items you want to remove
  7. Confirm deletion in the popup with verification warnings
  8. The item will fade out and be removed from the results table

What Gets Displayed:

Each detected item shows:

⚠️ CRITICAL: Before Deleting Anything

Examples of Safe Deletions:

What Happens When You Delete:

  1. You click the "Delete" button for a specific item
  2. A confirmation popup appears with verification requirements showing the exact item name and type
  3. After confirmation, the plugin starts a database transaction for safety
  4. It deletes the specific entry from wp_options, wp_postmeta, or drops the custom table entirely
  5. It logs the action with your username and timestamp
  6. The transaction commits (or rolls back if there's an error)
  7. The deleted item fades out from the results table with a red background
  8. Database statistics are automatically refreshed to reflect the freed space
  9. If all items are deleted, a success message appears: "✅ All Clean! No detected ghost data remaining."
💡 Best Practice: Run this scanner after major plugin cleanups or when setting up a migrated/cloned site. It's especially useful after switching from one major plugin to another (like changing page builders or SEO plugins). The scanner helps identify leftover configuration that's just taking up space. Also run the Database Structure Analysis tool (Advanced tab) to find any additional unused tables not in the legacy plugin database.

Technical Notes:

🎯 5.5. Targeted Optimizations

Located directly under the Database Health Score, this section offers four specialized cleanup tools that target specific areas of database bloat often missed by general cleaners. Each tool uses a multi-pass, JOIN-based approach to find orphaned data through actual referential checks — not just pattern matching.

🔪 5.6. Detailed Database Cleanup

This section provides a button for every single item listed in the Database Statistics. It allows you to clean items one by one with full control.

⚠️ IMPORTANT: Safe vs. Unsafe (Review First)

Most items are "safe" to clean. However, some items are marked with a ⚠️ Warning Icon. These are "unsafe" because they involve deleting data you might want to review first.

⚙️ How the Cleanup Engine Works

Every cleanup operation in this section shares the same underlying architecture, which sets it apart from standard database plugins:

⚡ 5.7. Advanced Database Optimization

These are powerful tools for database maintenance. 💾 Always create a backup before using them.

🔍 5.8. Database Structure Analysis

Inside section 9, under the Advanced tab, this tool provides a complete map of your database structure and allows you to remove unused tables.

🔢 5.9. MySQL Index Manager

The MySQL Index Manager is a powerful diagnostic tool that analyzes your database for missing or redundant indexes. Unlike standard cleanup tools, this module uses Prefix-Matching Analysis to ensure your database structure is optimized for high-traffic environments and complex queries, such as those generated by WooCommerce.

ℹ️ ENTERPRISE APPROACH: The manager does not simply look for index names. It analyzes the actual columns and their order. If a "Super-Index" (e.g., columns A, B, and C) already exists, the plugin is smart enough to know that a "Sub-Index" (e.g., column A) is redundant and can be safely removed to save disk space and speed up write operations.

🔍 Analysis Categories

🚀 Workflow: Scan & Apply

  1. Initiate Scan: Click the "Scan for Missing Indexes" button. The plugin reads all index metadata for your entire database from information_schema.STATISTICS in a single query, then performs analysis in PHP — minimizing database load during the scan.
  2. Review Recommendations:
    • Recommendations will display the Table, Column(s), and a detailed Reason explaining the performance benefit.
  3. Apply Fixes: Click "Fix Index" to add a missing index or "Remove Bloat" to remove a redundant one. All index operations run in a background worker (via WP-Cron) so they never block your browser or time out regardless of table size.

🔒 Lock-Free Index Operations

Adding or removing indexes on large tables can be a risky operation on busy sites. The Index Manager handles this intelligently:

⚠️ CAUTION: LARGE TABLES

Adding or dropping indexes on tables with millions of rows can take several minutes. Thanks to Online DDL, your site remains accessible during the operation. However, it is still recommended to perform these operations during low-traffic periods on very large databases.

🛡️ 5.10. Referential Integrity Scanner

The Referential Integrity Scanner is a specialized sanitation tool designed to find "Zombie Data"—rows in your database that point to parent data that no longer exists.

ℹ️ THE PROBLEM: Standard cleanup tools often miss complex relationships. For example, if a Post (ID: 123) was deleted directly via SQL or a buggy plugin, the Post Meta (which points to post_id = 123) might remain forever. This scanner specifically hunts down these broken links.

🔍 What It Detects

🚀 How to Use

  1. Scan: Click the "Scan Database Integrity" button. The tool will check foreign key relationships across your core tables.
  2. Review: Unlike the standard cleaner, this tool provides specific examples. It will show you the exact Issue Type (e.g., "Post Meta (Orphaned)") and provide sample IDs (e.g., #452: _edit_lock) so you can verify the data is truly junk.
  3. Fix: Click the "Fix Orphans" button next to any issue found. The plugin uses a batched deletion process to remove the orphaned rows without timing out your server.
⚠️ SAFETY FIRST

While orphaned data is generally safe to remove (as it points to nothing), always create a database backup before running integrity fixes, just as you would with any database operation.

🛠️ Technical Resilience

The Index Manager includes several important safeguards:

↳↰ 5.11. Database Search & Replace

Located in the "Advanced" tab, this professional-grade tool allows you to find and replace text strings across your entire database. It is essential for tasks like migrating domains (http → https), updating shortcodes, or fixing bulk content errors.

🚨 CRITICAL WARNING

This is a destructive operation. Changes made here cannot be "undone" without restoring a backup.
💾 You must create a fresh database backup (Section 1) immediately before running this tool.

🌟 Key Features:

🛠️ How to Use:

  1. Input Terms: Enter the text you want to find (e.g., http://old-site.com) and the text to replace it with (e.g., https://new-site.com).
  2. 🔡 Case Sensitivity: By default, searches are case-insensitive. Check "Case Sensitive" for exact-case matching (e.g., replacing a specific variable name or brand capitalization).
  3. 🔗 Partial Match:
    • Unchecked (default): Unicode word-boundary matching. Use this for replacing standalone words in content.
    • Checked: Substring matching anywhere in the string. Required for URL updates, domain changes, and any partial text replacements.
  4. Select Tables: Leave as "All Tables" for a full-site update, or use Ctrl/Cmd+Click to select specific tables.
  5. 🔎 Step 1 — Dry Run: Click this button first. The plugin scans your database in 4-second AJAX chunks and shows a highlighted preview of every match found. Review carefully before proceeding.
  6. ↳↰ Step 2 — Execute Replacement: Once you have verified the dry run results, click this to perform the actual replacement. Execution also runs in 4-second AJAX chunks with keyset pagination (WHERE pk > last_seen LIMIT 300) so it is resumable and never re-processes already-updated rows. Each batch of 300 rows is wrapped in a START TRANSACTION … COMMIT block. A failed batch triggers a ROLLBACK and logs the error — subsequent tables continue processing.

📋 Common Use Cases & Examples

🔒 Example 1: HTTP to HTTPS Migration

Goal: Update all URLs from http:// to https://

Search For: http://yourdomain.com
Replace With: https://yourdomain.com
Case Sensitive: ❌ Unchecked
Partial Match: Checked (Required for URL updates)

⚠️ Important: Partial Match Mode is essential here. Without it, the tool would only match "http://yourdomain.com" as a standalone word, missing occurrences like "Visit http://yourdomain.com/page" or links embedded in content.

🌐 Example 2: Domain Name Change

Goal: Change all references from old domain to new domain

Search For: oldsite.com
Replace With: newsite.com
Case Sensitive: ❌ Unchecked
Partial Match: Checked
📝 Example 3: Word-Only Replacement

Goal: Replace a specific word across all posts without affecting similar words

Search For: test
Replace With: exam
Case Sensitive: ❌ Unchecked
Partial Match: ❌ Unchecked

ℹ️ Result: With Partial Match unchecked, "This is a test." will become "This is an exam." but "testing" and "latest" will remain unchanged.

🔤 Example 4: Case-Sensitive Brand Name

Goal: Fix incorrect capitalization of a brand name

Search For: iPhone
Replace With: iPhone Pro
Case Sensitive: Checked
Partial Match: ❌ Unchecked

ℹ️ Result: Only "iPhone" (exact case) will be replaced. "iphone" or "IPHONE" will be ignored.

🎯 Understanding Match Modes

Scenario Partial Match OFF Partial Match ON
Search: "test" ✅ "This is a test."
❌ "testing"
❌ "latest"
✅ "This is a test."
✅ "testing"
✅ "latest"
Search: "http://" ❌ "http://example.com"
(No matches - needs word boundaries)
✅ "http://example.com"
✅ "Visit http://site.com"
✅ All URL occurrences
Search: "Apple"
(Case Sensitive ON)
✅ "I like Apple."
❌ "apple" (wrong case)
❌ "Appleton" (not a word)
✅ "I like Apple."
❌ "apple" (wrong case)
✅ "Appleton" (partial match)

⚙️ Best Practices

⚠️ Common Mistakes to Avoid

⏰ 6. Automatic Backup & Cleanup (Section 10)

This section provides a "set it and forget it" scheduler for all the tools you just learned about.

⚙️ 6.1. Configuring the Scheduler

🔄 6.2. What the Scheduler Does (when it runs):

The scheduler will run in one of two modes, depending on your settings: *backup & cleanup* or *backup only*:

  1. First, it 💾 creates a new database backup.
  2. Then, it 🚀 runs the One-Click Optimization (all safe cleanups + table optimization).
  3. Finally, it 📊 enforces the backup limit, deleting the oldest backup if necessary.
  4. If enabled, it sends a success or failure email.

📧 6.3. Understanding Email Notifications (Success & Failure)

This is a key "pro" feature.

⏱️ 6.4. A Note on WP-Cron

This scheduler uses the built-in WordPress Cron system (wp_schedule_single_event). This is not a "true" cron job, which means it relies on someone visiting your website to trigger the schedule.

If you set a schedule for 3:00 AM, the tasks will run on the first site visit that occurs at or after 3:00 AM. For most sites, this is perfectly reliable.

⚡ 7. Performance Features Manager (Section 11)

This is a complete, standalone performance suite.

🚫 7.1. CRITICAL: Do NOT Use With Other Caching Plugins

🚨 WARNING

The Server-Side Page Caching and Browser Caching features in this section will conflict with other caching plugins like WP Rocket, LiteSpeed Cache, W3 Total Cache, WP Super Cache, etc.

🤔 You must choose ONE.

If you are already using another caching plugin, 🚫 DO NOT enable "Server-Side Page Caching" or "Browser Caching" in WP Optimal State PRO. You can, however, still use all the "WordPress Core Optimizations" (Section 7.4).

💨 7.2. Feature: Server-Side Page Caching

This is the single most effective way to speed up your site. It converts heavy PHP processing into instant static HTML. When a visitor requests a page, a lightweight cached file is served directly, bypassing slow PHP and database queries. For example, after enabling this, viewing your homepage for the second time will load instantly from a pre-generated HTML file instead of rebuilding the page from scratch. Combine this with browser caching for ultimate performance.

🔍 How to Verify Caching is Working:

After enabling page caching, you can easily confirm it's working by checking the page source:

  1. Visit any page on your site (while logged out or in a private/incognito window).
  2. Right-click anywhere on the page and select "View Page Source" (or press Ctrl+U on Windows / Cmd+Option+U on Mac).
  3. Scroll all the way to the very bottom of the HTML source code.
  4. Look for this comment: <!-- Cached by WP Optimal State Plugin -->
If you see this comment: ✅ The page was served from the static cache — your site is now delivering lightning-fast performance!
If you don't see it: The page was generated dynamically (this is normal for logged-in users, cart pages, or first visits before the cache is built).

🌐 7.3. Feature: Browser Caching (.htaccess)

This complements Server Caching. It tells a visitor's browser to save static files (like your logo, CSS, and JS) on their computer.

The following code block will be automatically added to the .htaccess file when this feature is activated:

👉 CLICK TO EXPAND (.htaccess code)
# ============================================================
# BEGIN WP Optimal State Caching
# ============================================================

# 1. EXPIRATION HEADERS (mod_expires)
<IfModule mod_expires.c>
ExpiresActive On
ExpiresDefault "access plus 30 days"
ExpiresByType image/jpeg"access plus 1 year"
ExpiresByType image/png "access plus 1 year"
ExpiresByType image/gif "access plus 1 year"
ExpiresByType image/webp"access plus 1 year"
ExpiresByType image/avif"access plus 1 year"
ExpiresByType image/svg+xml "access plus 1 year"
ExpiresByType image/x-icon"access plus 1 year"
ExpiresByType font/woff2"access plus 1 year"
ExpiresByType font/woff "access plus 1 year"
ExpiresByType font/ttf"access plus 1 year"
ExpiresByType font/otf"access plus 1 year"
ExpiresByType video/mp4 "access plus 1 year"
ExpiresByType video/webm"access plus 1 year"
ExpiresByType audio/mpeg"access plus 1 year"
ExpiresByType audio/ogg "access plus 1 year"
ExpiresByType application/wasm"access plus 1 year"
ExpiresByType text/css"access plus 1 month"
ExpiresByType application/javascript "access plus 1 month"
ExpiresByType application/x-javascript "access plus 1 month"
ExpiresByType text/html "access plus 24 hours"
</IfModule>

# 2. CACHE-CONTROL & SECURITY HEADERS (mod_headers)
<IfModule mod_headers.c>
Header always set X-Content-Type-Options "nosniff"
Header always set X-Frame-Options "SAMEORIGIN"
Header always set Referrer-Policy "strict-origin-when-cross-origin"
Header unset X-Powered-By
Header always set X-Permitted-Cross-Domain-Policies "none"
Header always set Permissions-Policy "camera=(), microphone=(), geolocation=(), payment=(), usb=(), gyroscope=(), accelerometer=(), magnetometer=(), ambient-light-sensor=(), fullscreen=(self)"
Header always set Cross-Origin-Resource-Policy "same-site"
Header always set Content-Security-Policy "frame-ancestors 'self'; object-src 'none'; base-uri 'self'; form-action 'self'"
<FilesMatch "\.(css|js|ico|jpg|jpeg|png|gif|webp|avif|svg|woff2|woff|ttf|eot|mp4|webm|mp3|ogg|aac|m4a|flac|wasm)$">
Header set Cache-Control "max-age=31536000, public, immutable"
</FilesMatch>
<FilesMatch "\.(html|htm)$">
Header set Cache-Control "public, max-age=86400, must-revalidate" env=!PHP_CACHE_HEADERS
</FilesMatch>
<FilesMatch "^(wp-config\.php|readme\.html|license\.txt|xmlrpc\.php)$">
Header set Cache-Control "no-cache, no-store, must-revalidate"
Header set Pragma "no-cache"
Header set Expires "0"
</FilesMatch>
<If "%{REQUEST_URI} =~ m#^/wp-login\.php# || %{REQUEST_URI} =~ m#^/wp-admin/#">
Header set Cache-Control "no-cache, no-store, must-revalidate"
Header set Pragma "no-cache"
Header set Expires "0"
</If>
Header set Vary "Accept-Encoding"
Header unset ETag
FileETag None
</IfModule>

# 3. COMPRESSION (mod_brotli + mod_deflate)
<IfModule mod_brotli.c>
AddOutputFilterByType BROTLI_COMPRESS text/html text/plain text/css text/xml text/javascript
AddOutputFilterByType BROTLI_COMPRESS application/javascript application/json application/xml application/xhtml+xml
AddOutputFilterByType BROTLI_COMPRESS application/rss+xml application/wasm
AddOutputFilterByType BROTLI_COMPRESS image/svg+xml
</IfModule>

<IfModule mod_deflate.c>
DeflateCompressionLevel 6
AddOutputFilterByType DEFLATE text/plain
AddOutputFilterByType DEFLATE text/html
AddOutputFilterByType DEFLATE text/css
AddOutputFilterByType DEFLATE text/xml
AddOutputFilterByType DEFLATE text/javascript
AddOutputFilterByType DEFLATE application/javascript
AddOutputFilterByType DEFLATE application/json
AddOutputFilterByType DEFLATE application/xml
AddOutputFilterByType DEFLATE application/xhtml+xml
AddOutputFilterByType DEFLATE application/rss+xml
AddOutputFilterByType DEFLATE application/wasm
AddOutputFilterByType DEFLATE image/svg+xml
AddOutputFilterByType DEFLATE image/x-icon
AddOutputFilterByType DEFLATE font/woff
AddOutputFilterByType DEFLATE font/woff2
SetEnvIfNoCase Request_URI "\.(?:gz|br|zip|bz2|rar|7z|xz)$"no-gzip dont-vary
SetEnvIfNoCase Request_URI "\.(?:jpg|jpeg|png|gif|webp|avif|ico)$" no-gzip dont-vary
SetEnvIfNoCase Request_URI "\.(?:woff|woff2|ttf|otf|eot)$" no-gzip dont-vary
SetEnvIfNoCase Request_URI "\.(?:mp4|webm|avi|mov|mkv|flv|ogv)$" no-gzip dont-vary
SetEnvIfNoCase Request_URI "\.(?:mp3|ogg|aac|m4a|flac|wav|opus)$"no-gzip dont-vary
SetEnvIfNoCase Request_URI "\.pdf$" no-gzip dont-vary
SetEnvIfNoCase Request_URI "\.swf$" no-gzip dont-vary
</IfModule>

# 4. PERFORMANCE TUNING
# Disable directory listing
Options -Indexes

# 5. HTTPS / HSTS (only on SSL vhosts)
<IfModule mod_ssl.c>
Header always set Strict-Transport-Security "max-age=31536000"
</IfModule>
# ============================================================
# END WP Optimal State Caching
# ============================================================

🖥 7.3.1. Nginx Server Configuration (Security + Caching)

ℹ️ IMPORTANT: Nginx Users

If your server runs on Nginx instead of Apache, the Browser Caching (.htaccess) feature cannot be activated automatically because Nginx does not use .htaccess files.

All other plugin features work normally on Nginx servers, including:

This section provides the configuration you need to manually add to your Nginx configuration file to enable browser caching and secure your plugin directories.

📍 Where to Add This Configuration

You need to add the configuration blocks below to your Nginx configuration file. This file is typically located at:

⚠️ Important: Add these blocks inside your server { ... } block for your WordPress site.

🔐 Step 1: Secure Plugin Directories (Important)

Add this configuration to block direct access to sensitive plugin directories, such as database backups and your custom settings:

👉 CLICK TO EXPAND: Directory Security Configuration
# ============================================================
# WP Optimal State - Directory Security (Nginx)
# ============================================================

# Block access to plugin settings directory
location ~* /wp-content/uploads/optistate-settings/ {
    deny all;
    return 403;
}

# Block access to database backup directory
location ~* /wp-content/uploads/optistate/db-backups/ {
    deny all;
    return 403;
}

# Block access to temp restore directory
location ~* /wp-content/uploads/optistate/db-restore-temp/ {
    deny all;
    return 403;
}

# Allow only .html files in cache directory, block everything else
location ~* /wp-content/uploads/optistate/page-cache/ {
    location ~* \.html$ {
        # Allow HTML files to be served
    }
    location ~* {
        deny all;
        return 403;
    }
}
-------------------

🚀 Step 2: Browser Caching Configuration (Optional)

Add this configuration to enable browser caching for static assets and speed up site loading for returning visitors:

👉 CLICK TO EXPAND: Browser Caching Configuration
# ============================================================
# BEGIN WP Optimal State - Browser Caching (Nginx)
# ============================================================

# ------------------------------
# 0. Basic server tuning (safe defaults)
# ------------------------------
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
server_tokens off;
etag off;

# ------------------------------
# 1. Compression: Brotli (if compiled) + Gzip fallback
# ------------------------------
# Brotli (requires ngx_brotli)
brotli on;
brotli_comp_level 6;
brotli_types text/plain text/css application/javascript application/json application/xml application/rss+xml application/wasm image/svg+xml;

# Gzip fallback
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_types text/plain text/css application/javascript application/x-javascript application/json application/xml application/rss+xml application/wasm image/svg+xml;

# ------------------------------
# 2. Security and common headers
# ------------------------------
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header X-Permitted-Cross-Domain-Policies "none" always;
add_header Permissions-Policy "camera=(), microphone=(), geolocation=(), payment=(), usb=(), gyroscope=(), accelerometer=(), magnetometer=(), ambient-light-sensor=(), fullscreen=(self)" always;
add_header Cross-Origin-Resource-Policy "same-site" always;
add_header Content-Security-Policy "frame-ancestors 'self'; object-src 'none'; base-uri 'self'; form-action 'self'" always;
add_header Vary "Accept-Encoding" always;

# HSTS only on HTTPS
if ($scheme = https) {
    add_header Strict-Transport-Security "max-age=31536000" always;
}

# Hide PHP server header from upstream if possible
fastcgi_hide_header X-Powered-By;

# ------------------------------
# 3. Immutable static assets (1 year) — immutable for fingerprinted assets
# ------------------------------
location ~* \.(?:css|js|ico|jpg|jpeg|png|gif|webp|avif|svg|woff2|woff|ttf|eot|mp4|webm|mp3|ogg|aac|m4a|flac|wasm)$ {
    expires 365d;
    add_header Cache-Control "public, max-age=31536000, immutable" always;
    access_log off;
    log_not_found off;
    try_files $uri =404;
}

# ------------------------------
# 4. Static HTML fallback (24 hours)
# ------------------------------
location ~* \.(?:html|htm)$ {
    expires 24h;
    add_header Cache-Control "public, max-age=86400, must-revalidate" always;
    try_files $uri $uri/ =404;
}

# ------------------------------
# 5. PHP handling — let WordPress/plugins control PHP headers
# ------------------------------
location ~ \.php$ {
    include fastcgi_params;
    fastcgi_split_path_info ^(.+\.php)(/.+)$;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    fastcgi_pass unix:/run/php/php-fpm.sock;
    fastcgi_read_timeout 300;
}

# ------------------------------
# 6. Login/admin and sensitive files — never cache
# ------------------------------
location = /wp-login.php {
    add_header Cache-Control "no-cache, no-store, must-revalidate" always;
    add_header Pragma "no-cache" always;
    add_header Expires "0" always;
    include fastcgi_params;
    fastcgi_pass unix:/run/php/php-fpm.sock;
}

location ^~ /wp-admin/ {
    add_header Cache-Control "no-cache, no-store, must-revalidate" always;
    add_header Pragma "no-cache" always;
    add_header Expires "0" always;
    try_files $uri $uri/ /index.php?$args;
}

location ~* ^/(?:wp-config\.php|readme\.html|license\.txt|xmlrpc\.php)$ {
    add_header Cache-Control "no-cache, no-store, must-revalidate" always;
    add_header Pragma "no-cache" always;
    add_header Expires "0" always;
    deny all;
    return 404;
}

# ------------------------------
# 7. Reduce logging for static assets
# ------------------------------
location ~* \.(?:css|js|jpg|jpeg|png|gif|webp|avif|svg|ico|woff|woff2|ttf|eot)$ {
    access_log off;
    log_not_found off;
}

# ============================================================
# END WP Optimal State - Browser Caching (Nginx)
# ============================================================
-------------------

📝 Step 3: Apply the Configuration

  1. Access your server via SSH or your hosting control panel's file manager.
  2. Open your Nginx configuration file for editing (the location depends on your server setup).
  3. Add both configuration blocks inside your server { ... } block.
  4. Test your configuration by running:
    sudo nginx -t
  5. If the test passes, reload Nginx:
    sudo systemctl reload nginx
⚠️ IMPORTANT

If you're not comfortable editing Nginx configuration files, please contact your hosting provider or system administrator for assistance. Incorrect Nginx configuration can cause your site to become inaccessible.

Always backup your configuration file before making changes.

✅ Verification

After applying the configuration, you can verify it's working by:

🏗️ 7.4. Feature: WordPress Core Optimizations (A-Z)

This is a comprehensive suite of toggles and configurations designed to disable or optimize non-essential WordPress features that can slow down your site.
These are all safe to use alongside other third-party caching plugins.

🔐 Advanced Security Features

7.4.1. File Path Validation & Path Traversal Protection

The plugin implements multi-layer file path validation to prevent directory traversal attacks and unauthorized file access:

Validation Layers
  1. Path Normalization: All file paths are normalized using wp_normalize_path() to convert backslashes to forward slashes and resolve relative paths.
  2. Boundary Checking: Every file operation verifies the path starts with the allowed directory (typically wp-content/uploads/optistate-*).
  3. Malicious Pattern Detection: Blocks paths containing:
    • ../ or ..\ (directory traversal)
    • Null bytes (\0) - common in exploit attempts
  4. Canonical Path Resolution: When using direct filesystem access (FS_METHOD='direct'), the system resolves symlinks with realpath() and verifies the canonical path is still within allowed boundaries.
🛡️ Example Attack Prevention:
Malicious input: /uploads/optistate-data/../../../wp-config.php
Result: Blocked - path normalization resolves this to /wp-config.php, which fails the boundary check.

7.4.2. JSON Data Encryption for Sensitive Information

Settings containing potentially sensitive data are encrypted using AES-256-CBC:

Encryption Implementation
What Gets Encrypted?

Currently, encryption is available via OPTISTATE_Utils::encrypt_data() for:

💡 Note: The plugin detects whether OpenSSL is available. If not, data is stored as plaintext with a warning logged. Check phpinfo() for OpenSSL support status.

7.4.3. SQL Injection Protection

Multiple layers protect against SQL injection attacks:

Protection Mechanisms
Example Code (from class-optistate-activation.php)
// Safe table name validation before dropping
if (!preg_match('/^[a-zA-Z0-9_]+$/', $table_name)) {
    continue; // Skip invalid table names
}
if (strlen($table_name) > 64) {
    continue; // Skip names exceeding MySQL limit
}

// Use WordPress's identifier placeholder if available
if (method_exists($wpdb, 'remove_placeholder_escape')) {
    $wpdb->query($wpdb->prepare("DROP TABLE IF EXISTS %i", $table_name));
} else {
    // Fallback: manual backtick escaping with protection
    $safe_table_name = str_replace('`', '``', $table_name);
    $wpdb->query("DROP TABLE IF EXISTS `{$safe_table_name}`");
}
🔒 Additional Safety: The plugin never accepts table names directly from user input. All table operations use hardcoded constants or validated WordPress table name patterns.

7.4.4. Nonce Verification & AJAX Security

Every AJAX request requires valid nonce verification:

7.4.5. Login Protection System

The plugin includes a full brute-force protection system that tracks failed login attempts by IP address and blocks repeat offenders for a configurable period. It is designed to be both accurate and very fast — the critical path on login page loads is optimized to avoid database queries whenever possible.

Configuration Options
Three-Layer Check Sequence (Critical Path)

When a visitor hits the login page, the block check runs in this exact sequence, stopping at the first result to minimize overhead:

  1. Request-level cache: A PHP static variable caches the result for the current request. If is_access_blocked() is called twice in the same request (once for login_init, once for authenticate), the second call returns instantly with no transient or database read.
  2. Transient fast-path (block): Checks optistate_block_{ip_hash}. If the transient exists and its stored blocked_until timestamp is still in the future, the visitor is blocked immediately — no database query.
  3. Transient fast-path (clean): Checks optistate_clean_{ip_hash}. If this transient exists, the IP was recently confirmed as not blocked — return clean immediately. This 60-second clean cache eliminates database reads for legitimate repeated login attempts.
  4. Database query (cold path): Only if both transients are absent does the engine query the wp_optistate_login_protect table. On a hit, the result is immediately cached back into the block transient for the duration of the remaining block period. On a miss (legitimate user), the clean transient is set for 60 seconds.
Recording Failed Attempts

When a login fails, the engine uses a single INSERT … ON DUPLICATE KEY UPDATE query to either create a new record or atomically increment the attempt counter for the existing IP. The block timestamp is set in the same query using an IF(attempts_count >= max, blocked_until, 0) expression — making the transition from "tracking" to "blocked" a single atomic SQL operation with no race condition. The user agent is also stored (truncated to 255 bytes, UTF-8 safe) for audit purposes. A successful login from the same IP immediately deletes its record and clears both transients.

IP Address Resolution

The IP resolution logic correctly handles proxy chains:

Blocking Scope

Blocking applies to all three WordPress login surfaces simultaneously:

Automatic Record Cleanup

The table is self-maintaining. A scheduled cleanup routine runs automatically and deletes: expired block records (blocks whose blocked_until timestamp has passed), and casual attempt records (IPs with no block that have had no activity in the last 24 hours). If more than 100 records are deleted in a single cleanup pass and the table has more than 1MB of overhead, OPTIMIZE TABLE is automatically run to reclaim space.

Dedicated Database Table

Attempt data is stored in a dedicated wp_optistate_login_protect table with a UNIQUE KEY on ip_address (enabling the atomic INSERT/UPDATE), and compound indexes on (blocked_until, updated_at) and updated_at for fast cleanup queries. The table is never included in plugin backups and is recreated automatically on plugin reactivation.

✅ Security Audit Result: These combined protections make WP Optimal State PRO resistant to common WordPress vulnerabilities including:

📊 7.5. Feature: Performance Metrics (PageSpeed)

Located under the 'Statistics' tab in section 7, this module integrates the Google PageSpeed Insights API directly into your WordPress dashboard. It allows you to monitor real-world performance metrics without leaving the platform, focusing on the Core Web Vitals that impact your search engine rankings and user experience.

🔑 API Configuration & Security

📈 Understanding the 7 Key Metrics

The plugin retrieves seven specific data points. The results are color-coded based on Google's official performance thresholds:

Logged Metrics Glossary:

💾 Smart Caching & Logging

🤖 7.6. Feature: Bad Bot Blocker

Not all traffic to your website is human or helpful. Resource-intensive bots—such as aggressive SEO crawlers, backlink analyzers, and competitive intelligence tools—can consume up to 40% of your server resources without providing any value to your business or visitors.

💡 The Benefit: By blocking these bots at the application level, you save CPU cycles and RAM, ensuring your server remains responsive for real visitors and legitimate search engines like Google and Bing.

🎯 What This Feature Blocks

The Bad Bot Blocker targets specific categories of bots that consume resources without benefiting your website:

✅ What This Feature DOES NOT Block:

🤖 Default Blocked Bots List

When enabled, the following bots are blocked by default. This list has been carefully curated to include only resource-intensive crawlers that provide no direct benefit to your website:

Bot Name Purpose Impact
MJ12bot Majestic SEO backlink crawler HIGH
AhrefsBot Ahrefs backlink database crawler VERY HIGH
SemrushBot Semrush SEO platform crawler VERY HIGH
DotBot Moz Link Explorer crawler HIGH
PetalBot Huawei Petal Search crawler VERY HIGH
Bytespider ByteDance/TikTok AI crawler VERY HIGH
Mauibot Unknown bot from AWS MEDIUM
MegaIndex Russian SEO backlink crawler HIGH
SerpstatBot Serpstat SEO platform crawler HIGH
BLEXBot WebMeUp backlink checker HIGH
DataForSeoBot DataForSEO API crawler HIGH
AspiegelBot SEO competitive analysis crawler HIGH
📝 Customization Available: You can customize this list directly in the plugin settings by adding or removing bot user agents (one per line). To learn more about specific bots and their purposes, visit the Cloudflare Bot Directory.

⚙️ How It Works

🖥️ Server Compatibility

✅ Works on ALL web servers:

📊 Performance Difference:

⚠️ Important Notes:

💡 When Should You Use This Feature?

✅ Recommended for:

⚠️ Consider disabling if:

💡 PRO TIP: Nginx Users

For maximum performance, we recommend combining this feature with the Nginx security rules provided below. This allows your server to drop bad traffic at the web server level, before it even reaches PHP or WordPress—resulting in even greater resource savings.

🚀 Nginx Implementation Guide

If you are using an Nginx server, add the following block to your server configuration file (e.g., /etc/nginx/sites-available/your-domain.com) inside the server { } block. This will block bots at the web server level for maximum efficiency:

# WP-OPTIMAL-STATE: High-Performance Bot Blocking
if ($http_user_agent ~* (MJ12bot|AhrefsBot|SemrushBot|DotBot|PetalBot|Bytespider|Mauibot|MegaIndex|SerpstatBot|BLEXBot|DataForSeoBot|AspiegelBot)) {
    return 403;
}

Important: After adding this configuration:

  1. Test your configuration: nginx -t
  2. If test passes, reload Nginx: systemctl reload nginx
  3. Monitor your server logs to ensure legitimate traffic isn't affected

🎯 8. Optimization Strategies: Putting It All Together

Here are a few "recipes" for common scenarios.

🚀 8.1. Strategy 1: The First-Time Setup (5-Minute Tune-Up)

  1. 💾 Backup: Go to Section 1 -> Click Create Backup Now.
  2. 🔍 Diagnose: Go to Section 3 -> Click Refresh Analysis to see your starting Health Score.
  3. ✨ Optimize: Go to Section 2 -> Click 🚀 Optimize Now.
  4. ⏰ Automate: Go to Section 10 -> Set "Run Tasks" to 7 days and your preferred time. Check 📧 Email Notifications. Click Save Settings.
  5. 🛡️ Harden: Go to Section 11 -> Activate all the "WordPress Core Optimizations" (Emoji Scripts, XML-RPC, etc.). Click Save Performance Settings.
  6. ✅ Done. Your database is now clean and will stay clean automatically.

🆘 8.2. Strategy 2: The "My Site is Slow" Emergency Plan

  1. 💾 Backup: Go to Section 1 -> Click Create Backup Now.
  2. 🔍 Diagnose: Go to Section 6. Look at Autoload Data Size. If this is high (e.g., > 1 MB), this is your problem.
  3. 🔧 Fix Autoload: Go to Section 9 -> Click ⚙️ Optimize Autoloaded Options.
  4. 🔧 Fix Overhead: Go to Section 9 -> Click ⚡ Optimize All Tables.
  5. 💨 Enable Caching: (If you have no other cache plugin) Go to Section 11 / Server-Side Page Caching.
    • Enable Server-Side Page Caching. Use the "Include Safe" query mode.
    • Enable Browser Caching (.htaccess).
    • Click Save Performance Settings.
  6. 🗑️ Purge & Preload: Go to Section 11 / Server-Side Page Caching -> Click 🗑️ Purge All Cache. If you enabled "Automatic Preload," this will start the cache warming process.
  7. ✅ Done. Your site should now be significantly faster.

📅 8.3. Strategy 3: The Monthly Maintenance Tune-Up

(Assuming you already have the automatic schedule running).

  1. 🔍 Check Backups: Go to Section 1. Make sure your automated backups are being created.
  2. ❤️ Review Health: Go to Section 3. Check your Health Score.
  3. 🔪 Manual Cleanup: Go to Section 8. Manually clean the "unsafe" items if you wish:
    • Click "Clean Now" for 🗑️ Trashed Posts.
    • Click "Clean Now" for ⏳ Unapproved Comments (if you've already moderated them).

📥 9. Settings & Security (Section 12)

This utility allows you to save all your plugin configurations to a single .json file. You can use this to create a backup of your settings or to quickly migrate your exact setup to another website. You can also restrict plugin access to specific administrator accounts.

🚨 IMPORTANT: What is NOT Exported

This feature ONLY exports the plugin's settings, such as your configurations for scheduled tasks, performance features, and user access restrictions. It does NOT export your database backups, cached pages, or activity logs. Always download your database backups separately from Section 1.

📤 9.1. Exporting Settings

  1. Navigate to Section 12: Settings & Security in the plugin dashboard.
  2. Click the "Export Settings" button.
  3. Your browser will download a file named optistate-settings-YYYY-MM-DD-His.json.
  4. Keep this file in a safe place.

📤 9.2. Importing Settings

This will completely overwrite all your current plugin settings. This is useful for restoring your configuration after an update (as described in Section 2.7) or for setting up a new site.

  1. Click the "Choose JSON File" button and select the json file you previously exported.
  2. The plugin validates the file. It must be a valid .json file, under 1MB, and contain the "WP Optimal State" signature.
  3. Once validated, click the "Import Settings" button.
  4. A confirmation pop-up will appear warning you that your current settings will be overwritten. Click "OK" to proceed.
  5. After a successful import, you will be prompted to reload the page to see the new settings take effect.

🔒 9.3. User Access Control

Restrict plugin access to specific administrator accounts. If no users are selected, all administrators can use the plugin.

⚠️ WARNING: Lockout Risk

Do not lock yourself out! Always include your own account in the allowed users list. If you save without selecting your account, you will be immediately locked out of the plugin.

How it works:

Configuration steps:

  1. Navigate to Section 12 in the plugin dashboard.
  2. Scroll to "User Access Control".
  3. Check the boxes next to administrators you want to allow access.
  4. Make sure YOUR account is checked (it will be highlighted with a blue border).
  5. Click "✓ Save User Access Settings".
💡 Use Case: In a multi-admin environment, you can limit who can perform database operations and change plugin settings. This prevents accidental changes by less experienced administrators or limits sensitive operations to specific team members.

To restore full access:

Simply uncheck all user checkboxes and save. This removes all restrictions and allows all administrators to access the plugin again.

If you get locked out:

🛡️ 9.4. Login Page Protection (Brute Force Defense)

Brute force attacks—where automated bots attempt to guess your administrator password thousands of times per minute—are the most common threat to WordPress sites. This feature provides a robust, multi-layered defense to block these attackers before they can compromise your site.

✅ Key Benefits:

  • Prevents unauthorized access by locking out suspicious IP addresses.
  • Reduces server CPU usage by blocking bot-driven login attempts.
  • Includes specialized support for Cloudflare users.

⚙️ Configuration Settings

Cloudflare Compatibility Mode

If your site uses Cloudflare, standard security tools often see the Cloudflare Server IP instead of the Visitor's Real IP. This can lead to "False Positives" where you accidentally block Cloudflare itself, potentially breaking your site access.

☁️ Enable Cloudflare Support: When this is turned ON, the plugin ignores the standard remote address and instead looks for the HTTP_CF_CONNECTING_IP header. This ensures that the actual attacker is blocked, while Cloudflare's traffic remains safe.

⚠️ NOTICE: Only enable this if your site is actively routed through Cloudflare. Enabling it on a non-Cloudflare site may allow attackers to spoof their IP address.

📋 Managing Blocks & Transients

The system is designed to be "self-healing." Blocked IPs are stored as Transients in your database, which automatically expire after your chosen Block Duration. If you accidentally block yourself:

  1. Log in from a different IP address (like a mobile hotspot).
  2. Go to Plugins > Installed Plugins.
  3. Find WP Optimal State, then Deactivate and Activate it again; this will flush all active blocks and clear the security cache.
💡 PRO TIP: Activity Logging

All lockouts are recorded in the Activity Log. Periodically review your logs to see which IPs are being blocked. If you see persistent attacks from a specific range, you may want to block that entire country or range at the firewall level (Cloudflare WAF).

🔧 10. Troubleshooting & Advanced FAQ

🏗️ 11. Technical Architecture

This section documents the internal structure of the plugin: its security design principles, its PHP class layout, and its key configuration constants. All information here is drawn directly from the source code.

🔒 11.1. Security-First Principles

Every subsystem in the plugin was designed with security as a primary constraint, not an afterthought:

🧩 11.2. Key PHP Classes & JavaScript Objects

The plugin is organized into focused, single-responsibility classes. The main entry point bootstraps them via an SPL autoloader that maps class names to filenames automatically.

Plugin Constants & Configuration Values

The following constants are defined in the main OPTISTATE class and govern paths, cache durations, and other key behaviours across the plugin:

Constant Value Purpose
PLUGIN_NAME WP Optimal State (Pro) Display name used in notices and logs.
VERSION 1.3.1 Current plugin version.
OPTION_NAME optistate_settings WordPress option key for in-database settings.
NONCE_ACTION optistate_nonce Action string used for all AJAX nonce verification.
STATS_TRANSIENT optistate_db_metrics_cache_v2 Transient key for cached database-statistics data.
STATS_CACHE_DURATION 12 hours How long database statistics remain cached before a refresh is needed.
SETTINGS_DIR_NAME optistate-settings Directory under uploads/ for settings and log files. Preserved on deactivation.
BACKUP_DIR_NAME optistate/db-backups Directory for all .sql.gz backup files. Preserved on deactivation.
TEMP_DIR_NAME optistate/db-restore-temp Temporary staging directory during restores. Deleted on deactivation.
CACHE_DIR_NAME optistate/page-cache Directory for server-side page-cache files. Deleted on deactivation.
SETTINGS_FILE_NAME settings.json Filename for the persistent settings file inside SETTINGS_DIR_NAME.
LOG_FILE_NAME optimization-log.json Filename for the activity/audit log inside SETTINGS_DIR_NAME.
GENERATED_SETTINGS_FILE_NAME generated-settings.php Auto-generated PHP settings cache for fast runtime reads.
TRACKING_PARAMS 13 parameters
(see "Purpose" column)
URL query parameters recognised as tracking/referral strings and stripped from page-cache keys. Includes utm_source, utm_medium, utm_campaign, utm_content, utm_term, fbclid, gclid, msclkid, mc_cid, mc_eid, _ga, ref, and source.

🔐 11.3. Advanced Security Features

File Path Validation & Path Traversal Protection

The plugin implements multi-layer file path validation to prevent directory traversal attacks:

Validation Layers

  1. Path Normalization: Uses wp_normalize_path() to convert backslashes and resolve relative paths
  2. Boundary Checking: Verifies paths start with allowed directory (typically wp-content/uploads/optistate-*)
  3. Malicious Pattern Detection: Blocks ../, ..\, and null bytes (\0)
  4. Canonical Path Resolution: When FS_METHOD='direct', resolves symlinks with realpath() and verifies canonical path
🛡️ Example Attack Prevention:
Input: /uploads/optistate-data/../../../wp-config.php
Result: Blocked - normalizes to /wp-config.php, fails boundary check

SQL Injection Protection

Multiple layers protect against SQL injection:

Data Encryption

Sensitive settings are encrypted using AES-256-CBC:

AJAX Security

Every AJAX request requires:

✅ OWASP Compliance: These protections address:
  • SQL Injection (A03:2021)
  • Path Traversal (A01:2021)
  • CSRF Attacks (A01:2021)
  • Sensitive Data Exposure (A02:2021)

📝 12. Disclaimer

This plugin provides powerful, low-level access to your WordPress database and server configuration. It is designed to be safe, secure, and effective. However, all servers and WordPress installations are different.

By using WP Optimal State PRO, you agree that you are doing so at your own risk. The author is not responsible for any data loss, site downtime, or other issues that may arise from the use or misuse of this software.

💾 Always create a backup before performing any optimization.

🧩 13. Developer API (Hooks & Filters)

WP Optimal State PRO provides hooks for developers to extend functionality or integrate with other systems.

Filters

Actions

🆘 14. Technical Support

As a lifetime licence holder, you are entitled to priority support.

Before using the support form, please get your license key and be sure to include it in your request along with your website URL.

Also, check the FAQs, as you may find the answer to your question there.