January 20, 2026
Dynamically show Fluent Cart Coupons Count on the Frontend

Jack of all trades, Master of none
Reading Time: 10 minutes

If you’re using Fluent Cart on WordPress and you’ve created a coupon with a usage limit (example: 10 uses), you might want to add urgency on the frontend:
“Only X coupons available!”
The problem is that most WordPress sites use page caching (Swiss Performance, WP Rocket, LiteSpeed, Cloudflare, etc.). That means a normal shortcode can get cached and your number won’t update in real time.
In this tutorial, I’ll show you how to display coupon remaining count dynamically, even on cached pages, using a lightweight AJAX approach, and as a bonus, we’ll also hide a section (by class) automatically when the coupon reaches 0 remaining.
What we’re building
You’ll be able to place this shortcode anywhere:
[fluentcart_coupon_remaining_live
code="YOURCODE"
text="%d coupons available"
]It will:
- ✅ show the remaining number (example:
30 coupons available) - ✅ update automatically (without needing to clear cache)
- ✅ work inside Any Builder
- ✅ let you customize the “sold out” message
- ✅ hide any section/container with a specific CSS class when remaining = 0
Why the normal shortcode fails when caching is enabled
A normal shortcode runs on the server when WordPress generates the page. With caching enabled, that page HTML is saved and reused, so your “X coupons available” may get stuck showing an old number.
To fix this, we render a placeholder on the page and then fetch the real “remaining” count after page load using AJAX. Since the number is loaded dynamically, the cache doesn’t freeze it.
The use case:
I was building this Online Store in Bricks Builder, and I wanted to show a section fully dynamic, with the Available promo coupon, with a copy button, and a countdown timer.
For the Copy Button, and the Countown Timer, I’ve used Bricks Extras elements. The countdown timer allows you to hide a section when the timer reaches zero, using Bricks Extras custom interactions. But, I still wanted to show how many coupons were available, dynamically, and also hide the section if the Coupon itself reaches zero.
This is the section I was building:

For the rest of the content, I used ACF Fields in an options page where I could show, the coupon percentage save, the campaign title, and the date for the countdown timer. I also have a toggle to show/hide the section.
Now all that was missing was the dynamic value of the Fluent Cart Coupon. Let’s get to that now.
Step 1: First you have to create your Fluent Cart Coupon
For this to work, you need to create a Fluent Cart Coupon with an usage limit. In the “Maximum Discount Uses“, set the “Total Limit“.
And you’ll end with a Coupon just like this one:

