Zamok – Security and Site Tools

Description

Zamok replaces a stack of single-purpose plugins — for admin enhancements, security hardening, SMTP email delivery, image optimization, database search-and-replace, database cleanup, and full-site backups — with one maintainable, modular package. Every feature is a toggle. Turn on what you need, leave the rest off.

About the name: Zamok (Замок) is Ukrainian for both castle and lock — strength and security in one word. The name is a small tribute to the people of Ukraine. 🇺🇦

Commitments

  • 100% free and open source. GPL-2.0-or-later, forever. No “pro” version, no paid tier, no upsell, no ads.
  • No tracking or telemetry. No usage statistics, no analytics, no phone-home, no self-updater. The only network connections it makes are ones you configure: your SMTP server and your off-site SFTP backup server.
  • Lean by design. Modules load only when enabled; nothing runs that you haven’t turned on.

What it does

Zamok is fully modular. Every feature is a self-contained module you switch on or off from a single admin page, grouped into clear categories.

Core debloat

  • Dashboard Widgets — removes all dashboard widgets and the welcome panel.
  • Comments — completely disables the comment system; existing comments preserved.
  • File & Site Editors — disables the Theme/Plugin File Editors and the Site Editor.
  • Gravatars — disables Gravatar avatars to stop external requests to gravatar.com.
  • Toolbar Cleanup — removes the WP logo menu, “+ New” menu, Help tab, and footer text.
  • Disable REST API — blocks REST access for non-authenticated users.
  • Disable Feeds — disables all RSS, Atom, and RDF feeds.
  • Disable Embeds — disables oEmbed auto-discovery and the embed script.
  • Disable Auto-Updates — turns off automatic core/plugin/theme updates.
  • Disable Author Archives — returns 404 for author archives; prevents enumeration.
  • Disable Archive Pages — returns 404 for category, tag, and date archives; filters them from the sitemap.
  • Disable Smaller Components — removes version disclosure, legacy meta tags, emoji, frontend Dashicons, and jQuery Migrate.
  • Disable XML-RPC — disables XML-RPC, removes the X-Pingback header, blocks pingbacks.
  • Heartbeat Control — disables Heartbeat on the frontend and slows it in admin.
  • Disable AI Features (WP 7.0+) — unhooks the AI Client, Abilities API, and Connectors.
  • Disable Application Passwords — closes the Application Passwords auth surface.
  • Limit Post Revisions — caps stored revisions per post (default: last 10).
  • Strip Comment Author IP (GDPR) — stops WordPress storing commenter IPs.

Enhancements

  • Email — SMTP delivery, a forced consistent From address, and a full email log with view/resend/auto-clean.
  • Image Optimization — auto-resizes and converts new uploads to WebP using native WordPress image processing.
  • Better Link Search — relevance ranking, clearer result labels, and a post-type filter in the link modal.
  • Content Duplication — one-click duplicate for pages, posts, custom post types, and taxonomy terms. Copies all content, taxonomy assignments, custom fields, and term meta (including ACF fields).
  • Media Replacement — replace a media file while keeping the same ID, date, and filename.
  • SVG Upload — allows SVG uploads with automatic sanitization.
  • Missed Schedule Fix — publishes scheduled posts that missed their time.
  • Admin Notices Cleanup — hides plugin spam notices, keeps the important ones.
  • Custom Login URL — changes the login URL from wp-login.php to a custom slug.
  • Email-Only Login — restricts login to email addresses only.
  • Site Identity on Login Page — replaces the WP logo/link with your site icon and URL.
  • User Info Columns — adds Last Login and Registration Date to the Users list.
  • Disable Gutenberg — restores the Classic Editor; removes block styles.

