Digital Sovereignty for everyone

Changelog

  • 3.4.0: Breaking change: the get-errors and get-error abilities now return site_id instead of blog_id on each error, in line with every other LocalHero ability, which names a site site_id. There is no blog_id alias. The log table and the admin screen keep blog_id; only the ability output changes.
  • 3.3.4: Shorter MCP ability descriptions. The opening sentence of get-errors and get-error-stats now says what the ability does and returns in under 125 characters, because discover-abilities lists only that sentence. The detail follows unchanged. Wording only: no change to behaviour, inputs or outputs.
  • 3.3.3: Removes the class_exists() guards wrapped around the plugin’s own class declarations (the main plugin class, the table class and the admin list table). The guards protected nothing, since WordPress loads each plugin file once and the includes are loaded with require_once, and on this server an unextended class wrapped this way can be bound at compile time, making the guard skip the plugin’s setup silently with no error, as happened to LH Tasks in September 2026. Behaviour is unchanged. The class_exists() checks for other plugins’ classes (WP_List_Table, LH Beacon) stay.
  • 3.3.2: Source file URLs are now stored exactly as reported. They were sanitised as plain text, which deletes percent-encoded characters, so the encoded comma in an image URL’s fit or resize size was dropped (fit=1200,803 was stored as fit=1200803) and the URL looked like a malformed Photon URL when the image itself was fine. A source file that is an http or https URL is now sanitised as a URL, like the page URL; anything else is still sanitised as text. An error whose source file has percent-encoded characters before its query string starts a new row once, since its signature changes.
  • 3.3.1: get-error now ends its description with the permission it needs, “Requires install_plugins; main site only.”, like the other two abilities. The ability category is renamed from javascript-error-log to lh-javascript-error-log, matching the plugin’s text domain.
  • 3.3.0: JavaScript errors are now reported through LH Beacon instead of the plugin’s own admin-ajax endpoint, which fixes reports from logged-out visitors being dropped. The old endpoint checked a nonce printed into the page, and on pages served from cache that nonce expires, so reports from those visitors (crawlers especially) failed with a 403 and were lost. Reports now ride on LH Beacon’s shared request when the page is hidden or closed, with no nonce. LH Beacon checks the origin and identifies a logged-in visitor from their login cookie, so the user ID is still recorded. LH Beacon is now required (Requires Plugins: lh-beacon), and without it the script is not loaded. The browser script records each error once (message, source, line, column and stack) and keeps its payload within a byte budget (4096 by default, filterable with lh_js_error_log_return_beacon_budget) by shortening stack traces and then dropping later errors, because LH Beacon refuses a whole request that is too large. The first 20 errors on a page are kept (lh_js_error_log_max_errors_per_beacon). Error signatures are unchanged, so new reports keep counting against existing rows. Extension filtering and the per-IP rate limit are unchanged. The admin-ajax action lh_js_error_log-log_js_errors and the bundled LH_Register_file_class have been removed.
  • 3.2.1: Fixes the 3.2.0 upgrade, which never ran: the admin check was hooked to network_admin_init, an action WordPress does not have, and activation can run the previous copy of the code. The table is now upgraded wherever it is about to be used (beacons, cron, MCP calls and admin loads), with a database lock so only one request upgrades it at a time. The upgrade also merges the existing rows that share a signature into one row each, with the summed count, earliest first-seen and latest last-seen, so the counts reflect the history already logged.
  • 3.2.0: Repeated errors are now counted instead of logged again. Each distinct error is one row: when it recurs, its error_count goes up, a new last_seen time is recorded, and the page, user agent, user and stack trace are refreshed to the latest occurrence, while the logged time stays as when it was first seen. An error’s signature is now its site, message, source file without its query string (so a ?ver= change no longer splits it), line and column; the page URL is no longer part of it, so the same error on many pages counts as one. Existing rows are rehashed on the new signature when the schema upgrades (schema 7). Errors raised by browser extensions (chrome-extension://, moz-extension:// and similar, filterable through lh_js_error_log_extension_markers) are no longer logged, and existing ones are removed, since they are not ours to fix. The admin list gains sortable Last Seen and Count columns and sorts by Last Seen by default. The daily purge now removes errors not seen for a month, so an error that keeps recurring keeps its count. get-errors and get-error-stats filter by last_seen and accept a new kind filter (exceptions or failed resource loads), and records include last_seen. Adds plugin_version(), read from the plugin header.

If you like this plugin please consider making a donation to further development

Install LHero.org

lhero.org

Open it straight from your home screen, full screen and quicker to load.

  1. Tap the Share button . If you cannot see it, tap ••• first.
  2. Scroll down and tap Add to Home Screen.
  3. Tap Add.
  1. Tap the browser menu â‹®.
  2. Tap Install app or Add to Home screen.
  1. In the menu bar, choose File, then Add to Dock.

Use your browser's menu to install this site or add it to your home screen.