| @@ -39,19 +39,8 @@ | ||
| 39 | 39 | |
| 40 | 40 | $formData = Arr::get($cart->checkout_data, 'form_data', []); |
| 41 | 41 | $this->storeSettings = new StoreSettings(); |
| 42 | 42 | |
| 43 | - $billingValidations = array_filter(CheckoutFieldsSchema::getCheckoutFieldsRequirements('billing', 'physical')); | |
| 44 | - $storeCountry = (new StoreSettings())->get('store_country'); | |
| 45 | - if (!Arr::has($billingValidations, 'country') && Arr::get($formData, 'billing_country') !== $storeCountry) { | |
| 46 | - $formData['billing_country'] = $storeCountry; | |
| 47 | - // save $this->cart | |
| 48 | - $checkoutData = $this->cart->checkout_data; | |
| 49 | - $checkoutData['form_data'] = $formData; | |
| 50 | - $this->cart->checkout_data = $checkoutData; | |
| 51 | - $this->cart->save(); | |
| 52 | - } | |
| 53 | - | |
| 54 | 43 | $fallbackCountry = ''; |
| 55 | 44 | $HTTP_CF_IP_COUNTRY = Arr::get(App::request()->server(), 'HTTP_CF_IPCOUNTRY'); |
| 56 | 45 | |
| 57 | 46 | if ($HTTP_CF_IP_COUNTRY) { |
| @@ -161,9 +150,8 @@ | ||
| 161 | 150 | <?php |
| 162 | 151 | $hookData = [ |
| 163 | 152 | 'cart' => $this->cart |
| 164 | 153 | ]; |
| 165 | - do_action_deprecated('fluent_cart/afrer_checkout_page_start', [$hookData], '1.3.16', 'fluent_cart/after_checkout_page_start', 'Use fluent_cart/after_checkout_page_start instead of fluent_cart/afrer_checkout_page_start.'); | |
| 166 | 154 | do_action('fluent_cart/after_checkout_page_start', $hookData); |
| 167 | 155 | } |
| 168 | 156 | |
| 169 | 157 | public function renderNotices() |
| @@ -219,9 +207,8 @@ | ||
| 219 | 207 | <div class="fct_checkout_form"> |
| 220 | 208 | <div class="fct_checkout_form_items"> |
| 221 | 209 | <?php $this->renderNameFields(); ?> |
| 222 | 210 | |
| 223 | - | |
| 224 | 211 | <?php $this->renderCreateAccountField(); ?> |
| 225 | 212 | |
| 226 | 213 | <?php do_action('fluent_cart/before_billing_fields', ['cart' => $this->cart]); ?> |
| 227 | 214 | |
| @@ -316,8 +303,127 @@ | ||
| 316 | 303 | } |
| 317 | 304 | (new FormFieldRenderer())->renderSection($schema); |
| 318 | 305 | } |
| 319 | 306 | |
| 307 | + public function renderB2BToggle() | |
| 308 | + { | |
| 309 | + if (!CheckoutFieldsSchema::hasAnyBusinessFields()) { | |
| 310 | + return; | |
| 311 | + } | |
| 312 | + | |
| 313 | + if (CheckoutFieldsSchema::isB2BOnlyMode()) { | |
| 314 | + $this->renderBusinessDetailsSection(true); | |
| 315 | + return; | |
| 316 | + } | |
| 317 | + | |
| 318 | + $isB2B = Arr::get($this->cart->checkout_data, 'form_data.is_business', 'no') === 'yes'; | |
| 319 | + | |
| 320 | + $hasBusinessSection = CheckoutFieldsSchema::isCompanyNameEnabled() | |
| 321 | + || CheckoutFieldsSchema::isLegalRegistrationIdEnabled() | |
| 322 | + || CheckoutFieldsSchema::isVatNumberEnabled(); | |
| 323 | + | |
| 324 | + $extraAtts = [ | |
| 325 | + 'data-fluent-cart-b2b-toggle' => 'yes', | |
| 326 | + 'aria-expanded' => $isB2B ? 'true' : 'false', | |
| 327 | + ]; | |
| 328 | + if ($hasBusinessSection) { | |
| 329 | + $extraAtts['aria-controls'] = 'fct_b2b_business_section'; | |
| 330 | + } | |
| 331 | + ?> | |
| 332 | + <div class="fct_b2b_toggle_wrapper fct-has-default-font-size"> | |
| 333 | + <?php | |
| 334 | + (new FormFieldRenderer())->renderField([ | |
| 335 | + 'type' => 'checkbox', | |
| 336 | + 'id' => 'is_business', | |
| 337 | + 'name' => 'is_business', | |
| 338 | + 'checkbox_value' => 'yes', | |
| 339 | + 'label' => __('I am purchasing as a business', 'fluent-cart'), | |
| 340 | + 'value' => $isB2B ? 'yes' : '', | |
| 341 | + 'extra_atts' => $extraAtts, | |
| 342 | + ]); | |
| 343 | + ?> | |
| 344 | + </div> | |
| 345 | + <?php | |
| 346 | + $this->renderBusinessDetailsSection($isB2B); | |
| 347 | + } | |
| 348 | + | |
| 349 | + public function renderBusinessDetailsSection($isVisible) | |
| 350 | + { | |
| 351 | + $hasCompany = CheckoutFieldsSchema::isCompanyNameEnabled(); | |
| 352 | + $hasLegalReg = CheckoutFieldsSchema::isLegalRegistrationIdEnabled(); | |
| 353 | + $hasVat = CheckoutFieldsSchema::isVatNumberEnabled(); | |
| 354 | + | |
| 355 | + if (!$hasCompany && !$hasLegalReg && !$hasVat) { | |
| 356 | + return; | |
| 357 | + } | |
| 358 | + | |
| 359 | + $formData = Arr::get($this->cart->checkout_data, 'form_data', []); | |
| 360 | + $isCompanyRequired = CheckoutFieldsSchema::isCompanyNameRequired(); | |
| 361 | + $isLegalRequired = CheckoutFieldsSchema::isLegalRegistrationIdRequired(); | |
| 362 | + $style = $isVisible ? '' : 'display:none'; | |
| 363 | + ?> | |
| 364 | + <div id="fct_b2b_business_section" | |
| 365 | + data-fluent-cart-b2b-section | |
| 366 | + class="fct_checkout_form_section fct_b2b_business_section" | |
| 367 | + style="<?php echo esc_attr($style); ?>" | |
| 368 | + role="group" | |
| 369 | + aria-label="<?php esc_attr_e('Business Details', 'fluent-cart'); ?>"> | |
| 370 | + <div class="fct_form_section_body"> | |
| 371 | + <div class="fct_checkout_input_group"> | |
| 372 | + <?php if ($hasCompany): ?> | |
| 373 | + <?php | |
| 374 | + $companyLabel = __('Company Name', 'fluent-cart'); | |
| 375 | + $companyValue = Arr::get($formData, 'billing_company_name', ''); | |
| 376 | + ?> | |
| 377 | + <div data-fluent-cart-checkout-page-form-input-wrapper | |
| 378 | + class="fct_input_wrapper" | |
| 379 | + id="billing_company_name_wrapper"> | |
| 380 | + <label for="billing_company_name" class="sr-only"> | |
| 381 | + <?php echo esc_html($companyLabel); ?> | |
| 382 | + </label> | |
| 383 | + <input type="text" | |
| 384 | + name="billing_company_name" | |
| 385 | + id="billing_company_name" | |
| 386 | + autocomplete="organization" | |
| 387 | + placeholder="<?php echo esc_attr($companyLabel . ($isCompanyRequired ? ' *' : '')); ?>" | |
| 388 | + value="<?php echo esc_attr($companyValue); ?>" | |
| 389 | + aria-label="<?php echo esc_attr($companyLabel); ?>" | |
| 390 | + <?php if ($isCompanyRequired): ?> data-b2b-required="yes"<?php endif; ?> | |
| 391 | + <?php if ($isCompanyRequired && $isVisible): ?> required aria-required="true"<?php endif; ?> | |
| 392 | + /> | |
| 393 | + </div> | |
| 394 | + <?php endif; ?> | |
| 395 | + | |
| 396 | + <?php if ($hasLegalReg): ?> | |
| 397 | + <?php | |
| 398 | + $legalLabel = __('Legal Registration ID', 'fluent-cart'); | |
| 399 | + $legalValue = Arr::get($formData, 'billing_legal_registration_id', ''); | |
| 400 | + ?> | |
| 401 | + <div data-fluent-cart-checkout-page-form-input-wrapper | |
| 402 | + class="fct_input_wrapper" | |
| 403 | + id="billing_legal_registration_id_wrapper"> | |
| 404 | + <label for="billing_legal_registration_id" class="sr-only"> | |
| 405 | + <?php echo esc_html($legalLabel); ?> | |
| 406 | + </label> | |
| 407 | + <input type="text" | |
| 408 | + name="billing_legal_registration_id" | |
| 409 | + id="billing_legal_registration_id" | |
| 410 | + autocomplete="off" | |
| 411 | + placeholder="<?php echo esc_attr($legalLabel . ($isLegalRequired ? ' *' : '')); ?>" | |
| 412 | + value="<?php echo esc_attr($legalValue); ?>" | |
| 413 | + aria-label="<?php echo esc_attr($legalLabel); ?>" | |
| 414 | + <?php if ($isLegalRequired): ?> data-b2b-required="yes"<?php endif; ?> | |
| 415 | + <?php if ($isLegalRequired && $isVisible): ?> required aria-required="true"<?php endif; ?> | |
| 416 | + /> | |
| 417 | + </div> | |
| 418 | + <?php endif; ?> | |
| 419 | + <?php do_action('fluent_cart/checkout/b2b_extra_fields', ['cart' => $this->cart]); ?> | |
| 420 | + </div> | |
| 421 | + </div> | |
| 422 | + </div> | |
| 423 | + <?php | |
| 424 | + } | |
| 425 | + | |
| 320 | 426 | public function validateAddressField($config, $fields) |
| 321 | 427 | { |
| 322 | 428 | |
| 323 | 429 | $type = Arr::get($config, 'type', 'billing'); // billing or shipping |
| @@ -407,8 +513,10 @@ | ||
| 407 | 513 | echo '<div class="fct_checkout_billing_and_shipping">'; |
| 408 | 514 | |
| 409 | 515 | $this->renderBillingAddressFields(); |
| 410 | 516 | |
| 517 | + $this->renderB2BToggle(); | |
| 518 | + | |
| 411 | 519 | if (!$requireShipping) { |
| 412 | 520 | echo '</div>'; |
| 413 | 521 | return; |
| 414 | 522 | } |
| @@ -628,8 +736,10 @@ | ||
| 628 | 736 | |
| 629 | 737 | |
| 630 | 738 | $selectedId = Arr::get($this->cart->checkout_data, 'shipping_data.shipping_method_id', ''); |
| 631 | 739 | |
| 740 | + $selectedId = CartHelper::resolveAutoSelectShippingMethod($this->cart, $availableShippingMethods ?: [], $selectedId); | |
| 741 | + | |
| 632 | 742 | if (!$availableShippingMethods || is_wp_error($availableShippingMethods)) { |
| 633 | 743 | (new ShippingMethodsRender($availableShippingMethods, $selectedId))->render(); |
| 634 | 744 | } else { |
| 635 | 745 | foreach ($availableShippingMethods as $method) { |
| @@ -665,8 +775,9 @@ | ||
| 665 | 775 | } |
| 666 | 776 | |
| 667 | 777 | $selectedPaymentMethod = Arr::get($this->cart->checkout_data, 'form_data._fct_pay_method', ''); |
| 668 | 778 | $activePaymentMethods = PaymentMethods::getActiveMethodInstance($this->cart); |
| 779 | + $hadActiveMethods = !empty($activePaymentMethods); | |
| 669 | 780 | |
| 670 | 781 | $activePaymentMethods = apply_filters('fluent_cart/checkout_active_payment_methods', $activePaymentMethods, [ |
| 671 | 782 | 'cart' => $this->cart |
| 672 | 783 | ]); |
| @@ -671,11 +782,28 @@ | ||
| 671 | 782 | 'cart' => $this->cart |
| 672 | 783 | ]); |
| 673 | 784 | |
| 674 | 785 | if (!$selectedPaymentMethod && !empty($activePaymentMethods)) { |
| 675 | - $selectedPaymentMethod = $activePaymentMethods[0] ? $activePaymentMethods[0]->getMeta('route') : ''; | |
| 786 | + // reset() not [0] — the filter above may return a non-zero-indexed array. | |
| 787 | + $firstMethod = reset($activePaymentMethods); | |
| 788 | + $selectedPaymentMethod = $firstMethod ? $firstMethod->getMeta('route') : ''; | |
| 676 | 789 | } |
| 677 | 790 | |
| 791 | + /** | |
| 792 | + * The payment method rendered as checked. An add-on that renders its own | |
| 793 | + * selector outside this list (e.g. saved payment methods) returns a route | |
| 794 | + * that is not in the list, so no gateway here is checked — the page then | |
| 795 | + * arrives with the add-on's choice already selected instead of a gateway | |
| 796 | + * being checked first and switched over by JS after load. | |
| 797 | + * | |
| 798 | + * @param string $selectedPaymentMethod | |
| 799 | + * @param array $context ['cart' => Cart, 'payment_methods' => array] | |
| 800 | + */ | |
| 801 | + $selectedPaymentMethod = (string) apply_filters('fluent_cart/checkout/selected_payment_method', $selectedPaymentMethod, [ | |
| 802 | + 'cart' => $this->cart, | |
| 803 | + 'payment_methods' => $activePaymentMethods | |
| 804 | + ]); | |
| 805 | + | |
| 678 | 806 | $checkoutMethodStyle = $this->storeSettings->get('checkout_method_style', 'logo'); |
| 679 | 807 | |
| 680 | 808 | ?> |
| 681 | 809 | <div id="fluent_payment_methods" class="fluent_payment_methods"> |
| @@ -702,9 +830,13 @@ | ||
| 702 | 830 | ?> |
| 703 | 831 | <?php endforeach; ?> |
| 704 | 832 | <?php else: ?> |
| 705 | 833 | <?php |
| 706 | - $emptyText = esc_html__('No Payment method is activated for this site yet.', 'fluent-cart'); | |
| 834 | + if ($hadActiveMethods) { | |
| 835 | + $emptyText = esc_html__('None of the available payment methods can process this order. Please contact the store.', 'fluent-cart'); | |
| 836 | + } else { | |
| 837 | + $emptyText = esc_html__('No Payment method is activated for this site yet.', 'fluent-cart'); | |
| 838 | + } | |
| 707 | 839 | if (current_user_can('manage_options')) { |
| 708 | 840 | $emptyText .= '<a href="' . esc_url(URL::getDashboardUrl('settings/payments')) . '" target="_blank">' . esc_html__('Activate from settings.', 'fluent-cart') . '</a>'; |
| 709 | 841 | } |
| 710 | 842 | echo '<div class="fct-empty-state">' . wp_kses_post($emptyText) . '</div>'; |
| @@ -816,9 +948,9 @@ | ||
| 816 | 948 | 'route' => $route, |
| 817 | 949 | 'method_title' => $methodTitle, |
| 818 | 950 | 'method_style' => $methodStyle, |
| 819 | 951 | ]; |
| 820 | - $paymentMethodClass = apply_filters_deprecated('fluent_cart_payment_method_list_class', ['', $pmContext], '1.3.16', 'fluent_cart/payment_method_list_class', 'Use fluent_cart/payment_method_list_class instead of fluent_cart_payment_method_list_class.'); | |
| 952 | + $paymentMethodClass = ''; | |
| 821 | 953 | $paymentMethodClass = apply_filters('fluent_cart/payment_method_list_class', $paymentMethodClass, $pmContext); |
| 822 | 954 | |
| 823 | 955 | ?> |
| 824 | 956 | <div class="<?php echo "fluent-cart-checkout_embed_payment_container fluent-cart-checkout_embed_payment_container_" . esc_attr($route . ' ' . $paymentMethodClass); ?>" |