Skip to content

Instantly share code, notes, and snippets.

@aimahdi
Last active January 22, 2026 04:50
Show Gist options
  • Select an option

  • Save aimahdi/6cf355706085ce28a3529219a84405c5 to your computer and use it in GitHub Desktop.

Select an option

Save aimahdi/6cf355706085ce28a3529219a84405c5 to your computer and use it in GitHub Desktop.

Custom Checkout Fields & Stripe Processing Fee

This document describes how to add custom checkout fields (Purchase Order Reference & User Note) and a 2.7% credit card processing fee for Stripe payments in FluentCart.

Features

  • Purchase Order Reference Field: Optional text field on checkout
  • User Note Field: Optional textarea for order notes
  • Stripe Processing Fee: 2.7% fee automatically added to Stripe payments only
  • Email Shortcodes: Use {{order.purchase_order_reference}}, {{order.user_note}}, and {{order.processing_fee}} in email templates
  • Order Display: Fields and fee displayed in admin and customer order details

Installation

Add the following code to /app/Hooks/actions.php:

1. Custom Checkout Fields

// Add fields to checkout form
add_filter('fluent_cart/checkout_page_name_fields_schema', function($nameFields, $context) {
    $cart = $context['cart'] ?? null;
    $purchaseOrderRef = '';
    $userNote = '';
    if ($cart) {
        $formData = ($cart->checkout_data ?? [])['form_data'] ?? [];
        $purchaseOrderRef = $formData['purchase_order_reference'] ?? '';
        $userNote = $formData['user_note'] ?? '';
    }
    
    $nameFields['purchase_order_reference'] = [
        'id' => 'purchase_order_reference',
        'name' => 'purchase_order_reference',
        'type' => 'text',
        'data-type' => 'text',
        'label' => __('Purchase Order Reference', 'fluent-cart'),
        'required' => 'no',
        'placeholder' => __('PO Number (Optional)', 'fluent-cart'),
        'value' => $purchaseOrderRef,
    ];
    
    $nameFields['user_note'] = [
        'id' => 'user_note',
        'name' => 'user_note',
        'type' => 'textarea',
        'data-type' => 'textarea',
        'label' => __('Order Notes', 'fluent-cart'),
        'required' => 'no',
        'placeholder' => __('Add any special instructions or notes...', 'fluent-cart'),
        'value' => $userNote,
        'rows' => 3,
    ];
    
    return $nameFields;
}, 10, 2);

// Save to order meta
add_action('fluent_cart/order_created', function($order) {
    $cart = \FluentCart\App\Models\Cart::query()->where('order_id', $order->id)->first();
    if ($cart) {
        $formData = ($cart->checkout_data ?? [])['form_data'] ?? [];
        if (!empty($formData['purchase_order_reference'])) {
            $order->updateMeta('purchase_order_reference', sanitize_text_field($formData['purchase_order_reference']));
        }
        if (!empty($formData['user_note'])) {
            $order->updateMeta('user_note', sanitize_textarea_field($formData['user_note']));
        }
    }
}, 10, 1);

// Display in order details
add_action('fluent_cart/admin_order_details_after_billing', function($order) {
    $poRef = $order->getMeta('purchase_order_reference');
    $userNote = $order->getMeta('user_note');
    if ($poRef || $userNote) {
        echo '<div class="fluent-cart-order-custom-fields" style="margin-top: 20px; padding: 15px; background: #f9f9f9; border-radius: 4px;">';
        echo '<h3 style="margin-top: 0;">' . __('Additional Information', 'fluent-cart') . '</h3>';
        if ($poRef) echo '<p><strong>' . __('Purchase Order Reference:', 'fluent-cart') . '</strong> ' . esc_html($poRef) . '</p>';
        if ($userNote) echo '<p><strong>' . __('Order Notes:', 'fluent-cart') . '</strong><br>' . nl2br(esc_html($userNote)) . '</p>';
        echo '</div>';
    }
}, 10, 1);

