Direct answer
Use the sale end date already stored by WooCommerce. On the exact simple-product page, confirm the product is currently on sale, read its native future end date once, format it with the WordPress site locale and timezone, and print one escaped sentence. If any condition is missing or uncertain, print nothing.
Sale End Date for WooCommerce follows that read-only boundary. Free adds one enable switch. Pro adds a short prefix, three native positions, and date-only or date-and-time formatting.
A date sentence and a countdown are different products
| Feature | What it needs | Main failure surface |
|---|---|---|
| Static sale-end sentence | One valid native future date | Correct product, timezone, and output location |
| Live countdown | Repeated browser updates and synchronization | JavaScript, stale pages, tabs, clocks, caches, and layout |
| Promotion engine | Campaign rules and price mutations | Pricing authority, schedules, conflicts, and recovery |
A merchant who only wants “Offer ends July 30” does not need ticking JavaScript, a custom timer template, campaign state, progress bars, fake urgency, or background jobs.
Public support reports show the cost of broader countdown surfaces. One merchant reported a countdown plugin interfering with the native sale price field. Another reported a per-product timer missing in an Elementor product template. A separate topic reports a fatal error alongside cart and free-shipping problems. These reports document individual incidents only. They do not establish that every timer is unsafe.
Let WooCommerce own the sale
WooCommerce should remain the sole authority for regular price, sale price, start date, and end date. The merchant creates the schedule in the native product editor. A display helper reads it.
That rule prevents several dangerous shortcuts:
- Do not copy the date into a second plugin option that can drift.
- Do not extend an expired date automatically.
- Do not infer an end date from a campaign label or cached page.
- Do not write a sale price when the date is present.
- Do not show a deadline when WooCommerce says the sale is inactive.
WooCommerce's official product editor documentation describes the native product data and pricing surface. StoreFixKit adds no second price or schedule editor.
Use the site's timezone, not the browser clock
The same timestamp can represent different calendar dates in different timezones. A store promise should use the timezone configured by the store owner.
WordPress's wp_date() reference documents formatting with a supplied timezone. A safe display flow should:
- Receive a valid WooCommerce date object.
- Confirm its timestamp is in the future.
- Read the WordPress date format, and optionally time format.
- Format with the WordPress site timezone and locale.
- Escape the prefix and complete sentence.
It should not switch to the visitor's device clock, because two shoppers could then see different calendar dates for the same store schedule.
Put the sentence in one native product location
WooCommerce's current wc-template-hooks.php source lists the native single-product summary callbacks and priorities. A small helper can use that existing summary hook instead of overriding a template.
Three positions are enough for a focused paid layer:
- after the price;
- the default summary position;
- after the purchase area.
Using native priorities keeps output inside WooCommerce's normal product summary. It does not guarantee that a builder or block executes the same hook. If a custom template omits it, fail quietly rather than injecting a selector or copying theme markup.
Set up and verify the date
- Edit a native simple product.
- Enter its regular and sale prices.
- Open WooCommerce's Schedule control and save a future end date.
- Open WooCommerce > Sale End Date.
- Enable Show the scheduled sale end date and save.
- Open the exact public product while signed out.
- Confirm the sale is active and one sentence shows the expected site-local date.
- Open a product with no end date and confirm no sentence appears.
- Test an expired sale and a sale that has not started.
The correct pass condition is conditional output. A plugin that prints a sentence on every product, or displays an expired deadline, is not solving the same job.
Diagnose a missing or wrong date
| Symptom | Check first | Safe expected result |
|---|---|---|
| No sentence | Free switch, simple product type, active sale, future native date | One sentence only when all are valid |
| Date is off by a day | WordPress timezone and saved timestamp | Site-local calendar date |
| Time is missing | Pro format and WordPress time format | Date only in Free; date and time only when selected |
| Builder template is blank | Whether it runs the native summary hook | Default template works; unsupported builder stays unchanged |
| Variable product has several dates | Variation ownership | No guessed date in this release |
| Sentence appears twice | Duplicate hook execution | At most one sentence per request |
Start with the native WooCommerce product page. If it is correct there, the underlying date is valid and the custom display surface is the likely boundary. Do not clear every cache or disable every plugin before identifying which surface owns the missing hook.
Keep formatting plain
A trustworthy deadline sentence needs no fake scarcity. The default can be as simple as:
Offer ends July 30, 2026.
The prefix should be plain text and capped. HTML, icons, scripts, timers, progress bars, dynamic urgency claims, and visitor-specific localization introduce a larger security and truth surface.
StoreFixKit caps the Pro prefix at 60 characters and allows only three positions plus two site-defined format choices. When Pro licensing is unavailable, Free falls back to its local date-only sentence.
Test failure and rollback
Release acceptance should cover:
- Active simple-product sale with a future end date.
- Missing date, expired date, inactive sale, malformed object, and wrong queried product.
- Duplicate hook execution.
- WooCommerce missing.
- Pro or license API unavailable.
- Update, downgrade, rollback, deactivation, default uninstall, and explicit cleanup.
- Desktop and 390-pixel mobile output.
- Unchanged prices, dates, products, carts, and orders.
The StoreFixKit 0.1.2 release drill exercised those package and lifecycle boundaries on a real WordPress and WooCommerce installation. Packaged Plugin Check reported zero errors and zero warnings across Free and Pro. This is package evidence, not a claim that every builder runs WooCommerce's native hook.
Resource boundary
A static sentence does not need a scheduled job. WooCommerce already decides when a sale is active, and the page request already has the exact product.
The Batch 14 measured product-page run covered 25 requests with all six plugins active and 25 inactive. The active state added one database query at the median and P95, 2 MB of measured PHP memory, no plugin HTTP call, no plugin-owned write, and no unrelated frontend asset. Repeat the benchmark on the real hosting stack before a high-traffic launch.
Common mistakes
Maintaining a second end date
Two authorities eventually disagree. Read WooCommerce's date instead.
Showing a countdown for a missing date
An inferred timer is a false deadline. Missing or uncertain state should render nothing.
Using the visitor's clock
The browser clock can be wrong and can move the promised date between timezones. Use the store timezone.
Guessing the selected variation
A variable product can have several sale schedules. Do not show one date until the exact selected variation contract is implemented and tested.
Editing the sale when display fails
A missing sentence is not proof that the price schedule is corrupt. Diagnose the output hook and product identity before touching commercial data.
Market boundary
The official WooCommerce Marketplace lists a current Simple Sale Countdown Timer offer, and WordPress.org has established timer plugins. That proves an active broader category. It does not prove demand or revenue for a narrower read-only sentence.
The commercial hypothesis is that some nontechnical merchants prefer a truthful date with no timer maintenance, script, template, or campaign engine. Measure StoreFixKit installs, setup completion, valid date renders, trial starts, paid conversions, refunds, renewals, and support load. A competitor price or install count is not StoreFixKit traction.
FAQ
How do I show when a WooCommerce sale ends?
Save the sale schedule in WooCommerce, then read the native future end date on the exact active simple-product page and format it with the WordPress site timezone.
Do I need a countdown timer?
No. A static end-date sentence needs no ticking JavaScript or background job.
Will this change the sale price or schedule?
Not in this design. It only reads WooCommerce's existing state.
Why is no date shown for a variable product?
Different variations can have different schedules. This release fails passive instead of guessing which date the shopper means.
What happens when Pro is unavailable?
Free continues to show its valid date-only sentence at the default native position.
Focused plugin
Use the one-job implementation.
Show shoppers the real future end date already saved in a native WooCommerce sale schedule, without changing prices or dates and without a countdown, script, background job, or fake deadline.