Egenverk Lagom

Changelog for Egenverk Lagom

What changed in each plugin, newest first.

The changelog text is in English, as in the plugin.

Atom feed

Version 0.20.0

Added

  • Database (M5): while switched on, shows (in a section under the settings) the 25 largest site tables (plus any smaller one worth optimizing) and the 20 largest autoloaded options with owner guesses. One table can be optimized per confirmed click only when it is at most 500 MB, has at least 20 MB and 20 % free inside (InnoDB shows a few MB free in almost every small table, which a rebuild does not return), and the database data directory has at least twice its size free. Larger tables get a maintenance-window explanation. Autoload can be stopped per option, never for protected WordPress options, and each change can be undone from the log. Nothing is deleted or changed automatically; the limits keep rebuilds away from large production tables and protect available disk space.
  • tests/database-test.php (wp eval-file).

Version 0.19.0

Added

  • Heartbeat, transients and sessions (M4): slows the admin heartbeat and, each night at 03:00 site time (kept across daylight-saving changes), asks WordPress to delete expired transients and removes expired WooCommerce sessions in batches. Core leaves expired transient rows behind when a persistent object cache is active; Lagom forces the database cleanup after showing the counts first. The run keeps 60 measured rows and the card shows the last 10. On dev, 11 363 expired rows took 1 969 ms to remove.
  • tests/housekeeping-test.php (wp eval-file).

Version 0.18.0

Added

  • Request watch (M3): with the module on, every wc-ajax call (per endpoint), admin-ajax.php call (per action, Heartbeat labelled), REST call (per route pattern, so /wp/v2/pages/3 and /4 are one row; unknown routes as no-route, and calls refused before they run, such as by a permission check, by their path with numbers as {id}) and wp-cron.php hit adds one short line to a file for that minute under uploads/egenverk-lagom/watch/. No database write and no cache on the request path: about 18 µs per call measured on dev, and files stop growing at 2 MB a minute. A WP-Cron job sums finished minutes every minute into the last hour's counts and deletes the files; the card shows the top 25 endpoints (total, peak per minute, last minute) and warns when WP-Cron has not run, the folder is not writable or a minute hit the cap.
  • When an endpoint passes the threshold in one minute, admins see a notice on every admin screen until they dismiss it, and one email per endpoint per hour goes to the address on the card, or the site's admin email.
  • Nothing about the visitor is stored (no IP, user, cookie, query string or body). Switching the module off stops counting and deletes the files, once at once and once ten minutes later, since a persistent object cache can serve the old setting to the front end for a while. Uninstall removes the counts, alerts, scheduled jobs and the folder.
  • tests/watch-test.php (wp eval-file; run it as the web server user, or chown the folder afterwards).

Fixed

  • tests/scheduler-test.php passes phpcs (multi-item arrays on one line).

Version 0.17.0

Added

  • Scheduler cleanup (M2): with the module on, Action Scheduler's own cleaner removes finished and canceled jobs older than "Keep finished jobs for" (default 14 days, Action Scheduler's own is 30) and failed jobs older than "Keep failed jobs for" (default 90 days), with their log rows. "Finished jobs per cleanup run" sets how many finished and canceled jobs go per status each queue run; Action Scheduler 4.0 removes failed ones 20 at a time on its own, by design, so they never crowd out the rest. Lagom sets Action Scheduler's filters and never runs its own delete on its tables. Action Scheduler below 4.0 never removes failed jobs; there Lagom adds one daily job that asks Action Scheduler's cleaner to remove them.
  • The switch saves on only after Show what would be removed has counted, for the values in the form, the finished, canceled and failed jobs and log rows that would go, within the last 10 minutes; lowering a retention while the module is on needs a new count too. The count also shows which Action Scheduler version runs and any log rows that belong to no job (left alone).
  • A log keeps removals per day and source (200 rows); the card shows the last 20 and the total for the last 30 days. Uninstall removes the log, the counts and the daily job.
  • tests/scheduler-test.php (wp eval-file).

Changed

  • "Rows per batch" became "Finished jobs per cleanup run", 20–500, default 100 (was 50–5000 rows, default 500), since it now sets Action Scheduler's batch size and Action Scheduler cleans inside each queue run: on dev one run of 500 per status removed 520 jobs in 9.5 s, about 18 ms each, which would hold up the jobs waiting behind it.

