How to make basket total zero with a checkbox in WooCommerce

I am trying to create a bespoke plugin that adds a checkbox to the checkout and if clicked it makes all items in the basket free. I have created a functions file in my plugin that brings up an email address box for payment to be deferred to and the functions are supposed to disable all payment methods and make all items free, therefore not needing any payment details. <?php if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly. } class WCPP_Functions { public function __construct() { add_action( 'woocommerce_review_order_before_payment', array( $this, 'add_custom_checkbox_and_email_field' ) ); add_action( 'woocommerce_checkout_process', array( $this, 'validate_custom_email_field' ) ); add_action( 'woocommerce_before_calculate_totals', array( $this, 'adjust_order_total' ), 20, 1 ); add_action( 'woocommerce_checkout_create_order', array( $this, 'store_original_order_total' ), 20, 2 ); add_action( 'woocommerce_admin_order_totals_after_total', array( $this, 'display_original_order_total' ) ); add_action( 'woocommerce_admin_order_data_after_billing_address', array( $this, 'display_custom_email_in_order_meta' ), 5 ); add_filter( 'woocommerce_order_has_status', array( $this, 'allow_zero_total_orders_without_payment' ), 10, 3 ); add_filter( 'woocommerce_available_payment_gateways', array( $this, 'disable_payment_gateways_for_zero_total' ) ); // Display in Order Received Page, Order Email, and My Account add_action( 'woocommerce_thankyou', array( $this, 'display_deferred_payment_email_in_order' ), 20 ); add_action( 'woocommerce_email_order_meta', array( $this, 'display_deferred_payment_email_in_order' ), 20 ); add_action( 'woocommerce_order_item_meta_end', array( $this, 'display_deferred_payment_email_in_my_account_orders' ), 20, 4 ); add_action( 'woocommerce_before_thankyou', array( $this, 'remove_thankyou_page_error_notices' ), 1 ); } public function add_custom_checkbox_and_email_field() { ?> <div id="custom-checkbox-container"> <p> <label for="wcpp_checkbox"> <input type="checkbox" id="wcpp_checkbox" name="wcpp_checkbox"> Please check this box to defer payment to patient </label> </p> <p id="patient_email_field" style="display: none;"> <label for="patient_email">Enter patient email address:</label> <input type="email" id="patient_email" name="patient_email" /> </p> </div> <?php } public function validate_custom_email_field() { // Check if the checkbox is ticked if ( isset($_POST['wcpp_checkbox']) && $_POST['wcpp_checkbox'] === 'on' ) { // Check if the email field is empty if ( empty($_POST['patient_email']) ) { wc_add_notice( __( 'Please enter an email address.' ), 'error' ); } } } public function adjust_order_total( $cart ) { // Only proceed if we're on the checkout page and not in the admin if ( is_admin() && ! defined( 'DOING_AJAX' ) ) { return; } if ( isset($_POST['post_data']) ) { parse_str($_POST['post_data'], $post_data); } else { $post_data = $_POST; } // Check if the deferred payment checkbox is ticked if ( isset($post_data['wcpp_checkbox']) && $post_data['wcpp_checkbox'] === 'on' ) { // Calculate the original total manually $cart_total = 0; foreach ( $cart->get_cart() as $cart_item ) { $cart_total += $cart_item['line_subtotal'] + $cart_item['line_subtotal_tax']; } // Subtract any cart discounts (subtotal is used since it doesn't include tax) $cart_total -= $cart->get_cart_discount_total(); // Add a fee to negate the total, effectively making it £0 $cart->add_fee( 'Deferred Payment', -$cart_total, false ); } } public function allow_zero_total_orders_without_payment( $result, $order_id, $status ) { $order = wc_get_order( $order_id ); if ( $order->get_total() == 0 ) { return true; } return $result; } public function disable_payment_gateways_for_zero_total( $available_gateways ) { // Ensure we're checking during checkout if ( is_checkout() ) { // Parse the post data if it's sent via AJAX during checkout if ( isset($_POST['post_data']) ) { parse_str($_POST['post_data'], $post_data); } else { $post_data = $_POST; } // Check if the custom checkbox is checked if ( isset($post_data['wcpp_checkbox']) && $post_data['wcpp_checkbox'] === 'on' ) { // If the checkbox is checked, disable all payment gateways $available_gateways = array(); } } return $available_gateways; } public function store_original_order_total( $order, $data ) { // Only store the original total if the deferred payment checkbox was ticked if ( isset($_POST['wcpp_checkbox']) && $_POST['wcpp_checkbox'] === 'on' ) { // Calculate the original total manually again during order creation $original_total = 0; foreach ( $order->get_items() as $item_id => $item ) { $original_total += $item->get_subtotal() + $item->get_subtotal_tax(); } // Store the original total in the order meta if ( $original_total > 0 ) { $order->update_meta_data( '_original_total', $original_total ); $order->set_total( 0 ); } // Store the patient's email if provided if ( !empty($_POST['patient_email']) ) { $order->update_meta_data( '_patient_payment_email', sanitize_email( $_POST['patient_email'] ) ); } } } public function display_original_order_total( $order_id ) { $order = wc_get_order($order_id); $original_total = $order->get_meta( '_original_total' ); if ( $original_total ) { echo '<tr><td class="label">Original Total (amount due to patient):</td><td>' . wc_price( $original_total ) . '</td></tr>'; } } private function get_deferred_payment_email( $order ) { return $order->get_meta( '_patient_payment_email' ); } private function output_deferred_payment_email( $order ) { $patient_email = $this->get_deferred_payment_email( $order ); if ( ! empty( $patient_email ) ) { echo '<p><strong>' . __( 'Deferred Payment Email' ) . ':</strong> ' . esc_html( $patient_email ) . '</p>'; } } public function display_custom_email_in_order_meta( $order_id ) { $order = wc_get_order( $order_id ); $this->output_deferred_payment_email( $order ); } // Display Deferred Payment Email in Order Received Page and Order Emails public function display_deferred_payment_email_in_order( $order_id ) { $order = wc_get_order( $order_id ); $this->output_deferred_payment_email( $order ); if( $order->has_status( 'processing' ) && $order->get_total() == 0 ) { $order->update_status( 'completed' ); } } // Display Deferred Payment Email in "My Account > Orders" public function display_deferred_payment_email_in_my_account_orders( $item_id, $item, $order, $plain_text ) { $this->output_deferred_payment_email( $order ); } public function remove_thankyou_page_error_notices() { if ( is_wc_endpoint_url( 'order-received' ) && isset( $_GET['key'] ) ) { // Ensure we're on the "Order Received" page $order_id = wc_get_order_id_by_order_key( $_GET['key'] ); $order = wc_get_order( $order_id ); if ( $order && $order->get_total() == 0 ) { // Remove all notices wc_clear_notices(); } } } } I've also tried to use javascript along with the PHP functions: jQuery(document).ready(function($) { function togglePaymentMethods() { if ($('#wcpp_checkbox').is(':checked')) { $('#patient_email_field').show(); $('.wc_payment_method').hide().find('input').prop('disabled', true); } else { $('#patient_email_field').hide(); $('.wc_payment_method').show().find('input').prop('disabled', false); } $('body').trigger('update_checkout'); } // Attach the toggle function to the checkbox change event $('#wcpp_checkbox').on('change', function() { togglePaymentMethods(); }); // Trigger the toggle function on page load togglePaymentMethods(); }); If I try to defer payment it still says card number information is needed or invalid payment method. I've looked at other questions on here and already tried this one but it didn't work: Disable payment method Woocommerce Note: I am using classic WooCommerce cart and checkout pages (shortcode). EDIT: I updated my php file so it allows me to place the order but now on the order recieved page it says "Unfortunately your order cannot be processed as the originating bank/merchant has declined your transaction. Please attempt your purchase again.".

Comment (0)

You’ll be in good company