{"id":380659,"date":"2026-10-08T23:33:19","date_gmt":"2026-10-08T23:33:19","guid":{"rendered":"https:\/\/wordpress.org\/plugins\/settings-undo\/"},"modified":"2026-10-08T23:32:47","modified_gmt":"2026-10-08T23:32:47","slug":"dotance-settings-history","status":"publish","type":"plugin","link":"https:\/\/twd.wordpress.org\/plugins\/dotance-settings-history\/","author":23562247,"comment_status":"closed","ping_status":"closed","template":"","meta":{"version":"1.1.0","stable_tag":"1.1.0","tested":"7.1.3","requires":"5.9","requires_php":"7.4","requires_plugins":null,"header_name":"Dotance Settings History and Restore","header_author":"Usman","header_description":"Every settings change is recorded. See who changed what, compare old vs new, and undo it in one click. Works with any plugin or theme.","assets_banners_color":"627489","last_updated":"2026-10-08 23:32:47","external_support_url":"","external_repository_url":"","donate_link":"","header_plugin_uri":"https:\/\/dotance.com\/plugins\/settings-undo\/","header_author_uri":"https:\/\/dotance.com","rating":0,"author_block_rating":0,"active_installs":0,"downloads":67,"num_ratings":0,"support_threads":0,"support_threads_resolved":0,"author_block_count":0,"sections":["description","installation","faq","changelog"],"tags":{"1.1.0":{"tag":"1.1.0","author":"dotance","date":"2026-10-08 23:32:47","revision":3735691}},"upgrade_notice":{"1.1.0":"<p>Adds checkpoints and rollback, update markers, critical-change alerts, export, WP-CLI and a redesigned screen. A second table is created automatically on upgrade.<\/p>","1.0.2":"<p>Recreates the history table automatically if a migration or restore dropped it.<\/p>","1.0.0":"<p>First release.<\/p>"},"ratings":[],"assets_icons":{"icon-128x128.png":{"filename":"icon-128x128.png","revision":3735690,"resolution":"128x128","location":"assets","locale":"","width":128,"height":128},"icon-256x256.png":{"filename":"icon-256x256.png","revision":3735690,"resolution":"256x256","location":"assets","locale":"","width":256,"height":256}},"assets_banners":{"banner-1544x500.png":{"filename":"banner-1544x500.png","revision":3735690,"resolution":"1544x500","location":"assets","locale":"","width":1544,"height":500},"banner-772x250.png":{"filename":"banner-772x250.png","revision":3735690,"resolution":"772x250","location":"assets","locale":"","width":772,"height":250}},"assets_blueprints":{},"all_blocks":[],"tagged_versions":["1.1.0"],"block_files":[],"assets_screenshots":{"screenshot-1.png":{"filename":"screenshot-1.png","revision":3735690,"resolution":"1","location":"assets","locale":"","width":1440,"height":900},"screenshot-2.png":{"filename":"screenshot-2.png","revision":3735690,"resolution":"2","location":"assets","locale":"","width":1440,"height":900},"screenshot-3.png":{"filename":"screenshot-3.png","revision":3735690,"resolution":"3","location":"assets","locale":"","width":1440,"height":900},"screenshot-4.png":{"filename":"screenshot-4.png","revision":3735690,"resolution":"4","location":"assets","locale":"","width":1440,"height":900},"screenshot-5.png":{"filename":"screenshot-5.png","revision":3735690,"resolution":"5","location":"assets","locale":"","width":1440,"height":900},"screenshot-6.png":{"filename":"screenshot-6.png","revision":3735690,"resolution":"6","location":"assets","locale":"","width":1440,"height":900}},"screenshots":{"1":"The timeline: one card per save, with who, when, which plugin, and which screen. Checkpoints and update markers sit between them.","2":"Inside a change set: every option the save touched, with Diff and Undo per row.","3":"A key-level diff of an array option, collapsed to the keys that changed.","4":"Undoing a protected option asks you to type its name.","5":"Rolling back to a checkpoint: a preview of every option before anything changes.","6":"Settings: retention, what is recorded, noisy options, critical-change alerts."}},"plugin_section":[262246],"plugin_tags":[1433,152,10708,1253,18329],"plugin_category":[],"plugin_contributors":[280364],"plugin_business_model":[],"class_list":["post-380659","plugin","type-plugin","status-publish","hentry","plugin_section-dashboard-widgets","plugin_tags-history","plugin_tags-restore","plugin_tags-rollback","plugin_tags-settings","plugin_tags-undo","plugin_contributors-dotance","plugin_committers-dotance"],"banners":{"banner":"https:\/\/ps.w.org\/dotance-settings-history\/assets\/banner-772x250.png?rev=3735690","banner_2x":"https:\/\/ps.w.org\/dotance-settings-history\/assets\/banner-1544x500.png?rev=3735690","banner_rtl":false,"banner_2x_rtl":false},"icons":{"svg":false,"icon":"https:\/\/ps.w.org\/dotance-settings-history\/assets\/icon-128x128.png?rev=3735690","icon_2x":"https:\/\/ps.w.org\/dotance-settings-history\/assets\/icon-256x256.png?rev=3735690","generated":false},"screenshots":[{"src":"https:\/\/ps.w.org\/dotance-settings-history\/assets\/screenshot-1.png?rev=3735690","caption":"The timeline: one card per save, with who, when, which plugin, and which screen. Checkpoints and update markers sit between them."},{"src":"https:\/\/ps.w.org\/dotance-settings-history\/assets\/screenshot-2.png?rev=3735690","caption":"Inside a change set: every option the save touched, with Diff and Undo per row."},{"src":"https:\/\/ps.w.org\/dotance-settings-history\/assets\/screenshot-3.png?rev=3735690","caption":"A key-level diff of an array option, collapsed to the keys that changed."},{"src":"https:\/\/ps.w.org\/dotance-settings-history\/assets\/screenshot-4.png?rev=3735690","caption":"Undoing a protected option asks you to type its name."},{"src":"https:\/\/ps.w.org\/dotance-settings-history\/assets\/screenshot-5.png?rev=3735690","caption":"Rolling back to a checkpoint: a preview of every option before anything changes."},{"src":"https:\/\/ps.w.org\/dotance-settings-history\/assets\/screenshot-6.png?rev=3735690","caption":"Settings: retention, what is recorded, noisy options, critical-change alerts."}],"raw_content":"<!--section=description-->\n<p>WordPress keeps revisions for posts and pages. It keeps nothing for settings. Save the wrong value on a plugin's options screen, or watch a colleague change something on Friday evening, and there is no history to go back to.<\/p>\n\n<p>Dotance Settings History and Restore is that history. It records every real change to the options table made by a logged-in user \u2013 in WordPress itself, in any plugin, in any theme \u2013 and puts a timeline under <strong>Tools \u2192 Settings Undo<\/strong> with an Undo button on every entry.<\/p>\n\n<p><strong>What you see for each change<\/strong><\/p>\n\n<ul>\n<li>Who made it, and when<\/li>\n<li>Which plugin, theme or WordPress core wrote it<\/li>\n<li>Which screen it came from \u2013 \"Settings \u203a Reading\", a plugin's admin page, the Customizer, a REST route<\/li>\n<li>The value before and after: short values right on the row (\"10 \u2192 12\"), arrays as a key-level diff that reaches into nested keys (added, removed and changed), collapsed to what moved<\/li>\n<li>A short note you can add to any change set, so the timeline says why<\/li>\n<\/ul>\n\n<p><strong>Undo and roll back<\/strong><\/p>\n\n<ul>\n<li>Undo one option, or every option a single save touched, in one click<\/li>\n<li><strong>Checkpoints<\/strong>: save a named marker (\"Before the redesign\") and later roll every setting back to how it was at that moment, after a preview of every option and its value<\/li>\n<li><strong>Roll back one person or one plugin<\/strong>: put back everything a user changed, or everything a plugin or theme wrote, in the last hour, day, week or month<\/li>\n<li><strong>Update markers<\/strong>: plugin, theme and core updates and activations show up on the timeline, so \"what changed after that update?\" has an answer and a Roll back button<\/li>\n<li>Every rollback shows a preview first, flags options that someone else changed afterwards, and is itself recorded, so it can be undone too<\/li>\n<li>Options that could lock you out \u2013 site URL, home URL, active plugins, theme, user roles \u2013 ask you to type the option name before they are restored<\/li>\n<\/ul>\n\n<p><strong>Know when something critical changes<\/strong><\/p>\n\n<ul>\n<li>Optional email when site URL, home URL, admin email, search-engine visibility, open registration or the default role changes, with who changed it and from which plugin (off by default)<\/li>\n<li>A \"noisy options\" hint shows options a plugin rewrites over and over, with one click to ignore them<\/li>\n<li>An admin-bar menu shows the last few changes and an \"Undo the last change set\" shortcut<\/li>\n<\/ul>\n\n<p><strong>Designed to be quiet<\/strong><\/p>\n\n<p>A settings log is only useful if it is readable, so the plugin does not record everything. Transients, cron state, rewrite rules, update-check timestamps, cache keys and plugin version bumps are ignored. One settings form save that writes twelve options is one card in the timeline, not twelve. A plugin that changes a value and puts it straight back within the same request leaves no entry. Changes made by cron, WP-CLI or anonymous requests are off by default and can be switched on, and you can add your own option names (with <code>*<\/code> wildcards) to the ignore list on the Settings tab.<\/p>\n\n<p><strong>Safe by default<\/strong><\/p>\n\n<ul>\n<li>Only administrators (<code>manage_options<\/code>) can view the timeline or undo anything<\/li>\n<li>Values under keys that look like passwords, tokens or API keys are masked in the display and in exports; the stored value is intact, so an undo still works<\/li>\n<li>Old rows are pruned daily by age and by row count, both configurable<\/li>\n<li>Deleting the plugin keeps the history unless you tick \"delete data on uninstall\"; a \"Delete all history\" button clears it on demand<\/li>\n<li>Nothing is sent anywhere. The plugin makes no external requests and loads no remote fonts or scripts; its two typefaces are bundled (SIL Open Font License)<\/li>\n<\/ul>\n\n<p><strong>Export, WP-CLI and REST<\/strong><\/p>\n\n<ul>\n<li>Download the filtered history as CSV or JSON, for an audit or a support ticket<\/li>\n<li>WP-CLI: <code>wp settings-undo list|diff|undo|undo-group|checkpoint|checkpoints|rollback|export|prune|clear<\/code><\/li>\n<li>A read-only REST route (<code>\/wp-json\/settings-undo\/v1\/changes<\/code>) and, on WordPress 6.9+, a read-only Ability for AI assistants. Neither can change a setting.<\/li>\n<\/ul>\n\n<p><strong>For developers<\/strong><\/p>\n\n<ul>\n<li><code>settings_undo_ignored_options<\/code> \u2013 filter an array of option names or <code>*<\/code> globs to ignore<\/li>\n<li><code>settings_undo_max_value_size<\/code> \u2013 filter the byte cap above which a value is logged but not stored (default 512 KB)<\/li>\n<li><code>settings_undo_alert_options<\/code> \u2013 filter the options that trigger the critical-change email<\/li>\n<li><code>settings_undo_recorded<\/code> \u2013 action fired after a change is stored<\/li>\n<\/ul>\n\n<p>Not in this version: multisite network options, and post content (WordPress revisions already cover that).<\/p>\n\n<!--section=installation-->\n<ol>\n<li>Upload the <code>settings-undo<\/code> folder to <code>\/wp-content\/plugins\/<\/code>, or install it from the Plugins screen.<\/li>\n<li>Activate it. The history tables are created on activation.<\/li>\n<li>Go to <strong>Tools \u2192 Settings Undo<\/strong>. Save any settings page and it will appear there.<\/li>\n<\/ol>\n\n<!--section=faq-->\n<dl>\n<dt id=\"does%20it%20slow%20the%20site%20down%3F\"><h3>Does it slow the site down?<\/h3><\/dt>\n<dd><p>No. Nothing runs on the front end for visitors, apart from the admin-bar menu for logged-in administrators, which you can switch off. Recording happens only when an option actually changes, and only after a cheap check that the option is not on the ignore list. Reading the timeline is a handful of queries per page.<\/p><\/dd>\n<dt id=\"why%20does%20a%20change%20i%20made%20not%20appear%3F\"><h3>Why does a change I made not appear?<\/h3><\/dt>\n<dd><p>Either the option is on the ignore list (transients, cron, caches, version numbers and similar noise), or the value was written by a background process \u2013 cron, WP-CLI or an anonymous request \u2013 which is not recorded unless you switch that on under Settings.<\/p><\/dd>\n<dt id=\"how%20does%20a%20checkpoint%20work%3F\"><h3>How does a checkpoint work?<\/h3><\/dt>\n<dd><p>It records a position in the history, not a copy of your database. Rolling back replays the earliest recorded value of every option changed since then, shows you the result first, and lets you untick anything you want to keep. It can only restore settings the plugin recorded, so a checkpoint is only as complete as the history behind it.<\/p><\/dd>\n<dt id=\"can%20i%20undo%20activating%20or%20deactivating%20a%20plugin%3F\"><h3>Can I undo activating or deactivating a plugin?<\/h3><\/dt>\n<dd><p>The <code>active_plugins<\/code> option is recorded and can be restored, with a typed confirmation. Note that restoring the list does not run a plugin's own activation or deactivation routines.<\/p><\/dd>\n<dt id=\"where%20is%20the%20data%20stored%3F\"><h3>Where is the data stored?<\/h3><\/dt>\n<dd><p>In two tables, <code>{prefix}settings_undo_log<\/code> and <code>{prefix}settings_undo_marks<\/code> (checkpoints, update markers and notes). Uninstalling the plugin leaves them in place unless \"delete data on uninstall\" is enabled.<\/p><\/dd>\n<dt id=\"is%20the%20diff%20available%20for%20every%20change%3F\"><h3>Is the diff available for every change?<\/h3><\/dt>\n<dd><p>Values larger than 512 KB (serialised) are logged as \"too large to store\": you can see that the option changed, who changed it and when, but not the values, and they cannot be undone. The cap can be raised with the <code>settings_undo_max_value_size<\/code> filter.<\/p><\/dd>\n<dt id=\"does%20it%20work%20on%20multisite%3F\"><h3>Does it work on multisite?<\/h3><\/dt>\n<dd><p>This version is built and tested for single sites. Network options are not recorded.<\/p><\/dd>\n\n<\/dl>\n\n<!--section=changelog-->\n<h4>1.1.0<\/h4>\n\n<ul>\n<li>New: checkpoints and rollback \u2013 save a named marker and roll all settings back to it, or roll back everything one person or one plugin changed, with a preview and per-option control.<\/li>\n<li>New: plugin, theme and core update markers on the timeline, with a Roll back button.<\/li>\n<li>New: notes on change sets.<\/li>\n<li>New: optional email alert when a critical option changes (site URL, home URL, admin email, search-engine visibility, open registration, default role).<\/li>\n<li>New: noisy-options hint with one-click ignore.<\/li>\n<li>New: CSV and JSON export, WP-CLI commands, read-only REST route and WordPress Ability.<\/li>\n<li>New: admin-bar menu with the last changes and \"Undo the last change set\".<\/li>\n<li>New: redesigned timeline and detail panel, a roomier diff view, and a redesigned Settings screen.<\/li>\n<li>Bundled Onest and JetBrains Mono fonts (SIL Open Font License); nothing is loaded from the internet.<\/li>\n<\/ul>\n\n<h4>1.0.2<\/h4>\n\n<ul>\n<li>The history table is now recreated automatically if it goes missing while the plugin is active, for example after a migration or restore that skips custom tables.<\/li>\n<li>Readme: describes the ignore list, the Dashboard widget, Delete all history and the inline before\/after values.<\/li>\n<\/ul>\n\n<h4>1.0.1<\/h4>\n\n<ul>\n<li>New animated Settings Undo icon beside the page title.<\/li>\n<\/ul>\n\n<h4>1.0.0<\/h4>\n\n<ul>\n<li>First release: records add, update and delete of any option by a logged-in user; groups a request's writes into one change set; timeline with source, user, date and option filters; key-level diffs; undo one entry or a whole change set; typed confirmation for protected options; masking of secret-looking keys; daily pruning by age and row count.<\/li>\n<\/ul>","raw_excerpt":"Records every settings change: who, what, before and after. Undo in one click or roll back to a checkpoint. Works with any plugin or theme.","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/twd.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/380659","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/twd.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin"}],"about":[{"href":"https:\/\/twd.wordpress.org\/plugins\/wp-json\/wp\/v2\/types\/plugin"}],"replies":[{"embeddable":true,"href":"https:\/\/twd.wordpress.org\/plugins\/wp-json\/wp\/v2\/comments?post=380659"}],"author":[{"embeddable":true,"href":"https:\/\/twd.wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/dotance"}],"wp:attachment":[{"href":"https:\/\/twd.wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=380659"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/twd.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=380659"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/twd.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=380659"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/twd.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=380659"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/twd.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=380659"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/twd.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=380659"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}