Security

  • Two-Factor Authentication — TOTP authenticator app, emailed code, or single-use backup codes; enforced per role; fully self-hosted. Does not affect REST, XML-RPC, application passwords, WP-CLI, or cron.
  • Brute Force Protection — locks out IPs after repeated failed logins, with escalating duration (1 hour, 6 hours, 24 hours, 1 week).
  • IP Banning — blocks abusive IPs automatically (escalating, up to 7 days) plus manual bans, an allowlist, and a ban log. No permanent bans — entries expire and self-clean.
  • System Hardening — server/filesystem hardening via .htaccess (protect system files, disable directory browsing, block PHP execution in writable dirs) and disables the dashboard file editor.
  • Block User Enumeration — blocks ?author=N and gates the REST users endpoint.
  • Admin Creation Alert — emails you the moment an administrator is created or a user is promoted to admin.

Tools

  • Database Tools — operator-run utilities under Zamok Tools: a serialization-safe Search & Replace and a Database Cleanup for revisions, trash, spam, expired transients, and orphaned meta. Nothing runs on its own — every action is a manual click.

Backups

  • Backups — full-site backup of files and database as a single encrypted package. Builds in resumable, timeout-safe steps so it works on shared hosting, with optional scheduling and off-site SFTP push. Archives are encrypted at rest with libsodium; both the browser download and the SFTP upload deliver a plain, restore-anywhere zip. Each package includes a standalone restore installer — just upload it, open in a browser, and follow the wizard.

Plugin-specific cleanup

  • Clean Up Yoast SEO — removes promotional modals, upsell popups, menu bloat, the dashboard widget, admin bar menu, and premium upsell cards.
  • Clean Up WooCommerce — removes marketplace suggestions, setup wizards, inbox notifications, payment install offers, and extension upsells.

Plugin-specific modules auto-disable when the target plugin is not active.

What it replaces

Zamok can replace the following plugins — gaining all their features while cutting admin page load times by ~20%, database queries by ~60%, and memory usage by ~25% (median results across 125 real before/after benchmarks; sites without WooCommerce typically see larger gains — around 21% faster loads and 62% fewer queries):

  • WP Mail SMTP / Post SMTP Email module (SMTP, forced From, delivery log)
  • Solid Security / Kadence Security / Wordfence Brute Force, IP Banning, Two-Factor, Login URL, System Hardening, User Enumeration
  • Two Factor Authentication Two-Factor module (TOTP, email, backup codes)
  • Smush / EWWW / ShortPixel Image Optimization module (WebP conversion)
  • Safe SVG / SVG Support SVG Upload module (sanitized SVGs)
  • Better Search Replace Database Tools (serialization-safe search & replace)
  • WP-Optimize Database Tools (cleanup) + Heartbeat Control + Smaller Components
  • Disable Comments Comments module
  • Duplicate Post / Yoast Duplicate Post Content Duplication module
  • Duplicate Taxonomy Terms (ACF) Content Duplication module (term duplication with full ACF field support)
  • Duplicator / UpdraftPlus / All-in-One WP Migration Backups module (encrypted, scheduled, SFTP)
  • WPS Hide Login Custom Login URL module
  • Enable Media Replace Media Replacement module

For Developers: AI Image Marking

The AI Image Marking module records whether a media image is AI-generated using
the IPTC Digital Source Type vocabulary, preserves that marker through Zamok’s
WebP conversion, and exposes it to your theme. It renders NO front-end output by
design — the visible disclosure (your EU AI Act Article 50(4) duty as the site)
is the theme’s job. The module gives you the flag; you render the notice.

Stored values (attachment meta _zamok_ai_source):

  • “ (empty) — not AI-generated
  • trainedAlgorithmicMedia — fully AI-generated from a prompt (no real photo input)
  • compositeWithTrainedAlgorithmicMedia — AI applied to a real photo (real content was an input)

Read it (each is one cached read — pick whichever suits):

zamok_ai_source( int $attachment_id ): string — the value, or '' .
zamok_is_ai_generated( int $attachment_id ): bool — true when marked.

if ( function_exists( 'zamok_is_ai_generated' ) && zamok_is_ai_generated( $id ) ) {
    // render your disclosure — figcaption, badge, data-attribute, whatever fits
}

Without a Zamok dependency, it also rides along on core metadata and REST:

$meta = wp_get_attachment_metadata( $id );
$ai   = $meta['ai_source'] ?? '';        // key absent if Zamok is inactive

