Skip to content

Changelog

What changed in each release of Loyalty, in terms of what it means for you rather than which files moved.

1.1.1 — 3 October 2026

A shopfront you added after installing keeps the programme through an update. A store with nothing saved for it of its own runs the default store's programme. Until now an update wrote the shipped defaults for that store as if somebody had chosen them, so from then on it ran with the programme off, earning not started and a rate of 0. An update now writes a second store only what was saved for it. Its settings form also shows what it actually runs, the default store's settings, where it used to show the shipped defaults, so saving one field there no longer stops earning on that store. A store an earlier update already switched off keeps the settings that update wrote: open it in the store selector, switch it back on and save.

The warning about OpenCart's own GDPR erasure appears on every release it breaks. OpenCart's erasure deletes the account and then fails on 4.1.0.0, 4.1.0.1 and 4.1.0.2 as well as on 4.1.0.3, but Loyalty's screen only said so on 4.1.0.3. It now says so on all four.

The expiry warning email greets a customer by their name as typed. A first name containing & or a quotation mark arrived with the HTML code in its place.

A points-history line written by another extension, or added by hand, is shown as text on the customer's points page, never as markup. Lines Loyalty and OpenCart's own form write look as they did.

An API user with no key is refused. OpenCart's own form will not save an API user without a key, but one edited by hand in the database could have one, and the API would have let in a caller presenting that user's name and an empty key. Nothing about what the API answers has changed.

Nothing to do on update. No setting is added or changed, nothing is added to the database, and the API is exactly as it was.

1.1.0 — 2 October 2026

An erased customer is no longer named by a movement's key. Erasing a customer — deleting them, OpenCart's own GDPR erasure, or the remove-everything screen — already emptied the customer from their points history and kept the rows. The key Loyalty gives a welcome bonus, a birthday award and an expiry was built from the customer's account number, though, and it stayed on the emptied row. Those keys are now rewritten to name the movement instead. A key built from an order is kept, because the order survives the erasure, and a key another extension wrote through the award call is kept as that extension wrote it. The update itself rewrites the keys left on customers erased before it.

A read-only JSON API, off until you switch it on. Your CRM or accounting system can read every movement of points — where it came from, whether it still counts, and what changed since a moment — and every customer's balance as OpenCart holds it, with when the expirable part goes. Points are never given a money value, and nothing can be awarded, spent or changed through it. Switch it on under API on the default store's settings; a caller signs in as an OpenCart API user under System → Users → API. The API lists every field, and limits and guarantees says what it cannot do.

Nothing to do on update. One new setting, the API switch, which arrives off. The update adds one column and one index to the points ledger table; movements from before the update carry no "changed" date until they next change.

1.0.0 — 26 September 2026

The first release. There is no previous version, so nothing below is a change. This entry is the baseline every later one is measured against.

What ships:

  • earning on orders, as a percentage of the goods, per store and per customer group, awarded once when an order first reaches a status you tick, and only for orders placed after you pressed Start awarding points;
  • reversal, the whole award taken back once when an order reaches a status you tick for refunds, even when that takes a balance below zero;
  • spending at checkout through Loyalty's own order total, with a slider on the cart that steps in whole units of currency, a minimum balance, a cap on the share of an order points may pay, and the exchange rate frozen on each order when it is created;
  • a welcome bonus for new accounts and a birthday bonus read from a Date custom field of your own;
  • expiry of dormant points, off until you switch it on, never without a warning email first, and only ever of points Loyalty itself awarded;
  • the customer's Reward Points page replaced by one that leads with the balance and what it is worth, says what will expire and when, and names the order behind a negative balance;
  • what the store owes, in points, on the Loyalty screen, with a confirmation that names the effect in money before a new exchange rate makes the points outstanding buy less;
  • the award seam, through which another installed extension awards or deducts points exactly once.

What it does not do is the shorter list, and the one to read first.

It runs on every OpenCart release from 4.0.2.0 to 4.1.0.4, and refuses to install below 4.0.2.0 rather than half-working. On 4.1.0.4 expiry, the warning email, the birthday bonus and the repair of failed writes run only from a crontab line calling php extension/loyalty/loyalty.php, because OpenCart's own scheduler cannot reach any extension on that release. On 4.1.0.3 OpenCart's own GDPR erasure stops partway through, which Loyalty's screen says. See limits.

The Remove everything held about a person screen removes Loyalty's part in every customer at once, and leaves OpenCart's own reward rows, which are the balances, where they are; see limits.

What an update keeps

Your settings come back, with the exceptions below. An update is an uninstall and then an install, and OpenCart deletes an extension's settings at the uninstall step. Loyalty keeps its own copy of them and puts them back afterwards. Each store keeps its own, apart from total_loyalty_status, total_loyalty_sort_order, module_loyalty_diary_verbose_until and module_loyalty_api_enabled, which Loyalty reads once for the whole installation.

These are asked for again rather than put back:

  • module_loyalty_diary_verbose_until — Detailed logging comes back off after an update, the way a fresh install does. An upgrade is an uninstall and a reinstall, and putting a diagnostic window back is how a store ends up verbose months after the support exchange that asked for it ended.

A setting a release adds does not change what your store does. Its default is what Loyalty did before the setting existed, so an update never asks you to go and set something to get back the behaviour you already had.

What this cannot tell you is whether a release changed how a setting behaves, as against whether it survives. Nothing derives that from the code, so it is written by hand: a release that changes an answer you relied on says so in its own entry above, as its own paragraph and never among what is new.