{"id":190567,"date":"2024-05-12T04:37:37","date_gmt":"2024-05-12T04:37:37","guid":{"rendered":"https:\/\/wordpress.org\/plugins\/simple-editor-control\/"},"modified":"2026-08-25T02:10:45","modified_gmt":"2026-08-25T02:10:45","slug":"simple-editor-control","status":"publish","type":"plugin","link":"https:\/\/ar.wordpress.org\/plugins\/simple-editor-control\/","author":22011295,"comment_status":"closed","ping_status":"closed","template":"","meta":{"version":"6.0.0","stable_tag":"6.0.0","tested":"7.1","requires":"5.5","requires_php":"7.4","requires_plugins":null,"header_name":"Simple Editor Control \u2013 File History, Diff & Restore","header_author":"tlloancy","header_description":"Surveillance des modifications des fichiers via l'\u00e9diteur de fichiers WordPress.","assets_banners_color":"5e2f21","last_updated":"2026-08-25 02:10:45","external_support_url":"","external_repository_url":"","donate_link":"","header_plugin_uri":"https:\/\/wordpress.org\/plugins\/simple-editor-control\/","header_author_uri":"https:\/\/profiles.wordpress.org\/tlloancy\/","rating":5,"author_block_rating":0,"active_installs":10,"downloads":1948,"num_ratings":1,"support_threads":0,"support_threads_resolved":0,"author_block_count":0,"sections":["description","installation","faq","changelog"],"tags":{"1.0.1":{"tag":"1.0.1","author":"tlloancy","date":"2024-09-25 06:40:09"},"2.0.0":{"tag":"2.0.0","author":"tlloancy","date":"2024-09-25 12:56:36"},"2.0.1":{"tag":"2.0.1","author":"tlloancy","date":"2024-09-25 22:12:53"},"2.0.2":{"tag":"2.0.2","author":"tlloancy","date":"2024-09-27 04:49:48"},"2.1.2":{"tag":"2.1.2","author":"tlloancy","date":"2024-09-28 03:42:41"},"2.3.0":{"tag":"2.3.0","author":"tlloancy","date":"2024-09-29 05:04:29"},"2.4.0":{"tag":"2.4.0","author":"tlloancy","date":"2024-10-12 00:40:04"},"2.4.1":{"tag":"2.4.1","author":"tlloancy","date":"2024-10-13 02:23:37"},"2.5.0":{"tag":"2.5.0","author":"tlloancy","date":"2024-10-14 08:43:38"},"2.6.0":{"tag":"2.6.0","author":"tlloancy","date":"2024-10-19 08:24:18"},"2.7.0":{"tag":"2.7.0","author":"tlloancy","date":"2024-10-19 13:26:42"},"2.7.1":{"tag":"2.7.1","author":"tlloancy","date":"2024-10-19 19:45:00"},"2.7.2":{"tag":"2.7.2","author":"tlloancy","date":"2024-10-21 12:18:48"},"2.7.3":{"tag":"2.7.3","author":"tlloancy","date":"2024-10-25 14:58:14"},"3.0.0":{"tag":"3.0.0","author":"tlloancy","date":"2024-10-26 04:39:51"},"3.0.1":{"tag":"3.0.1","author":"tlloancy","date":"2024-11-06 15:20:43"},"4.0.0":{"tag":"4.0.0","author":"tlloancy","date":"2026-05-11 13:18:19"},"4.0.1":{"tag":"4.0.1","author":"tlloancy","date":"2026-05-11 13:29:30"},"4.1.0":{"tag":"4.1.0","author":"tlloancy","date":"2026-05-11 15:00:22"},"5.0.0":{"tag":"5.0.0","author":"tlloancy","date":"2026-05-26 23:35:50"},"6.0.0":{"tag":"6.0.0","author":"tlloancy","date":"2026-08-25 02:10:45"}},"upgrade_notice":{"6.0.0":"<p>Major rebuild. Fixes file corruption on restore and wrong diffs. Old history is migrated automatically and the legacy table kept as backup. Strongly recommended for all users.<\/p>"},"ratings":{"1":0,"2":0,"3":0,"4":0,"5":1},"assets_icons":{"icon-256x256.png":{"filename":"icon-256x256.png","revision":3159420,"resolution":"256x256","location":"assets","locale":"","width":256,"height":256}},"assets_banners":{"banner-772x250.png":{"filename":"banner-772x250.png","revision":3159421,"resolution":"772x250","location":"assets","locale":"","width":772,"height":250}},"assets_blueprints":{},"all_blocks":[],"tagged_versions":["1.0.1","2.0.0","2.0.1","2.0.2","2.1.2","2.3.0","2.4.0","2.4.1","2.5.0","2.6.0","2.7.0","2.7.1","2.7.2","2.7.3","3.0.0","3.0.1","4.0.0","4.0.1","4.1.0","5.0.0","6.0.0"],"block_files":[],"assets_screenshots":{"screenshot-1.png":{"filename":"screenshot-1.png","revision":3159422,"resolution":"1","location":"assets","locale":"","width":1729,"height":662},"screenshot-2.png":{"filename":"screenshot-2.png","revision":3159422,"resolution":"2","location":"assets","locale":"","width":1693,"height":667}},"screenshots":{"1":"Revision timeline with per-save added\/removed counts and one-click restore.","2":"Side-by-side diff of a tracked save."}},"plugin_section":[],"plugin_tags":[8533,9151,18643,152,6243],"plugin_category":[],"plugin_contributors":[232640],"plugin_business_model":[],"class_list":["post-190567","plugin","type-plugin","status-publish","hentry","plugin_tags-audit","plugin_tags-diff","plugin_tags-file-editor","plugin_tags-restore","plugin_tags-revisions","plugin_contributors-tlloancy","plugin_committers-tlloancy"],"banners":{"banner":"https:\/\/ps.w.org\/simple-editor-control\/assets\/banner-772x250.png?rev=3159421","banner_2x":false,"banner_rtl":false,"banner_2x_rtl":false},"icons":{"svg":false,"icon":"https:\/\/ps.w.org\/simple-editor-control\/assets\/icon-256x256.png?rev=3159420","icon_2x":"https:\/\/ps.w.org\/simple-editor-control\/assets\/icon-256x256.png?rev=3159420","generated":false},"screenshots":[{"src":"https:\/\/ps.w.org\/simple-editor-control\/assets\/screenshot-1.png?rev=3159422","caption":"Revision timeline with per-save added\/removed counts and one-click restore."},{"src":"https:\/\/ps.w.org\/simple-editor-control\/assets\/screenshot-2.png?rev=3159422","caption":"Side-by-side diff of a tracked save."}],"raw_content":"<!--section=description-->\n<p>You edited <code>functions.php<\/code> in <strong>Appearance \u2192 Theme File Editor<\/strong>, saved, and the site went down. Or a plugin file was quietly modified and you want to know who, when, and what exactly changed.<\/p>\n\n<p>Simple Editor Control records <strong>every save made through the WordPress theme and plugin file editors<\/strong> \u2014 automatically, with zero setup. For each save it stores the complete file, compressed and sealed with a SHA-256 integrity hash, along with the user and the timestamp.<\/p>\n\n<p><strong>History you can trust<\/strong><\/p>\n\n<ul>\n<li>Every revision stores the <em>full file content<\/em> \u2014 revisions are independent, so your history can never drift or corrupt.<\/li>\n<li>The very first tracked save also captures the file as it was <em>before<\/em> the change, so the original state is always recoverable.<\/li>\n<li>A save is only recorded after WordPress actually wrote it. Saves that core refused or rolled back (fatal PHP error) never pollute the history.<\/li>\n<li>SHA-256 integrity check on every read: a corrupted revision is detected and refused, never silently written to disk.<\/li>\n<\/ul>\n\n<p><strong>Diffs worthy of git<\/strong><\/p>\n\n<ul>\n<li>Real Myers diff algorithm (jsdiff) rendered by diff2html \u2014 side-by-side or unified, with syntax awareness.<\/li>\n<li>Instant context switching (0 to 25 lines) with no server round-trip.<\/li>\n<li>Added\/removed line counts on every revision in the timeline.<\/li>\n<li><strong>Compare any two revisions<\/strong> of a file, not just consecutive ones.<\/li>\n<\/ul>\n\n<p><strong>Restore without fear<\/strong><\/p>\n\n<ul>\n<li>One-click restore of any revision (arm, then confirm \u2014 no accidental clicks).<\/li>\n<li>Before overwriting, the current on-disk content is snapshotted as a new revision: a restore can never lose data, even changes made outside WordPress.<\/li>\n<li>When restoring a PHP file of an <em>active<\/em> plugin or theme, the site is probed afterwards; if a fatal error is detected, the previous content is put back automatically. No white screen.<\/li>\n<li>Restore requires the same capabilities as the core editors, and is disabled entirely when <code>DISALLOW_FILE_EDIT<\/code> is set \u2014 the audit trail never becomes a policy bypass.<\/li>\n<\/ul>\n\n<p><strong>Respectful of your site<\/strong><\/p>\n\n<ul>\n<li>Old revisions are pruned automatically (configurable, default: last 100 per file).<\/li>\n<li>Deactivation keeps your history; deletion removes everything, including database tables.<\/li>\n<li>All third-party libraries are bundled with human-readable sources: <a href=\"https:\/\/github.com\/kpdecker\/jsdiff\">jsdiff<\/a> (BSD-3-Clause) and <a href=\"https:\/\/github.com\/rtfpessoa\/diff2html\">diff2html<\/a> (MIT).<\/li>\n<\/ul>\n\n<!--section=installation-->\n<ol>\n<li>Install and activate through <strong>Plugins \u2192 Add New<\/strong>, or upload to <code>\/wp-content\/plugins\/<\/code>.<\/li>\n<li>That's it \u2014 tracking is automatic. Edit any file through <strong>Appearance \u2192 Theme File Editor<\/strong> or <strong>Plugins \u2192 Plugin File Editor<\/strong>.<\/li>\n<li>Browse the history under <strong>Tools \u2192 Editor Control<\/strong>.<\/li>\n<\/ol>\n\n<!--section=faq-->\n<dl>\n<dt id=\"is%20this%20related%20to%20gutenberg%20or%20the%20post%20editor%3F\"><h3>Is this related to Gutenberg or the post editor?<\/h3><\/dt>\n<dd><p>No. It tracks the <em>file<\/em> editors (<code>theme-editor.php<\/code> and <code>plugin-editor.php<\/code>), which edit PHP\/CSS\/JS files of your themes and plugins.<\/p><\/dd>\n<dt id=\"are%20changes%20made%20via%20ftp%20or%20ssh%20tracked%3F\"><h3>Are changes made via FTP or SSH tracked?<\/h3><\/dt>\n<dd><p>Not live. However, if a file drifted via FTP and you later restore a revision, the drifted content is snapshotted first \u2014 so even those changes end up preserved rather than lost.<\/p><\/dd>\n<dt id=\"what%20happens%20when%20i%20restore%20a%20broken%20php%20file%3F\"><h3>What happens when I restore a broken PHP file?<\/h3><\/dt>\n<dd><p>If the file belongs to an active plugin or theme, the plugin probes the site right after writing. On a fatal error it puts the previous content back automatically and tells you. Your site stays up.<\/p><\/dd>\n<dt id=\"i%20upgraded%20from%205.x%20%E2%80%94%20where%20is%20my%20old%20history%3F\"><h3>I upgraded from 5.x \u2014 where is my old history?<\/h3><\/dt>\n<dd><p>It was migrated automatically into the new storage engine, with a corrected replay of the old diff chains (labelled \u201cImported\u201d in the timeline). The old table is kept untouched as a backup and only removed if you delete the plugin.<\/p><\/dd>\n<dt id=\"how%20big%20does%20the%20database%20get%3F\"><h3>How big does the database get?<\/h3><\/dt>\n<dd><p>Each revision stores the full file, gzip-compressed \u2014 a typical <code>functions.php<\/code> compresses to a few KB. With the default cap of 100 revisions per file, a heavily edited file uses well under 1 MB.<\/p><\/dd>\n<dt id=\"can%20i%20delete%20the%20history%3F\"><h3>Can I delete the history?<\/h3><\/dt>\n<dd><p>Deactivating preserves it. Deleting the plugin removes everything: both database tables and all options.<\/p><\/dd>\n\n<\/dl>\n\n<!--section=changelog-->\n<h4>6.0.0 (25-Aug-2026)<\/h4>\n\n<p>Complete rebuild of the storage engine, the diff pipeline and the interface.<\/p>\n\n<ul>\n<li><strong>New storage engine<\/strong> \u2014 every revision now stores the full file content (gzip + SHA-256). Revisions are independent: no more diff chains, no replay, no possible history corruption. Existing 4.x\/5.x history is migrated automatically; the legacy table is preserved as a backup.<\/li>\n<li><strong>Fixed: restores could scramble files.<\/strong> The old replay applied multi-line insertions in reverse order, which could write broken PHP to disk. Migration replays old chains with the corrected order; new storage makes the bug impossible by design.<\/li>\n<li><strong>Fixed: the diff viewer dropped lines.<\/strong> Multi-line insertions were displayed as a single line at the wrong position. Diffs are now produced by jsdiff (real Myers algorithm) and match what git shows.<\/li>\n<li><strong>Fixed: saves are recorded only if they actually happened.<\/strong> Recording now happens after WordPress finished writing \u2014 saves refused by core or rolled back after a fatal error no longer appear in the history.<\/li>\n<li><strong>Fixed: quadratic diff engine removed.<\/strong> Editing large files (~2000+ lines) could exhaust PHP memory on save. Per-revision stats now use WordPress core's Text_Diff with a size guard.<\/li>\n<li><strong>New: crash-proof restore.<\/strong> Restoring a PHP file of an active plugin\/theme probes the site and rolls back automatically on fatal errors.<\/li>\n<li><strong>New: pre-restore snapshot.<\/strong> Whatever is on disk is saved as a revision before any restore overwrites it.<\/li>\n<li><strong>New: compare any two revisions<\/strong> of a file.<\/li>\n<li><strong>New: onboarding empty state<\/strong>, per-revision +\/- counts, origin badges (initial state, restored, imported), user display names, local-time dates (previously shown in the wrong timezone).<\/li>\n<li><strong>New: automatic pruning<\/strong> with a configurable per-file cap (default 100).<\/li>\n<li><strong>New: <code>uninstall.php<\/code><\/strong> \u2014 deleting the plugin now really removes its tables and options, as the FAQ always claimed.<\/li>\n<li><strong>New: <code>.pot<\/code> file shipped<\/strong>; the plugin is now actually translatable, as the readme always claimed.<\/li>\n<li><strong>Security: restore respects <code>DISALLOW_FILE_EDIT<\/code> \/ <code>DISALLOW_FILE_MODS<\/code><\/strong> and requires <code>edit_plugins<\/code> \/ <code>edit_themes<\/code> rather than only <code>manage_options<\/code>.<\/li>\n<li>Removed debug <code>error_log()<\/code> calls from production code.<\/li>\n<li>Redesigned admin UI following native WordPress admin patterns.<\/li>\n<li>Tested up to WordPress 7.1.<\/li>\n<\/ul>\n\n<h4>5.0.0 (27-May-2026)<\/h4>\n\n<ul>\n<li>One-click file restore, restore audit entries, <code>source_type<\/code> column, inline notices, editor deep links, diff re-render fixes, DB auto-upgrade.<\/li>\n<\/ul>\n\n<h4>4.1.0 (11-May-2026)<\/h4>\n\n<ul>\n<li>Fixed initial revision logic using the stored snapshot.<\/li>\n<\/ul>\n\n<h4>4.0.1 (11-May-2026)<\/h4>\n\n<ul>\n<li>Fixed incorrect table name reference.<\/li>\n<\/ul>\n\n<h4>4.0.0 (11-May-2026)<\/h4>\n\n<ul>\n<li>Migration to the sec_revisions table, hardened AJAX security, LCS diff engine, two-panel UI.<\/li>\n<\/ul>\n\n<h4>3.0.1<\/h4>\n\n<ul>\n<li>Minor fixes.<\/li>\n<\/ul>","raw_excerpt":"Broke functions.php in the file editor? Every save is tracked with git-style diffs and restorable in one click \u2014 with automatic crash rollback.","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/ar.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/190567","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/ar.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin"}],"about":[{"href":"https:\/\/ar.wordpress.org\/plugins\/wp-json\/wp\/v2\/types\/plugin"}],"replies":[{"embeddable":true,"href":"https:\/\/ar.wordpress.org\/plugins\/wp-json\/wp\/v2\/comments?post=190567"}],"author":[{"embeddable":true,"href":"https:\/\/ar.wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/tlloancy"}],"wp:attachment":[{"href":"https:\/\/ar.wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=190567"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/ar.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=190567"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/ar.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=190567"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/ar.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=190567"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/ar.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=190567"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/ar.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=190567"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}