GET /wp-json/wp/v2/media/123  →  { ..., "zamok_ai_source": "trainedAlgorithmicMedia" }

Note: the module preserves the plain IPTC/XMP marker through WebP conversion, but
it does not create signed C2PA Content Credentials (that requires a trust-listed
certificate, impossible from PHP), and installing it does not by itself make a
site compliant — the visible disclosure is yours to render.

Screenshots

Installation

  1. Upload the zamok folder to /wp-content/plugins/, or install the zip via Plugins Add New Upload Plugin.
  2. Activate the plugin through the Plugins menu in WordPress.
  3. Open the new Zamok menu in the admin sidebar.
  4. Toggle on the modules you want.

Requires PHP 8.4 or higher and WordPress 7.0 or higher.

FAQ

Is it really free?

Yes. GPL-2.0-or-later, forever. There is no pro tier, no upsell, no feature locked behind a payment. We built this to replace plugins whose business model is upselling you — adding our own would defeat the point.

Does it collect any data or phone home?

No. There is no usage tracking, analytics, telemetry, or licensing call-home. Everything runs on your own server. The only outbound connections are ones you configure and opt into: your SMTP server (Email module) and your SFTP server (Backups module). The backup worker makes a local loopback request to your site’s own admin-ajax.php to advance background jobs, and the standalone restore installer optionally fetches fresh salts from wordpress.org (with a local fallback).

Will it lock me out if I enable Two-Factor Authentication?

Two-Factor is opt-in and defaults off. Backup codes are mandatory at setup, an administrator can reset any user’s 2FA from the user-edit screen, and the ZAMOK_2FA_DISABLE constant in wp-config.php is an emergency escape hatch.

Can I store secrets outside the database?

Yes. SMTP, SFTP, and the backup encryption key can be pinned in wp-config.php via ZAMOK_SMTP_PASSWORD, ZAMOK_SFTP_PASSWORD / ZAMOK_SFTP_KEY, and ZAMOK_BACKUP_KEY. Secrets stored in the database are encrypted with libsodium.

Does it work on Nginx?

Every module works on any server. The System Hardening module writes .htaccess rules, which apply on Apache/LiteSpeed; on Nginx those rules are inert and the documented Nginx snippets should be used instead.

Reviews

Read all 1 review

Contributors & Developers

“Zamok – Security and Site Tools” is open source software. The following people have contributed to this plugin.

Contributors

Changelog

1.0.8

  • Security: hardened login URL, user enumeration, REST API, 2FA, SVG uploads, IP bans and restore installer.
  • Fix: backups now include their restore key, plus 40+ backup, restore and module fixes.

