Search code examples
phpwordpresswoocommercehook-woocommercecustom-fields

Custom checkbox in WooCommerce admin edit product for a payment fee calculation


Following Exclude some products from calculated additional fee in WooCommerce answer to my previous question, I have made some changes to the array from my previous code.
Then, I added a checkbox to the product edit page: If it is active (checked), tax will not be calculated for that product. And if it is inactive (unchecked by default) the tax will be calculated.

1. Modify the Function to Include an Excluded Array:

// +9% tax add-fee on paypal
add_action( 'woocommerce_cart_calculate_fees', 'add_checkout_fee_for_gateway', 10, 1 );
function add_checkout_fee_for_gateway( $cart ) {
    if ( is_admin() && ! defined( 'DOING_AJAX' ) ) 
        return;

    // Retrieve excluded product IDs from post meta
    $excluded_product_ids = get_option('excluded_product_ids', array());
    
    // Only on checkout page and for specific payment method ID
    if ( is_checkout() && ! is_wc_endpoint_url() 
    && WC()->session->get('chosen_payment_method') === 'paypal' ) {
        $percentage_rate      = 0.09; // Defined percentage rate
        $custom_subtotal      = 0; // Initializing
        
        // Loop through cart items
        foreach( $cart->get_cart() as $item ) {
            // Calculate items subtotal from non excluded products
            if( ! in_array($item['product_id'], $excluded_product_ids) ) {
                $custom_subtotal += (float) $item['line_subtotal'];
            }
        }

        if ( $custom_subtotal > 0 ) {
            $cart->add_fee( __('9% value added tax'), ($custom_subtotal * $percentage_rate), true, '' );
        }
    }
}

2. Add Checkbox to Product Edit Page:

// Add checkbox to product edit page
add_action('woocommerce_product_options_general_product_data', 'add_custom_product_field');
function add_custom_product_field() {
    global $post;

    // Checkbox field
    woocommerce_wp_checkbox(
        array(
            'id'            => 'exclude_from_tax',
            'wrapper_class' => 'show_if_simple',
            'label'         => __('Exclude from Tax Calculation'),
            'description'   => __('Check this box to exclude this product from tax calculation.'),
            'value'         => get_post_meta($post->ID, 'exclude_from_tax', true) ? 'yes' : 'no',
        )
    );
}

// Save checkbox value
add_action('woocommerce_process_product_meta', 'save_custom_product_field');
function save_custom_product_field($post_id) {
    // Checkbox field
    $checkbox = isset($_POST['exclude_from_tax']) ? 'yes' : 'no';
    update_post_meta($post_id, 'exclude_from_tax', $checkbox);
}

OR this: (combined version! (maybe better all in one))

add_action('woocommerce_cart_calculate_fees', 'add_checkout_fee_and_product_field', 10, 1);
function add_checkout_fee_and_product_field($cart) {
    if (is_admin() && !defined('DOING_AJAX'))
        return;

    // Retrieve excluded product IDs from post meta
    $excluded_product_ids = get_option('excluded_product_ids', array());

    // Add checkbox to product edit page
    add_action('woocommerce_product_options_general_product_data', 'add_custom_product_field');
    function add_custom_product_field() {
        global $post;

        // Checkbox field
        woocommerce_wp_checkbox(
            array(
                'id' => 'exclude_from_tax',
                'wrapper_class' => 'show_if_simple',
                'label' => __('Exclude from Tax Calculation'),
                'description' => __('Check this box to exclude this product from tax calculation.'),
                'value' => get_post_meta($post->ID, 'exclude_from_tax', true) ? 'yes' : 'no',
            )
        );
    }

    // Save checkbox value
    add_action('woocommerce_process_product_meta', 'save_custom_product_field');
    function save_custom_product_field($post_id) {
        // Checkbox field
        $checkbox = isset($_POST['exclude_from_tax']) ? 'yes' : 'no';
        update_post_meta($post_id, 'exclude_from_tax', $checkbox);
    }

    // Only on checkout page and for specific payment method ID
    if (is_checkout() && !is_wc_endpoint_url() && WC()->session->get('chosen_payment_method') === 'paypal') {
        $percentage_rate = 0.09; // Defined percentage rate
        $custom_subtotal = 0; // Initializing

        // Loop through cart items
        foreach ($cart->get_cart() as $item) {
            // Calculate items subtotal from non excluded products
            if (!in_array($item['product_id'], $excluded_product_ids)) {
                $custom_subtotal += (float)$item['line_subtotal'];
            }
        }

        if ($custom_subtotal > 0) {
            $cart->add_fee(__('9% value added tax'), ($custom_subtotal * $percentage_rate), true, '');
        }
    }
}

Now I don't know if my method and codes are correct? Is there incompatibility with plugins, themes, or the core of WordPress and WooCommerce actually? Or will it not be created in new and future versions? Does it not damage the database? Is it possible to do this in a better, safer and easier way with cleaner and less code?


Solution

  • There are some mistakes and missing things in your code.

    Try the following revised code version instead:

    // Percentage tax fee for defined payment methods IDs
    add_action( 'woocommerce_cart_calculate_fees', 'add_checkout_fee_for_gateway' );
    function add_checkout_fee_for_gateway( $cart ) {
        if ( is_admin() && ! defined( 'DOING_AJAX' ) ) 
            return;
    
        $targeted_payment_methods = array('paypal', 'bacs', 'cheque'); // Define the payment method(s) ID(s)
        
        // Only on checkout page and for specific payment method ID
        if ( is_checkout() && ! is_wc_endpoint_url() 
        && in_array(WC()->session->get('chosen_payment_method'),  $targeted_payment_methods) ) {
            $percentage_rate  = 0.09; // Defined percentage rate
            $custom_subtotal  = 0; // Initializing
            
            // Loop through cart items
            foreach( $cart->get_cart() as $item ) {
                // Get the WC_Product object
                $product = wc_get_product( $item['product_id'] );
                // Check if the product is excluded from fee calculation
                if( $product->get_meta('_tax_fee_excluded') !== 'yes' ) {
                    // Calculate items subtotal from non excluded products
                    $custom_subtotal += (float) $item['line_subtotal'];
                }
            }
    
            if ( $custom_subtotal > 0 ) {
                $cart->add_fee( __('9% value added tax'), ($custom_subtotal * $percentage_rate), true, '' );
            }
        }
    }
    
    // Update checkout on payment method change
    add_action( 'woocommerce_checkout_init', 'update_checkout_on_payment_method_change' );
    function update_checkout_on_payment_method_change() {
        wc_enqueue_js("$('form.checkout').on( 'change', 'input[name=payment_method]', function(){
            $(document.body).trigger('update_checkout');
        });");
    }
    
    // Display a checkbox to Admin Product edit pages
    add_action('woocommerce_product_options_general_product_data', 'add_admin_product_custom_field');
    function add_admin_product_custom_field() {
    
        // Checkbox field
        woocommerce_wp_checkbox( array(
            'id'            => '_tax_fee_excluded',
            'wrapper_class' => 'show_if_simple',
            'label'         => __('Exclude from Tax Calculation'),
            'description'   => __('Check this box to exclude this product from tax calculation.')
        ) );
    }
    
    // Save checkbox value from product edit page
    add_action('woocommerce_admin_process_product_object', 'save_admin_product_custom_field_value');
    function save_admin_product_custom_field_value( $product ) {
        $product->update_meta_data('_tax_fee_excluded', isset($_POST['_tax_fee_excluded']) ? 'yes' : 'no');
    }
    

    Code goes in functions.php file of your child theme (or in a plugin). Tested and works.