Limits and guarantees¶
Wishlist becomes the only wishlist your storefront has, and it emails your customers. This page writes out what that promises and exactly where the promise stops. It is the page to read before you buy, and the page to send a customer's question to afterwards.
Everything here is deliberate. Where a limit exists because of how OpenCart itself works, that is said rather than implied.
At a glance¶
| If you are asking | The short answer |
|---|---|
| Are guests emailed about price drops or restocks? | No. Alerts are for logged-in customers only, because a guest has no email address. More |
| Can I see a guest's wishlist in the admin or through the API? | No. Guests are counts in the report and nothing else. More |
| Can I export the report as a CSV? | Yes. Download CSV gives every row matching your filters, with counts and catalogue fields and never a person. More |
| Does the Wishlist box work with a full-page cache? | Only if the cache leaves out the pages carrying it. It shows each shopper their own saves. More |
| Is anything sent the moment a price changes? | No. Alerts go out on a scheduled sweep, and something has to be running it. More |
| Does it work on OpenCart 4.1.0.4? | Yes, but OpenCart's own scheduler cannot run there, so the sweep and the tidy-up need one of Wishlist's own two doors. More |
| Can I switch a customer's alerts on for them? | No. Only the customer can, from their own wishlist page. More |
| Can a customer have more than one list? | No. One wishlist per shopper per store. More |
| Are guest wishlists kept forever? | No. One untouched for the retention window (180 days unless you change it) is deleted. More |
| Does uninstalling delete the wishlists? | No. All five tables stay; removing what is held is a screen of its own. More |
The two narrowings¶
Two of the features are narrower than their names suggest. Know these before you buy rather than after.
- Alerts are for logged-in customers only, because a guest has no email address. Guests get a wishlist that survives, a share link and bulk add-to-cart; they are never emailed and there is nowhere for them to give an address. Asking for one is consent, storage and an unsubscribe path for somebody the store cannot otherwise identify, and this version does not have that.
- Guest wishlists are not browsable in admin, and are not readable through the API either. Guests are counts in the report and nothing else. There is no customer record to hang a panel off, and guest identity deliberately holds nothing identifying: a random token, the products under it, and when it was last looked at or added to. That token is authority over the list rather than a name for it, which is why no version of this extension will publish one.
OpenCart versions¶
- Wishlist runs on the OpenCart releases ticked on its marketplace listing, and each is there because a full install-to-uninstall pass was run on it.
- Below OpenCart 4.0.2.0 it refuses to install and says so: no tables, no settings, no events. That release is the first with a scheduler for the alerts to run under, and an extension that installed below it would have a storefront that worked and alerts that silently never fired.
- Below the PHP floor it refuses to install as well, and that refusal is written to the store's error log rather than shown on the screen. The floor and where to look are on requirements.
- A release newer than the tested ones installs and runs, and says on its own screen that it is untested. A version nobody has run a pass against is not the same thing as a version known to be broken.
- OpenCart's own scheduler does not run on OpenCart 4.1.0.4. It is OpenCart's bug, it kills every scheduled task on the store rather than only ours, the storefront wishlist is unaffected, and the repair is upstream's. Left alone, what that costs on that release is the hourly alert sweep and the daily guest tidy-up; what it does not cost is anything a shopper touches. Wishlist says all of this on its own settings screen.
There are two doors out of it, and they are the reason Wishlist claims the
release rather than refusing it. Neither goes near cron.php, and both work
normally there:
- **The two web addresses** on Wishlist's settings screen, under **Running
the scheduled jobs**, fetched by a host's cron panel or a third-party cron
service: the sweep hourly, the purge once a day.
- **`php extension/wishlist/wishlist.php sweep`** and **`… purge`** from your
store's directory, run from crontab lines on the same two cycles.
Both are in install, with the lines to paste. Set one of them up and nothing above happens to you.
What neither door does is let anybody run these jobs. The web addresses carry a secret generated when the extension was installed, compared in constant time, and a store whose secret is somehow empty refuses every caller rather than admitting every caller; the commands refuse anything that is not a terminal. The sweep makes your store email its own customers and the purge deletes rows, and an unguarded route would let a stranger do both.
What a wishlist is¶
- One wishlist per shopper. No named lists, no move to another list, no copying between them. An owner is their wishlist.
- A guest is a browser, not a person. The list is found by a first-party cookie holding a random token. Clearing cookies, switching browser or opening a private window is a different shopper as far as the store is concerned, and the old list becomes unreachable rather than deleted. It goes at the end of the retention window.
- A guest who signs in has their list merged, and merging never doubles a product: saving the same thing twice is one entry. The guest rows go; the account keeps everything.
- A logged-in customer's saved products are OpenCart's own, in core's
customer_wishlisttable, which Wishlist never creates, alters or drops. - Saved products are per store. On a multi-store install, a list saved on one storefront is that storefront's; the same customer shopping on the second one has a second list there. This is core's own behaviour and Wishlist keeps it.
Sharing¶
- One share link per shopper per store, and it is off until they create it.
- The page behind a link shows the saved products and nothing about the owner: no name, no email, no order history, no count of anything else. A link is handed around by the person who made it, so the token is the whole of the access control.
- Replacing a link revokes the old one immediately. Anyone holding the previous URL gets the same not available page as somebody who typed a token at random. Switching the link off does the same thing without losing it.
- A shared list is live. What it shows is what the owner has saved right now, at today's prices, not a snapshot of the moment it was shared.
- There is no way to see who opened a link, or how often, or to expire one after a date.
Add all to cart¶
- What can be added is added, and the rest is named with the reason. The button does not refuse the whole list because one row needs a size chosen.
- A product needing a choice is not added, and the shopper is linked to the product page, which is where a required option or a subscription plan is chosen. A wishlist row is a product and nothing else, so those choices do not exist to carry.
- Out of stock follows your own checkout setting. Where the store does not let a shopper check out with an out-of-stock line, the row is refused and said so; where it does, the line goes in exactly as the product page's own button would add it.
- A product no longer on sale is reported and left alone. Nothing about pressing add-to-cart deletes a row from somebody's wishlist; on a shared list that would be a write to a stranger's.
- Quantities are the store's minimum, one line per saved product. There is no quantity box on a wishlist.
Alerts¶
- Nothing is sent by a page view. Both alerts are sent by a sweep, woken hourly. Sweep Runs on the settings screen can make it act less often (daily, weekly or monthly) but never more often than the hourly wake-up. A store where nothing is running that sweep sends nothing. There are three ways to run it (OpenCart's own scheduler, a web address fetched from a cron panel, or a command from a crontab line), and they are in install. There is no button in the admin that sends the waiting alerts on a click, because alerts that depend on someone pressing a button every hour would not go out reliably.
- Saving a product subscribes that customer to both alerts, and the tick-boxes on their own wishlist page are how they narrow it or switch it off. If nobody were subscribed until they found a tick-box, the alerts would only reach shoppers who went looking for them. The page says in one line what the store will email them about.
- Only the customer can switch an alert on. Nothing in the admin can do it for them: what they asked to be emailed about is their own consent, so the Wishlist tab on their record shows it and never sets it. A product added to their list from the admin arrives with both alerts off, and stays that way until they tick one.
- One email per customer per store per sweep. Twelve products that all moved is one email with twelve rows, not twelve emails.
- A back-in-stock alert fires on the crossing, not on the level. It is sent when a product the shopper saved while it was unavailable becomes available again. Saving something that is in stock and stays in stock never mails anybody, which is also what stops the first sweep after an install emailing every customer you have.
- A price-drop alert measures against what the product page showed when they saved it: the special if there was one, tax included where your store displays it that way, in the store's default currency. A shopper browsing in another currency sees a converted figure; the comparison is not made in it, because a baseline converted at one moment and compared at another would move on an exchange rate alone.
- The same product cannot mail the same person twice in 24 hours on the same axis, unless you change Cooldown Per Product, which each storefront sets for itself, anywhere from one hour to fourteen days. A price oscillating across the threshold does not mail hourly.
- At most 200 customers are emailed per sweep by default, which you can change. The hour a catalogue-wide price change lands, whoever misses the cut keeps their place (nothing is consumed) and goes on the next sweep, oldest first, so nobody is passed over repeatedly.
- A store with no mail engine configured is skipped, and nothing is consumed. Configure mail a fortnight later and every waiting alert goes on the next sweep; the queue does not empty itself in the meantime.
- A refused send is retried; a sent one is not resent. The baseline moves after the send rather than before it, so a mail server that was down means the alert waits. The cost of that choice is that a mail sent twice is possible where a mail lost is not.
- Nothing in the email is re-checked between the sweep and the send, and the email says as much: it names the moment the store looked and links every row to the product page, which is the live position.
- Alert emails carry no
List-Unsubscribeheader, because OpenCart's mail library cannot set one: it accepts a subject, a sender and two body parts and nothing else. The in-body link is the off switch. A store large enough to meet Gmail's bulk-sender threshold is already relaying through a mail provider, which adds the header itself. - One click on that link stops every wishlist alert for that customer on that store, before the page renders, with no session and no login. It is not per-product, because a link labelled unsubscribe that silenced only one row would not do what it says.
- An unsubscribe outlives the wishlist it was made from. Saving something new afterwards does not resubscribe them. Turning individual alerts back on from their own wishlist page does, which is the customer's own decision and the only way back on.
- The emails carry no images, including the store's logo, and no offer beyond the products the shopper themselves saved.
- There is no template editor. The two emails are the extension's own templates and language files, and an update overwrites an edited one exactly as it overwrites an edited OpenCart language file.
- Deleting a customer in the admin takes their alerts and their share link with them. Their saved products go the way core deletes them.
The report and the customer tab¶
- There is no all-time demand figure and none is faked. Every number counts what is on somebody's wishlist right now, so removing an item lowers it. The report says so on the screen.
- Guests are counted and never listed. Guests is a number; there is no row to click through to and no way to see what one guest saved.
- The alert columns count customers only, because guests are never emailed.
- Products deleted from the catalogue keep their rows, shown as Product #n, since deleted. A wishlist entry is a shopper's, and the report is where you see it, so it is not hidden.
- Download CSV gives you the report as a spreadsheet. The button is on the
report's filter panel. The file holds every row matching the filters in that
panel, not only the page on screen, in the order the table is sorted. Each
row is a product: its id, name, model, status (
enabled,disabledordeleted), stock, price and special, then how many shoppers have it saved (total, customers and guests, counting owners rather than units) and how many customers are waiting for stock or watching the price. Prices are the catalogue's own figures, unformatted. A deleted product keeps its id, its counts anddeleted, and its name, model, stock and prices are empty. The file never holds a guest, a customer or an address, only counts. Who can download it is whoever can open the report. - The CSV is for a person and the API is for a system. The API, off until you switch it on, answers the same two splits per product, and a credential you create yourself can also read every alert row there. It still cannot read a guest list, a share link or an email address, and it cannot write anything.
- There is no scheduled email of the report.
- The Wishlist tab needs core's customer form to be recognisable. It is spliced into the page beside core's own tabs, and a theme that rewrote that form loses the tab rather than the page: the screen renders exactly as OpenCart rendered it.
- Adding a product to a customer's wishlist from the admin adds no alerts. Whether they want to be emailed is theirs to say.
Storage and tidy-up¶
- A guest wishlist untouched for the retention window is deleted, with its saved products and its share link. The default is 180 days, and the window is measured from when the guest last looked at or added to their list rather than from when each item was saved, so somebody active does not lose the thing they saved first.
- The tidy-up is a daily scheduled job, and it also removes rows naming a product, a customer or a guest that no longer exists. It never removes an unsubscribe: a marker deleted as orphaned would resubscribe somebody who told the store to stop.
- It works in batches of 500 per kind per run and leaves the remainder for the next day. That keeps the first run after an upgrade, on a store with years of guests on it, from timing out.
- A logged-in customer's wishlist is never expired. Retention is a guest window only.
- On OpenCart 4.1.0.4 OpenCart's scheduler cannot run the tidy-up either, for
the same reason it cannot run the sweep, and the same two doors run it there:
the Purge address on the settings screen, or
php extension/wishlist/wishlist.php purge.
The wishlist box¶
- It shows the shopper looking at the page their own saves, the most recent first, up to Saved Products Shown (4 unless you change it, from 1 to 12), as the same product cards your theme draws for Featured, with a link to their whole wishlist underneath. Guest or signed in, in this store only.
- It shows nowhere until you place it, in Design → Layouts, and it has one limit for every layout it is on. It is not a module you add instances of.
- It shows nothing at all when there is nothing to show: to a guest who has saved nothing, on the saved product's own page when that is the only thing saved, and on the wishlist page itself, which already is the list. A saved product your store no longer sells is left out, so the box can show fewer than the limit.
- It sets no cookie and writes nothing. A guest who has never saved a product is not given a cookie by seeing a page with the box on it, and showing the box does not count as a visit to their wishlist for the retention window.
- A full-page cache can show one shopper's box to another. OpenCart has no
full-page cache of its own, but an extension or a server cache that serves one
stored copy of a page to many visitors would serve the box inside it too. The
header's wishlist counter has the same exposure with less in it. If you run
one, leave out the pages carrying the box, or every request carrying the
wishlist_guestcookie or a signed-in session. - Its wording is ours. Your wishlist and See your whole wishlist are language strings, not something you set on the settings screen.
Removal¶
- Uninstalling hands the wishlist back to OpenCart. The events that put Wishlist in front of the wishlist routes go with it, so the next request gets core's own page, with every logged-in customer's saved products intact, because they were never anywhere else.
- Uninstalling leaves all five tables in place, frozen. Nothing writes to them, nothing reads them, and they do not grow. That is why an update (an uninstall followed by an install, as far as OpenCart is concerned) keeps every guest wishlist, share link and alert subscription on the store.
- Removing what Wishlist holds is a screen of its own, used while the
extension is still installed. Show me what is held, and how to remove it
on Wishlist's settings screen opens Remove everything held about a person,
which lists every guest wishlist, saved guest product, share link and alert
row with a count, and removes them only when you press its button. It cannot
be undone. It needs its own permission (see
install), and the link is absent for
a group without it. Your settings and OpenCart's own
customer_wishlistare not touched; the extension goes on running with nothing in it. What each row is, and what removes it, is on what this holds about a person. - An erasure takes the unsubscribe with it. Removing everything, or erasing one customer from Customers → Personal Data, deletes their unsubscribe along with their alerts. A customer whose account still exists and who saves a product afterwards is signed up for both alerts again, as any customer with no unsubscribe on record is.
-
The five tables are
wishlist_guest,wishlist_guest_item,wishlist_share,wishlist_alertandwishlist_setting, each behind your store's own table prefix. A store owner who wants the tables themselves gone runs one statement in their own database tool, with the extension uninstalled first:sql DROP TABLE `oc_wishlist_guest`, `oc_wishlist_guest_item`, `oc_wishlist_share`, `oc_wishlist_alert`, `oc_wishlist_setting`;Replace
oc_with your store's prefix.oc_customer_wishlistis not on that list and must not be added to it. It is OpenCart's own table, holding what your logged-in customers saved, and it is there whether this extension ever was. -
An update takes the Wishlist box off every layout. Removing the old version from Extensions → Modules, the first step of an update, makes OpenCart delete every placement of it, and Wishlist keeps no copy. Place it again in Design → Layouts afterwards. Saved Products Shown is kept.
- Permissions granted at install are never revoked. A grant reaches only the group that installed the extension, where you may since have given the same screens to three more; revoking would strip one and leave three. What is left behind is a permission row naming a route that no longer resolves, which does nothing at all.
- Both scheduled jobs come back enabled on the next install. Switching one off in Extensions → Cron Jobs stops it until the next update, which re-creates both rows. To stop alerts in a way that survives an update, switch the alert types off on Wishlist's own settings screen, since those settings are remembered.
Coexistence¶
- Wishlist is the only wishlist the storefront has while it is installed. Every hit on OpenCart's own wishlist routes is handled by this extension, for logged-in customers as well as guests. That is what makes one code path, one saved-product list and one alert baseline possible. Another extension that replaces the same routes will fight with it.
- No core file is edited and no OpenCart table is altered, so nothing here survives an uninstall except the data, and nothing here has to be undone by hand.
- Back In Stock is a different product for a different shopper, and neither needs the other. That one takes an email address on a product page from somebody with no account and no wishlist; this one emails logged-in customers about the things they saved. A shopper could be on both lists and get both emails; the two extensions do not read each other's rows.
Language¶
Wishlist says four things to a shopper: the wishlist page itself, the public page behind a share link, the alert emails, and the page an unsubscribe link opens. The emails are different. They are sent by an hourly sweep with nobody standing in front of the store, so each is rendered in the language on that customer's own record rather than in whatever language the sweep happened to start in: the recipient's language, named outright, not the store's. Which of our strings a named native speaker has actually read, and in which language, is answered and counted on the shared language promise page rather than restated here.
Four points follow. The first decides what a shopper sees:
- A string nobody has translated yet reaches a shopper in English, never blank
and never as the identifier it is stored under. Every string of ours is
served with English underneath it, string by string rather than language by
language, so a half-finished translation is a page in two languages instead of
a page with holes in it. That floor is deliberate: an alert email printing
text_price_headingwhere a heading belongs is worse for a store than one that briefly says Price drop. - The screens you work in are translated as far as somebody has read them and no further, and the rest is English. A string a named reviewer has signed off is served in your admin language; a string nobody has read is served in English rather than blank; and a string whose English has since been reworded goes back to English until it is read again. Which string is in which state is on that page, per language, counted rather than claimed.
- Three sentences are yours to write, per language and per storefront, and
an update does not reach them. The heading on a shared list page, the line an alert email opens
with, and the wording on the unsubscribe link in its footer. Each language is
saved on its own, so writing Dutch this week leaves the German you wrote last
month exactly as it was. A box left empty uses our wording rather than none,
shown in the box in grey, so you can tell inherited from written. This
is the answer to there is no template editor above: editing our files under
extension/is a different act with a different outcome, because an update replaces those files and takes your change with them. - Upgrading from a release without the wording panel files your existing shared list title under your storefront's default language. It was one box with no language at all before then, and the only page it appears on is a storefront page, so that is the only accurate place to put it. Filing it under English would have served English wording to every shopper if you had typed it in Dutch. If your storefront runs in more than one language, look at the wording panel after upgrading: the heading is there, under your default, and the other languages read ours until you write it in them too.
Anything not described on this page should be assumed absent. If you are about to rely on behaviour that is not written here, ask before you buy.