1.0.7

  • Fix: on a shop where Zamok was activated before WooCommerce, every product review, star rating and review form disappeared regardless of the “Keep WooCommerce product reviews” setting. Whether WooCommerce counted as present was decided while plugin files were still loading; it is now decided when a page is built.
  • Fix: saving the settings while WooCommerce was switched off silently turned “Keep WooCommerce product reviews” off with it, because an undrawn tickbox reads as unticked. The stored preference is now kept as it was.
  • Fix: updating the plugin while a backup was running could finish it as an empty file recorded as complete — and that empty backup counted as the newest good one, so housekeeping could delete a real older backup to make room. A build that cannot find its files now fails, and leaves existing backups alone.
  • Fix: if a prepared download went missing from the server, the Backups screen showed “Preparing download…” indefinitely with no way to ask again, even though the backup was intact. It is now reported as failed, which offers the existing “Retry preparing download”.
  • Fix: saving the off-site SFTP form, or importing settings, silently broke SMTP. Both rewrite the whole settings record, running the stored password through the encrypting sanitizer a second time so it could no longer be decrypted. The sanitizer now recognises an already-encrypted value.
  • Security: the restore installer now asks for a restore key before it will do anything. Previously it asked only for the archive filename, which is always “archive.zip” and is printed inside the package, so anyone reaching installer.php during a restore could point the site at a database of their own. The key is shown on the Backups screen and is not stored in the package.
  • Security: two-factor authentication can now also refuse XML-RPC logins from users who use it, since xmlrpc.php cannot ask for a second factor. New sites get this on; a site that already had 2FA on gets it off, because enabling it during an update would have stopped Jetpack and the mobile app signing in unasked. Application passwords are still accepted, and are now matched to the account they authenticated.
  • Security: the plaintext database dump written during a restore is no longer called database.sql. On Nginx, where the installer’s protective rules do not apply, that fixed name meant the whole database could be downloaded by anyone during the import.
  • Security: the trusted-proxy setting now accepts the proxy’s own address ranges, and honours forwarded client-IP headers only from them. Any other truthy value behaves as before and trusts whatever connects, which is spoofable whenever the origin is reachable directly.
  • Fix: the restore installer’s table-prefix field is now read-only. Changing it produced a site whose configuration named a prefix no table in the restored database used.
  • Fix: mysqldump output is now checked before it is accepted. Only “the file is not empty” was verified, so a dump cut short by a memory limit, a full disk or a permissions error was stored as complete. The exit status and the dump’s completion marker are both required now, with anything else falling back to the built-in dumper. The database password is also no longer passed on the command line.
  • Fix: the built-in dumper now reads each table in primary-key order. Large tables are read across several passes, and without a fixed order rows could be missed or written twice — and a duplicated row stops a restore.
  • Fix: photos taken on a phone no longer come out sideways. WebP conversion ignored the rotation recorded by the camera, which the converted file cannot carry.
  • Fix: replacing a large image with a smaller one could leave the attachment pointing at a file that had been deleted.
  • Fix: “Duplicate” is now offered on WooCommerce product categories and tags, and on taxonomies added by other plugins and themes.
  • Fix: the Tables tool no longer offers to delete tables belonging to plugins it did not recognise. WPML, Rank Math, Wordfence, LiteSpeed, WP Rocket, Elementor, Smush and around forty others name their tables differently from their folder. Tables that still cannot be matched now require the name to be typed out, and multisite per-site tables are recognised properly.
  • Fix: system hardening writes its rules, then asks the site for a page and takes them back out if the server errors. On hosts that do not permit one directive, Apache returned a 500 for the whole site including the dashboard, with no way back for a non-technical admin.
  • Fix: an email that failed to send is no longer announced on every dashboard screen. It now shows on Zamok’s own pages, with a count on the Email Log menu item.
  • Fix: the SMTP conversation stored in the email log no longer contains the message itself. Every send stored the full body and its attachments regardless of the “store message body” setting.
  • Fix: several hooks declared strict parameter types another plugin could violate, stopping the site with a fatal error rather than being ignored. This is the same fault as the 1.0.3 login-URL crash, found in the sitemap, REST authentication, login and logout hooks.
  • Fix: the restore wizard no longer fails with “Security check failed” partway through on connections whose address changes between requests, such as mobile networks and corporate VPNs.
  • Fix: automatic bans on IPv6 now cover the /64 block the address sits in. A single IPv6 address is one of eighteen quintillion given to the same customer, so banning it stopped nobody.
  • Fix: the addresses of the last ten administrator logins are protected from automatic bans, not only the most recent. On a site with several administrators, a colleague became bannable again as soon as someone else signed in.
  • Changed: new installs keep email log entries for 30 days instead of 90, since stored messages can contain password-reset links and customer details. Existing sites keep their setting.
  • Changed: new warnings on modules whose effects are invisible while you are logged in — Heartbeat Control, Disable XML-RPC, Custom Login URL, Email-only login, Block User Enumeration, System Hardening, Image Optimization and Disable Application Passwords.
  • Changed: the off-site SFTP settings now say plainly that the copy on the remote server is not encrypted.
  • Improve: several small performance fixes — schema-version checks no longer cost an uncached query on every page load, the hardening rules are no longer re-read from disk on every dashboard request, and the active-bans list is capped at a size that keeps it cheap.
  • Security: plaintext files used while building backups and prepared downloads now prefer WordPress’s private temporary directory instead of uploads. Each job remembers its work directory across worker ticks and fails safely if it disappears; guarded uploads storage remains the fallback.
  • Changed: prepared downloads now expire after seven days to reclaim disk space. Their size is shown on the Backups screen, where they can also be removed without deleting the backup.
  • Fix: downloading a large backup timed out. The package was assembled inside the download request — every part decrypted, merged and re-zipped before a byte was sent, which on a 342 MB backup was 81 seconds of silence, past most servers’ timeout. It is now assembled in the background by the same resumable worker, so the first byte arrives in well under a second, with live progress while it builds.
  • Fix: a package build that failed no longer marks the backup itself as failed, wipes its working files, or sends a scheduled-backup failure email.
  • Fix: preparing a package no longer blocks taking a new backup, and now checks there is enough free disk space before it starts.
  • Fix: leftover working files from a package build interrupted by the server are now cleaned up on the next idle worker run, instead of staying on disk until the next build.
  • Security: the prepared restore package is stored encrypted, like the backup it was made from. The directory it sits in is protected by rules Apache and IIS honour but Nginx ignores, so unencrypted it would have been an unauthenticated download of every site file, the database and wp-config.php. It is decrypted as it downloads.
  • Security: files written while a backup is built were named from a predictable counter (build-1.sql) and protected only by a rule Nginx does not read. During a build those files are not yet encrypted, so an unauthenticated request could have retrieved the database and wp-config.php by guessing the name. Work files now carry an unguessable name derived from the site’s own secret keys.
  • Changed: backups are encrypted in 8 MB frames instead of 25 MB, lowering peak memory during backup and restore on smaller hosts. Existing backups still restore normally.
  • Security: sending a backup off-site no longer leaves a readable copy inside uploads. The copy exists because the off-site file is deliberately unencrypted so it can still be restored if the server is lost, but it was named from the site address and the date and so could be guessed first try, and can sit there for hours during a transfer. It is now written to the private temporary directory under a secret-key-derived name and deleted as each part finishes. The same applies to the multi-part download folder.
  • Security: anything left behind by a backup the server killed mid-transfer is now cleaned up on the next idle run, including files left by earlier versions under the old predictable names. Previously an interrupted transfer could leave a readable copy of the site on disk indefinitely.
  • Fix: if the off-site connection breaks during an upload it is now thrown away and re-established rather than reused. A broken SSH connection can leave the two ends out of step, which made everything afterwards — including the check of how much had been sent — unreliable.
  • Fix: removed a web-server rule that could return a server error for the backups folder on older Apache installations, the same fault that broke the restore installer in 1.0.4.
  • Security: the Tables tool no longer offers to delete tables belonging to a plugin, theme or library currently in use. It matched each table to a single plugin folder and got it wrong whenever the folder name was not the obvious one — with the paid copy of WPForms running, every stored entry was listed as leftover data one click from deletion. Plugins whose tables are named differently from their folder were not recognised at all, and no theme was ever considered. On the test site this took the tables offered from 24 to 13, all genuinely leftovers.
  • Security: deleting a table that still contains rows now always requires typing its name. Only tables the tool could not identify asked for that, so a table it identified wrongly needed nothing more than clicking OK.
  • Fix: “Disable Feeds” now actually withholds the feed. It returned a 404 but still sent the complete feed — every post title, link and excerpt — so anything that does not check the status code received the lot. Addresses ending in /feed/ were blocked; the ?feed= form, which works on every site, was not.
  • Fix: the tables list no longer labels WooCommerce’s own tables as WordPress core. The core list was read from a value plugins add themselves to, so the label depended on what had loaded.
  • New: a saved SMTP password can now be removed. Leaving the field blank keeps the existing one, which is right for a masked field but left no way to say “no password at all” without editing the database. A “Remove the saved password” box appears whenever one is stored.
  • Fix: the proxy warning now also appears on the Bans screen, which is where an address is actually banned. Behind an undeclared proxy every visitor shares one address, so a single ban there can lock out all of them.
  • Fix: the export screen now says plainly that a settings file without credentials still contains the SMTP host, port and username. Only the password and the off-site connection are withheld.
  • Fix: “Disable REST API” no longer stops a WooCommerce shop taking guest orders. The block cart and checkout are built on the Store API, so blocking everything unauthenticated meant only logged-in customers could check out — invisible while testing as an administrator. The Store API now stays open when WooCommerce is active and the administrative endpoints stay closed; other namespaces can be opened with the new zamok_rest_guest_namespaces filter.
  • Fix: turning off comments no longer silently removes WooCommerce product reviews, which are stored as comments. A new “Keep WooCommerce product reviews” option, on by default, keeps reviews working on products while comments stay off everywhere else. Moderate them under Products, Reviews.
  • Fix: status colours on Zamok’s screens now follow a dark dashboard. They were written directly onto each element, which overrides any stylesheet, so green, red and amber stayed light and hard to read. Delete keeps its warning colour either way.

