Changelog
The full paper trail for a plugin that does one thing and refuses to apologise for it.
What changed, when, and — in most cases — why the version number moved.
August 2026
v1.1.0
Released 9 August 2026 — GitHub Release
Endpoints can now choose where they sit in the customer portal menu, instead of always queuing up behind Profile like everybody else.
Menu Placement
Requested by @Joe-Bloggs in #62 and tracked in #141. The endpoint editor has a new Menu Placement field: put an endpoint at the top, directly under Dashboard, after any other built-in item, or at the very bottom. Existing endpoints keep the slot they already had, so upgrading moves nothing.
FluentCart's API drops every custom endpoint immediately before profile and
offers no position argument, so the finished menu is reordered afterwards on
fluent_cart/global_customer_menu_items. Items belonging to other plugins are
passed through untouched — this reorders, it never curates.
Placement is anchored, not numbered, and that is the interesting part
FluentCart's menu is not the same for every visitor: it hides Licenses without Pro or with the license module off, and hides Subscription Plans from customers who have none. An absolute "position 2" would therefore land beside a different neighbour for different people — a promise nobody can keep.
So placement anchors to a named item and degrades honestly. Choose "After Licenses" on a site with no licenses and the endpoint takes the slot where Licenses would have been, by walking up to the nearest visible item. "Before Subscription Plans" walks down for the same reason. Either way it lands in the same visual gap rather than at the bottom of the menu.
Portal Extender has tests now
It had none. It has 57, covering placement resolution, hidden anchors, grouped endpoints, third-party items surviving a reorder, and the icon sanitiser whitelist from 1.0.4 — including a test that scans every permitted attribute for anything shaped like an event handler, so that whitelist cannot quietly widen later. The plugin is now in the CI matrix on PHP 8.4 and 8.5.
v1.0.4
Released 9 August 2026 — GitHub Release
Endpoint icons now appear on the front end, which is where icons are generally most useful.
Icons survive the trip to the customer portal
Reported by @Joe-Bloggs in #62: the icon showed in the admin, picked correctly, saved correctly — and then rendered as nothing at all in the portal.
FluentCart runs every portal menu icon through wp_kses() with a whitelist of
svg, path and g. Nothing else survives. A Dashicon is a <span>, so it was
deleted outright and could never render. Any SVG built from circle, rect,
line or polyline came out as an empty <svg></svg>. And viewBox was
stripped from everything, because wp_kses lowercases attribute names before
matching while the whitelist key is camelCase.
Portal Extender now widens that whitelist through FluentCart's own
fct_allowed_svg_tags filter, merging on top of it rather than replacing it, so
other plugins' entries survive. The shape elements, the stroke and fill
presentation attributes, lowercase viewbox and the Dashicon <span> are all
allowed through.
It remains a whitelist. script, foreignObject, use, xlink:href, href,
inline event handlers and style on SVG elements are still stripped, and that
is covered by a test that throws a deliberately hostile icon at it.
Dashicons are actually loaded now
Surviving sanitisation is only half of it — WordPress does not load the Dashicons stylesheet on the front end for ordinary visitors, so the markup would have rendered as an empty box regardless. The stylesheet is now enqueued on the portal, and only when an active endpoint genuinely uses a Dashicon.
Reordering endpoints within the portal menu was requested in the same issue and
is tracked separately in #141. No FluentCart change is needed for it —
the interesting part is that FluentCart hides licenses and subscriptions
from some visitors, so an absolute "position 2" is not a promise anyone can keep.
March 2026
v1.0.3
Released 6 March 2026 — GitHub Release
Fixed a fatal error when multiple FCHub plugins are active at the same time. The shared GitHubUpdater class used a class_exists guard that PHP's OPcache cheerfully ignored during early class binding — so the second plugin to load would redeclare the class and take the site down. Wrapped the class inside the conditional so OPcache actually respects it.
v1.0.2
Released 3 March 2026 — GitHub Release
Minimum PHP bumped to 8.1, minimum WordPress to 6.4. Functionally identical to v1.0.1. Your portal pages still work exactly the same — I just stopped pretending PHP 7.4 was acceptable.
v1.0.1
Released 3 March 2026 — GitHub Release
First release under the monorepo slash-tag convention. The plugin didn't change. The tag format did. Milestones come in all shapes and sizes.
v1.0.0
Released 3 March 2026 — GitHub Release
The initial release. FluentCart's customer portal is useful — but it only shows what FluentCart decides to show. This plugin adds custom pages to it, no PHP required. Build a "Manage Subscription" page with an embedded form. Add a help centre link. Stick a shortcode in there. Whatever your portal is missing, you can probably add it now.
Content sources
Six ways to populate a custom portal page:
| Source | What it renders |
|---|---|
| WordPress Page | Renders an existing page by ID — content, blocks, the lot |
| Shortcode | Any shortcode, executed in portal context |
| HTML | Raw HTML, for when you know exactly what you want |
| iframe | Embed external tools, forms, or dashboards |
| Redirect | Sends the user somewhere else — portal page as a nav shortcut |
| Post / CPT | Any post or custom post type by ID |
Icons and display
Three icon types for your custom nav entries: SVG (inline), Dashicons (WordPress native), or image URL. Supports dark mode out of the box — icons and labels adapt without extra configuration.
Reorder portal pages via drag-and-drop. Toggle endpoints active or inactive without deleting them. Slugs auto-generate from the page title, or set your own.
Cleanup
Full uninstall cleanup. When you remove the plugin, it removes its database entries. No ghost data lingering in your wp_options.