Version 0.16.1

Fixed

  • Old bookmarks to tools.php?page=lagom now reach Tools → Lagom instead of "Sorry, you are not allowed to access this page": WordPress refuses the unknown page before admin_init, where the redirect used to run.
  • The zip from bin/package.sh gives every file and folder readable modes, so fonts copied with private modes no longer answer 403 on servers where the web server runs as another user.

Version 0.16.0

Added

  • Dashboard widgets (M1): with the module on, the widgets ticked on Tools → Lagom are removed from the dashboard before it is drawn, in every column, so their render code never runs (the Kustom widget calls its API twice per load there). Hiding a widget in Screen Options only hides it. Lagom still records every widget first, so a removed one stays in the list and can be unticked. Work a plugin does while registering its widget, or scripts it enqueues for the dashboard, are not affected; the asset rules handle the latter.
  • tests/dashboard-test.php (wp eval-file).

Version 0.15.0

Added

  • PageSpeed Insights as a second opinion (M6f): Tools → Lagom lists every scanned public page type (not wp-admin, not the order endpoints) with a Run PageSpeed button, mobile or desktop. Google opens the page once, logged out, with an empty cart, and reports the score, LCP, TBT and CLS, and how much of each CSS and JS file went unused, matched to the scan's handles where the address is the same. The section is labelled "estimate, public pages only" and only shows results: rules still come from coverage runs and the verification run. A result where Google was redirected to another page (checkout with an empty cart goes to the cart) is refused, not stored.
  • The API key is optional (without one Google allows only a few runs a day). It is stored on the server in a non-autoloaded option, or set as EGENVERK_LAGOM_PSI_KEY in wp-config.php; the page says only whether a key is set, the key is sent only in the server's request to Google, and it is scrubbed from any error message before that is stored or shown. The address sent is always a scanned page of this site, never one from the form. Uninstall removes the key and the results.
  • tests/pagespeed-test.php (wp eval-file; Google is never called, the request is answered by a filter).

Version 0.14.0

Added

  • Whole plugins per address (M6e): a plugin rule stops an active plugin from loading at all — its PHP, CSS and JS — on addresses starting with a path (or exactly one address). It needs a small must-use plugin, which Lagom writes only when you click Install the mu-plugin on Tools → Lagom, next to an explanation of what it does and why: a normal plugin loads too late to stop others. Update and remove buttons sit beside it; switching the module off or uninstalling Lagom removes the file.
  • The mu-plugin reads one autoloaded option and does nothing unless a rule matches. It never acts in wp-admin, on AJAX, REST, cron, WP-CLI, XML-RPC, logins, form submissions (only GET and HEAD), WooCommerce API callbacks, post previews or page builders, on cart, checkout and account pages (order endpoints included), or on the addresses in a never-list you keep on the page (payment and shipping callbacks, landing pages). WooCommerce and Lagom itself (by its real folder name) are never switched off. Addresses are compared in one form — decoded, lower case, without index.php, with a trailing slash — so /Cart, /cart and /index.php/cart/ are the same page, and prefixes match whole path segments (/blog/ covers /blog/x/, not /blog-posts/). Plugin rules need pretty permalinks; with plain ones the mu-plugin does nothing and new rules are refused. A preview with the token is kept out of page caches.
  • Plugin rules go through the same steps as file rules: preview, verification, live, log. A plugin rule cannot go live without the current mu-plugin, and a verification counts only if the mu-plugin was installed and current, since without it the rules were not applied. Their page types are the scanned pages the address covers; a rule that covers no scanned page, or lies inside a never-listed address, is refused. Preview links carry a short-lived signed token, since no user is known when the mu-plugin runs; the coverage runner gets one that dies with its run key.
  • tests/plugin-rules-test.php (wp eval-file).

Changed

  • Verification opens each page twice without rules and leaves out whatever moves between those visits (sliders, rotating banners), so only changes caused by the rules count; elements are still compared by identity (tag, id, classes), so a slider whose script stops running still fails the check. Before, a slider on the front page could fail a check at random.

Version 0.13.0