1.0.6

  • New: AI Image Marking module. Mark media-library images as AI-generated using the IPTC Digital Source Type vocabulary (fully generated vs. AI-applied-to-a-real-photo), for EU AI Act transparency and Google Merchant. Native Media column and bulk actions, a per-image selector, and the marker is preserved through Zamok’s WebP conversion (GD otherwise strips all metadata). Provides a theme API (zamok_ai_source() / zamok_is_ai_generated(), a wp_get_attachment_metadata() [‘ai_source’] key and a REST field); the visible on-page disclosure is left to the theme by design. See docs/ai-image-marking.md.
  • Fix: backups corrupted every value containing a percent sign. The dump escaped values with _real_escape(), which appends an internal placeholder to protect literal % and is meant to be stripped again by prepare(). The token was written straight to the .sql file, so a % became 66 characters — breaking values like “/%postname%/” and, critically, serialized data, whose stored length no longer matched its content. Backups taken before this fix are affected; re-create them after updating.
  • Fix: the portable installer download now works for large backups. A backup split into multiple parts (over ~400 MB) refused to build its self-contained installer and pointed at a download button that no longer exists. All parts are now merged into one restore package.
  • Fix: blank white admin page after a bulk action on WordPress 7.0. Its new admin View Transitions use attr()-based CSS that current Chrome skips on any admin redirect, leaving a blank frame; Zamok now dequeues that core stylesheet.

