{"id":303002,"date":"2026-05-27T23:18:17","date_gmt":"2026-05-27T23:18:17","guid":{"rendered":"https:\/\/wordpress.org\/plugins\/optrion\/"},"modified":"2026-05-28T00:30:30","modified_gmt":"2026-05-28T00:30:30","slug":"orpharion","status":"publish","type":"plugin","link":"https:\/\/skr.wordpress.org\/plugins\/orpharion\/","author":13218462,"comment_status":"closed","ping_status":"closed","template":"","meta":{"version":"1.1.4","stable_tag":"1.1.4","tested":"7.0","requires":"6.8","requires_php":"8.3","requires_plugins":null,"header_name":"Orpharion","header_author":"mt8biz","header_description":"Track which plugin or theme accesses each wp_options row, then quarantine or clean orphans.","assets_banners_color":"090d16","last_updated":"2026-05-28 00:30:30","external_support_url":"","external_repository_url":"","donate_link":"","header_plugin_uri":"","header_author_uri":"","rating":0,"author_block_rating":0,"active_installs":0,"downloads":56,"num_ratings":0,"support_threads":0,"support_threads_resolved":0,"author_block_count":0,"sections":["description","installation","faq","changelog"],"tags":{"1.1.3":{"tag":"1.1.3","author":"mt8.biz","date":"2026-05-27 23:18:00"},"1.1.4":{"tag":"1.1.4","author":"mt8.biz","date":"2026-05-28 00:30:30"}},"upgrade_notice":[],"ratings":[],"assets_icons":{"icon-128x128.png":{"filename":"icon-128x128.png","revision":3551404,"resolution":"128x128","location":"assets","locale":"","width":128,"height":128},"icon-256x256.png":{"filename":"icon-256x256.png","revision":3551404,"resolution":"256x256","location":"assets","locale":"","width":256,"height":256}},"assets_banners":{"banner-1544x500.png":{"filename":"banner-1544x500.png","revision":3551370,"resolution":"1544x500","location":"assets","locale":"","width":1544,"height":500},"banner-772x250.png":{"filename":"banner-772x250.png","revision":3551370,"resolution":"772x250","location":"assets","locale":"","width":772,"height":250}},"assets_blueprints":{},"all_blocks":[],"tagged_versions":["1.1.3","1.1.4"],"block_files":[],"assets_screenshots":[],"screenshots":[]},"plugin_section":[],"plugin_tags":[1328,3786,153,2218,247],"plugin_category":[54,59],"plugin_contributors":[78477],"plugin_business_model":[],"class_list":["post-303002","plugin","type-plugin","status-publish","hentry","plugin_tags-autoload","plugin_tags-cleanup","plugin_tags-database","plugin_tags-options","plugin_tags-performance","plugin_category-security-and-spam-protection","plugin_category-utilities-and-tools","plugin_contributors-mt8biz","plugin_committers-mt8biz"],"banners":{"banner":"https:\/\/ps.w.org\/orpharion\/assets\/banner-772x250.png?rev=3551370","banner_2x":"https:\/\/ps.w.org\/orpharion\/assets\/banner-1544x500.png?rev=3551370","banner_rtl":false,"banner_2x_rtl":false},"icons":{"svg":false,"icon":"https:\/\/ps.w.org\/orpharion\/assets\/icon-128x128.png?rev=3551404","icon_2x":"https:\/\/ps.w.org\/orpharion\/assets\/icon-256x256.png?rev=3551404","generated":false},"screenshots":[],"raw_content":"<!--section=description-->\n<p>The <code>wp_options<\/code> table accumulates leftovers from plugins and themes that have been deactivated or deleted but never cleaned up. Those rows bloat the autoload payload on every page load and there is no built-in way to decide which ones are safe to remove.<\/p>\n\n<p>Orpharion observes which options are actually read at runtime, attributes each read to the plugin or theme that caused it, and surfaces the raw signals (accessor, autoload flag, size, last-read timestamp) so administrators can decide what to remove:<\/p>\n\n<ol>\n<li><strong>Observe<\/strong> \u2014 the tracker records when and by whom each option is read, using the live PHP backtrace to identify the real caller.<\/li>\n<li><strong>Quarantine<\/strong> \u2014 rename the option temporarily so WordPress and the accessing plugin can no longer see it; confirm nothing breaks.<\/li>\n<li><strong>Delete<\/strong> \u2014 the row is removed from both <code>wp_options<\/code> and the tracking table. Use the <strong>Export selected<\/strong> bulk action first if you want a restore copy; Orpharion never writes option_value content to the server filesystem on your behalf (option_value can contain API keys, SMTP credentials, and other secrets that should not leak into backups of <code>wp-content\/<\/code>).<\/li>\n<\/ol>\n\n<p>Core WordPress options are locked out of destructive operations, on both the deletion and the import side.<\/p>\n\n<p>The full PHP source ships uncompiled with the plugin; the non-compiled source of the compiled admin bundle (<code>build\/index.js<\/code>, <code>build\/index.css<\/code>) is published at https:\/\/github.com\/mt8\/orpharion \u2014 see the <strong>Source code<\/strong> section below for the exact build steps.<\/p>\n\n<h3>Source code<\/h3>\n\n<p>The published plugin ships with the compiled admin bundle in <code>build\/<\/code> (<code>build\/index.js<\/code>, <code>build\/index.css<\/code>, <code>build\/index.asset.php<\/code>). The non-compiled source for that bundle lives in <code>src\/<\/code> in the public GitHub repository:<\/p>\n\n<ul>\n<li>Repository: https:\/\/github.com\/mt8\/orpharion<\/li>\n<li>Build tool: <a href=\"https:\/\/www.npmjs.com\/package\/@wordpress\/scripts\">@wordpress\/scripts<\/a> (uses webpack + Babel under the hood).<\/li>\n<li><p>Reproduce the bundle:<\/p>\n\n<ol>\n<li>Clone the repository.<\/li>\n<li>Install dependencies: <code>npm install<\/code> (Node.js version compatible with <code>@wordpress\/scripts<\/code> is required).<\/li>\n<li>Build: <code>npm run build<\/code> \u2014 produces the same <code>build\/<\/code> files that are shipped with the plugin.<\/li>\n<li>Watch mode for development: <code>npm run start<\/code>.<\/li>\n<\/ol><\/li>\n<\/ul>\n\n<p>PHP code is shipped uncompiled and is the same in the published ZIP and in the repository.<\/p>\n\n<h3>Features<\/h3>\n\n<ul>\n<li>Per-option read tracking via dynamically registered <code>option_{$name}<\/code> filters, so every <code>get_option()<\/code> call is attributed to the real plugin or theme on the call stack.<\/li>\n<li>Accessor inference (live tracker data \u2192 slug prefix \u2192 curated core list) with an active \/ inactive flag so you can filter down to options whose owner is no longer present.<\/li>\n<li>Sortable options table with individual columns for accessor, autoload, size, and last-read timestamp \u2014 no opaque composite score.<\/li>\n<li>Quarantine mode with automatic expiry (restore \/ delete \/ keep) and a manifest table that flags options that are still being accessed.<\/li>\n<li><strong>No server-side backup<\/strong>: JSON exports are browser downloads (or explicit CLI <code>--output<\/code>), never written to disk on the server \u2014 so option_value content does not leak into <code>wp-content\/<\/code> snapshots.<\/li>\n<li>REST API under <code>\/wp-json\/orpharion\/v1\/*<\/code> (requires <code>manage_options<\/code>).<\/li>\n<li>WP-CLI commands for scripted pipelines, including <code>--accessor-type<\/code> \/ <code>--inactive-only<\/code> filters on <code>list<\/code>, <code>export<\/code>, and <code>clean<\/code> (<code>clean<\/code> requires an explicit <code>--i-have-a-backup<\/code> acknowledgment).<\/li>\n<\/ul>\n\n<h3>License<\/h3>\n\n<p>This plugin is licensed under the GPL, version 2 or later.<\/p>\n\n<!--section=installation-->\n<ol>\n<li>Upload the plugin directory or install the zip via <strong>Plugins \u2192 Add New \u2192 Upload<\/strong>.<\/li>\n<li>Activate the plugin.<\/li>\n<li>Open the <strong>Orpharion<\/strong> menu in the WordPress admin sidebar and let the tracker run for a few days before acting on the results.<\/li>\n<\/ol>\n\n<!--section=faq-->\n<dl>\n<dt id=\"is%20tracking%20safe%20to%20leave%20on%20in%20production%3F\"><h3>Is tracking safe to leave on in production?<\/h3><\/dt>\n<dd><p>Yes. Tracking is buffered in memory and flushed once per request at <code>shutdown<\/code>. A sampling-rate option and a 10-minute activation window triggered by admin traffic keep the overhead predictable.<\/p><\/dd>\n<dt id=\"will%20deleting%20an%20option%20break%20my%20site%3F\"><h3>Will deleting an option break my site?<\/h3><\/dt>\n<dd><p>Use Quarantine first. A quarantined option is renamed, not deleted; if anything breaks you can restore it with one click. Only permanently delete after you have confirmed nothing is broken during the quarantine window.<\/p><\/dd>\n<dt id=\"what%20happens%20to%20my%20data%20if%20i%20uninstall%20the%20plugin%3F\"><h3>What happens to my data if I uninstall the plugin?<\/h3><\/dt>\n<dd><p>Uninstalling restores any active quarantines to their original names, drops the custom tracking and quarantine tables, removes plugin-owned options, and clears the scheduled cron job. Your regular <code>wp_options<\/code> data is untouched.<\/p><\/dd>\n<dt id=\"where%20does%20the%20name%20%22orpharion%22%20come%20from%3F\"><h3>Where does the name \"Orpharion\" come from?<\/h3><\/dt>\n<dd><p>The orpharion is a Renaissance plucked-string instrument invented in England in 1581 by John Rose. The name is a 16th-century coinage from Orpheus and Arion, two legendary musicians of Greek mythology. Music by John Dowland, William Byrd, and others was published for it. The plugin borrows the name as a nod to the idea of carefully tuning what sits in your <code>wp_options<\/code> table.<\/p><\/dd>\n\n<\/dl>\n\n<!--section=changelog-->\n<h4>1.1.4<\/h4>\n\n<ul>\n<li>Assets: add the square plugin icon (128\u00d7128 and 256\u00d7256) used by the WordPress.org plugin directory listing and the installed plugins screen. No functional changes.<\/li>\n<\/ul>\n\n<h4>1.1.3<\/h4>\n\n<ul>\n<li>readme: the <strong>Source code<\/strong> section (public GitHub repository and <code>npm run build<\/code> reproduction steps for the compiled admin bundle) is now placed directly after <strong>Description<\/strong> so the build-source pointer is immediately visible.<\/li>\n<li>readme: <code>Tested up to<\/code> bumped to 7.0 to reflect the current WordPress release.<\/li>\n<li>Read tracker: plugin and mu-plugin frame classification in <code>Tracker::classify_trace()<\/code> now goes through <code>plugin_basename()<\/code> instead of comparing against <code>WP_PLUGIN_DIR<\/code> \/ <code>WPMU_PLUGIN_DIR<\/code> directly. This reuses WP core's plugins-root resolution (including symlink awareness via <code>$wp_plugin_paths<\/code>) without duplicating the constant references in plugin code. Behavior is unchanged for standard setups; the legacy <code>mu:<\/code> slug prefix on mu-plugin readers is dropped (it was not consulted anywhere downstream).<\/li>\n<\/ul>\n\n<h4>1.1.2<\/h4>\n\n<ul>\n<li>Admin menu icon: the opacity override is now attached to a registered style handle via <code>wp_add_inline_style()<\/code> on <code>admin_enqueue_scripts<\/code> instead of being printed as an inline <code>&lt;style&gt;<\/code> tag from <code>admin_head<\/code>. Visual behavior is unchanged.<\/li>\n<li>Read tracker: the <code>WP_PLUGIN_DIR<\/code> and <code>WPMU_PLUGIN_DIR<\/code> references used to classify backtrace frames are now routed through <code>wp_normalize_path()<\/code>, with a comment recording why those constants are referenced (identifying <em>other<\/em> plugins' install roots \u2014 Orpharion's own location is resolved from <code>__FILE__<\/code>).<\/li>\n<li>Documentation: <code>readme.txt<\/code> now includes a \"Source code\" section pointing to the public GitHub repository (<code>https:\/\/github.com\/mt8\/orpharion<\/code>) and the <code>npm run build<\/code> flow used to regenerate the bundled admin assets.<\/li>\n<\/ul>\n\n<h4>1.1.1<\/h4>\n\n<ul>\n<li>WP-CLI: <code>wp orpharion export --output=&lt;file&gt;<\/code> now requires a bare <code>*.json<\/code> filename and always writes into <code>wp-content\/uploads\/orpharion\/<\/code>. Absolute or relative paths and non-<code>.json<\/code> extensions are rejected so option_value content (which can include API keys, SMTP credentials, and other secrets) cannot be written to a web-accessible location. The export directory is created on demand with <code>index.html<\/code> and <code>.htaccess<\/code> so it is not browseable.<\/li>\n<\/ul>\n\n<h4>1.1.0<\/h4>\n\n<ul>\n<li>Renamed the plugin from \"Optrion\" to \"Orpharion\" to remove an external trademark conflict before the WordPress.org review. The slug, text domain, REST namespace, WP-CLI command, internal option keys, hooks, and the quarantine rename prefix all move from <code>optrion<\/code>\/<code>optrion_<\/code> to <code>orpharion<\/code>\/<code>orpharion_<\/code>. There is no in-place migration: this is a one-shot rename done before any wp.org release.<\/li>\n<\/ul>\n\n<h4>1.0.3<\/h4>\n\n<ul>\n<li>Consolidated the protected-option rules (WordPress core options, Orpharion's own <code>orpharion_*<\/code> namespace, and the quarantine rename namespace) into a single <code>ProtectedOptions<\/code> helper. The cleaner, importer, quarantine, and options-list filter now all derive their behavior from that one source of truth, with consistent name normalization across all of them.<\/li>\n<\/ul>\n\n<h4>1.0.2<\/h4>\n\n<ul>\n<li>Options list: pick rows per page (25 \/ 50 \/ 100 \/ 200) and jump directly to a page number.<\/li>\n<li>Options list: the quarantine \/ export \/ delete action bar is now also rendered below the table, so you can act on a selection without scrolling back up.<\/li>\n<li>Hardened the protected-option check to match the storage layer's collation semantics (case-insensitive, trailing whitespace tolerant), so a non-canonical spelling cannot slip past Orpharion's safeguards.<\/li>\n<\/ul>\n\n<h4>1.0.1<\/h4>\n\n<ul>\n<li>Hardened the importer to mirror the cleaner's protected-name set: WordPress core options, Orpharion's own internal options (<code>orpharion_*<\/code>), and the quarantine rename namespace are skipped instead of being written to <code>wp_options<\/code>. Skipped entries are reported in the import summary and the WP-CLI output.<\/li>\n<\/ul>\n\n<h4>1.0.0<\/h4>\n\n<ul>\n<li>Initial public release.<\/li>\n<li>Per-option read tracking: every <code>get_option()<\/code> call is attributed to the real plugin or theme on the PHP backtrace.<\/li>\n<li>Options list with individual signal columns (accessor, autoload, size, last accessed) and inactive-only \/ autoload-only \/ accessor-type filters.<\/li>\n<li>Quarantine workflow with manifest table, automatic expiry (restore \/ delete \/ keep), and a still-accessed guard that blocks deletion of options that are still being read.<\/li>\n<li>No server-side persistence of option_value content: JSON exports are browser downloads only.<\/li>\n<li>REST API under <code>\/wp-json\/orpharion\/v1\/*<\/code> (requires <code>manage_options<\/code>).<\/li>\n<li>WP-CLI commands for scripted pipelines, including <code>--accessor-type<\/code>, <code>--inactive-only<\/code>, and <code>--autoload-only<\/code> filters on <code>list<\/code>, <code>export<\/code>, and <code>clean<\/code>.<\/li>\n<li>Full Japanese localization.<\/li>\n<\/ul>","raw_excerpt":"Track which plugin or theme accesses each wp_options row, then quarantine or clean orphans.","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/skr.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/303002","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/skr.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin"}],"about":[{"href":"https:\/\/skr.wordpress.org\/plugins\/wp-json\/wp\/v2\/types\/plugin"}],"replies":[{"embeddable":true,"href":"https:\/\/skr.wordpress.org\/plugins\/wp-json\/wp\/v2\/comments?post=303002"}],"author":[{"embeddable":true,"href":"https:\/\/skr.wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/mt8biz"}],"wp:attachment":[{"href":"https:\/\/skr.wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=303002"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/skr.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=303002"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/skr.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=303002"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/skr.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=303002"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/skr.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=303002"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/skr.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=303002"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}