Inline Collapsible Coupon At Checkout
The toggle button collapses/expands the input field.
Quick setup checklist:
- Paste into your Child / Main theme’s
functions.php - Make sure
wc-checkoutscript is loaded on your checkout page it’s by default in WooCommerce. - The nonce is generated fresh on each page load for security.
- Customize the CSS colors to match your brand currently uses a neutral dark button and green success state.
<?php // Remove If Already Exists
/**
* Inline Collapsible Coupon At Checkout
* -------------------------------------------------------------
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/* -------------------------------------------------------------
* 1. Remove WooCommerce's default Coupon
* ----------------------------------------------------------- */
add_action( 'init', function () {
remove_action( 'woocommerce_before_checkout_form', 'woocommerce_checkout_coupon_form', 10 );
} );
/* -------------------------------------------------------------
* 2. Custom coupon box inside the order review.
* Auto re-renders on update_checkout => stays in sync.
* ----------------------------------------------------------- */
add_action( 'woocommerce_review_order_before_payment', 'sscoupon_render_box', 10 );
function sscoupon_render_box() {
if ( ! wc_coupons_enabled() ) {
return;
}
?>
<div class="sscoupon-wrap">
<div class="sscoupon-form">
<input type="text" id="sscoupon-code" class="sscoupon-input"
placeholder="<?php esc_attr_e( 'Discount code', 'woocommerce' ); ?>"
autocomplete="off" />
<button type="button" id="sscoupon-apply" class="sscoupon-btn">
<?php esc_html_e( 'Apply', 'woocommerce' ); ?>
</button>
</div>
<div class="sscoupon-message" aria-live="polite"></div>
<div class="sscoupon-active">
<?php sscoupon_render_active(); ?>
</div>
</div>
<?php
}
/* -------------------------------------------------------------
* 3. Applied coupons as removable chips
* ----------------------------------------------------------- */
function sscoupon_render_active() {
$applied = WC()->cart->get_applied_coupons();
if ( empty( $applied ) ) {
return;
}
foreach ( $applied as $code ) {
$amount = WC()->cart->get_coupon_discount_amount( $code, WC()->cart->display_cart_ex_tax );
?>
<div class="sscoupon-chip">
<span class="sscoupon-chip-tag">
<svg viewBox="0 0 20 20" width="13" height="13" aria-hidden="true">
<path fill="currentColor" d="M9.05 2H4a2 2 0 0 0-2 2v5.05c0 .53.21 1.04.59 1.41l6.95 6.95a2 2 0 0 0 2.82 0l5.05-5.05a2 2 0 0 0 0-2.82l-6.95-6.95A2 2 0 0 0 9.05 2ZM6 7a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"/>
</svg>
<?php echo esc_html( strtoupper( $code ) ); ?>
</span>
<span class="sscoupon-chip-amt">−<?php echo wp_kses_post( wc_price( $amount ) ); ?></span>
<a href="#" class="sscoupon-remove" data-code="<?php echo esc_attr( $code ); ?>"
aria-label="<?php esc_attr_e( 'Remove coupon', 'woocommerce' ); ?>">×</a>
</div>
<?php
}
}
/* -------------------------------------------------------------
* 4. AVAILABLE COUPONS list (all active/published coupons)
* Rendered right under the box; re-renders on update_checkout.
* ----------------------------------------------------------- */
add_action( 'woocommerce_review_order_before_payment', 'sscoupon_render_available', 15 );
function sscoupon_render_available() {
if ( ! wc_coupons_enabled() ) {
return;
}
$coupons = sscoupon_get_active_coupons();
if ( empty( $coupons ) ) {
return;
}
?>
<div class="sscoupon-list">
<div class="sscoupon-list-head"><?php esc_html_e( 'Available coupons', 'woocommerce' ); ?></div>
<?php foreach ( $coupons as $coupon ) :
$code = $coupon->get_code();
// Skip coupons that are already applied (they show as chips above).
if ( WC()->cart->has_discount( $code ) ) {
continue;
}
?>
<div class="sscoupon-card">
<div class="sscoupon-card-ico" aria-hidden="true">
<svg viewBox="0 0 24 24" width="20" height="20">
<path fill="currentColor" d="M12 1.5l2.1 1.6 2.6-.3 1 2.4 2.4 1-.3 2.6L21.5 12l-1.6 2.1.3 2.6-2.4 1-1 2.4-2.6-.3L12 22.5l-2.1-1.6-2.6.3-1-2.4-2.4-1 .3-2.6L2.5 12l1.6-2.1-.3-2.6 2.4-1 1-2.4 2.6.3L12 1.5z"/>
<text x="12" y="15.5" text-anchor="middle" font-size="9" font-weight="700" fill="#fff" font-family="Arial">%</text>
</svg>
</div>
<div class="sscoupon-card-body">
<span class="sscoupon-card-code"><?php echo esc_html( strtoupper( $code ) ); ?></span>
<p class="sscoupon-card-desc"><?php echo esc_html( sscoupon_describe( $coupon ) ); ?></p>
<a href="#" class="sscoupon-knowmore"><?php esc_html_e( 'Know more', 'woocommerce' ); ?></a>
<div class="sscoupon-details" hidden>
<?php echo wp_kses_post( sscoupon_details( $coupon ) ); ?>
</div>
</div>
<button type="button" class="sscoupon-card-apply" data-code="<?php echo esc_attr( $code ); ?>">
<?php esc_html_e( 'Apply', 'woocommerce' ); ?>
</button>
</div>
<?php endforeach; ?>
</div>
<?php
}
/**
* Fetch active (published, non-expired) coupons.
* Filter 'sscoupon_active_coupons' lets you customise the list.
*
* @return WC_Coupon[]
*/
function sscoupon_get_active_coupons() {
$ids = get_posts( array(
'post_type' => 'shop_coupon',
'post_status' => 'publish',
'posts_per_page' => 20,
'orderby' => 'menu_order title',
'order' => 'ASC',
'fields' => 'ids',
) );
$now = time();
$coupons = array();
foreach ( $ids as $id ) {
$coupon = new WC_Coupon( $id );
$expires = $coupon->get_date_expires();
// "Active" = not expired. (No min-spend / eligibility checks.)
if ( $expires && $expires->getTimestamp() < $now ) {
continue;
}
$coupons[] = $coupon;
}
return apply_filters( 'sscoupon_active_coupons', $coupons );
}
/** Short description shown on the card. Uses the coupon's own description, else a fallback. */
function sscoupon_describe( $coupon ) {
$desc = trim( $coupon->get_description() );
if ( '' !== $desc ) {
return $desc;
}
$amount = $coupon->get_amount();
if ( 'percent' === $coupon->get_discount_type() ) {
return sprintf( esc_html__( 'FLAT %s%% off', 'woocommerce' ), wc_format_decimal( $amount, '' ) );
}
return sprintf( esc_html__( '%s off', 'woocommerce' ), wp_strip_all_tags( wc_price( $amount ) ) );
}
/** Extra info revealed by "Know more". */
function sscoupon_details( $coupon ) {
$lines = array();
if ( $coupon->get_minimum_amount() > 0 ) {
$lines[] = sprintf( esc_html__( 'Minimum order value: %s', 'woocommerce' ), wp_strip_all_tags( wc_price( $coupon->get_minimum_amount() ) ) );
}
if ( $coupon->get_maximum_amount() > 0 ) {
$lines[] = sprintf( esc_html__( 'Maximum order value: %s', 'woocommerce' ), wp_strip_all_tags( wc_price( $coupon->get_maximum_amount() ) ) );
}
if ( $coupon->get_date_expires() ) {
$lines[] = sprintf( esc_html__( 'Valid till %s', 'woocommerce' ), esc_html( date_i18n( get_option( 'date_format' ), $coupon->get_date_expires()->getTimestamp() ) ) );
}
if ( $coupon->get_free_shipping() ) {
$lines[] = esc_html__( 'Free shipping included', 'woocommerce' );
}
if ( empty( $lines ) ) {
$lines[] = esc_html__( 'Apply at checkout to avail this offer.', 'woocommerce' );
}
return '<ul><li>' . implode( '</li><li>', $lines ) . '</li></ul>';
}
/* -------------------------------------------------------------
* 5. AJAX: apply coupon
* ----------------------------------------------------------- */
add_action( 'wp_ajax_sscoupon_apply', 'sscoupon_apply' );
add_action( 'wp_ajax_nopriv_sscoupon_apply', 'sscoupon_apply' );
function sscoupon_apply() {
check_ajax_referer( 'sscoupon-nonce', 'nonce' );
$code = isset( $_POST['code'] ) ? wc_format_coupon_code( wp_unslash( $_POST['code'] ) ) : '';
if ( '' === $code ) {
wp_send_json_error( array( 'message' => __( 'Please enter a discount code.', 'woocommerce' ) ) );
}
$applied = WC()->cart->apply_coupon( $code );
WC()->cart->calculate_totals();
$messages = sscoupon_pull_notices();
if ( $applied ) {
wp_send_json_success( array( 'message' => $messages ? $messages : __( 'Discount applied.', 'woocommerce' ) ) );
}
wp_send_json_error( array( 'message' => $messages ? $messages : __( 'This discount code is not valid.', 'woocommerce' ) ) );
}
/* -------------------------------------------------------------
* 6. AJAX: remove coupon
* ----------------------------------------------------------- */
add_action( 'wp_ajax_sscoupon_remove', 'sscoupon_remove' );
add_action( 'wp_ajax_nopriv_sscoupon_remove', 'sscoupon_remove' );
function sscoupon_remove() {
check_ajax_referer( 'sscoupon-nonce', 'nonce' );
$code = isset( $_POST['code'] ) ? wc_format_coupon_code( wp_unslash( $_POST['code'] ) ) : '';
if ( '' !== $code ) {
WC()->cart->remove_coupon( $code );
WC()->cart->calculate_totals();
}
wc_clear_notices();
wp_send_json_success();
}
/** Helper: collect & clear WooCommerce notices into one string */
function sscoupon_pull_notices() {
$out = array();
$notices = wc_get_notices();
foreach ( array( 'error', 'success', 'notice' ) as $type ) {
if ( ! empty( $notices[ $type ] ) ) {
foreach ( $notices[ $type ] as $n ) {
$out[] = is_array( $n ) ? $n['notice'] : $n;
}
}
}
wc_clear_notices();
return implode( ' ', array_map( 'wp_strip_all_tags', $out ) );
}
/* -------------------------------------------------------------
* 7. CSS
* ----------------------------------------------------------- */
add_action( 'wp_head', 'sscoupon_css' );
function sscoupon_css() {
if ( ! function_exists( 'is_checkout' ) || ! is_checkout() ) {
return;
}
?>
<style>
/* ---- Coupon input box ---- */
.sscoupon-wrap{ margin:18px 0 14px; }
.sscoupon-form{ display:flex; gap:12px; align-items:stretch; }
.sscoupon-input{
flex:1 1 auto; padding:14px 16px; border:1px solid #d6d6d6; border-radius:8px;
font-size:14px; line-height:1.2; color:#2b2b2b; background:#fff; outline:none;
transition:border-color .15s ease, box-shadow .15s ease;
}
.sscoupon-input::placeholder{ color:#9a9a9a; }
.sscoupon-input:focus{ border-color:#1a1a1a; box-shadow:0 0 0 1px #1a1a1a; }
.sscoupon-btn{
flex:0 0 auto; min-width:84px; padding:0 22px; border:1px solid #e2e2e2;
border-radius:8px; background:#f2f2f2; color:#6f6f6f; font-size:14px; font-weight:500;
cursor:pointer; transition:background .15s ease, color .15s ease;
}
.sscoupon-btn:hover{ background:#e7e7e7; color:#3d3d3d; }
.sscoupon-btn.is-loading{ opacity:.6; pointer-events:none; }
.sscoupon-message{ font-size:13px; margin-top:8px; }
.sscoupon-message.is-error{ color:#c0392b; }
.sscoupon-message.is-success{ color:#1e7e34; }
/* ---- Applied chips ---- */
.sscoupon-active{ margin-top:12px; display:flex; flex-direction:column; gap:8px; }
.sscoupon-chip{
display:flex; align-items:center; gap:8px; padding:8px 12px; background:#f6f6f6;
border:1px solid #ececec; border-radius:8px; font-size:13px;
}
.sscoupon-chip-tag{ display:inline-flex; align-items:center; gap:6px; font-weight:600; color:#1a1a1a; }
.sscoupon-chip-amt{ color:#1e7e34; font-weight:600; }
.sscoupon-remove{
margin-left:auto; text-decoration:none; color:#9a9a9a; font-size:18px; line-height:1;
width:20px; height:20px; display:inline-flex; align-items:center; justify-content:center;
border-radius:50%; transition:background .15s ease, color .15s ease;
}
.sscoupon-remove:hover{ background:#e2e2e2; color:#1a1a1a; }
/* ---- Available coupons list ---- */
.sscoupon-list{ margin-top:6px; display:flex; flex-direction:column; gap:12px; }
.sscoupon-list-head{ font-size:13px; font-weight:600; color:#444; margin:6px 0 2px; }
.sscoupon-card{
display:flex; align-items:flex-start; gap:12px;
padding:14px 16px; background:#fafafa; border:1px solid #ededed; border-radius:12px;
}
.sscoupon-card-ico{ flex:0 0 auto; color:#d6336c; margin-top:2px; }
.sscoupon-card-body{ flex:1 1 auto; min-width:0; }
.sscoupon-card-code{
display:inline-block; position:relative; padding:3px 12px; margin-bottom:6px;
font-size:14px; font-weight:700; letter-spacing:.04em; color:#1a1a1a;
border:1px dashed #c7c7c7; border-radius:4px; background:#fff;
}
/* little ticket notches */
.sscoupon-card-code::before,
.sscoupon-card-code::after{
content:""; position:absolute; top:50%; width:7px; height:7px;
background:#fafafa; border:1px dashed #c7c7c7; border-radius:50%; transform:translateY(-50%);
}
.sscoupon-card-code::before{ left:-4px; }
.sscoupon-card-code::after{ right:-4px; }
.sscoupon-card-desc{ margin:2px 0 4px; font-size:13px; color:#555; line-height:1.4; }
.sscoupon-knowmore{ font-size:12px; color:#3b82f6; text-decoration:none; }
.sscoupon-knowmore:hover{ text-decoration:underline; }
.sscoupon-details{ margin-top:6px; font-size:12px; color:#666; }
.sscoupon-details ul{ margin:0; padding-left:16px; }
.sscoupon-details li{ margin:2px 0; }
.sscoupon-card-apply{
flex:0 0 auto; align-self:center; min-width:74px; padding:9px 18px;
border:1px solid #cfcfcf; border-radius:8px; background:#fff; color:#333;
font-size:13px; font-weight:600; cursor:pointer;
transition:background .15s ease, border-color .15s ease, color .15s ease;
}
.sscoupon-card-apply:hover{ background:#1a1a1a; border-color:#1a1a1a; color:#fff; }
.sscoupon-card-apply.is-loading{ opacity:.6; pointer-events:none; }
@media (max-width:480px){
.sscoupon-card{ flex-wrap:wrap; }
.sscoupon-card-apply{ align-self:flex-start; }
}
</style>
<?php
}
/* -------------------------------------------------------------
* 8. JS
* ----------------------------------------------------------- */
add_action( 'wp_footer', 'sscoupon_js' );
function sscoupon_js() {
if ( ! function_exists( 'is_checkout' ) || ! is_checkout() ) {
return;
}
$ajax = admin_url( 'admin-ajax.php' );
$nonce = wp_create_nonce( 'sscoupon-nonce' );
?>
<script>
(function ($) {
var AJAX = '<?php echo esc_js( $ajax ); ?>';
var NONCE = '<?php echo esc_js( $nonce ); ?>';
var pendingMsg = null;
function showMsg(text, type) {
$('.sscoupon-message')
.removeClass('is-error is-success')
.addClass(type === 'error' ? 'is-error' : 'is-success')
.text(text || '');
}
function applyCode(code, $btn) {
code = (code || '').trim();
showMsg('', '');
if ($btn) { $btn.addClass('is-loading'); }
$.post(AJAX, { action: 'sscoupon_apply', code: code, nonce: NONCE })
.done(function (res) {
if (res && res.success) {
pendingMsg = res.data.message;
$('#sscoupon-code').val('');
$(document.body).trigger('update_checkout'); // refresh totals, chips & list
} else {
showMsg(res && res.data ? res.data.message : 'Something went wrong.', 'error');
}
})
.fail(function () { showMsg('Network error. Please try again.', 'error'); })
.always(function () { if ($btn) { $btn.removeClass('is-loading'); } });
}
function removeCode(code) {
$.post(AJAX, { action: 'sscoupon_remove', code: code, nonce: NONCE })
.done(function () { $(document.body).trigger('update_checkout'); });
}
$(document.body).on('updated_checkout', function () {
if (pendingMsg) { showMsg(pendingMsg, 'success'); pendingMsg = null; }
});
// Main box apply
$(document).on('click', '#sscoupon-apply', function () {
applyCode($('#sscoupon-code').val(), $(this));
});
$(document).on('keypress', '#sscoupon-code', function (e) {
if (e.which === 13) { e.preventDefault(); applyCode($(this).val(), $('#sscoupon-apply')); }
});
// Card apply
$(document).on('click', '.sscoupon-card-apply', function () {
applyCode($(this).data('code'), $(this));
});
// Remove chip
$(document).on('click', '.sscoupon-remove', function (e) {
e.preventDefault();
removeCode($(this).data('code'));
});
// Know more toggle
$(document).on('click', '.sscoupon-knowmore', function (e) {
e.preventDefault();
var $d = $(this).siblings('.sscoupon-details');
var open = !$d.prop('hidden');
$d.prop('hidden', open);
$(this).text(open ? '<?php echo esc_js( __( 'Know more', 'woocommerce' ) ); ?>'
: '<?php echo esc_js( __( 'Hide details', 'woocommerce' ) ); ?>');
});
})(jQuery);
</script>
<?php
}