Added

  • Rule proposals (M6d): after a coverage run, Tools → Lagom lists per page type the files that are not ruled yet and were unused (CSS, ticked) or only ran their start-up code (JS, left to choose). A file stays out when something used on that page type depends on it. "Add ticked as preview rules" adds them in dependency order.
  • Verification run: bin/lagom-coverage --verify opens every page type that has rules in preview with the rules off and on, at desktop and phone size, runs the same interactions and compares console errors, failed requests, interactions that stopped working and the layout of every visible element (more than 2 % changed fails). --shots dir saves both screenshots per page. Results go to a new REST route egenverk-lagom/v1/coverage/verify.
  • A passed check lets the page type's rules go live without the skip confirmation. A check belongs to the exact set of rules on that page type: adding or removing a rule there makes it stale. Rules verified together go live together (every preview rule sharing a page type with it), so visitors never get a combination that was not checked. The rules table shows per page type "verified", "verification failed" (with the reasons), "rules changed, verify again" or "not verified"; the change log records each outcome.
  • Cart and checkout pass only in a full run with something in the cart: a read-only pass on them is recorded as failed (also when the runner itself was made stricter with --read-only), and an empty cart fails the check. A full verification run adds a simple product from the plan to the cart first. Order-pay and order-received need a real order and never pass a run, so no rule may target them (a rule there would also hold back every rule verified together with it).
  • Console errors are compared with where they came from, so a new error with the same text as an existing one still fails the check; the layout comparison uses every class and the horizontal scroll position.

Changed

  • Coverage runs visit every page at a desktop and a phone size and count a file as used if either used it, so phone-only stylesheets are no longer reported unused.
  • CSS files with @font-face or @keyframes and no matching style rule are shown as "fonts or animations only, check by eye" instead of "unused" and are never proposed: rule usage cannot tell whether a font or an animation is used.
  • The rules option is created with the module's current switch, so a site whose rules option was removed does not ignore previews until the next settings save.

Version 0.12.0

Added

  • Coverage runs (M6c, docs/coverage-runner.md): Tools → Lagom lists a plan of one page per page type (scanned pages and suggestions, own addresses can be added), creates a run key, and shows per file and page type what the last run saw: "unused here", "start-up only" or "used", with the share of the file that ran.
  • bin/lagom-coverage (developer tool, not in the zip): a headless browser with a temporary profile that opens each planned page once, records which JS functions are called after load and which CSS rules match, runs standard non-destructive interactions, and uploads a per-file summary.
  • Run keys are shown once, valid for at most 30 minutes, bound to one user and one run, stored only as a hash, logged (created, plan fetched, results uploaded, revoked) and revocable; revoking or replacing a key also ends the login it handed out. A new key retires the user's previous one.
  • Production is read-only, decided by the site: tracking blocked (on by default everywhere), every non-GET request aborted, cart-changing requests aborted, no navigation away from the planned page, and no clicks in wp-admin. Service workers may not start and WebSockets are closed in every run, so nothing reaches the network outside the runner's checks. Full runs on other environments put a simple product in the cart before visiting cart and checkout.
  • REST routes egenverk-lagom/v1/coverage/plan and /results, each needing a valid run key; uploads are kept only for planned pages the scan recorded (a page that redirected is filed under the page type it landed on, if the scan saw it there), and every text is sanitised.
  • Uninstall removes the plan, runs, results and log.
  • tests/coverage-test.php (wp eval-file).

Version 0.11.0