1.0.5

  • New: WooCommerce module — an opt-in setting to disable the Analytics/Reports/Homescreen dashboard on stores that don’t use it, removing its background queries and asset overhead from every WooCommerce admin page.
  • Improve: the WooCommerce module now throttles Action Scheduler’s task-queue check, which otherwise runs on every page load, admin or front end, and skips a database read for a payment-incentive banner already being hidden.
  • Improve: Disable XML-RPC now blocks xmlrpc.php outright, returning 403 on every server including Nginx, where .htaccess rules do not apply. Previously it only stripped the pingback header and filtered methods, so the endpoint stayed reachable and still answered system.* calls.
  • New: Database Cleanup adds two WooCommerce actions, shown only when WooCommerce is active — flipping onboarding-wizard and task-list options so they load only when needed, and removing already-actioned inbox notes, which WooCommerce never deletes once dismissed.
  • New: clear warnings on modules that can break things which aren’t obvious while logged in — Disable REST API (payment webhooks, block checkout, contact forms), Comments (hides product reviews) and Disable Feeds (RSS email campaigns, product feeds). The warning shows before you enable the module.
  • Fix: Brute Force and IP Banning now detect a proxy or CDN and warn you to configure the trusted-proxy setting first. Without it every visitor is seen as the same IP, so one attacker could get that shared address banned and lock out the site. A successful admin login can no longer store a proxy IP as trusted.
  • Fix: IP Banning no longer flags requests to /.well-known/ as suspicious — a standard location used by SSL certificate renewal, where treating it as an attack could interfere with issuance.
  • Fix: System Hardening now also blocks license.txt, which scanners flag as information disclosure. It already protected readme.html, readme.txt and wp-config.php; the Nginx rule already covered it.
  • Improve: System Hardening also blocks wp-config backup copies (.bak/.save/.old/.orig/~), .env files, .DS_Store, debug.log and error_log, and database dumps (.sql/.sql.gz). It deliberately leaves .zip/.tar alone, since many sites serve legitimate downloads. The Apache and Nginx rule sets now protect exactly the same paths, and the PHP-execution block covers the php8/php9 and trailing-dot variants.
  • Improve: Block User Enumeration is now self-contained — it also removes authors from the XML sitemap and strips author name and URL from oEmbed responses. Those were previously closed only if you also enabled Disable Author Archives and Disable Embeds.
  • Fix: Disable Author Archives now stops ?author=1 requests before WordPress can act on them. A valid author id was redirected while an invalid one returned 404, so account ids were still enumerable.
  • Fix: Disable Embeds now returns 404 for the per-post embed page, and Comments returns 404 for comment-feed URLs. Both previously only removed the discovery links while the URLs kept responding.
  • Fix: the System Hardening .htaccess block is now always removed when the plugin is deleted, even with “remove all data on uninstall” off — it is reversible server configuration, not data.
  • Change: “Disable Archives” is now off by default; it returns 404s for category, tag and date archives, which only suits sites that don’t use them.
  • Change: System Hardening no longer blocks PHP execution inside the plugins and themes folders by default, since this can break some plugins’ and payment gateways’ callback files. The uploads block stays on.