add_action('fluent_cart/customer_order_details_after_billing', function($order) {
    $poRef = $order->getMeta('purchase_order_reference');
    $userNote = $order->getMeta('user_note');
    if ($poRef || $userNote) {
        echo '<div class="fluent-cart-order-custom-fields" style="margin-top: 20px; padding: 15px; background: #f9f9f9; border-radius: 4px;">';
        echo '<h3 style="margin-top: 0;">' . __('Additional Information', 'fluent-cart') . '</h3>';
        if ($poRef) echo '<p><strong>' . __('Purchase Order Reference:', 'fluent-cart') . '</strong> ' . esc_html($poRef) . '</p>';
        if ($userNote) echo '<p><strong>' . __('Order Notes:', 'fluent-cart') . '</strong><br>' . nl2br(esc_html($userNote)) . '</p>';
        echo '</div>';
    }
}, 10, 1);

// Email shortcodes
add_filter('fluent_cart/email_shortcode_order', function($shortcodes, $order) {
    $shortcodes['purchase_order_reference'] = esc_html($order->getMeta('purchase_order_reference') ?: '');
    $shortcodes['user_note'] = nl2br(esc_html($order->getMeta('user_note') ?: ''));
    return $shortcodes;
}, 10, 2);

2. Stripe Processing Fee (2.7%)

// Helper function
function fluent_cart_apply_stripe_processing_fee($order, $transaction = null) {
    if ($order->payment_method !== 'stripe') return 0;
    
    $processingFee = $order->getMeta('processing_fee', 0);
    if ($processingFee <= 0) {
        $processingFee = (int)round($order->subtotal * 0.027);
        if ($processingFee > 0) {
            $order->updateMeta('processing_fee', $processingFee);
            $order->updateMeta('processing_fee_rate', 0.027);
            $order->total_amount += $processingFee;
            $order->save();
            if ($transaction) {
                $transaction->total = $order->total_amount;
                $transaction->save();
            }
        }
    }
    return $processingFee;
}

// Calculate fee on order creation
add_action('fluent_cart/order_created', function($order) {
    if ($order->payment_method === 'stripe') {
        fluent_cart_apply_stripe_processing_fee($order);
    }
}, 5, 1);

// Add fee to payment intent (onsite payments)
add_filter('fluent_cart/payments/stripe_onetime_intent_args', function($intentData, $context) {
    $order = \FluentCart\Framework\Support\Arr::get($context, 'order');
    $transaction = \FluentCart\Framework\Support\Arr::get($context, 'transaction');
    if ($order && $order->payment_method === 'stripe') {
        $fee = fluent_cart_apply_stripe_processing_fee($order, $transaction);
        if ($fee > 0 && isset($intentData['amount'])) {
            $currency = $intentData['currency'] ?? $order->currency;
            $feeToAdd = \FluentCart\App\Helpers\CurrenciesHelper::isZeroDecimal($currency) 
                ? (int)round($fee / 100) 
                : (int)$fee;
            $intentData['amount'] = (int)$intentData['amount'] + $feeToAdd;
        }
    }
    return $intentData;
}, 10, 2);

// Add fee to checkout session (hosted payments)
add_filter('fluent_cart/payments/stripe_checkout_session_args', function($sessionData, $context) {
    $order = \FluentCart\Framework\Support\Arr::get($context, 'order');
    $transaction = \FluentCart\Framework\Support\Arr::get($context, 'transaction');
    if ($order && $order->payment_method === 'stripe') {
        $fee = fluent_cart_apply_stripe_processing_fee($order, $transaction);
        if ($fee > 0 && isset($sessionData['line_items'][0]['price_data']['unit_amount'])) {
            $currency = $order->currency;
            $feeToAdd = \FluentCart\App\Helpers\CurrenciesHelper::isZeroDecimal($currency) 
                ? (int)round($fee / 100) 
                : (int)$fee;
            $sessionData['line_items'][0]['price_data']['unit_amount'] += $feeToAdd;
        }
    }
    return $sessionData;
}, 10, 2);

// Display fee in order summary
add_filter('fluent_cart/order_summary_items', function($items, $order) {
    $fee = $order->getMeta('processing_fee', 0);
    if ($fee > 0 && $order->payment_method === 'stripe') {
        $rate = number_format($order->getMeta('processing_fee_rate', 0.027) * 100, 2);
        $items[] = [
            'label' => sprintf(__('Credit Card Processing Fee (%s%%)', 'fluent-cart'), $rate),
            'value' => \FluentCart\App\Helpers\Helper::toDecimal($fee, true, $order->currency),
            'type' => 'fee'
        ];
    }
    return $items;
}, 10, 2);

