Chapter 5: Add Minimum & Maximum Order Value Constraints
Right now, your discount applies whenever:
- Plugin is enabled
- Coupon code matches
But in real campaigns, you often need conditions like:
- “Valid only for orders above ₹999”
- “10% off up to orders of ₹5000”
In this chapter, we’ll:
- Add Min Order Value and Max Order Value settings in admin
- Update our discount logic to respect these constraints
- Show clear error messages when the cart doesn’t qualify
1. New Settings: Min & Max Order Value
We’ll introduce two new options:
- sdr_min_order_amount – Minimum cart subtotal required
- sdr_max_order_amount – Maximum cart subtotal allowed
If either is 0 or left empty, we treat it as no limit.
1.1. Update the form submission handler
Find your sdr_handle_settings_form_submit() in simple-discount-rules.php (from Chapter 4) and replace it with this version:
/**
* Handle settings form submission.
*/
function sdr_handle_settings_form_submit() {
// Check if our form was submitted.
if ( ! isset( $_POST['sdr_settings_submit'] ) ) {
return;
}
// Check nonce for security.
if ( ! isset( $_POST['sdr_settings_nonce'] ) || ! wp_verify_nonce( $_POST['sdr_settings_nonce'], 'sdr_save_settings' ) ) {
return;
}
// Check capability.
if ( ! current_user_can( 'manage_woocommerce' ) ) {
return;
}
// Checkout message (optional helper text).
$message = isset( $_POST['sdr_checkout_message'] )
? wp_kses_post( wp_unslash( $_POST['sdr_checkout_message'] ) )
: '';
// Enable discount (checkbox).
$enable_discount = isset( $_POST['sdr_enable_discount'] ) && 'yes' === $_POST['sdr_enable_discount']
? 'yes'
: 'no';
// Coupon code (simple text).
$coupon_code = isset( $_POST['sdr_coupon_code'] )
? sanitize_text_field( wp_unslash( $_POST['sdr_coupon_code'] ) )
: '';
// Discount type: flat or percentage.
$discount_type = isset( $_POST['sdr_discount_type'] )
? sanitize_text_field( wp_unslash( $_POST['sdr_discount_type'] ) )
: 'flat';
if ( ! in_array( $discount_type, array( 'flat', 'percentage' ), true ) ) {
$discount_type = 'flat';
}
// Discount value (amount or percentage).
$discount_value_raw = isset( $_POST['sdr_flat_discount_amount'] )
? wp_unslash( $_POST['sdr_flat_discount_amount'] )
: '';
$discount_value = floatval( $discount_value_raw );
if ( $discount_value < 0 ) {
$discount_value = 0;
}
// Minimum order amount.
$min_order_raw = isset( $_POST['sdr_min_order_amount'] )
? wp_unslash( $_POST['sdr_min_order_amount'] )
: '';
$min_order = floatval( $min_order_raw );
if ( $min_order < 0 ) {
$min_order = 0;
}
// Maximum order amount.
$max_order_raw = isset( $_POST['sdr_max_order_amount'] )
? wp_unslash( $_POST['sdr_max_order_amount'] )
: '';
$max_order = floatval( $max_order_raw );
if ( $max_order < 0 ) {
$max_order = 0;
}
// Save options.
update_option( 'sdr_checkout_message', $message );
update_option( 'sdr_enable_discount', $enable_discount );
update_option( 'sdr_coupon_code', $coupon_code );
update_option( 'sdr_discount_type', $discount_type );
update_option( 'sdr_flat_discount_amount', $discount_value );
update_option( 'sdr_min_order_amount', $min_order );
update_option( 'sdr_max_order_amount', $max_order );
// Add a settings updated flag so we can show a notice.
add_settings_error(
'sdr_messages',
'sdr_message',
__( 'Settings saved.', 'simple-discount-rules' ),
'updated'
);
}
add_action( 'admin_init', 'sdr_handle_settings_form_submit' );
1.2. Update the settings page UI
Now we’ll show two more fields in the Discount Settings section: Min Order Value and Max Order Value.
Find sdr_render_settings_page() and replace it with:
<?php
/**
* Render the plugin settings page.
*/
function sdr_render_settings_page() {
// Get current values from the options table.
$current_message = get_option(
'sdr_checkout_message',
__( 'Enter your special discount code at checkout to claim the offer.', 'simple-discount-rules' )
);
$enable_discount = get_option( 'sdr_enable_discount', 'no' );
$coupon_code = get_option( 'sdr_coupon_code', '' );
$discount_type = get_option( 'sdr_discount_type', 'flat' );
$discount_value = get_option( 'sdr_flat_discount_amount', 0 );
$min_order = get_option( 'sdr_min_order_amount', 0 );
$max_order = get_option( 'sdr_max_order_amount', 0 );
// Show any saved messages (from add_settings_error).
settings_errors( 'sdr_messages' );
?>
<div class="wrap">
<h1><?php esc_html_e( 'Simple Discount Rules – Settings', 'simple-discount-rules' ); ?></h1>
<form method="post" action="">
<?php wp_nonce_field( 'sdr_save_settings', 'sdr_settings_nonce' ); ?>
<h2><?php esc_html_e( 'General Message', 'simple-discount-rules' ); ?></h2>
<table class="form-table" role="presentation">
<tbody>
<tr>
<th scope="row">
<label for="sdr_checkout_message">
<?php esc_html_e( 'Checkout Helper Message', 'simple-discount-rules' ); ?>
</label>
</th>
<td>
<textarea
name="sdr_checkout_message"
id="sdr_checkout_message"
rows="4"
cols="50"
class="large-text"
><?php echo esc_textarea( $current_message ); ?></textarea>
<p class="description">
<?php esc_html_e( 'Shown near the discount code field on the checkout page. You can use it to explain the offer or conditions.', 'simple-discount-rules' ); ?>
</p>
</td>
</tr>
</tbody>
</table>
<h2><?php esc_html_e( 'Discount Settings', 'simple-discount-rules' ); ?></h2>
<table class="form-table" role="presentation">
<tbody>
<tr>
<th scope="row">
<?php esc_html_e( 'Enable Discount', 'simple-discount-rules' ); ?>
</th>
<td>
<label>
<input
type="checkbox"
name="sdr_enable_discount"
value="yes"
<?php checked( $enable_discount, 'yes' ); ?>
/>
<?php esc_html_e( 'Enable this custom discount rule', 'simple-discount-rules' ); ?>
</label>
<p class="description">
<?php esc_html_e( 'Uncheck to disable the custom discount even if a customer enters the correct code.', 'simple-discount-rules' ); ?>
</p>
</td>
</tr>
<tr>
<th scope="row">
<label for="sdr_coupon_code">
<?php esc_html_e( 'Coupon Code', 'simple-discount-rules' ); ?>
</label>
</th>
<td>
<input
type="text"
name="sdr_coupon_code"
id="sdr_coupon_code"
value="<?php echo esc_attr( $coupon_code ); ?>"
class="regular-text"
/>
<p class="description">
<?php esc_html_e( 'The exact text customers must enter at checkout (e.g., WELCOME10).', 'simple-discount-rules' ); ?>
</p>
</td>
</tr>
<tr>
<th scope="row">
<label for="sdr_discount_type">
<?php esc_html_e( 'Discount Type', 'simple-discount-rules' ); ?>
</label>
</th>
<td>
<select name="sdr_discount_type" id="sdr_discount_type">
<option value="flat" <?php selected( $discount_type, 'flat' ); ?>>
<?php esc_html_e( 'Flat amount (fixed value off)', 'simple-discount-rules' ); ?>
</option>
<option value="percentage" <?php selected( $discount_type, 'percentage' ); ?>>
<?php esc_html_e( 'Percentage (percent off order subtotal)', 'simple-discount-rules' ); ?>
</option>
</select>
<p class="description">
<?php esc_html_e( 'Choose whether the discount is a fixed amount or a percentage of the cart subtotal.', 'simple-discount-rules' ); ?>
</p>
</td>
</tr>
<tr>
<th scope="row">
<label for="sdr_flat_discount_amount">
<?php esc_html_e( 'Discount Value', 'simple-discount-rules' ); ?>
</label>
</th>
<td>
<input
type="number"
step="0.01"
min="0"
name="sdr_flat_discount_amount"
id="sdr_flat_discount_amount"
value="<?php echo esc_attr( $discount_value ); ?>"
class="small-text"
/>
<p class="description">
<?php echo wp_kses_post(
__(
'If type is <strong>Flat</strong>: this is the amount in store currency (e.g., 100 = ₹100 off).<br>If type is <strong>Percentage</strong>: this is the percent off (e.g., 10 = 10% off).',
'simple-discount-rules'
)
); ?>
</p>
</td>
</tr>
<tr>
<th scope="row">
<label for="sdr_min_order_amount">
<?php esc_html_e( 'Minimum Order Value', 'simple-discount-rules' ); ?>
</label>
</th>
<td>
<input
type="number"
step="0.01"
min="0"
name="sdr_min_order_amount"
id="sdr_min_order_amount"
value="<?php echo esc_attr( $min_order ); ?>"
class="small-text"
/>
<p class="description">
<?php esc_html_e( 'Optional. The discount only applies if the cart subtotal is at least this amount. Set 0 to ignore.', 'simple-discount-rules' ); ?>
</p>
</td>
</tr>
<tr>
<th scope="row">
<label for="sdr_max_order_amount">
<?php esc_html_e( 'Maximum Order Value', 'simple-discount-rules' ); ?>
</label>
</th>
<td>
<input
type="number"
step="0.01"
min="0"
name="sdr_max_order_amount"
id="sdr_max_order_amount"
value="<?php echo esc_attr( $max_order ); ?>"
class="small-text"
/>
<p class="description">
<?php esc_html_e( 'Optional. The discount only applies if the cart subtotal does not exceed this amount. Set 0 to ignore.', 'simple-discount-rules' ); ?>
</p>
</td>
</tr>
</tbody>
</table>
<?php submit_button( __( 'Save Changes', 'simple-discount-rules' ), 'primary', 'sdr_settings_submit' ); ?>
</form>
</div>
<?php
}
?>
2. Enforce Min/Max in the Discount Logic
We already calculate the cart subtotal in sdr_apply_flat_discount(). Now we’ll add constraint checks beforecalculating the final discount.
2.1. Update the discount application function
Find sdr_apply_flat_discount() (from Chapter 4) and replace it completely with:
<?php
/**
* Apply custom discount (flat or percentage).
*/
function sdr_apply_flat_discount( $cart ) {
if ( ! sdr_is_woocommerce_active() ) return;
if ( is_admin() && ! defined( 'DOING_AJAX' ) ) return;
// Settings
$enabled = get_option( 'sdr_enable_discount', 'no' );
$coupon_code = get_option( 'sdr_coupon_code', '' );
$discount_type = get_option( 'sdr_discount_type', 'flat' );
$discount_value = floatval( get_option( 'sdr_flat_discount_amount', 0 ) );
if ( 'yes' !== $enabled ) return;
if ( empty( $coupon_code ) || $discount_value <= 0 ) return; // Retrieve entered code from checkout session $entered_code = WC()->session->get( 'sdr_coupon_code', '' );
if ( empty( $entered_code ) ) return;
// Code does not match
if ( strcasecmp( $entered_code, $coupon_code ) !== 0 ) {
if ( isset( $_POST['sdr_coupon_code'] ) ) {
wc_add_notice( __( 'Invalid discount code.', 'simple-discount-rules' ), 'error' );
}
return;
}
// Calculate discount
$subtotal = $cart->get_subtotal();
$discount = 0;
if ( $discount_type === 'flat' ) {
$discount = min( $discount_value, $subtotal );
} elseif ( $discount_type === 'percentage' ) {
$discount = ( $subtotal * $discount_value ) / 100;
if ( $discount > $subtotal ) {
$discount = $subtotal;
}
}
if ( $discount <= 0 ) return; if ( isset( $_POST['sdr_coupon_code'] ) ) { wc_add_notice( $discount_type === 'percentage' ? sprintf( __( 'Your %s%% discount has been applied!', 'simple-discount-rules' ), $discount_value ) : __( 'Your special discount has been applied!', 'simple-discount-rules' ), 'success' ); } // Discount label text $label = ( $discount_type === 'percentage' ) ? sprintf( __( 'Special Discount (%s – %s%%)', 'simple-discount-rules' ), $coupon_code, $discount_value ) : sprintf( __( 'Special Discount (%s)', 'simple-discount-rules' ), $coupon_code ); $cart->add_fee( $label, -$discount );
}
add_action( 'woocommerce_cart_calculate_fees', 'sdr_apply_flat_discount', 20, 1 );
?>
Key points:
- We load sdr_min_order_amount and sdr_max_order_amount
- If subtotal < min or > max, we:
- Show a clear error message (only right after user interacts with the code)
- return; without applying discount



