cart = $cart; $this->requireShipping = $cart->requireShipping(); $this->hasSubscription = $cart->hasSubscription(); $formData = Arr::get($cart->checkout_data, 'form_data', []); $this->storeSettings = new StoreSettings(); $fallbackCountry = ''; $HTTP_CF_IP_COUNTRY = Arr::get(App::request()->server(), 'HTTP_CF_IPCOUNTRY'); if ($HTTP_CF_IP_COUNTRY) { $fallbackCountry = $HTTP_CF_IP_COUNTRY; } $this->billingAddress = [ 'full_name' => trim($this->cart->first_name . ' ' . $this->cart->last_name), 'country' => Arr::get($formData, 'billing_country', $fallbackCountry), 'address_1' => Arr::get($formData, 'billing_address_1', ''), 'address_2' => Arr::get($formData, 'billing_address_2', ''), 'city' => Arr::get($formData, 'billing_city', ''), 'state' => Arr::get($formData, 'billing_state', ''), 'postcode' => Arr::get($formData, 'billing_postcode', ''), 'company_name' => Arr::get($formData, 'billing_company_name', ''), 'phone' => Arr::get($formData, 'billing_phone', ''), ]; if ($this->requireShipping) { if (Arr::get($formData, 'ship_to_different', '') === 'yes') { $shippingCountry = Arr::get($formData, 'shipping_country', $fallbackCountry); $shippingValidations = array_filter(CheckoutFieldsSchema::getCheckoutFieldsRequirements('shipping', 'physical')); if (!Arr::has($shippingValidations, 'country')) { $shippingCountry = Arr::get($formData, 'billing_country'); } $this->shippingAddress = [ 'full_name' => Arr::get($formData, 'shipping_full_name', ''), 'country' => $shippingCountry, 'address_1' => Arr::get($formData, 'shipping_address_1', ''), 'address_2' => Arr::get($formData, 'shipping_address_2', ''), 'city' => Arr::get($formData, 'shipping_city', ''), 'state' => Arr::get($formData, 'shipping_state', ''), 'postcode' => Arr::get($formData, 'shipping_postcode', ''), 'company_name' => Arr::get($formData, 'shipping_company_name', ''), 'phone' => Arr::get($formData, 'shipping_phone', ''), ]; } else { $this->shippingAddress = $this->billingAddress; } } $this->config = $config; } public function render($config = []) { if ($config) { $this->config = wp_parse_args($config, $this->config); } $this->wrapperStart(); $this->renderNotices(); $this->renderCheckoutForm(); $this->wrapperEnd(); } public function getFragment($fragmentName) { $maps = [ 'shipping_methods' => 'renderShippingOptions', 'payment_methods' => 'renderPaymentMethods', 'cart_summary_fragment' => 'renderSummaryFragment' ]; if (isset($maps[$fragmentName])) { ob_start(); $this->{$maps[$fragmentName]}(); return ob_get_clean(); } return ''; } public function wrapperStart() { $classNames = [ 'fluent-cart-checkout-page', 'fct-checkout', 'fct-checkout-type-' . $this->cart->cart_group ]; $configClass = Arr::get($this->config, 'wrapper_class', ''); if ($configClass) { $classNames[] = $configClass; } $classNames = apply_filters('fluent_cart/checkout_page_css_classes', $classNames, [ 'cart' => $this->cart ]); $classNames = array_filter(array_unique($classNames)); $atts = [ 'class' => implode(' ', $classNames), 'data-fluent-cart-checkout-page' => '', ]; do_action('fluent_cart/before_checkout_page_start', [ 'cart' => $this->cart ]); ?>
role="main" aria-label=""> $this->cart ]; do_action('fluent_cart/after_checkout_page_start', $hookData); } public function renderNotices() { $notices = Arr::get($this->cart->checkout_data, '__cart_notices', []); $hookedNotices = apply_filters('fluent_cart/checkout_page_notices', [], [ 'cart' => $this->cart ]); if (!$notices && !$hookedNotices) { return; } ?>
request)); $current_url = add_query_arg(App::request()->all(), $current_url); $formAttributes = [ 'method' => 'POST', 'data-fluent-cart-checkout-page-checkout-form' => '', 'class' => 'fct_checkout fluent-cart-checkout-page-checkout-form', 'action' => $current_url, 'enctype' => 'multipart/form-data', ]; do_action('fluent_cart/before_checkout_form', ['cart' => $this->cart]); ?>
aria-label=""> $this->cart]); ?>
renderNameFields(); ?> renderCreateAccountField(); ?> $this->cart]); ?> renderAddressFields(); ?>
renderShippingOptions(); ?>
agreeTerms(); ?> $this->cart]); ?>
renderPaymentMethods(); ?>
$this->cart]); ?> renderCheckoutButton(); ?> $this->cart]); ?>
cart))->render(); ?> renderOrderNoteField(); ?> $this->cart]); ?>
$this->cart]); } public function wrapperEnd() { do_action('fluent_cart/before_checkout_page_close', [ 'cart' => $this->cart ]); ?>
$this->cart ]); } public function renderCreateAccountField($atts = []) { //check store settings also $attr_title = Arr::get($atts, 'title'); $extraClass = Arr::get($atts, 'wrapper_atts') ? '' : 'fct-has-default-font-size'; ?> storeSettings->get('user_account_creation_mode') === 'user_choice'): ?>
renderField([ 'type' => 'checkbox', 'id' => 'allow_create_account', 'name' => 'allow_create_account', 'checkbox_value' => 'yes', 'label' => $label, 'value' => Arr::get($this->cart->checkout_data, 'form_data.allow_create_account', ''), 'wrapper_class' => 'fct_create_account_wrapper', ]); ?>
cart); if (!$schema) { return; } (new FormFieldRenderer())->renderSection($schema); } public function renderB2BToggle() { if (!CheckoutFieldsSchema::hasAnyBusinessFields()) { return; } if (CheckoutFieldsSchema::isB2BOnlyMode()) { $this->renderBusinessDetailsSection(true); return; } $isB2B = Arr::get($this->cart->checkout_data, 'form_data.is_business', 'no') === 'yes'; $hasBusinessSection = CheckoutFieldsSchema::isCompanyNameEnabled() || CheckoutFieldsSchema::isLegalRegistrationIdEnabled() || CheckoutFieldsSchema::isVatNumberEnabled(); $extraAtts = [ 'data-fluent-cart-b2b-toggle' => 'yes', 'aria-expanded' => $isB2B ? 'true' : 'false', ]; if ($hasBusinessSection) { $extraAtts['aria-controls'] = 'fct_b2b_business_section'; } ?>
renderField([ 'type' => 'checkbox', 'id' => 'is_business', 'name' => 'is_business', 'checkbox_value' => 'yes', 'label' => __('I am purchasing as a business', 'fluent-cart'), 'value' => $isB2B ? 'yes' : '', 'extra_atts' => $extraAtts, ]); ?>
renderBusinessDetailsSection($isB2B); } public function renderBusinessDetailsSection($isVisible) { $hasCompany = CheckoutFieldsSchema::isCompanyNameEnabled(); $hasLegalReg = CheckoutFieldsSchema::isLegalRegistrationIdEnabled(); $hasVat = CheckoutFieldsSchema::isVatNumberEnabled(); if (!$hasCompany && !$hasLegalReg && !$hasVat) { return; } $formData = Arr::get($this->cart->checkout_data, 'form_data', []); $isCompanyRequired = CheckoutFieldsSchema::isCompanyNameRequired(); $isLegalRequired = CheckoutFieldsSchema::isLegalRegistrationIdRequired(); $style = $isVisible ? '' : 'display:none'; ?>
data-b2b-required="yes" required aria-required="true" />
$this->cart]); ?>
countries(); return [ 'address_select' => [ 'type' => 'address_select', 'address_type' => $type, 'options' => $allowedAddresses, 'title' => $addressLabel, 'label' => '', 'countries' => $countries, 'primary_address' => $primaryAddress, 'value' => Arr::get($primaryAddress, 'id'), 'requirements_fields' => $requirementsFields ] ]; } return $fields; } return $fields; } public function renderAddressFields() { $requireShipping = $this->requireShipping; // $formData = Arr::get($this->cart->checkout_data, 'form_data', []); // $billingAddress = $this->billingAddress; // $billingAddress['type'] = 'billing'; // $billingAddress['product_type'] = $requireShipping ? 'physical' : 'digital'; // $billingAddress['with_shipping'] = $requireShipping && Arr::get($formData, 'ship_to_different', '') !== 'yes'; // $billingAddress['billing_address_id'] = Arr::get($formData, 'billing_address_id', ''); // $billingFields = CheckoutFieldsSchema::getAddressBaseFields($billingAddress); // $billingFields = $this->validateAddressField($billingAddress, $billingFields); // foreach ($billingFields as &$field) { // if(empty($field['wrapper_atts'])) { // $field['wrapper_atts'] = []; // } // $field['wrapper_atts']['data-fluent-cart-checkout-page-form-input-wrapper'] = ''; // } // $billingFields = $this->maybeRearrangeAddressFields($billingFields); // $billingFields = apply_filters('fluent_cart/checkout_renderer/billing_fields', $billingFields, [ // 'checkout_renderer' => $this, // 'cart' => $this->cart // ]); // $formRender = new FormFieldRenderer(); echo '
'; $this->renderBillingAddressFields(); $this->renderB2BToggle(); if (!$requireShipping) { echo '
'; return; } $this->renderShipToDifferentField(); do_action('fluent_cart/after_billing_fields_section', ['cart' => $this->cart]); $this->renderShippingAddressFields(); echo ''; } public function renderBillingAddressFields($section_title = '') { $formData = Arr::get($this->cart->checkout_data, 'form_data', []); $requireShipping = $this->requireShipping; $billingAddress = $this->billingAddress; $billingAddress['type'] = 'billing'; $billingAddress['product_type'] = $requireShipping ? 'physical' : 'digital'; $billingAddress['with_shipping'] = $requireShipping && Arr::get($formData, 'ship_to_different', '') !== 'yes'; $billingAddress['billing_address_id'] = Arr::get($formData, 'billing_address_id', ''); $billingAddress['order_id'] = $this->cart->order_id ?? null; $billingFields = CheckoutFieldsSchema::getAddressBaseFields($billingAddress); $billingFields = $this->validateAddressField($billingAddress, $billingFields); foreach ($billingFields as &$field) { if (empty($field['wrapper_atts'])) { $field['wrapper_atts'] = []; } $field['wrapper_atts']['data-fluent-cart-checkout-page-form-input-wrapper'] = ''; } $billingFields = $this->maybeRearrangeAddressFields($billingFields); $billingFields = apply_filters('fluent_cart/checkout_renderer/billing_fields', $billingFields, [ 'checkout_renderer' => $this, 'cart' => $this->cart ]); do_action('fluent_cart/before_billing_fields_section', ['cart' => $this->cart]); $formRender = new FormFieldRenderer(); $title = __('Billing Address', 'fluent-cart'); if (!empty($section_title)) { $title = $section_title; } $formRender->renderSection([ 'id' => 'billing_address_section_section', 'type' => 'section', 'heading' => $title, 'fields' => $billingFields, 'wrapper_atts' => [ 'data-fluent-cart-checkout-page-form-section' => '', 'role' => 'region', 'aria-label' => __('Billing Address', 'fluent-cart') ] ]); } public function renderShipToDifferentField($atts = []) { $formRender = new FormFieldRenderer(); $attr_title = Arr::get($atts, 'title'); $extraClass = Arr::get($atts, 'wrapper_atts') ? '' : 'fct-has-default-font-size'; $title = __('Ship to a different address?', 'fluent-cart'); if (!empty($attr_title)) { $title = $attr_title; } ?>
renderField([ 'type' => 'checkbox', 'id' => 'ship_to_different', 'name' => 'ship_to_different', 'checkbox_value' => 'yes', 'label' => $title, 'value' => Arr::get($this->cart->checkout_data, 'form_data.ship_to_different', ''), 'extra_atts' => [ 'data-fluent-cart-ship-to-different-address' => 'yes', 'aria-controls' => 'shipping_address_section_section', ], ]); ?>
cart->checkout_data, 'form_data', []); $formRender = new FormFieldRenderer(); $shippingAddress = $this->shippingAddress; $shippingAddress['type'] = 'shipping'; $shippingAddress['product_type'] = 'physical'; $shippingAddress['shipping_address_id'] = Arr::get($formData, 'shipping_address_id', ''); $shippingFields = CheckoutFieldsSchema::getAddressBaseFields($shippingAddress); $shippingFields = $this->validateAddressField($shippingAddress, $shippingFields); $shippingFields = apply_filters('fluent_cart/checkout_renderer/shipping_fields', $shippingFields, [ 'checkout_renderer' => $this, 'cart' => $this->cart ]); foreach ($shippingFields as &$field) { if (empty($field['wrapper_atts'])) { $field['wrapper_atts'] = []; } $field['wrapper_atts']['data-fluent-cart-checkout-page-form-input-wrapper'] = ''; } $shippingFields = $this->maybeRearrangeAddressFields($shippingFields); $title = __('Shipping Address', 'fluent-cart'); if (!empty($section_title)) { $title = $section_title; } do_action('fluent_cart/before_shipping_fields_section', ['cart' => $this->cart]); $formRender->renderSection([ 'id' => 'shipping_address_section_section', 'type' => 'section', 'heading' => $title, 'fields' => $shippingFields, 'wrapper_atts' => [ 'data-fluent-cart-checkout-page-shipping-fields' => '', 'style' => Arr::get($this->cart->checkout_data, 'form_data.ship_to_different', '') === 'yes' ? '' : 'display:none', 'role' => 'region', 'aria-label' => __('Shipping Address', 'fluent-cart') ] ]); do_action('fluent_cart/after_shipping_fields_section', ['cart' => $this->cart]); } public function renderOrderNoteField($attr_title = '') { if ( !$this->requireShipping && apply_filters('fluent_cart/disable_order_notes_for_digital_products', true, [ 'cart' => $this->cart ]) ) { return; } $noteTitle = __('Leave a Note', 'fluent-cart'); if (!empty($attr_title)) { $noteTitle = $attr_title; } $fieldId = 'order_notes'; (new FormFieldRenderer())->renderField([ 'type' => 'textarea', 'id' => $fieldId, 'name' => 'order_notes', 'aria-label' => __('Order Notes', 'fluent-cart'), 'placeholder' => __('Notes about your order, e.g. Leave it at my doorstep.', 'fluent-cart'), 'extra_atts' => [ 'rows' => 4 ], 'wrapper_atts' => [ 'data-fct-item-toggle' => '', 'class' => 'fct-toggle-field fct_order_note' ], 'before_callback' => function ($field) use ($fieldId, $noteTitle) { $toggleId = 'order_notes_toggle'; $wrapperId = 'order_notes_wrapper'; ?> '; } ]); do_action('fluent_cart/after_order_notes_field', ['cart' => $this->cart]); } public function renderShippingOptions() { if (!$this->requireShipping) { return; } $countryCode = $this->shippingAddress['country'] ?: $this->billingAddress['country']; $stateCode = $this->shippingAddress['state'] ?: $this->billingAddress['state']; $billingValidations = array_filter(CheckoutFieldsSchema::getCheckoutFieldsRequirements('billing', 'physical')); if (!isset($billingValidations['country'])) { $countryCode = (new StoreSettings())->get('store_country'); } $availableShippingMethods = AddressHelper::getShippingMethods($countryCode, $stateCode); $selectedId = Arr::get($this->cart->checkout_data, 'shipping_data.shipping_method_id', ''); $selectedId = CartHelper::resolveAutoSelectShippingMethod($this->cart, $availableShippingMethods ?: [], $selectedId); if (!$availableShippingMethods || is_wp_error($availableShippingMethods)) { (new ShippingMethodsRender($availableShippingMethods, $selectedId))->render(); } else { foreach ($availableShippingMethods as $method) { $method->charge_amount = CartHelper::calculateShippingMethodCharge($method, $this->cart->cart_data); } (new ShippingMethodsRender($availableShippingMethods, $selectedId))->render(); } } /** * Get available shipping methods considering cart's shipping classes. * This is used by the frontend to display profile-aware methods. */ public function getProfileAwareShippingMethods($countryCode, $stateCode) { // Get general methods (backward compatible) $methods = AddressHelper::getShippingMethods($countryCode, $stateCode); if (is_wp_error($methods) || empty($methods)) { return $methods; } return $methods; } public function renderPaymentMethods($atts = []) { if ($this->cart->getEstimatedTotal() <= 0) { if (!$this->cart->hasSubscription() || $this->cart->getEstimatedRecurringTotal() <= 0) { return ''; } } $selectedPaymentMethod = Arr::get($this->cart->checkout_data, 'form_data._fct_pay_method', ''); $activePaymentMethods = PaymentMethods::getActiveMethodInstance($this->cart); $hadActiveMethods = !empty($activePaymentMethods); $activePaymentMethods = apply_filters('fluent_cart/checkout_active_payment_methods', $activePaymentMethods, [ 'cart' => $this->cart ]); if (!$selectedPaymentMethod && !empty($activePaymentMethods)) { // reset() not [0] — the filter above may return a non-zero-indexed array. $firstMethod = reset($activePaymentMethods); $selectedPaymentMethod = $firstMethod ? $firstMethod->getMeta('route') : ''; } /** * The payment method rendered as checked. An add-on that renders its own * selector outside this list (e.g. saved payment methods) returns a route * that is not in the list, so no gateway here is checked — the page then * arrives with the add-on's choice already selected instead of a gateway * being checked first and switched over by JS after load. * * @param string $selectedPaymentMethod * @param array $context ['cart' => Cart, 'payment_methods' => array] */ $selectedPaymentMethod = (string) apply_filters('fluent_cart/checkout/selected_payment_method', $selectedPaymentMethod, [ 'cart' => $this->cart, 'payment_methods' => $activePaymentMethods ]); $checkoutMethodStyle = $this->storeSettings->get('checkout_method_style', 'logo'); ?>

getMeta('route')); $this->renderPaymentMethod($method, [ 'selected_id' => $selectedPaymentMethod, 'style' => $checkoutMethodStyle, 'aria_checked' => $isSelected ? 'true' : 'false', 'role' => 'radio' ]); ?> ' . esc_html__('Activate from settings.', 'fluent-cart') . ''; } echo '
' . wp_kses_post($emptyText) . '
'; ?>
'submit', 'class' => 'fct_place_order_btn large', 'id' => 'fluent_cart_order_btn', 'data-fluent-cart-checkout-page-checkout-button' => '', 'data-value' => $placeOrderButtonText, 'disabled' => '' ]; // Parse $atts using WordPress shortcode_atts or wp_parse_args if (!empty($atts)) { // Extract attributes from string $parsed = shortcode_parse_atts($atts); if (isset($parsed['class'])) { $attributes['class'] .= ' ' . $parsed['class']; unset($parsed['class']); } $attributes = array_merge($attributes, $parsed); } ?>
getMeta('route'); $methodTitle = $method->getMeta('title'); $methodStyle = Arr::get($config, 'style', 'logo'); $inputAttributes = array_filter([ 'class' => 'form-radio-input', 'type' => 'radio', 'name' => '_fct_pay_method', 'id' => 'fluent_cart_payment_method_' . $route, 'value' => $route, 'required' => true, 'checked' => $route === Arr::get($config, 'selected_id', '') ? 'true' : '', 'role' => Arr::get($config, 'role', 'radio'), 'aria-checked' => Arr::get($config, 'aria_checked', 'false'), ]); $wrapperClass = $methodStyle === 'logo' ? 'fct_payment_method_logo' : 'fct_payment_method'; $wrapperAttributes = [ 'class' => $wrapperClass . ' ' . 'fct_payment_method_wrapper fct_payment_method_' . $route, 'tabindex' => '0', 'role' => 'presentation' ]; ?>
> /> getMeta('instructions')): ?>
$route, 'method_title' => $methodTitle, 'method_style' => $methodStyle, ]; $paymentMethodClass = ''; $paymentMethodClass = apply_filters('fluent_cart/payment_method_list_class', $paymentMethodClass, $pmContext); ?>
" aria-hidden="true"> $method, 'cart' => $this->cart, 'route' => $route ] ); ?>
'sub_section', 'wrapper_class' => 'fct_2_columns fct_checkout_city_postcode', 'fields' => [ 'city' => $cityField, 'postcode' => $postcodeField ], ]; } if (isset($fields['phone'])) { $phoneField = $fields['phone']; unset($fields['phone']); $fields['phone'] = $phoneField; } if (isset($fields['company_name'])) { $companyField = $fields['company_name']; unset($fields['company_name']); $fields['company_name'] = $companyField; } return $fields; } public function agreeTerms($atts = []) { if (!CheckoutFieldsSchema::isTermsVisible()) { return; } $termsText = CheckoutFieldsSchema::getTermsText(); $sectionId = 'agree_terms_section'; $extraClass = Arr::get($atts, 'wrapper_atts') ? '' : 'fct-has-default-font-size'; $title = Arr::get($atts, 'title'); ?>
cart))->render(false); } }