- 0.1.18: Shorter MCP ability descriptions. The opening sentence of get-site-report and list-sites now says what the ability does and returns in under 130 characters, because discover-abilities lists only that sentence. The detail follows unchanged. Wording only: no change to behaviour, inputs or outputs.
- 0.1.17: Sweeps that lose a batch now finish. A batch could die without completing, for example when the host killed the PHP process, and since each batch queues the next one only when it ends, nothing picked the sweep up again: on Prince Park Touch roughly one daily sweep in three stopped part way, so stale usage rows were never cleared and counts were not refreshed, and Action Scheduler reported the batch as failed an hour later. Each batch now records the last post it scanned, and a watchdog job checks every 15 minutes (filterable with lh_block_and_shortcode_auditor_return_stall_timeout) while a sweep is running; if no batch has finished in that time it resumes the sweep from that post under a new token, so a batch that was only stuck stops instead of racing it. Batches also keep scanned posts out of the in-memory object cache, since one queue runner can run many batches in a single process and with a persistent object cache nothing flushed it between them. Uninstall removes the new job and option.
- 0.1.16: The auditor’s MCP abilities now end their descriptions with the permission they need, “Requires install_plugins; main site only.” (following the return_mcp_capability filter), and describe their paging, sorting and registration-filter parameters, so MCP clients know who can call them and how to page through results.
- 0.1.15: Shortened the Description header to 150 characters or fewer, the wordpress.org limit that the compiled readme.txt enforces, so the plugin’s readme compiles and it can be pushed (lh-tasks 147801, part 5). plugin_version() now reads the Version header with get_file_data() instead of returning a hardcoded copy, so it can no longer drift from the header. No other functional change.
- 0.1.14: Version 0.1.14: exclude the ActivityPub plugin’s ap_outbox post type from scanning by default. Its posts are machine-written copies of outgoing fediverse activities, not editable content, so blocks and shortcodes in them were double-counted and reported against items that cannot be edited (for example an insert_post_block shortcode on princesparktouch outbox item 150232). ActivityPub profile extra fields (ap_extrafield, ap_extrafield_blog) are real user content and are still scanned. Scanner version goes to 5, so every site runs a fresh sweep and the existing outbox rows are removed as stale when it finishes. The sweep token check is marked impure for PHPStan, since another request can change the token between calls.
- 0.1.13: Version 0.1.13: fixes from a Plugin Check and PHPStan review. Adds the GPLv2-or-later License and License URI headers. Fixes a race where a forced re-sweep did not stop a sweep chain already running, so the old chain could delete rows the new one had not rewritten yet: each sweep now carries a token and superseded batches exit. Daily sweep and count refresh jobs now use void callbacks, the ability registrar calls each ability class’s register method directly, uninstall runs inside a prefixed function instead of using a global variable, and the readme description is shortened. The remaining findings are covered by the accepted list in conventions/coding-standards, which gained entries for plugin-owned custom tables, read-only admin screen parameters, the shared LH Network Tools menu and Plugin Check prefix misdetection.
- 0.1.12: Version 0.1.12: the usage list table’s network mode now uses the shared describe_object helper in the MCP abilities registrar for edit and view URLs (post edit screen, Site Editor for templates and template parts, the site’s widgets screen), instead of its own duplicate network_edit_link method, which is removed. The network screen and the find-tag-usage ability now build these links from one place. No behaviour change; site mode is unchanged.
- 0.1.11: Version 0.1.11: MCP abilities, registered on the main site only and gated to install_plugins (filterable), one class per ability. list-sites returns every active site with registered and unregistered counts, unregistered uses and capture and sweep state. get-site-report returns one site’s tags, filterable by type, registration and search. find-tag-usage returns a tag’s per-site summary and every post, template or widget using it network-wide, with titles and edit and view URLs. rescan-site asks a site to recapture and re-sweep itself. The registrar loads in every request since MCP runs over REST, and holds shared helpers; storage gains get_tag_sites and query_usage_network.
- 0.1.10: Version 0.1.10: network admin screen under the shared LH Network Tools menu (install_plugins, filterable). The overview lists every active site with unregistered and registered block and shortcode counts, unregistered uses and last update, with an All or With unregistered view, search and sorting. Each site opens its tag list (reusing the per-site summary table) with a site switcher and scan status, and each tag opens a details view rendered inside switch_to_blog, using a network mode of the usage table that builds edit links without the site’s post type registrations and hides per-item rescan. A network Rescan clears that site’s stored scanner version and fires a loopback so the site re-sweeps itself in its own context. Adds get_network_site_totals to storage.
- 0.1.9: Version 0.1.9: per-site admin screen under Tools > Blocks & Shortcodes, for site administrators (manage_options, filterable). The summary view lists the site’s registered and unregistered blocks and shortcodes with All, Unregistered and Registered views, a type filter, search, sortable provider and count columns, scan status and a Rescan action. Each used tag links to a details view listing every post or widget using it, with status views, Edit (including Site Editor templates), View and per-item Rescan actions. Adds paginated storage read methods; list tables take site ID and base URL so the network screen can reuse them. Admin classes load only in admin requests.
- 0.1.8: Version 0.1.8: exclude lh_wpn_message from scanning by default. These are machine-written web push notification logs (print_r dumps of the payload), tens of thousands of them on the main site, which only ever produced false positives and dominated sweep time. Scanner version goes to 4 so every site starts a fresh forced sweep and the old rows for these posts are removed as stale when it finishes. The exclusion stays filterable via the excluded post types filter.
- 0.1.7: Version 0.1.7: stricter unregistered shortcode detection (scanner version 3, which forces a re-sweep on every site). The print_r check now decodes HTML entities first, since newer lh_wpn_message push logs store the arrow escaped and about 9,300 main-site posts were still counted. Bare single-word bracketed text such as [the], [link] or [comments] in prose is no longer counted unless the tag is currently registered, has key=value attributes, or is used self-closing or enclosing; tags containing an underscore or hyphen still count as before. The candidate filter now also receives the match shape (attributes, self-closing, enclosing).
- 0.1.6: Version 0.1.6: background jobs move to Action Scheduler when available, with WP-Cron as the automatic fallback and no hard dependency. Adds a queue class that every scheduling call goes through. The scanner’s daily sweep, batch chain and coalesced count refresh now use it; the batch chain enqueues each next batch as an async job, so Action Scheduler keeps a sweep running within one queue-runner request instead of one batch per cron spawn. Any daily sweep still in WP-Cron is removed once when Action Scheduler is in use, and the schedule check runs at most every 12 hours per site. Uninstall clears jobs from both backends.
- 0.1.5: Version 0.1.5: shortcode false-positive fix and scanner versioning. Bracketed keys in print_r output stored as post content (for example lh_wpn_message push notification logs on the main site, around 650 posts) were counted as unregistered shortcodes; a match followed by => is now ignored. Adds a per-site scanner version option: when the scanning logic version changes, the site starts a fresh forced sweep on its next request instead of waiting for the daily sweep, so old false positives are cleared. start_sweep gains a force flag, and uninstall removes the new option.
- 0.1.4: Version 0.1.4: fix concurrent summary rewrites. The per-site summary lock used wp_cache_add, which is not atomic on this cache backend, so when the 0.1.3 version bump changed every site’s registry signature, busy sites ran several captures at once and logged duplicate-key errors on the summary table. The lock is now a MySQL GET_LOCK with zero wait, released with RELEASE_LOCK and automatically if the request dies. A signature-triggered capture also re-reads the stored signature after taking the lock and skips if another request has just captured. The version bump itself forces a clean recapture on every site.
- 0.1.3: Version 0.1.3: content scanner. Each site scans its own posts (all post types except system types, all statuses except auto-draft, inherit and trash) in cron batches of 100 via a daily sweep plus an immediate first sweep, rescans single posts on save, trash, untrash and delete, and scans block, text and custom HTML widgets. Blocks are found with a recursive parse_blocks walk, shortcodes with core’s shortcode regex using a generic lowercase tag pattern, ignoring HTML comments, pre and code elements, escaped tags, single-character tags and markdown-style links. Usage rows go to the central usage table, stale rows are removed at sweep end, and summary counts are refreshed from the last captured registry, with a loopback request to trigger a fresh registry capture. Storage gains get_site_registered_rows, delete_object_type_usage and delete_stale_usage; uninstall now also clears each site’s cron events and options.
- 0.1.2: Version 0.1.2: registry capture. Each site captures its own registered blocks and shortcodes at shutdown on a front-end request, with a provider guess per tag (asset URL, then callback file, then block namespace), and rewrites its summary rows merged with stored usage totals. Capture runs only when the site’s registry signature (active plugins, network plugins, theme, plugin version) changes or a capture is requested, behind an object-cache lock. Adds get_site_usage_totals() to the storage class.
- 0.1.1: Version 0.1.1: wire up central storage. Adds Network: true, Plugin URI and Author URI headers; plugin_init now loads the storage class, installs or upgrades the two central tables (summary and usage) on init when the network schema version option is out of date, and removes a site’s rows when the site is deleted via wp_uninitialize_site. Also adds uninstall.php and includes/index.php. No reporting or scanning yet.
- 0.1.0: Initial scaffold via lh-mcp-plugin-scaffolder: blank inactive plugin with main file, index.php guard and readme.md. No functionality yet.
Changelog
If you like this plugin please consider making a donation to further development