Added

  • Asset rules (M6b, docs/BRIEF-assets.md section 3): "Unload…" on a scanned CSS or JS file stops it loading on the page types you tick, front end or admin screens. Rules act on whole handles only.
  • Every new rule starts in preview: it applies only when an administrator opens a page with ?egenverk_lagom_assets=preview, with a note on the page saying how many rules were applied. Preview links per page type sit next to each rule.
  • Going live needs a passed verification run (arrives with the coverage runner). Until then an administrator can make a rule live only by ticking an explicit confirmation that the verification is skipped, which is logged and shown on the rule. Rules on cart, checkout, order-pay or order-received can never skip it.
  • A rule is refused when a file that depends on it would still load on that page type, when the file was not seen there in the last scan, or when it targets Tools → Lagom itself. Because WordPress re-adds a removed file when something still loaded depends on it, a rule only goes live once the rules on its dependants are live, and a dependant's rule cannot leave live (or be deleted) while a rule it depends on is live.
  • ?egenverk_lagom_assets=off turns every rule off for one request; scans ignore rules so the list stays complete. Back to preview and delete per rule; known page caches (WP Rocket, LiteSpeed, W3 Total Cache, WP Super Cache) are emptied after a change, otherwise the page asks you to.
  • Change log of the last 200 rule changes (who, when, what) on Tools → Lagom.
  • The switch and rules live in one small autoloaded option, so the front end reads them without a query; nothing is hooked while the module is off or no rule exists. Uninstall removes rules and log.
  • docs/decisions.md records the decisions behind the asset manager and order search; the brief now describes coverage (runner A plus PageSpeed B), the production safeguards and the PR order.
  • tests/asset-rules-test.php (wp eval-file).

Version 0.10.0

Added

  • CSS and JS per page module (off by default), first step of the asset manager (docs/BRIEF-assets.md). While it is on, an administrator opens any front-end page or admin screen with ?egenverk_lagom_assets=scan and Lagom records every CSS and JS file that page printed: handle, the file actually served, whether it is minified and whether the other build (.min or source) is on disk, size, inline code, owner (plugin, theme, core or external host), and what depends on it. Uninstall removes the stored scans. Scans are kept per page type (front page, shop, product, product category, cart, checkout, order received, account, page template, post type, admin screen), at most 40 page types.
  • The module card links one page of each type to scan; the list under the settings groups the files by plugin or theme, largest first, with the page types each file loads on. A small note on the scanned page confirms what was recorded.
  • Read-only: nothing is unloaded yet. Requests without the scan argument add no hook, and a scanned page is kept out of page caches.
  • tests/asset-scan-test.php (wp eval-file).

Changed

  • The header chip on Tools → Lagom names the asset scan among the live modules.

Version 0.9.0

Added

  • Lagom's own order search index for orders stored as posts, when no other plugin answers the search filter. A table {prefix}egvl_order_index holds one row per order with the normalised billing email, phone (E.164), postcode, first and last name, company and transaction id, each column indexed. Fast order search uses it once it is complete, so email, phone, postcode, transaction id and name are found fast without HPOS; until then only order numbers are, as before.
  • The index fills in batches of 500 orders through Action Scheduler with a 20-second pause between batches, optionally only between 00 and 06 in the site's time zone. Unticking "Build Lagom's own search index" pauses it and keeps what is built. Any admin page load restarts a fill whose last batch died, until the fill is done. The module card shows how many orders are indexed.
  • Once the table exists, orders are kept in step when they are created or saved (checkout included), and their row is removed when the order is deleted or anonymised by the WooCommerce personal data eraser, also while the fill is paused or the module is off. Uninstall drops the table and its options.
  • readme.txt has a Privacy section.
  • tests/order-index-test.php (wp eval-file).

Version 0.8.0

Added

  • Fast order search module (off by default). It reads the search term on the order list before anything is searched (order number, email, phone, postcode, transaction id or name) and looks each reading up in one indexed column. It never runs a LIKE '%…%' across order data, and WooCommerce's own search does not run.
  • A notice on the order list says how the term was read ("phone number +46722900612") and links to "Search all fields (slow)", which runs WooCommerce's normal search.
  • Answers come from another plugin through the new egenverk_lagom_order_search filter, with the query shape wc-customer-hub 4.125.0 answers (term, type, candidates, limit; documented in docs/order-search-filter.md), so on a site with wc-customer-hub email, phone, order number and name are fast without HPOS; otherwise from the HPOS tables: order number, email, transaction id and phone always, and name, company and postcode where the site has an index on those columns. With orders stored as posts, only order numbers are found fast until another plugin answers.
  • The module card says where answers come from on this site and which kinds of lookup have no index.
  • tests/order-search-classifier-test.php (plain php) and tests/order-search-test.php (wp eval-file, HPOS).

Version 0.7.1

Added

  • wordpress.org screenshots 1–3 in .wordpress-org/ (1280×800, the real page on a test site) and their captions under == Screenshots == in readme.txt.