Step 2: Add the live shortcode + AJAX endpoint
Add the code below to your theme’s functions.php (or, even better, a small custom plugin).
Tip: The custom plugin approach is cleaner long-term, especially if you change themes.
✅ Code to paste
<?php
add_action('init', function () {
// Shortcode outputs placeholder + JS that fetches remaining uses
add_shortcode('fluentcart_coupon_remaining_live', function ($atts) {
$atts = shortcode_atts([
'code' => '',
'text' => '%d coupons available',
'sold_out' => 'Sold out',
'unlimited' => 'Unlimited',
'refresh' => '60', // seconds
'loading_text' => 'Checking availability…',
// NEW (hide a section when sold out):
'hide_class' => '', // e.g. "coupon-cta"
'hide_mode' => 'hide', // "hide" or "remove"
], $atts, 'fluentcart_coupon_remaining_live');
$code = trim((string) $atts['code']);
if ($code === '') return '';
$id = 'fc-rem-' . substr(md5($code . wp_rand()), 0, 10);
$refresh = max(10, (int) $atts['refresh']);
$text = esc_js($atts['text']);
$sold_out = esc_js($atts['sold_out']);
$unlimited = esc_js($atts['unlimited']);
$loading = esc_html($atts['loading_text']);
$hideClass = trim((string) $atts['hide_class']);
$hideMode = ($atts['hide_mode'] === 'remove') ? 'remove' : 'hide';
$endpoint = esc_url_raw(admin_url('admin-ajax.php'));
ob_start(); ?>
<span id="<?php echo esc_attr($id); ?>"><?php echo $loading; ?></span>
<script>
(function(){
const el = document.getElementById('<?php echo esc_js($id); ?>');
if(!el) return;
const endpoint = '<?php echo esc_js($endpoint); ?>';
const code = '<?php echo esc_js($code); ?>';
const hideClass = <?php echo $hideClass ? json_encode($hideClass) : '""'; ?>;
const hideMode = <?php echo json_encode($hideMode); ?>;
function setHidden(isHidden){
if(!hideClass) return;
const nodes = document.querySelectorAll('.' + hideClass);
nodes.forEach(n => {
if (hideMode === 'remove') {
if (isHidden) n.remove();
} else {
n.style.display = isHidden ? 'none' : '';
}
});
}
function render(resp){
if(!resp || !resp.success){ return; }
const r = resp.data;
if (r.type === 'unlimited') {
el.textContent = '<?php echo $unlimited; ?>';
setHidden(false);
}
else if (r.type === 'sold_out') {
el.textContent = '<?php echo $sold_out; ?>';
setHidden(true);
}
else {
el.textContent = ('<?php echo $text; ?>').replace('%d', r.remaining);
setHidden(false);
}
}
async function fetchRemaining(){
try{
const fd = new FormData();
fd.append('action', 'fc_coupon_remaining');
fd.append('code', code);
const res = await fetch(endpoint, {
method: 'POST',
credentials: 'same-origin',
body: fd
});
const json = await res.json();
render(json);
}catch(e){}
}
fetchRemaining();
setInterval(fetchRemaining, <?php echo (int)$refresh; ?> * 1000);
})();
</script>
<?php
return ob_get_clean();
});
});
// AJAX handler (returns remaining uses as JSON)
add_action('wp_ajax_fc_coupon_remaining', 'fc_coupon_remaining_ajax');
add_action('wp_ajax_nopriv_fc_coupon_remaining', 'fc_coupon_remaining_ajax');
function fc_coupon_remaining_ajax() {
if (!class_exists('\FluentCart\App\Models\Coupon')) {
wp_send_json_error(['message' => 'FluentCart not available']);
}
$code = isset($_POST['code']) ? sanitize_text_field((string) $_POST['code']) : '';
if (!$code) {
wp_send_json_error(['message' => 'Missing code']);
}
$coupon = \FluentCart\App\Models\Coupon::where('code', $code)->first();
if (!$coupon || $coupon->status !== 'active') {
wp_send_json_error(['message' => 'Coupon not found/active']);
}
$used = (int) $coupon->use_count;
$conditions = (array) $coupon->conditions;
// Most FluentCart installs store total usage limit here:
$limit = isset($conditions['max_uses']) ? (int) $conditions['max_uses'] : 0;
if ($limit <= 0) {
wp_send_json_success(['type' => 'unlimited']);
}
$remaining = max(0, $limit - $used);
if ($remaining <= 0) {
wp_send_json_success(['type' => 'sold_out', 'remaining' => 0]);
}
wp_send_json_success(['type' => 'ok', 'remaining' => $remaining]);
}Step 3: Add the shortcode to your page
Inside your page, drop a shortcode element and paste:
[fluentcart_coupon_remaining_live
code="YOURCODE"
text="%d coupons available"
refresh="30"
]Recommended refresh value
refresh="30"orrefresh="60"is ideal.- Avoid very low values if your page gets a lot of traffic.
Step 4: Customize the “sold out” message
You can change the text that appears when it reaches 0 with the sold_out parameter:
[fluentcart_coupon_remaining_live
code="YOURCODE"
text="%d coupons available"
sold_out="No coupons left 😢"
]Or hide the label entirely:
[fluentcart_coupon_remaining_live
code="YOURCODE"
text="%d coupons available"
sold_out=""
]Step 5: Hide a Bricks section when the coupon hits 0 (NEW)
This is great for things like:
- hiding a “Limited offer” CTA section
- hiding a countdown block
- hiding a discount banner
5.1 Add a CSS class to the section/container
- Click the section (or container) you want to hide
- Add a class, for example:
coupon-cta
5.2 Tell the shortcode to hide that class on sold out
Use:
[fluentcart_coupon_remaining_live
code="YOURCODE"
text="%d coupons available"
sold_out="Offer ended"
hide_class="coupon-cta"
hide_mode="hide"
refresh="30"
]Hide vs remove
hide_mode="hide"→ setsdisplay:none(can show again if coupons become available and the script rechecks)hide_mode="remove"→ removes the element completely (no spacing), but it won’t reappear until page reload
Example remove mode:
[fluentcart_coupon_remaining_live
code="YOURCODE"
text="%d coupons available"
sold_out=""
hide_class="coupon-cta"
hide_mode="remove"
]Troubleshooting
“It stays on ‘Checking availability…’”
- Make sure that your PHP code is being rendered on the front-end.
“It never changes”
- Check if anything blocks
wp-admin/admin-ajax.php(security plugins / firewall rules). - If you use a CDN, make sure it’s not blocking POST requests.
“It shows Unlimited”
In FluentCart, a limit of 0 often means unlimited usage, set an actual number in the coupon settings.
Final notes (performance + caching)
This approach keeps the page fully cacheable for speed, while coupon availability updates dynamically.
Tools mentioned in this article
Thanks for reading!
- Wordpress
- Fluent Cart
- Tutorial
Loading..