HubGo - Shipping Management for WooCommerce
Extension that manages shipping options for WooCommerce stores.
Install
No release zip yet. The repository archive installs, but the folder name will carry the branch suffix and updates will not flow:
wp plugin install https://github.com/meumouse/hubgo/archive/refs/heads/main.zipHubGo is a WordPress plugin that extends WooCommerce with everything that happens around shipping: a product-page shipping calculator, order tracking, an "Order shipped" status with its own e-mail, a delivery promise stored on the order, and integrations with the shipping and automation plugins a store already uses.
Since 3.0.0 the plugin is API-first: the admin UI is a Vue 3 SPA that talks
exclusively to the hubgo/v1 REST namespace, and the storefront calculator is a
Vue bundle of its own.
- Author: MeuMouse.com
- Plugin page: https://meumouse.com/plugins/hubgo/
- License: GPLv2 or later — see license.md
- Changelog: CHANGELOG.md
- Contributor guidelines: AGENTS.md
Table of contents
- Requirements
- Features
- Installation
- Admin screens
- Storefront usage
- Integrations
- Licensing and updates
- Architecture
- REST API
- Extensibility
- Development
- Internationalization
- Versioning and releases
- Support
1. Requirements
| Requirement | Version |
|---|---|
| PHP | 7.4 or higher |
| WordPress | Tested up to 7.1 |
| WooCommerce | 6.0 or higher is enforced at runtime; the plugin header declares 9.0+ and is tested up to 11.0 |
| HPOS (custom order tables) | Compatible |
The plugin checks PHP and WooCommerce on plugins_loaded and, when something is
missing, renders an admin notice instead of booting its components. The
MDS registration is wired outside that gate, so updates keep working even without
WooCommerce.
For development you also need Node.js 18+ (Vite build and translation tooling) and Composer (PHP autoload and the MDS SDK).
2. Features
Shipping calculator on the product page
- Vue 3 storefront app rendered by a product-page hook, a shortcode or an Elementor widget — all three print the same mount node, so they can never drift apart.
- Delivery-date forecast: the carrier's estimate in business days plus the store's handling days, resolved into a real date ("Get it by …").
- Free-shipping badge driven by a configurable threshold.
- Preferred-method choice that is carried into the cart and the checkout.
- Optional "I do not know my postcode" finder, backed by the Google Maps integration when it is enabled.
- Automatic calculation for customers whose postcode is already known
(
enable_auto_shipping_calculator). - The calculation is side-effect free: it never writes to the cart, the customer session or the rate cache, which keeps the endpoint public and page caches intact.
Order tracking
- Tracking codes per order, with carrier and tracking URL.
- Admin metabox on the order screen.
- "My Account" view for the customer.
- Transactional e-mail carrying the tracking information.
- Read-only bridge to WooCommerce Shipment Tracking, plus a batched migration that imports its data into HubGo.
"Order shipped" order status
- Custom WooCommerce status
wc-shipped-order, listed next to Processing, with bulk actions and reports support. - Dedicated WooCommerce e-mail (
hubgo_shipped_order), overridable as a template.
Delivery promise and late-delivery watch
- What the shopper was told at the checkout is stored on the order
(
_hubgo_delivery_date,_hubgo_delivery_days,_hubgo_delivery_carrier,_hubgo_delivery_method), on both the classic and the block checkout, so every downstream consumer states the promise instead of a fresh quote. - A daily pass fires
Hubgo/Delivery/Overdueonce per order whose promised date has passed, in batches, with a grace period.
Appearance and copy
- Every storefront string is a setting, so an untouched install still reads in the site language.
- The calculator is styled exclusively through
--hubgo-calc-*CSS custom properties, driven by the Appearance tab and, per instance, by the Elementor widget.
3. Installation
From the WordPress admin panel
- Open your site's admin panel.
- Go to Plugins → Add New → Upload Plugin.
- Select
hubgo-<version>.zipand click Install Now. - Click Activate Plugin.
Via FTP
- Unzip
hubgo-<version>.zipon your computer. - Connect to your server over FTP.
- Upload the
hubgofolder intowp-content/plugins. - Go to Plugins → Installed Plugins and activate HubGo.
From source
The repository does not ship generated artifacts (app/dist/, admin/vendor/),
so a checkout has to be built before it runs:
npm install && npm run build
The result is release/hubgo-<version>.zip, which is the deliverable, plus the
staged tree in release/hubgo/. See Development.
4. Admin screens
HubGo owns a top-level HubGo menu with three subpages, each one a Vue bundle of its own:
| Page | Slug | Bootstrap route |
|---|---|---|
| Settings | hubgo-settings |
GET hubgo/v1/settings |
| Integrations | hubgo-integrations |
GET hubgo/v1/integrations |
| License | hubgo-license |
GET hubgo/v1/license |
hubgo-settings doubles as the parent menu slug, so links published before the
3.0.0 restructure keep working.
The Settings screen has four tabs:
- General — features, calculator behaviour and placement, preferred method.
- Appearance — colors and typography, container, free-shipping badge, postcode field, calculate button, delivery options, details window, layout.
- Texts — every storefront string.
- About — maintenance preferences, system status snapshot and the restore-defaults action.
All settings live in a single option, hubgo_settings, and are described by a
server-side schema (sections → cards → fields). The SPA renders whatever the
schema declares, which is why adding a setting means editing the schema, not the
UI.
The default capability for every admin and REST surface is manage_woocommerce,
filterable through Hubgo/Admin/Settings_Capability.
5. Storefront usage
Placement
The calculator's position is set in General → Calculator:
| Setting value | WordPress hook |
|---|---|
before_cart |
woocommerce_before_add_to_cart_form |
after_cart (default) |
woocommerce_after_add_to_cart_form |
meta_end |
woocommerce_product_meta_end |
shortcode |
nothing is hooked — place it yourself |
elementor |
nothing is hooked — use the widget |
The list is filterable via Hubgo/Shipping_Calculator/Positions.
Shortcode
Registered whichever position is selected, as the escape hatch for themes none of the hooks fit:
[hubgo_shipping_calculator]
Elementor widget
The shipping calculator widget renders the same component and adds per-instance style controls, built from the same token map the settings screen uses.
DOM events
The storefront app publishes browser events other scripts can listen to:
hubgo:shipping_calculatedhubgo:shipping_errorhubgo:shipping_preference_changed
Template overrides
Templates live in templates/ and are loaded with WooCommerce's template
loader, so a theme overrides them by copying the file into its own
woocommerce/ folder:
templates/shipping-calculator.php
templates/email/hubgo-tracking-info.php
templates/emails/hubgo-shipped-order.php
templates/myaccount/hubgo-tracking-info.php
6. Integrations
The Integrations screen is a card catalog with a category filter, a settings modal per integration and one-click install/activate for the plugins that are distributed on wordpress.org.
| Integration | What it does |
|---|---|
| Joinotify | WhatsApp automation: five triggers (order shipped, tracking code saved or removed, delivery date promised, delivery late), 33 placeholders and the conditions to branch on them |
| Melhor Envio | Stores the carrier that actually moves the parcel and the delivery time as standard rate meta, and makes the official plugin quote correctly from the product page |
| Frenet | Recovers the delivery forecast and the carrier from the Frenet response and puts the promised date back on the calculator |
| WooCommerce Shipment Tracking | Read-only bridge for its tracking items, plus a batched migration into HubGo |
| Google Maps | Address lookup that powers the postcode finder and the street name shown on the quote |
| Elementor | Registers the shipping calculator widget |
Two rules govern this area:
- Nothing in Core registers an address provider.
Address_ServicepublishesHubgo/Core/Address/Providerwith anulldefault, and the Google Maps integration answers it once its card is on and a key is saved — an install with the card off never reaches an external service. - A plugin HubGo installs is never patched. Incompatibilities are fixed from HubGo's side, through whatever public surface the other plugin exposes.
7. Licensing and updates
Licensing, signed updates (ed25519), rollback and the update heartbeat are
handled by the MDS PHP SDK (meumouse/mds-php-sdk ^1.3), installed with
Composer and registered by Core\License — there is no bespoke updater.
The update check is POST /v2/update-check on the MDS API, sent by the SDK with
the site domain, the product_slug (hubgo) and the installed
current_version; the license key travels with it while the update gate is
closed. What the answer may say about this site is two separate permissions,
not one:
License::allows_updates()— MDS still announces new versions here.License::allows_downloads()— MDS still hands over the package itself.
They usually agree, and where they do not the update interface follows them
rather than License::is_active(): MDS can waive either gate for one license
(how a customer who bought before HubGo required a key keeps updating), and a
release can be announced to every site with the ZIP reserved for licensed ones —
which shows up as a new version with no "Update now".
The version metadata WordPress renders (requires, tested, requires_php)
comes from the same response, off the product registered on MDS; the plugin
header carries the matching values.
MDS credentials are compile-time constants, overridable from wp-config.php:
HUBGO_MDS_API_URLHUBGO_MDS_API_KEYHUBGO_MDS_PUBLIC_KEY
License activation is currently switched off (License::ENABLED), and it
governs the key, not the product. HubGo is still registered with MDS and still
checks for updates — under the SDK's updates_only preset, which sends the
check with no license_key and lets MDS answer on the product's own gates. The
response is still verified against the ed25519 public key; no preset switches
that off.
What is gone while the switch is off: the License screen and its Vue bundle,
the hubgo/v1/license/* routes, the license heartbeat, rollback, the SDK
notices, and every Pro gate — License::is_active() answers true, so nothing
locks itself behind a key. Nothing was removed from the codebase: flip the
constant, or define it in wp-config.php, and the activation flow comes back
whole.
define( 'HUBGO_LICENSE_ENABLED', true );
This requires MDS to agree. With no key on the wire, /v2/update-check only
answers for a product whose update gate is open on the server.
The plugins list carries a Check for updates link either way, forcing a
fresh MDS check over POST hubgo/v1/updates/check.
8. Architecture
hubgo.php Plugin bootstrap: header, autoload, MDS SDK, Plugin::init()
admin/ All PHP backend code + Composer (PSR-4: MeuMouse\Hubgo\ => admin/src/)
src/Admin/ Admin screens, settings schema, persistence, system status
src/API/ REST layer (namespace hubgo/v1), one class per endpoint
src/Core/ Bootstrap, assets, licensing, address lookup, domain services
src/Emails/ WooCommerce e-mail classes
src/Integrations/ Integration registry + one class per third-party plugin
src/Views/ Storefront/admin rendering and calculator styling
app/ Vue 3 + Vite apps (admin SPA + storefront)
src/entries/ One entry per bundle (settings, integrations, license, storefront)
src/pages/ Admin page components
src/components/ Shared admin UI (fields, cards, modals, toasts, layout)
src/storefront/ Storefront calculator components, tokens and styles
src/utils/ REST client, i18n proxy, mount helper
assets/ Non-bundled admin CSS/JS and brand SVGs
templates/ Overridable WooCommerce templates
languages/ .pot/.po/.mo/.l10n.php + the translation CLI tooling
scripts/build.mjs Release pipeline (Vite + Composer + translations + zip)
release/ Build output (git-ignored)
Design points worth knowing before reading the code:
- Lazy bootstrap.
Plugin::init()is the only entry point. A hook → classes map decides when each component is instantiated, behind the dependency gate. - API-first. No
admin-ajax.phphandlers and no server-rendered settings form; the PHP page prints a mount node and a skeleton, everything else arrives over REST. - Schema-driven settings. One option, one write path, sanitization by field type. Every screen POSTs its full settings map.
- Generated artifacts are not committed.
app/dist/andadmin/vendor/are produced by the build, and the packaging step refuses to zip when the Vite manifest or the Composer autoload is missing.
AGENTS.md documents the conventions in full: PHP style, docblocks, security rules, the Vue and Tailwind rules, the field registry, motion tokens and the integration/migration contracts.
9. REST API
Namespace: hubgo/v1. Every response has the shape
{ status: 'success' | 'error', … }. Admin routes require the
manage_woocommerce capability and the wp_rest nonce in X-WP-Nonce; the
calculator and the address routes are public by necessity and protected by
caching, a per-visitor rate limit and a store-wide daily ceiling.
| Method | Route | Purpose |
|---|---|---|
GET |
/settings |
Bootstrap payload for the Settings screen (schema + values) |
POST |
/settings |
Persist the full settings map |
POST |
/settings/reset |
Restore defaults |
GET |
/integrations |
Bootstrap payload for the Integrations screen |
GET |
/providers |
Shipping providers/carriers list |
POST |
/plugins/install |
Install and activate an integration's plugin |
POST |
/migrations/run |
Process one migration batch |
POST |
/shipping/calculate |
Quote a product (public) |
GET |
/address/autocomplete |
Postcode finder suggestions (public) |
GET |
/address/resolve |
Resolve a suggestion into an address (public) |
GET |
/tracking |
Read the tracking items of an order |
POST |
/tracking |
Create a tracking item |
DELETE |
/tracking/<id> |
Delete a tracking item |
GET |
/license |
Bootstrap payload for the License screen |
POST |
/license/activate |
Activate a key |
POST |
/license/sync |
Revalidate the license |
POST |
/license/deactivate |
Deactivate this site |
POST |
/updates/check |
Force a fresh MDS update check |
The /license* routes are only registered while license activation is on; the
update route is always there — see Licensing and updates.
10. Extensibility
Hooks
Naming convention: Hubgo/Namespace/Thing — slash-separated, PascalCase
segments mirroring the class path. Published hooks are never renamed or removed.
Frequently used ones:
| Hook | Purpose |
|---|---|
Hubgo/Before_Init, Hubgo/After_Init |
Plugin bootstrap |
Hubgo/API/Routes |
Register or replace REST routes |
Hubgo/Admin/Settings/Schema |
Add sections, cards or fields |
Hubgo/Admin/Settings/Bootstrap_Data |
Extend the Settings bootstrap payload |
Hubgo/Integrations/Registered |
Register an integration class |
Hubgo/Integrations/Cards |
Filter the integration catalog |
Hubgo/Shipping_Calculator/Package |
Reshape the package before quoting |
Hubgo/Shipping_Calculator/Rates |
Filter the rates returned to the storefront |
Hubgo/Shipping_Calculator/Positions |
Add a product-page placement |
Hubgo/Shipping_Calculator/Delivery_Meta_Keys |
Where the carrier's forecast is read from |
Hubgo/Core/Address/Provider |
Supply the address lookup provider |
Hubgo/Tracking/Get_Items |
Inject tracking items owned by another plugin (display only) |
Hubgo/Tracking/Item_Saved, Hubgo/Tracking/Order_Shipped |
Tracking lifecycle |
Hubgo/Delivery/Promise_Saved, Hubgo/Delivery/Overdue |
Delivery promise lifecycle |
Hubgo/Migrations/Registered |
Register a data migration |
AGENTS.md carries the complete list.
Adding an integration
Extend Integrations\Integrations_Base, register the card first (so it is
listed even when the host plugin is missing), then bail out when the dependency
or the toggle is off, and register the class in Hubgo/Integrations/Registered.
Adding a field type
- Create the component under
app/src/components/fields/. - Register it in
fieldRegistry.js. - Add the field builder in PHP
Settings\Registryand a sanitizer case inSettings\Repository.
Registered types: toggle, text, textarea, select, color, number,
range, dimension, password. The registry is exposed as
window.HubgoFieldComponents and announces hubgo:field-registry-ready, so
external bundles can register or override widgets.
11. Development
Run from the plugin root.
npm run build
Full release pipeline: Vite build → Composer install --no-dev → refresh the
.pot → compile .mo / .l10n.php → stage the runtime files into
release/hubgo/ → zip them into release/hubgo-<version>.zip.
npm run dev
Vite dev server for the SPA.
npm run build:app
Frontend only, without packaging.
npm run build:fast
Re-stage and re-zip from the artifacts already on disk.
npm run build:translate
Full build plus AI re-translation of every locale (requires API keys in
languages/.env).
Useful scripts/build.mjs flags: --skip-app, --skip-composer,
--skip-translations, --translate, --engine=google|openai, --no-install,
--no-zip.
There is no automated test suite and no linter configured. Correctness is verified by reading the code and by manual testing in a WordPress install.
12. Internationalization
- Text domain:
hubgo, loaded from/languagesoninitat priority0. - Source strings are written in en-US and translated outward from there.
Code, identifiers, comments, docblocks, commit messages, the changelog and
this documentation are English; Portuguese lives only in the
pt_BR/pt_PTcatalogs. - Shipped locales:
en_US,es_ES,pt_BR,pt_PT,de_DE,fr_FR,it_IT. - Never call a translation function before
init— the text domain is not loaded yet and WordPress 6.7+ warns about it. - After adding strings, run
npm run pot(or a full build) and commit the regeneratedlanguages/artifacts.
Translation sub-commands: npm run pot, npm run translate:ai,
npm run compile:translations. See languages/README.md.
13. Versioning and releases
HubGo follows Semantic Versioning. The version appears in four places and they must stay in sync:
- The
Version:header inhubgo.php $plugin_versioninhubgo.phppackage.jsonapp/package.json
CHANGELOG.md follows Keep a Changelog, is written in en-US, and ships inside the zip — it is read by store owners, so it describes what changed for them.
14. Support
- Documentation and support: https://meumouse.com/plugins/hubgo/
- Contributing to this repository: read AGENTS.md first — it is the single source of truth for the project's conventions.
HubGo is released under the GPLv2 (or later) license. See license.md.