Changed

  • The "by egenverk" signature on Tools → Lagom, the bundled kit's brand files, the Lagom glyph and the wordpress.org banners and icons use the redrawn egenverk mark (even bars, a wider middle stroke).
  • CHECKLIST records the move of the GitHub repository to egenverk/egenverk-lagom, marks brand v3 done, and adds the order search brief (docs/BRIEF-order-search.md) and the asset manager module (M6).

Version 0.7.0

Added

  • Migration from the old keys: settings, recorded dashboard widgets and each user's skin and scheme choice move from lagom_* to egenverk_lagom_* once, on activation or on the first load after an update (a new folder means WordPress sees a new plugin, so the old one is deactivated and this one activated). Keys that already exist under the new name win. Uninstall removes both generations.
  • tests/migration-test.php (wp eval-file) checks the migration on a dev site and restores what it touched.
  • bin/package.sh builds dist/egenverk-lagom-<version>.zip with the folder egenverk-lagom/.

Changed

  • Renamed to Egenverk Lagom (shown as "Lagom by egenverk"). Slug, folder and text domain are egenverk-lagom, the main file is egenverk-lagom.php, PHP uses the Egenverk\Lagom namespace and the egenverk_lagom_ / EGENVERK_LAGOM_ prefixes, and CSS classes, custom properties and the JS global use egvl- / egenverkLagomAdmin. Author is Egenverk (https://egenverk.se); the wordpress.org contributor is vigg3.
  • The settings page moved to tools.php?page=egenverk-lagom; the old tools.php?page=lagom redirects there.
  • ?egenverk_lagom_skin=0 turns the skin off for one page; the old ?lagom_skin=0 keeps working.

Version 0.6.0

Added

  • wordpress.org banners (1544×500, 772×250) and icons (256, 128) in .wordpress-org/, with their sources in .wordpress-org/src/; not part of the plugin zip.

Changed

  • Tools → Lagom follows the Egenverk look (brand v3): the shared Egenverk UI kit is bundled in assets/egenverk-ui/ and loads only on this page, with Geist and Geist Mono self-hosted (no external request). The header carries the Lagom glyph, the title and the "by egenverk" signature; the accent is Lagom's product colour Mynta; the save bar and loading indicator come from the kit. The teal page palette and logo are gone from this page; the Skin module is unchanged.
  • The figures open with Revisions (a new read-only count, cached like the rest), Expired transients and Space, followed by autoloaded options, finished scheduler jobs and shop sessions, three to a row.
  • Switched-off module cards keep their text at full contrast instead of fading it below 4.5:1, and the page's own switches, text buttons and widget rows have 44 px targets.
  • readme.txt opens with what Lagom does, and the Plugin URI and donate link point to egenverk.se.
  • The header comment of the generated skin-strong.css reads "Built by bin/build-skin.php".

Version 0.5.0

Added

  • Every component in docs/skin-components.html now has skin rules: keyboard focus rings on every interactive element (:focus-visible, with a transparent outline that forced-colors mode shows), a CSS spinner in core's 20 px box that only turns while active (white inside primary buttons, slower under reduced motion), read-only, disabled and invalid fields, multiple selects with a tinted choice, the file picker button, a tinted list-table header with the active sort in the accent, a roomy empty state, active plugin rows in the palette, the folded menu's flyout heading as a mono label, WooCommerce help tips, plain <progress> bars, skeleton placeholders and confirmation dialogs (core's jQuery UI dialog and WooCommerce's modal, without clipping so dropdowns inside can spill out).
  • The components fixture loads WooCommerce's admin styles and core's dialog styles, so every section can be screenshot as it looks on a real screen.

Fixed

  • Plugin notices with notice-alt lost the status dot since 0.4.0; only core's update rows (which bring their own icon) go without it now.

Version 0.4.0

Added

  • The skin on wp-login.php: logo with the site name, the form as a card with the accent line, a remember-me switch, links side by side. Logged-out visitors follow prefers-color-scheme. Other front-end requests still read nothing.
  • Dashboard: widget handles appear on hover or keyboard focus (always on touch screens), the empty column is a dashed drop zone, and WooCommerce status is a grid of icon tiles.
  • WooCommerce order status pills per status in both schemes (processing, completed, on hold, failed/cancelled/refunded, pending).
  • A 3 px accent line on key-figure cards, the first card of an edit screen, WooCommerce status and the login form, in both schemes.
  • Order notes as soft cards; the customer's note tinted; the meta line in mono.
  • tests/fixtures/components-fixture.php: an admin page with WordPress markup for every section of the component sheet.

Changed

  • Radii follow reference v3: cards 10 px, buttons 7 px, fields 6 px, menu items 8 px (the 4 and 8 px settings scale with it).
  • The admin bar sits on the menu's surface instead of black.
  • Notices are cards with a status dot and halo instead of the left stripe; update rows and other alt notices keep their own icon and get no dot.
  • Tabs are underlined instead of boxed, still floated like core so plugins' floated siblings keep their place.
  • Update and comment counters are an orange warning pill; plain counters stay teal.
  • Tools → Lagom follows reference v3: mono labels, 30 px figures with the accent line, gradient icons on active modules, gradient save button.

Version 0.3.0

Added

  • Components on core's own selectors: notices as soft cards with the status stripe, postboxes and .card as cards, the settings .form-table on core screens as a card, quieter list tables with row hover, tabs, tablenav pagination, screen options, secondary text and delete links in the palette.
  • Checkboxes inside .form-table become 32×18 switches, never in list tables and not on WooCommerce order screens or the checkout settings tab. Lagom's own page uses the same switches.
  • Transitions of 150–200 ms everywhere, and none under prefers-reduced-motion.
  • Dark scheme per user (Light / Dark / Auto on the profile), set on <html> before the page renders, so no light flash. All colours are tokens; the admin menu's SVG icons are repainted to match.
  • skin.js guards the dark scheme against plugin styles: near-white panels get the dark surface and text under 4.5:1 is lightened towards white, keeping its hue. No filters, no inversion. db_schenker's own dark theme is switched on instead.
  • Admin menu on the page's own surface, light or dark, with only the active item debossed, flyout submenus as raised cards and counters as gradient pills.
  • Entrance: the first twelve blocks of a page rise and fade in once per load, 55 ms apart; switchable on the Skin card and always off under reduced motion.
  • Expression: 34 px page titles with a mono eyebrow (menu group and date; the room for it is only reserved when JavaScript runs), a faint glow and grain behind the content, cards that lift on hover, the status filter as a segmented control, readable WooCommerce status pills in both schemes.
  • Lagom's own page in the new palette with the new logo and a dark mapping.

Changed

  • bin/build-skin.php keeps comments in the generated skin-strong.css (they were dropped since 0.2.0's review fix).

Version 0.2.0

Added

  • Skin module (off by default) with its own card on Tools → Lagom and a live preview of font, corner radius and gradient.
  • Bundled fonts Manrope (default), Inter and Figtree as self-hosted woff2 (OFL), or the system font. Only the chosen font loads, on admin pages only, preloaded once from the plugin folder.
  • Skin tokens as CSS custom properties switched by body classes (lagom-skin, lagom-font-*, lagom-radius-*, lagom-grad); one static stylesheet, nothing generated per request.
  • Fields get a soft fill and a teal focus ring (1px solid plus a soft halo) instead of the blue outline, and turn white on focus; buttons and "Add new" get the teal palette, rounder corners and an optional gradient on primary buttons.
  • Cascade: the skin loads after core's admin styles on core's own selectors, so plugins printed later keep their look. "Lagom wins over other plugins' styles" switches to skin-strong.css, built by bin/build-skin.php with one extra class per selector.
  • Off switches: ?lagom_skin=0 for one page, "Use Lagom skin" on each user's own profile, a list of screen ids without the skin, and the block editor is always left alone.
  • Token defaults also sit on body, so a screen that prints its own <body> without the admin body classes still gets readable buttons.
  • .distignore for the shipped files; Plugin Check runs against those.

Version 0.1.0

Added

  • Settings page under Tools → Lagom with live health figures (database size, autoload, Action Scheduler backlog, expired transients, WooCommerce sessions), cached for 10 minutes.
  • Five module cards with switches and options; every module ships off and none acts on the site yet.
  • Logo files, Swedish translation, README and .gitignore.