3. Add a Discount Code Field on the Checkout Page
Instead of a floating form above checkout, we’ll integrate with WooCommerce’s checkout fields system. That way:
- The field looks like other checkout inputs
- WooCommerce handles field re-population and layout
- We can easily read the value when calculating discounts
3.1. Add a custom checkout field
Add this code to simple-discount-rules.php:
<?php
/* ----------------------------------------------------------
4. ADD DISCOUNT CODE FIELD IN CHECKOUT
---------------------------------------------------------- */
function sdr_add_discount_checkout_field( $fields ) {
$fields['billing']['sdr_coupon_code'] = array(
'type' => 'text',
'label' => __( 'Special Discount Code', 'simple-discount-rules' ),
'placeholder' => __( 'Enter discount code (optional)', 'simple-discount-rules' ),
'required' => false,
'class' => array('form-row-wide'),
'priority' => 999,
);
return $fields;
}
add_filter( 'woocommerce_checkout_fields', 'sdr_add_discount_checkout_field' );
?>
This will show a new text input on the checkout page under the billing fields.
3.2. Show our helper message above the field
We’ll show the “Checkout Helper Message” we configured in settings near the field, so customers know there is an offer.
Add this:
<?php
/* ----------------------------------------------------------
3. SHOW HELPER MESSAGE ABOVE BILLING FIELDS
---------------------------------------------------------- */
function sdr_show_checkout_helper_message() {
if ( ! sdr_is_woocommerce_active() ) return;
$msg = get_option('sdr_checkout_message', '');
if ( empty($msg) ) return;
echo '<div style="padding:12px; background:#eef7ff; border-left:4px solid #2271b1; margin-bottom:15px;">';
echo wp_kses_post( wpautop($msg) );
echo '</div>';
}
add_action( 'woocommerce_before_checkout_billing_form', 'sdr_show_checkout_helper_message', 5 );
?>
🔄 You can now remove the old sdr_checkout_hello_message() function and its add_action() from Chapter 1, because this new helper message replaces it.
4. Apply the Flat Discount When Code Matches
Now comes the money part.
WooCommerce lets you modify totals using the woocommerce_cart_calculate_fees hook. We’ll:
- Check if the plugin is enabled and configured
- Read the entered code from checkout or session
- If it matches the configured admin code, apply a negative fee (discount)
4.1. Store the entered code in session
We want the discount to persist as the user navigates in checkout (e.g., shipping changes, refresh). The simplest approach:
- On each request, if $_POST[‘sdr_coupon_code’] is present → save it to WC()->session
- If not in $_POST, read it from session during fee calculation
Add this:
<?php
/* ----------------------------------------------------------
5. SAVE ENTERED CODE IN SESSION (checkout AJAX updates)
---------------------------------------------------------- */
function sdr_capture_discount_code_to_session() {
if ( isset($_POST['sdr_coupon_code']) ) {
WC()->session->set(
'sdr_coupon_code',
sanitize_text_field( $_POST['sdr_coupon_code'] )
);
}
}
add_action( 'woocommerce_checkout_update_order_review', 'sdr_capture_discount_code_to_session' );
?>
WooCommerce calls woocommerce_checkout_update_order_review whenever the checkout form is updated, so this keeps the code in sync.
5. Test Your Constraints
Scenario A – Min order only
- Settings:
- Enable Discount: ✅
- Coupon Code: WELCOME10
- Discount Type: Percentage
- Discount Value: 10
- Min Order Value: 1000
- Max Order Value: 0 (ignored)
- Test:
- Cart subtotal ₹800 → enter WELCOME10 →
- Error: “This discount is only valid for orders of at least ₹1,000.00.”
- Cart subtotal ₹1500 → enter WELCOME10 →
- Success notice
- 10% off applied
- Cart subtotal ₹800 → enter WELCOME10 →
Scenario B – Max order only
- Settings:
- Min Order: 0
- Max Order: 5000
- Test:
- Cart subtotal ₹6000 → code applied →
- Error: “This discount is only valid for orders up to ₹5,000.00.”
- Cart subtotal ₹3000 → code applied →
- Discount works
- Cart subtotal ₹6000 → code applied →
Scenario C – Min + Max range
- Settings:
- Min Order: 1000
- Max Order: 5000
- Test:
- ₹900 → too low → min error
- ₹6000 → too high → max error
- ₹2500 → within range → discount applied
Quick Recap
In this chapter you:
- Added min and max order value settings
- Updated admin UI to clearly explain how to use them
- Enforced these constraints in your discount logic
- Added user-friendly error messages when the cart doesn’t qualify
Your plugin is now capable of realistic rules like:
“Get 10% off between ₹1000 and ₹5000 using code WELCOME10”
Next up in your plan is customer type constraints (new vs existing customers).







