// Email shortcode support
add_filter('fluent_cart/email_order_data', function($orderData, $order) {
    $fee = $order->getMeta('processing_fee', 0);
    if ($fee > 0 && $order->payment_method === 'stripe') {
        $rate = number_format($order->getMeta('processing_fee_rate', 0.027) * 100, 2);
        $orderData['processing_fee'] = \FluentCart\App\Helpers\Helper::toDecimal($fee, true, $order->currency);
        $orderData['processing_fee_label'] = sprintf(__('Credit Card Processing Fee (%s%%)', 'fluent-cart'), $rate);
    }
    return $orderData;
}, 20, 2);

Email Shortcodes

Use these shortcodes in email templates:

  • {{order.purchase_order_reference}} - Purchase Order Reference
  • {{order.user_note}} - User Note (formatted with line breaks)
  • {{order.processing_fee}} - Processing Fee (formatted currency, only shows for Stripe)

Configuration

Change Processing Fee Rate

Edit the rate in the helper function:

$processingFee = (int)round($order->subtotal * 0.027); // Change 0.027 to your rate (e.g., 0.03 for 3%)
$order->updateMeta('processing_fee_rate', 0.027); // Update this too

Make Fields Required

Change 'required' => 'no' to 'required' => 'yes' in the field definitions.

Change Field Placement

Fields are added to the name/email section. To add to billing section instead, use:

add_filter('fluent_cart/checkout_renderer/billing_fields', function($billingFields, $context) {
    // Same field definitions as above
    return $billingFields;
}, 10, 2);

Notes

  • Processing fee is calculated from subtotal (before discounts, shipping, tax)
  • Fee is stored in cents (FluentCart's internal format)
  • Fee is only applied to Stripe payments (not cash/offline)
  • Fee is added to the payment amount before it's sent to Stripe
  • All amounts are automatically converted for zero-decimal currencies (JPY, etc.)

Testing

  1. Create a test order with Stripe payment
  2. Verify fee appears in order total
  3. Check Stripe dashboard to confirm charge amount includes fee
  4. Verify fields display in admin and customer order details
  5. Test email shortcodes in email templates

Update: Display, fee in payment summary

$fee = 400;

/**
 * 1) Include the fee in displayed "estimated total".
 */
add_filter('fluent_cart/cart/estimated_total', function ($total, $data) use ($fee) {
    return (int) $total + (int) $fee;
}, 20, 2);

/**
 * 2) Render a line in the checkout summary (before Total row).
 */
add_action('fluent_cart/checkout/before_summary_total', function ($data) use ($fee) {
    ?>
    <li data-fct-test-gateway-fee-row>
        <span class="fct_summary_label"><?php echo esc_html__('Payment Processing Fee', 'fluent-cart'); ?></span>
        <span class="fct_summary_value"><?php echo esc_html(\FluentCart\App\Helpers\Helper::toDecimal($fee)); ?></span>
    </li>
    <?php
}, 9, 1);

/**
 * Block-based checkout summary footer does NOT call `fluent_cart/checkout/before_summary_total`.
 * So we inject the same `<li>` into the footer block output.
 */
add_filter('render_block_fluent-cart/checkout-summary-footer', function ($block_content) use ($fee) {
    // If already injected, do nothing
    if (strpos($block_content, 'data-fct-test-gateway-fee-row') !== false) {
        return $block_content;
    }

    $row = '<li data-fct-test-gateway-fee-row>'
        . '<span class="fct_summary_label">' . esc_html__('Payment Processing Fee', 'fluent-cart') . '</span>'
        . '<span class="fct_summary_value">' . esc_html(\FluentCart\App\Helpers\Helper::toDecimal($fee)) . '</span>'
        . '</li>';

    // Prefer inserting right before the Total row, if present
    $pos = strpos($block_content, 'class="fct_summary_items_total"');
    if ($pos !== false) {
        return substr($block_content, 0, $pos) . $row . substr($block_content, $pos);
    }

    // Fallback: insert before closing </ul>
    return str_replace('</ul>', $row . '</ul>', $block_content);
}, 10, 1);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment