phpwordpresswoocommercemetadataorders

Displaying a transaction Fee on WooCommerce Admin Order edit page


What I am trying to do is show a breakdown of the Woocommerce transaction fee being applied after the order total:

It would something like this:

A visual of where it should go, I have highlighted it and as you see it's just an error at the moment:

enter image description here

The code in my functions .php

    // Calculate and save transaction fee after order is created/paid
add_action('woocommerce_order_status_changed', 'add_transaction_fee_to_order_meta', 10, 3);
function add_transaction_fee_to_order_meta($order_id, $old_status, $new_status) {
    if ($new_status == 'processing' || $new_status == 'completed') {
        $order = wc_get_order($order_id);

        if (get_post_meta($order_id, '_transaction_fee', true) == '') {
            $order_total = $order->get_total();
            $transaction_fee = ($order_total * 0.015) + 0.25;

            update_post_meta($order_id, '_transaction_fee', $transaction_fee);

        }
    }
}


// Display transaction fee in admin order details *after* "Paid" line
add_action('woocommerce_admin_order_totals_after_total', 'display_transaction_fee_in_admin_order_details', 10, 2);
function display_transaction_fee_in_admin_order_details($order_id, $order) {
    $transaction_fee = get_post_meta($order_id, '_transaction_fee', true);

    if ($transaction_fee) {
        if (is_object($order) && is_a($order, 'WC_Order')) {
            ?>  <tr>
                <td class="label">Transaction Fee:</td>
                <td width="1%"></td>
                <td class="total">
                    <?php echo wc_price($transaction_fee); ?>
                </td>
            </tr>
            <tr>
                <td class="label">Total (after fee):</td>
                <td width="1%"></td>
                <td class="total">
                    <?php echo wc_price($order->get_total() - $transaction_fee); ?>
                </td>
            </tr>
            <?php
        } else {
            error_log("WC_Order object not available in display_transaction_fee_in_admin_order_details for order ID: " . $order_id);
        }
    }
}

Solution

  • Your code is not compatible High-Performance Order Storage (HPOS) and there are multiple mistakes, like:

    Try the following instead:

    // Calculate and save transaction fee after order is created/paid
    add_action('woocommerce_order_status_changed', 'add_transaction_fee_to_order_meta', 10, 4 );
    function add_transaction_fee_to_order_meta( $order_id, $old_status, $new_status, $order ) {
        $targeted_statuses = array('processing', 'completed');
    
        if ( in_array( $new_status, $targeted_statuses) && ! $order->get_meta('_transaction_fee') && $order->get_total() > 0 ) {
            $order->update_meta_data('_transaction_fee', ($order->get_total() * 0.015) + 0.25 );
            $order->save();
        }
    }
    
    
    // Display transaction fee in admin order details *after* "Paid" line
    add_action('woocommerce_admin_order_totals_after_total', 'display_transaction_fee_in_admin_order_details' );
    function display_transaction_fee_in_admin_order_details( $order_id ) {
        $order = wc_get_order($order_id);
        $args  = array( 'currency' => $order->get_currency() );
    
        if ( $transaction_fee = $order->get_meta('_transaction_fee') ) {
            printf('<tr>
                <td class="label">%s</td>
                <td width="%s"></td>
                <td class="total">%s</td>
            </tr>', esc_html__('Transaction Fee:'), '1%', wc_price($transaction_fee, $args ) );
    
            printf('<tr>
                <td class="label">%s</td>
                <td width="%s"></td>
                <td class="total">%s</td>
            </tr>', esc_html__('Total (after fee):'), '1%', wc_price( $order->get_total() - $transaction_fee, $args ) );
        }
    }
    

    It should better work without errors, and will be compatible with HPOS.

    enter image description here

    You may need to target the concerned payment gateway(s) in your first function, as actually your code is executed on all processing or completed orders, no matter what payment method has been used.