storeSettings = self::$cachedStoreSettings; return; } $defaultSettings = $this->getDefaultSettings(); $storeSettings = get_option($this->optionKey, []); $settings = wp_parse_args($storeSettings, $defaultSettings); $this->storeSettings = $settings; self::$cachedStoreSettings = $this->storeSettings; } protected function getDefaultSettings(): array { $defaultSettings = [ 'store_name' => get_bloginfo('name'), 'company_name' => '', 'legal_registration_id' => '', 'seller_vat_id' => '', 'seller_tax_id' => '', 'note_for_user_account_creation' => __('An user account will be created', 'fluent-cart'), 'checkout_button_text' => __('Checkout', 'fluent-cart'), 'view_cart_button_text' => __('View Cart', 'fluent-cart'), 'cart_button_text' => __('Add To Cart', 'fluent-cart'), 'popup_button_text' => __('View Product', 'fluent-cart'), 'out_of_stock_button_text' => __('Not Available', 'fluent-cart'), 'currency_position' => 'before', // 'thousand_separator' => 'comma', 'decimal_separator' => 'dot', 'checkout_method_style' => 'logo', 'enable_modal_checkout' => 'no', 'require_logged_in' => 'no', 'show_cart_icon_in_nav' => 'no', 'show_cart_icon_in_body' => 'yes', 'additional_address_field' => 'yes', 'hide_coupon_field' => 'no', 'user_account_creation_mode' => 'all', 'checkout_page_id' => '', 'custom_payment_page_id' => '', 'registration_page_id' => '', 'login_page_id' => '', 'cart_page_id' => '', 'receipt_page_id' => '', 'shop_page_id' => '', 'customer_profile_page_id' => '', 'customer_profile_page_slug' => '', 'currency' => 'USD', 'store_address1' => '', 'store_address2' => '', 'store_city' => '', 'store_country' => '', 'store_postcode' => '', 'store_state' => '', 'show_relevant_product_in_single_page' => 'yes', 'show_relevant_product_in_modal' => '', 'order_mode' => 'test', 'subscription_mode_guard' => 'yes', 'variation_view' => 'both', 'variation_columns' => 'masonry', 'enable_early_payment_for_installment' => 'yes', 'subscription_management_mode' => 'gateway_managed', 'subscription_system_charge' => 'no', 'modules_settings' => [], 'min_receipt_number' => '1', 'inv_prefix' => 'INV-', 'weight_unit' => 'kg', 'dimension_unit' => 'cm' ]; return apply_filters('fluent_cart/store_settings/values', $defaultSettings, []); } /** * @return array * * Get all store settings fields * @hook to use apply_filters("fluent_cart/store_setting_fields", $fields) */ public function fields($params = []): array { $pages = Pages::getPages(''); $previewLinks = [ 'shop_page_id' => $this->getShopPage(), 'customer_profile_page_id' => $this->getCustomerProfilePage(), 'cart_page_id' => $this->getCartPage(), 'checkout_page_id' => $this->getCheckoutPage(), 'receipt_page_id' => $this->getReceiptPage() ]; $isProActive = App::isProActive(); $proFeatureIcon = Vite::getAssetUrl('images/crown.svg'); // Read-only schedule for store-managed subscription renewals. Pulled live // from the same map the scheduler uses, so it stays accurate under the // fluent_cart/renewal/advance_creation_days filter. No editable knob — the timing is // deliberately built-in; developers tune it via that filter. $invoiceScheduleMap = RenewalService::getAdvanceCreationDaysMap(); $invoiceScheduleLabels = [ 'daily' => __('Daily', 'fluent-cart'), 'weekly' => __('Weekly', 'fluent-cart'), 'monthly' => __('Monthly', 'fluent-cart'), 'quarterly' => __('Quarterly', 'fluent-cart'), 'half_yearly' => __('Half-yearly', 'fluent-cart'), 'yearly' => __('Yearly', 'fluent-cart'), ]; // Structured renewal-order schedule for the SubscriptionModeManager // component (status card + guarded edit dialog). $invoiceScheduleList = []; foreach ($invoiceScheduleLabels as $invoiceScheduleKey => $invoiceScheduleLabel) { if (!isset($invoiceScheduleMap[$invoiceScheduleKey])) { continue; } $invoiceScheduleDays = (int) $invoiceScheduleMap[$invoiceScheduleKey]; $invoiceScheduleList[] = [ 'label' => $invoiceScheduleLabel, 'when' => $invoiceScheduleDays <= 0 ? __('on the due date', 'fluent-cart') /* translators: %d: number of days before the due date */ : sprintf(_n('%d day before due date', '%d days before due date', $invoiceScheduleDays, 'fluent-cart'), $invoiceScheduleDays), ]; } // Gateways declaring `system_subscription` — the only ones // subscription_system_charge can ever auto-charge. $systemChargeGateways = []; foreach (GatewayManager::getInstance()->all() as $systemChargeGateway) { if (!$systemChargeGateway->has('system_subscription') || $systemChargeGateway->isUpcoming()) { continue; } $systemChargeGatewayMeta = $systemChargeGateway->getMeta(); $systemChargeGateways[] = [ 'label' => Arr::get($systemChargeGatewayMeta, 'admin_title') ?: Arr::get($systemChargeGatewayMeta, 'label') ?: Arr::get($systemChargeGatewayMeta, 'title'), 'active' => $systemChargeGateway->isEnabled(), ]; } $fields = [ 'setting_tabs' => [ 'type' => 'section', 'disable_nesting' => true, 'default_tab' => 'store_setup', 'hide_tab_switch' => true, 'schema' => [ 'store_setup' => [ 'id' => '', 'title' => __('Store Setup', 'fluent-cart'), 'show_title' => false, 'type' => 'section', 'disable_nesting' => true, 'columns' => [ 'default' => 1, 'md' => 1 ], 'schema' => [ 'name_grid' => [ 'type' => 'grid', 'columns' => [ 'default' => 1, 'md' => 3 ], 'disable_nesting' => true, 'schema' => [ 'label' => [ 'type' => 'html', 'value' => '' . __('Store Name', 'fluent-cart') . '
' . __('Enter the public name of your online store.', 'fluent-cart') . '
' ], "store_name" => [ 'wrapperClass' => 'col-span-2 flex items-center', "label" => '', "type" => "input", "value" => "", ], ] ], 'hr' => [ 'type' => 'html', 'value' => '
' ], 'logo_grid' => [ 'type' => 'grid', 'columns' => [ 'default' => 1, 'md' => 3 ], 'disable_nesting' => true, 'schema' => [ 'label' => [ 'type' => 'html', 'value' => '' . __('Store Logo', 'fluent-cart') . '
' . __("Upload your brand's logo. Recommended width: 512 pixels minimum.", 'fluent-cart') . '
' ], "store_logo" => [ "label" => false, "type" => "media", "value" => "", 'multiple' => false, // if `condition_type` not specified then all condition type will be `and` // 'conditions' => [ // [ // 'key' => 'store_name', // 'operator' => '==', // 'value' => [ // 'accessor' => 'order_mode' // ] // ], // ], ], ] ], 'hr2' => [ 'type' => 'html', 'value' => '
' ], 'mode_grid' => [ 'type' => 'grid', 'columns' => [ 'default' => 1, 'md' => 3 ], 'disable_nesting' => true, 'schema' => [ 'label' => [ 'type' => 'html', 'value' => '' . __('Store Mode', 'fluent-cart') . '
' . __("Select your store's operating mode: `Test` for setup, `Live` for real transactions.", 'fluent-cart') . '
' ], 'order_mode' => [ 'wrapperClass' => 'col-span-2 flex items-center', "label" => '', "type" => "radio", "options" => [ [ "label" => __('Live', 'fluent-cart'), "value" => 'live', ], [ "label" => __('Test', 'fluent-cart'), "value" => 'test', ], ], "value" => "live" ], ] ], 'settings_hr' => [ 'type' => 'html', 'value' => '
' ], 'address_grid' => [ 'type' => 'grid', 'columns' => [ 'default' => 1, 'md' => 3 ], 'disable_nesting' => true, 'schema' => [ 'label' => [ 'type' => 'html', 'value' => '' . __('Store Address', 'fluent-cart') . '
' . __("Provide your physical business address details.", 'fluent-cart') . '
' ], 'address_input_grid' => [ 'wrapperClass' => 'fct-compact-form', 'type' => 'grid', 'disable_nesting' => true, 'class' => 'col-span-2', 'schema' => [ 'store_address_component' => [ 'type' => 'component', 'component' => 'StoreSettings/AddressComponent', 'wrapperClass' => 'col-span-full' ], 'store_address1' => [ 'type' => 'hidden', ], 'store_address2' => [ 'type' => 'hidden', ], 'store_city' => [ 'type' => 'hidden', ], 'store_postcode' => [ 'type' => 'hidden', ], 'store_country' => [ 'type' => 'hidden', ], 'store_state' => [ 'type' => 'hidden', ], ] ], ] ], 'settings_hr_2' => [ 'type' => 'html', 'value' => '
' ], 'business_details_grid' => [ 'type' => 'grid', 'id' => 'business_details', 'columns' => [ 'default' => 1, 'md' => 3 ], 'disable_nesting' => true, 'schema' => [ 'label' => [ 'type' => 'html', 'value' => '' . __('Business Details', 'fluent-cart') . '
' . __('Add your legal business identity details used for store records and compliance.', 'fluent-cart') . '
' ], 'business_details_fields' => [ 'type' => 'grid', 'columns' => [ 'default' => 1, 'md' => 2 ], 'disable_nesting' => true, 'wrapperClass' => 'col-span-2', 'schema' => [ 'company_name' => [ 'label' => __('Company Name', 'fluent-cart'), 'type' => 'input', 'value' => '', ], 'legal_registration_id' => [ 'label' => __('Legal Registration ID', 'fluent-cart'), 'type' => 'input', 'value' => '', ], 'seller_vat_id' => [ 'label' => __('Seller VAT ID', 'fluent-cart'), 'type' => 'input', 'value' => '', ], 'seller_tax_id' => [ 'label' => __('Seller Tax ID', 'fluent-cart'), 'type' => 'input', 'value' => '', ], ] ], ] ], 'settings_hr_3' => [ 'type' => 'html', 'value' => '
' ], 'currency_grid' => [ 'type' => 'grid', 'columns' => [ 'default' => 1, 'md' => 3 ], 'disable_nesting' => true, 'schema' => [ 'label' => [ 'type' => 'html', 'value' => '' . __('Checkout Currency', 'fluent-cart') . '
' . __("Select the primary currency for your store.", 'fluent-cart') . '
' ], "currency" => [ 'wrapperClass' => 'col-span-2 flex items-center', "label" => '', "type" => "select", 'filterable' => true, "options" => CurrencySettings::getFormattedCurrencies(), "value" => "USD" ], ] ], 'hr3' => [ 'type' => 'html', 'value' => '
' ], 'decimal_separator_grid' => [ 'type' => 'grid', 'columns' => [ 'default' => 1, 'md' => 3 ], 'disable_nesting' => true, 'schema' => [ 'label' => [ 'type' => 'html', 'value' => '' . __('Number Format', 'fluent-cart') . '
' . __("Select the character used to separate thousands or decimals in prices.", 'fluent-cart') . '
' ], 'decimal_separator' => [ 'wrapperClass' => 'col-span-2 flex items-start flex-col', "label" => '', "type" => "radio", "options" => [ [ "label" => __('Comma & Dot (eg 10,000.00)', 'fluent-cart'), "value" => 'dot' ], [ "label" => __('Dot & Comma (eg 10.000,00)', 'fluent-cart'), "value" => 'comma' ], ], "value" => "dot" ], ] ], 'hr4' => [ 'type' => 'html', 'value' => '
' ], 'currency_position_grid' => [ 'type' => 'grid', 'columns' => [ 'default' => 1, 'md' => 3 ], 'disable_nesting' => true, 'schema' => [ 'label' => [ 'type' => 'html', 'value' => '' . __('Currency Formatting', 'fluent-cart') . '
' . __("Select how the currency should be formatted.", 'fluent-cart') . '
' ], 'currency_position' => [ 'wrapperClass' => 'col-span-2 flex items-center', "label" => '', "type" => "select", "options" => [ [ "label" => __('Symbol before (eg: $100)', 'fluent-cart'), "value" => 'before', ], [ "label" => __('Symbol after (eg: 100$)', 'fluent-cart'), "value" => 'after', ], [ "label" => __('ISO before (eg: USD 100)', 'fluent-cart'), "value" => 'iso_before', ], [ "label" => __('ISO after (eg: 100 USD)', 'fluent-cart'), "value" => 'iso_after', ], [ "label" => __('Symbol & ISO (eg: $100 USD)', 'fluent-cart'), "value" => 'symbool_before_iso', ], [ "label" => __('ISO & Symbol (eg: USD 100$)', 'fluent-cart'), "value" => 'symbool_after_iso', ], [ "label" => __('ISO-Symbol (eg: USD $100)', 'fluent-cart'), "value" => 'symbool_and_iso', ], ], "value" => "before" ], ] ], 'hr5' => [ 'type' => 'html', 'value' => '
' ], 'checkout_style_grid' => [ 'type' => 'grid', 'columns' => [ 'default' => 1, 'md' => 3 ], 'disable_nesting' => true, 'schema' => [ 'label' => [ 'type' => 'html', 'value' => '' . __('Payment View', 'fluent-cart') . '
' . __("Select how payment options are visually presented on checkout.", 'fluent-cart') . '
' ], "checkout_method_style" => [ 'wrapperClass' => 'col-span-2 flex items-center', "type" => "component", 'component' => 'PaymentView', 'label' => false, "options" => [ [ "label" => '', "value" => 'logo', ], [ "label" => __('Label Selector', 'fluent-cart'), "value" => 'radio', ], ], "value" => "logo" ], ] ], // 'settings_hr_modal' => [ // 'type' => 'html', // 'value' => '
' // ], // // 'modal_checkout_grid' => [ // 'type' => 'grid', // 'columns' => [ // 'default' => 1, // 'md' => 3 // ], // 'disable_nesting' => true, // 'schema' => [ // 'label' => [ // 'type' => 'html', // 'value' => '' . __('Buy Now Button Behavior', 'fluent-cart') . ' //
' . __("Choose how the Buy Now button behaves. Modal checkout provides a seamless experience without leaving the product page.", 'fluent-cart') . '
' // ], // "enable_modal_checkout" => [ // 'wrapperClass' => 'col-span-2 flex items-center', // "label" => '', // "type" => "radio", // "options" => [ // [ // "label" => __('Redirect to Checkout Page', 'fluent-cart'), // "value" => 'no', // ], // [ // "label" => __('Open Checkout in Modal', 'fluent-cart'), // "value" => 'yes', // ], // ], // "value" => "no" // ], // ] // ], ], ], // 'button_setup' => [ // 'title' => __('Button Setup', 'fluent-cart'), // 'type' => 'tab-pane', // 'disable_nesting' => true, // 'schema' => [ // 'button_setup_settings' => [ // 'title' => __('Button Setup', 'fluent-cart'), // 'type' => 'section', // 'disable_nesting' => true, // 'columns' => [ // 'default' => 1, // 'md' => 2 // ], // 'schema' => [ // "checkout_button_text" => [ // "label" => __('Checkout Button Text', 'fluent-cart'), // "type" => "input", // "value" => __('Buy now', 'fluent-cart') // ], // "cart_button_text" => [ // "label" => __('Cart Button Text', 'fluent-cart'), // "type" => "input", // "value" => __('Add to cart', 'fluent-cart') // ], // // "popup_button_text" => [ // "label" => __('Popup Button Text', 'fluent-cart'), // "type" => "input", // "value" => __('View Product', 'fluent-cart') // ], // "out_of_stock_button_text" => [ // "label" => __('Out of Stock Button Text', 'fluent-cart'), // "type" => "input", // "value" => __('Out of stock', 'fluent-cart') // ], // "view_cart_button_text" => [ // "label" => __('View Cart Button Text', 'fluent-cart'), // "type" => "input", // "value" => __('View Cart', 'fluent-cart') // ], // // "note_for_user_account_creation" => [ // "label" => __('Note for User Account Creation,', 'fluent-cart'), // "type" => "input", // "value" => __('You have subscription product in your cart, an account will be created', 'fluent-cart') // ], // ], // ] // ] // ], 'pages_setup' => [ 'id' => '', 'title' => __('Pages Setup', 'fluent-cart'), 'show_title' => false, 'type' => 'section', 'disable_nesting' => true, 'columns' => [ 'default' => 1, 'md' => 1 ], 'schema' => [ 'shop_page_grid' => [ 'type' => 'grid', 'columns' => [ 'default' => 1, 'md' => 3, ], 'disable_nesting' => true, 'schema' => [ 'label' => [ 'type' => 'html', 'value' => '' . __('Select Shop Page', 'fluent-cart') . '
' . __("Select the page that showcases all of your products.", 'fluent-cart') . '
' ], 'shop_page_id' => [ 'wrapperClass' => 'col-span-2', 'page_title' => __('Shop', 'fluent-cart'), 'type' => 'component', 'component' => 'StoreSettings/PageSelector', 'page_key' => 'shop_page_id', 'preview_link' => $previewLinks['shop_page_id'], 'options' => $pages, 'hide_note' => true, 'value' => '', 'note' => \FluentCart\App\Helpers\Helper::getShortcodeInstructionString( '[fluent_cart_products]', __('Products', 'fluent-cart') ), ], ] ], 'hr1' => [ 'type' => 'html', 'value' => '
' ], 'customer_profile_grid' => [ 'type' => 'grid', 'columns' => [ 'default' => 1, 'md' => 3 ], 'disable_nesting' => true, 'schema' => [ 'label' => [ 'type' => 'html', 'value' => '' . __('Select Customer Profile Page', 'fluent-cart') . '
' . __("Select the page where customers will manage their profile, orders, and downloads.", 'fluent-cart') . '
' ], 'customer_profile_page_id' => [ 'wrapperClass' => 'col-span-2', 'label' => false, 'page_title' => __('Account', 'fluent-cart'), 'type' => 'component', 'component' => 'StoreSettings/PageSelector', 'page_key' => 'customer_profile_page_id', 'preview_link' => $previewLinks['customer_profile_page_id'], 'hide_note' => true, 'options' => $pages, 'value' => '', 'note' => \FluentCart\App\Helpers\Helper::getShortcodeInstructionString( '[fluent_cart_customer_profile]', __('Account', 'fluent-cart') ), ], ] ], 'hr2' => [ 'type' => 'html', 'value' => '
' ], 'cart_page_grid' => [ 'type' => 'grid', 'columns' => [ 'default' => 1, 'md' => 3 ], 'disable_nesting' => true, 'schema' => [ 'label' => [ 'type' => 'html', 'value' => '' . __('Select Cart Page', 'fluent-cart') . '
' . __("Select the page that will display customer's current shopping cart.", 'fluent-cart') . '
' ], 'cart_page_id' => [ 'wrapperClass' => 'col-span-2', 'label' => false, 'page_title' => __('Cart', 'fluent-cart'), 'type' => 'component', 'component' => 'StoreSettings/PageSelector', 'page_key' => 'cart_page_id', 'preview_link' => $previewLinks['cart_page_id'], 'hide_note' => true, 'options' => $pages, 'value' => '', 'note' => \FluentCart\App\Helpers\Helper::getShortcodeInstructionString( '[fluent_cart_cart]', __('Cart', 'fluent-cart') ), ], ] ], 'hr3' => [ 'type' => 'html', 'value' => '
' ], 'receipt_page_grid' => [ 'type' => 'grid', 'columns' => [ 'default' => 1, 'md' => 3 ], 'disable_nesting' => true, 'schema' => [ 'label' => [ 'type' => 'html', 'value' => '' . __('Select Receipt Page', 'fluent-cart') . '
' . __("Select the page that will display order summary after a successful purchase.", 'fluent-cart') . '
' ], 'receipt_page_id' => [ 'wrapperClass' => 'col-span-2', 'label' => false, 'page_title' => __('Receipt', 'fluent-cart'), 'type' => 'component', 'component' => 'StoreSettings/PageSelector', 'page_key' => 'receipt_page_id', 'preview_link' => $previewLinks['receipt_page_id'], 'hide_note' => true, 'options' => $pages, 'value' => '', 'note' => \FluentCart\App\Helpers\Helper::getShortcodeInstructionString( '[fluent_cart_receipt]', __('Receipt', 'fluent-cart') ), ], ] ], 'hr4' => [ 'type' => 'html', 'value' => '
' ], 'checkout_page_grid' => [ 'type' => 'grid', 'columns' => [ 'default' => 1, 'md' => 3 ], 'disable_nesting' => true, 'schema' => [ 'label' => [ 'type' => 'html', 'value' => '' . __('Select Checkout Page', 'fluent-cart') . '
' . __("Select the page where customers will finalize their purchase.", 'fluent-cart') . '
' ], 'checkout_page_id' => [ 'wrapperClass' => 'col-span-2', 'label' => false, 'page_title' => __('Checkout', 'fluent-cart'), 'type' => 'component', 'component' => 'StoreSettings/PageSelector', 'page_key' => 'checkout_page_id', 'preview_link' => $previewLinks['checkout_page_id'], 'hide_note' => true, 'options' => $pages, 'value' => '', 'note' => \FluentCart\App\Helpers\Helper::getShortcodeInstructionString( '[fluent_cart_checkout]', __('Checkout', 'fluent-cart') ), ], ] ] ] ], 'single_product_setup' => [ 'title' => __('Product Page', 'fluent-cart'), 'show_title' => false, 'type' => 'section', 'disable_nesting' => true, 'columns' => [ 'default' => 1, 'md' => 1 ], 'schema' => [ 'product_settings_grid' => [ 'type' => 'grid', 'columns' => [ 'default' => 1, 'md' => 3 ], 'disable_nesting' => true, 'schema' => [ 'label' => [ 'type' => 'html', 'value' => '' . __('Single Product Setup', 'fluent-cart') . '
' . __("Control the display of relevant information.", 'fluent-cart') . '
' ], 'fields' => [ 'type' => 'grid', 'columns' => [ 'default' => 1, 'md' => 1 ], 'disable_nesting' => true, 'schema' => [ "show_relevant_product_in_single_page" => [ "label" => __('Show Relevant In Single Page', 'fluent-cart'), "type" => "checkbox", "value" => "yes" ], "show_relevant_product_in_modal" => [ "label" => __('Show Relevant In Product Modal', 'fluent-cart'), "type" => "checkbox", "value" => "no" ], ] ] ] ], 'hr' => [ 'type' => 'html', 'value' => '
' ], 'image_zoom_grid' => [ 'type' => 'grid', 'columns' => [ 'default' => 1, 'md' => 3 ], 'disable_nesting' => true, 'schema' => [ 'label' => [ 'type' => 'html', 'value' => '' . __('Image Zooming', 'fluent-cart') . '
' . __("Enable Image zoom in single product.", 'fluent-cart') . '
' ], 'fields' => [ 'type' => 'grid', 'columns' => [ 'default' => 1, 'md' => 1 ], 'disable_nesting' => true, 'schema' => [ "enable_image_zoom_in_single_product" => [ "label" => __('Enable Zoom in Single Product', 'fluent-cart'), "type" => "checkbox", "value" => "no" ], "enable_image_zoom_in_modal" => [ "label" => __('Enable Zoom in Modal', 'fluent-cart'), "type" => "checkbox", "value" => "no" ], ] ] ] ], 'hr_image_zoom' => [ 'type' => 'html', 'value' => '
' ], 'variation_grid' => [ 'type' => 'grid', 'columns' => [ 'default' => 1, 'md' => 3 ], 'disable_nesting' => true, 'schema' => [ 'label' => [ 'type' => 'html', 'value' => '' . __('Variation View', 'fluent-cart') . '
' . __("Defines how product variations are visually presented to customers.", 'fluent-cart') . '
' ], "variation_view" => [ 'wrapperClass' => 'col-span-2 flex items-center', "label" => false, "type" => "select", "options" => [ [ "label" => __('Image', 'fluent-cart'), "value" => 'image', ], [ "label" => __('Text', 'fluent-cart'), "value" => 'text', ], [ "label" => __('Image with Text', 'fluent-cart'), "value" => 'both', ], ], "value" => "" ], ] ], 'hr2' => [ 'type' => 'html', 'value' => '
' ], 'variation_column_grid' => [ 'type' => 'grid', 'columns' => [ 'default' => 1, 'md' => 3 ], 'disable_nesting' => true, 'schema' => [ 'label' => [ 'type' => 'html', 'value' => '' . __('Variation Columns', 'fluent-cart') . '
' . __("Set the column layout for how product variations are displayed within product sections.", 'fluent-cart') . '
' ], "variation_columns" => [ 'wrapperClass' => 'col-span-2 flex items-center', "label" => false, "type" => "select", "options" => [ [ "label" => __('One Column', 'fluent-cart'), "value" => 'one', ], [ "label" => __('Two Columns', 'fluent-cart'), "value" => 'two', ], [ "label" => __('Three Columns', 'fluent-cart'), "value" => 'three', ], [ "label" => __('Four Columns', 'fluent-cart'), "value" => 'four', ], [ "label" => __('Masonry', 'fluent-cart'), "value" => 'masonry', ], ], "value" => "" ], ] ], 'hr3' => [ 'type' => 'html', 'value' => '
' ], 'product_slug_grid' => [ 'type' => 'grid', 'columns' => [ 'default' => 1, 'md' => 3 ], 'disable_nesting' => true, 'schema' => [ 'label' => [ 'type' => 'html', 'value' => '' . __('Product Slug', 'fluent-cart') . '
' . __("Set Product Slug.", 'fluent-cart') . '
' ], "product_slug" => [ 'wrapperClass' => 'col-span-2 flex items-center', "label" => false, "type" => "input", "value" => "" ], ] ], ], ], 'cart_and_checkout' => [ 'title' => __('Cart & checkout', 'fluent-cart'), 'show_title' => false, 'type' => 'section', 'disable_nesting' => true, 'columns' => [ 'default' => 1, 'md' => 1 ], 'schema' => [ "show_cart_icon_in_body" => [ "label" => __('Cart Icon In Body', 'fluent-cart'), "type" => "checkbox", "value" => "yes", 'note' => sprintf( /* translators: %1$s: Display instruction text, %2$s: "Use this" text, %3$s: Copy to clipboard tooltip, %4$s: CSS class name, %5$s: CSS class description text */ "

%1\$s

%2\$s %4\$s %5\$s

", __('Display the cart icon in the body of the website', 'fluent-cart'), __('Use this', 'fluent-cart'), __('Copy to clipboard', 'fluent-cart'), 'fcart-cart-toggle-button', __('CSS class to display the cart link/icon anywhere else.', 'fluent-cart') ) ], 'hr2' => [ 'type' => 'html', 'value' => '
' ], "require_logged_in" => [ "label" => __('Require user to be logged in for checkout (Coming soon)', 'fluent-cart'), "type" => "checkbox", "value" => "no", 'note' => "
" . __('Enforce that customers must be logged into their account to complete a purchase.', 'fluent-cart') . "
", 'wrapperClass' => 'disabled' ], 'hr3' => [ 'type' => 'html', 'value' => '
' ], 'user_account_creation_mode_grid' => [ 'type' => 'grid', 'columns' => [ 'default' => 1, 'md' => 3 ], 'disable_nesting' => true, 'schema' => [ 'label' => [ 'type' => 'html', 'value' => '' . __('User Account Creation Mode', 'fluent-cart') . '
' . __("User account will be created regardless of the mode if the order has a subscription.", 'fluent-cart') . '
' ], 'user_account_input_grid' => [ 'type' => 'grid', 'disable_nesting' => true, 'class' => 'col-span-2', 'schema' => [ 'user_account_creation_mode' => [ 'wrapperClass' => 'col-span-2 flex items-center', "label" => '', "type" => "radio", "options" => [ [ "label" => __('Create User Account Automatically after payment ', 'fluent-cart'), "value" => 'all', 'note' => "
" . __('User account will be created automatically after payment.', 'fluent-cart') . "
", 'option_class' => 'mb-2.5' ], [ "label" => __('Give checkbox to create account on checkout page', 'fluent-cart'), "value" => 'user_choice', 'note' => "
" . __('User will have an option to create an account during checkout.', 'fluent-cart') . "
", 'option_class' => 'mb-2.5' ], [ "label" => __('No need to create account for onetime purchases', 'fluent-cart'), "value" => 'only_subscription', 'note' => "
" . __('User account will not be created for onetime purchases.', 'fluent-cart') . "
", ], ], "value" => "all" ], ] ], ] ], // "allow_checkout_signup" => [ // "label" => __('Allow customers to create account during one-time checkout', 'fluent-cart'), // "type" => "checkbox", // "value" => "no", // 'note' => "
" . __('Provide an option for customers to create a user account during a single, non-recurring checkout process.', 'fluent-cart') . "
" // ], // "force_ssl" => [ // "label" => __('Force page to SSL (https)', 'fluent-cart'), // "type" => "checkbox", // "value" => "no" // ], 'hr5' => [ 'type' => 'html', 'value' => '
' ], "hide_coupon_field" => [ "label" => __('Hide coupon field on checkout', 'fluent-cart'), "type" => "checkbox", "value" => "no", 'note' => "
" . __('Hide the coupon code input field on the checkout page.', 'fluent-cart') . "
" ], 'hr6' => [ 'type' => 'html', 'value' => '
' ], 'order_invoice_grid' => [ 'type' => 'grid', 'columns' => [ 'default' => 1, 'md' => 3 ], 'disable_nesting' => true, 'schema' => [ 'label' => [ 'type' => 'html', 'value' => '' . __('Receipt Settings', 'fluent-cart') . '
' . __("Setup your receipt.", 'fluent-cart') . '
' ], 'invoice_input_grid' => [ 'type' => 'grid', 'disable_nesting' => true, 'class' => 'col-span-2', 'schema' => [ "min_receipt_number" => [ 'wrapperClass' => 'col-span-2 flex flex-col', "label" => __('Minimum Receipt Number', 'fluent-cart'), "type" => "input", "value" => "", 'note' => sprintf( "
%s
", sprintf( /* translators: %s is the next receipt number */ __('Next Receipt Number: %s', 'fluent-cart'), OrderService::getNextReceiptNumber() ) ), ], "inv_prefix" => [ 'wrapperClass' => 'col-span-2 flex flex-col', "label" => __('Receipt Prefix', 'fluent-cart'), "type" => "input", "value" => "", ], ] ], ] ], ] ], 'subscriptions_setup' => [ 'title' => __('Subscriptions', 'fluent-cart'), 'show_title' => false, 'type' => 'section', 'disable_nesting' => true, 'columns' => [ 'default' => 1, 'md' => 1 ], 'schema' => [ 'subscription_early_payment_grid' => [ 'type' => 'grid', 'wrapperClass' => 'items-start mb-6', 'columns' => [ 'default' => 1, 'md' => 3 ], 'disable_nesting' => true, 'schema' => [ 'label' => [ 'type' => 'html', 'value' => '' . __('Early Payment', 'fluent-cart') . (!$isProActive ? ' ' . esc_attr__('Pro feature', 'fluent-cart') . '' : '') . '
' . __('Let customers pay remaining installments before their due date.', 'fluent-cart') . '
' ], 'fields' => [ 'type' => 'grid', 'columns' => [ 'default' => 1, 'md' => 1 ], 'disable_nesting' => true, 'class' => 'col-span-2', 'schema' => [ 'enable_early_payment_for_installment' => [ 'label' => __('Enable early payment for installment', 'fluent-cart'), 'type' => 'checkbox', 'value' => 'yes', 'disabled' => !$isProActive, 'wrapperClass' => !$isProActive ? 'disabled' : '', 'note' => !$isProActive ? "
" . __('This is a FluentCart Pro feature.', 'fluent-cart') . "
" : "
" . __('Allow customers to pay remaining installments early from subscription screens.', 'fluent-cart') . "
" ] ] ] ] ], 'subscription_management_mode_grid' => [ 'type' => 'grid', 'wrapperClass' => 'items-start', 'columns' => [ 'default' => 1, 'md' => 3 ], 'disable_nesting' => true, 'schema' => [ 'label' => [ 'type' => 'html', 'value' => sprintf( /* translators: 1: setting label, 2: setting description */ '%1$s
%2$s
', __('Renewal Billing', 'fluent-cart'), __('Choose how recurring subscription payments are collected.', 'fluent-cart') ) ], 'fields' => [ 'type' => 'grid', 'columns' => [ 'default' => 1, 'md' => 1 ], 'disable_nesting' => true, 'class' => 'col-span-2', 'schema' => [ // Compact, guarded control: shows only the CURRENT mode with a // short how-it-works summary and a Change button. Editing goes // through a disclaimer confirm + dialog so the store-wide // billing decision can never be flipped by a stray click. 'subscription_management_mode' => [ 'label' => false, 'component' => 'StoreSettings/SubscriptionModeManager', 'disable_nesting' => true, 'value' => 'gateway_managed', // Read-only renewal-order schedule, built live from the // same map the scheduler uses (filterable). 'schedule_items' => $invoiceScheduleList, // Which gateways auto-charge is actually possible on. 'system_charge_gateways' => $systemChargeGateways, ], // Keep these in the form payload — the component above writes // them; without a schema entry the keys would drop out of the // saved values. 'subscription_system_charge' => [ 'type' => 'hidden', 'value' => 'no', ], 'subscription_manual_fallback' => [ 'type' => 'hidden', 'value' => 'no', ], ] ] ] ], 'subscription_mode_guard_grid' => [ 'type' => 'grid', 'wrapperClass' => 'items-start mt-6', 'columns' => [ 'default' => 1, 'md' => 3 ], 'disable_nesting' => true, 'schema' => [ 'label' => [ 'type' => 'html', 'value' => sprintf( /* translators: 1: setting label, 2: setting description */ '%1$s
%2$s
', __('Staging Protection', 'fluent-cart'), __('Prevent staging or test copies of your store from billing real customers.', 'fluent-cart') ) ], 'fields' => [ 'type' => 'grid', 'columns' => [ 'default' => 1, 'md' => 1 ], 'disable_nesting' => true, 'class' => 'col-span-2', 'schema' => [ 'subscription_mode_guard' => [ 'label' => __('Don\'t bill live subscriptions from this site while it is in test mode', 'fluent-cart'), 'type' => 'checkbox', 'value' => 'yes', 'note' => sprintf( /* translators: 1: the setting's explanatory note text */ "
%1\$s
", __('In test mode, this site won\'t invoice, charge, or email live subscriptions — so a staging copy can never double-bill customers. Billing from this site resumes when it is live again.', 'fluent-cart') ) ], ] ] ] ], ] ], ] ], ]; // Only show weight/dimension unit fields to users with shipping-sensitive permission if (PermissionManager::hasPermission(['store/sensitive'])) { $storeSchema = &$fields['setting_tabs']['schema']['store_setup']['schema']; $storeSchema['weight_unit_grid'] = [ 'type' => 'grid', 'columns' => ['default' => 1, 'md' => 3], 'disable_nesting' => true, 'schema' => [ 'label' => [ 'type' => 'html', 'value' => '' . __('Weight Unit', 'fluent-cart') . '
' . __('Unit used for product weight measurements.', 'fluent-cart') . '
' ], 'weight_unit' => [ 'wrapperClass' => 'col-span-2 flex items-center', 'label' => '', 'type' => 'select', 'options' => [ ['label' => __('kg', 'fluent-cart'), 'value' => 'kg'], ['label' => __('g', 'fluent-cart'), 'value' => 'g'], ['label' => __('lbs', 'fluent-cart'), 'value' => 'lbs'], ['label' => __('oz', 'fluent-cart'), 'value' => 'oz'], ], 'value' => 'kg' ], ] ]; $storeSchema['dimension_unit_grid'] = [ 'type' => 'grid', 'columns' => ['default' => 1, 'md' => 3], 'disable_nesting' => true, 'schema' => [ 'label' => [ 'type' => 'html', 'value' => '' . __('Dimension Unit', 'fluent-cart') . '
' . __('Unit used for product dimension measurements.', 'fluent-cart') . '
' ], 'dimension_unit' => [ 'wrapperClass' => 'col-span-2 flex items-center', 'label' => '', 'type' => 'select', 'options' => [ ['label' => __('cm', 'fluent-cart'), 'value' => 'cm'], ['label' => __('mm', 'fluent-cart'), 'value' => 'mm'], ['label' => __('in', 'fluent-cart'), 'value' => 'in'], ['label' => __('m', 'fluent-cart'), 'value' => 'm'], ], 'value' => 'cm' ], ] ]; } return apply_filters("fluent_cart/store_settings/fields", $fields, []); } public function isModuleTabEnabled(): bool { $fields = $this->fields(); return isset($fields['setting_tabs']['schema']['modules_tab']); } /** * @param string|null $key like stripe or paypal * All store settings if key is not provided * @return mixed * */ public function get($key = null, $default = null) { if (empty($key)) { return $this->storeSettings; } if (is_array($key)) { $data = Arr::only($this->storeSettings, $key); } else { $data = Arr::get($this->storeSettings, $key); } return empty($data) ? $default : $data; } public function moduleSettings(): array { $settings = $this->get('modules_settings', []); return Arr::wrap($settings); } /** * @param array $settings like Stripe or PayPal settings array * Save store settings * @return array * */ public function save(array $settings) { $prevSettings = get_option($this->optionKey, []); $prevSettings = wp_parse_args($prevSettings, $this->getDefaultSettings()); $settings = wp_parse_args($settings, $prevSettings); $customerProfilePageId = Arr::get($settings, 'customer_profile_page_id', 0); if ($customerProfilePageId) { $settings['customer_profile_page_slug'] = $this->getCustomerDashboardPageSlug($customerProfilePageId, false); } update_option($this->optionKey, $settings, true); $this->storeSettings = $settings; self::$cachedStoreSettings = $this->storeSettings; wp_cache_delete(self::CACHE_KEY, self::CACHE_GROUP); $isSlugChanged = Arr::get($prevSettings, 'product_slug') !== Arr::get($settings, 'product_slug'); $isAccountPageChanged = Arr::get($prevSettings, 'customer_profile_page_slug') !== Arr::get($settings, 'customer_profile_page_slug'); if ($isSlugChanged || $isAccountPageChanged) { flush_rewrite_rules(); delete_option('rewrite_rules'); } return $this->storeSettings; } public function set(string $key, $value) { return $this->save([ $key => $value ]); } public function getCurrency() { return $this->get('currency', 'USD'); } public function getCurrencySymbol() { $currency = $this->getCurrency(); return CurrenciesHelper::getCurrencySign($currency); } public function isCheckoutPage(): bool { global $post; $pageId = $this->getCheckoutPageId(); return intval($pageId) === intval($post->ID); } public function getCheckoutPageId() { return Arr::get($this->storeSettings, 'checkout_page_id'); } public function getPagesSettings(): array { return Arr::only( $this->storeSettings, [ 'checkout_page_id', 'custom_payment_page_id', 'registration_page_id', 'login_page_id', 'cart_page_id', 'receipt_page_id', 'shop_page_id', 'customer_profile_page_id', 'customer_profile_page_slug', ] ); } public function getCheckoutPage(): string { if ($pageID = $this->getCheckoutPageId()) { return $this->getPageLink($pageID); } return ''; } public function getCustomerProfilePageId() { return Arr::get($this->storeSettings, 'customer_profile_page_id'); } public function getCustomerProfilePage(): string { if ($pageId = $this->getCustomerProfilePageId()) { return $this->getPageLink($pageId); } return ''; } public function getCartPageId() { return Arr::get($this->storeSettings, 'cart_page_id'); } public function getCartPage(): string { if ($pageId = $this->getCartPageId()) { if (Pages::isPage($pageId)) { return $this->getPageLink($pageId); } } return ''; } public function getShopPageId() { return Arr::get($this->storeSettings, 'shop_page_id'); } public function getShopPage(): string { if ($pageId = $this->getShopPageId()) { if (Pages::isPage($pageId)) { return $this->getPageLink($pageId); } } return ''; } public function getReceiptPageId() { return Arr::get($this->storeSettings, 'receipt_page_id'); } public function getReceiptPage(): string { if ($pageId = $this->getReceiptPageId()) { if (Pages::isPage($pageId)) { return $this->getPageLink($pageId); } } return home_url(); } public function getBuyButtonText(): string { return esc_html(Arr::get($this->storeSettings, 'checkout_button_text', __('Buy now', 'fluent-cart'))); } public function getViewCartButtonText(): string { return esc_html(Arr::get($this->storeSettings, 'view_cart_button_text', __('View Cart', 'fluent-cart'))); } /** * @return string * * Get cart button text */ public function getCartButtonText(): string { return esc_html(Arr::get($this->storeSettings, 'cart_button_text', __('Add To Cart', 'fluent-cart'))); } public function toArray(): array { return $this->storeSettings; } /** * @return string * * Get the base address1 for the store. */ public function getBaseAddressLine1() { return Arr::get($this->storeSettings, 'store_address1'); } public function getFormattedFullAddress() { $addressParts = [ trim(Arr::get($this->storeSettings, 'store_address1') ?? ''), trim(Arr::get($this->storeSettings, 'store_address2') ?? ''), trim(Arr::get($this->storeSettings, 'store_city') ?? ''), trim(AddressHelper::getStateNameByCode( Arr::get($this->storeSettings, 'store_state'), Arr::get($this->storeSettings, 'store_country') )), trim(Arr::get($this->storeSettings, 'store_postcode') ?? ''), trim(AddressHelper::getCountryNameByCode(Arr::get($this->storeSettings, 'store_country'))) ]; // Filter out empty or null parts $addressParts = array_filter($addressParts, function ($part) { return $part !== ''; }); // Join parts with comma and space $addressString = implode(', ', $addressParts); return $addressString; } /** * @return string * * Get the base address2 for the store. */ public function getBaseAddressLine2() { return Arr::get($this->storeSettings, 'store_address2'); } /** * @return string * * Get the base country for the store. */ public function getBaseCountry() { return Arr::get($this->storeSettings, 'store_country'); } /** * @return string * * Get the base state for the store. */ public function getBaseState() { return Arr::get($this->storeSettings, 'store_state'); } /** * @return string * * Get the base city for the store. */ public function getBaseCity() { return Arr::get($this->storeSettings, 'store_city'); } /** * @return string * * Get the base postcode for the store. */ public function getBasePostcode() { return Arr::get($this->storeSettings, 'store_postcode'); } public function getInvoicePrefix() { // @todo: make this dynamic from settings return $this->get('inv_prefix', ''); } public function getInvoiceSuffix(): string { return ''; } public function getCustomerDashboardPageSlug($pageId = null, $cached = true) { $slug = Arr::get($this->storeSettings, 'customer_profile_page_slug', ''); if ($cached && $slug) { return $slug; } if (!$pageId) { $pageId = Arr::get($this->storeSettings, 'customer_profile_page_id'); } if (!$pageId || !get_post($pageId)) { return $slug; } $url = get_page_link($pageId); $url = rtrim($url, '/'); if (!$url) { return $slug; } return trim(str_replace(home_url('/'), '', $url), '/'); } /** * Get theme colors as CSS variable string. * * @return string */ public function getThemeColors(): string { $themeSetup = $this->get('theme_setup'); $colors = ''; if (!empty($themeSetup) && is_array($themeSetup)) { foreach ($themeSetup as $key => $value) { if (!empty($value)) { $safeKey = preg_replace('/[^a-zA-Z0-9\-_]/', '', $key); $safeValue = preg_replace('/[;\{\}]/', '', $value); $colors .= "$safeKey: $safeValue;"; } } } return $colors; } public function getPageLink($pageId = null): string { if (!$pageId || !get_post($pageId)) { return ''; } $link = get_page_link($pageId); if (!empty($link)) { return Str::endsWith($link, '/') ? $link : $link . '/'; } return ''; } }