1.0.4

  • Improve: the Insert/Edit Link search now finds category, tag and product-category archive pages, not just posts, pages and products. Each taxonomy gets its own filter pill, and matching terms appear inline as you search.
  • Fix: choosing a link in the enhanced Insert/Edit Link modal now works inside Advanced Custom Fields link fields, instead of being silently discarded.
  • Fix: with the Custom Login URL module active, logging out no longer shows an extra “Do you really want to log out?” screen.
  • Fix: the taxonomy filter control in the Insert/Edit Link modal is now readable when a dark-mode dashboard plugin is active.
  • Fix: the portable restore installer failed on Apache servers running PHP via FPM/CGI (for example Plesk and cPanel) — its protective .htaccess used a directive only valid under mod_php and blocked the installer’s own entry point, causing a 500 and then a 403.
  • Improve: redesigned the restore wizard with a clearer step tracker, guided wording and a refined layout.
  • Security: hardened the standalone restore installer — restore steps now run only in the confirmed order, and the destination database password is encrypted while stored on disk during a restore.
  • Security: the background backup worker can no longer be triggered by unauthenticated visitors; it now requires an internal one-time token. Scheduled backups are unaffected.
  • Security: more reliable visitor-IP detection behind a trusted reverse proxy, so spoofed forwarded headers cannot be used to evade IP bans.

1.0.3

  • Fix: the Custom Login URL module could crash a site when another plugin generated an admin URL with a non-integer blog id — a strict type check on a WordPress site_url filter argument. The filter now accepts the loose types WordPress passes.

1.0.2

  • New: tiered (GFS) backup retention — keep the N most recent plus daily, weekly, monthly and yearly backups, applied to both local and off-site copies. The newest backup is always kept.
  • New: backup storage modes — Local only, Mirror (local + off-site), or Off-site only, where the local copy is removed after a verified upload and downloads stream straight from your SFTP server. Off-site backups are stored as plain, directly-usable archives.
  • Change: replaces the previous keep-last-N retention. Defaults retain at least as much as before, so existing sites are not pruned more aggressively on update.

1.0.1

  • New: Database Tools Tables. Lists every database table with its size and the core feature or plugin it belongs to, and lets you delete leftover tables from inactive or removed plugins. Core and active-plugin tables are protected. Deletion is confirmation-gated and irreversible — back up first.

1.0.0

  • Initial release — 41 toggleable modules across Core Debloat, Enhancements, Security, Tools, and Backups.
  • GPL-2.0-or-later. No tracking, no telemetry, no paid tier.