post_type != 'page') { return $states; } $targetKeys = [ 'checkout_page_id' => __('Checkout Page', 'fluent-cart'), 'cart_page_id' => __('Cart Page', 'fluent-cart'), 'receipt_page_id' => __('Receipt Page', 'fluent-cart'), 'shop_page_id' => __('Shop Page', 'fluent-cart'), 'customer_profile_page_id' => __('Customer Profile Page', 'fluent-cart'), ]; $pagesConfig = (new StoreSettings())->getPagesSettings(); $pagesConfig = Arr::only($pagesConfig, array_keys($targetKeys)); if (!is_array($pagesConfig)) { return $states; } $pagesConfig = array_filter($pagesConfig); if (empty($pagesConfig)) { return $states; } $pagesConfig = array_flip($pagesConfig); $targetKey = Arr::get($pagesConfig, $post->ID); if ($targetKey && isset($targetKeys[$targetKey])) { $logo = ''; $states['fluent_cart'] = '' . $logo . '' . $targetKeys[$targetKey] . ''; } return $states; } public function outputFluentCartDarkModeScript() { global $pagenow; $page = $_GET['page'] ?? ''; $postType = $_GET['post_type'] ?? ''; // post.php?post=ID&action=edit omits post_type; resolve it from the post ID. if ($pagenow === 'post.php' && empty($postType)) { $postId = (int) App::request()->get('post', 0); $postType = $postId ? (string) get_post_type($postId) : ''; } $isFluentCartPage = $page === 'fluent-cart'; $isTaxonomyList = $pagenow === 'edit-tags.php' && $postType === FluentProducts::CPT_NAME; $isTermEditPage = $pagenow === 'term.php' && $postType === FluentProducts::CPT_NAME; $isProductEditPage = ($pagenow === 'post.php' || $pagenow === 'edit.php') && $postType === FluentProducts::CPT_NAME; if (!$isFluentCartPage && !$isTaxonomyList && !$isTermEditPage && !$isProductEditPage) { return; } // Runs synchronously in
before any paint — applies the dark class and // data-fct-theme attribute to so logos and the theme icon render correctly // from the very first frame, with no light-to-dark flash. echo ''; } public function enqueueDarkModeToggleForTaxonomy() { global $pagenow; $postType = $_GET['post_type'] ?? ''; $isTaxonomyList = $pagenow === 'edit-tags.php' && $postType === FluentProducts::CPT_NAME; $isTermEditPage = $pagenow === 'term.php' && $postType === FluentProducts::CPT_NAME; if ($isTaxonomyList || $isTermEditPage) { Vite::enqueueScript( 'fluent_cart_dark_mode_toggle', 'admin/dark-mode-toggle.js', [], FLUENTCART_VERSION, true ); } } private function getDarkModeInitScript(): string { return "(function(){" . "var k='fluent_theme_mode',c='fluent_theme_dark'," . "s=localStorage.getItem(k)||localStorage.getItem('fcart_admin_theme')," . "t=s==='dark'?'dark':s==='light'?'light':'system'," . "d=s==='dark'||s==='system:dark'||((!s||s==='system')&&window.matchMedia&&window.matchMedia('(prefers-color-scheme: dark)').matches);" . "document.documentElement.setAttribute('data-fct-theme',t);" . "if(d)document.documentElement.classList.add(c);" . "})();"; } public function init() { add_action('admin_menu', array($this, 'addAdminMenu')); /* * Disable Gutenberg for Products */ add_filter('parent_file', function ($parent_file) { global $submenu_file, $current_screen, $pagenow; $postType = $_GET['post_type'] ?? ''; if ($postType == FluentProducts::CPT_NAME && $current_screen->post_type == FluentProducts::CPT_NAME) { if ($pagenow == 'post.php') { $submenu_file = 'edit.php?post_type=' . $current_screen->post_type; } if ($pagenow == 'edit-tags.php') { $taxonomy = $_GET['taxonomy'] ?? ''; $submenu_file = 'edit-tags.php?taxonomy=' . esc_attr($taxonomy) . '&post_type=' . $current_screen->post_type; } $parent_file = 'fluent-cart'; } return $parent_file; }); add_action('fluent_cart/admin_menu', array($this, 'renderAdminMenu')); // add_action('in_admin_header', array($this, 'maybeRenderAdminMenu')); add_action('edit_form_top', array($this, 'pushProductNav')); add_action('admin_bar_menu', [$this, 'globalEnqueueAssets'], 10, 1); } public function addAdminMenu() { $capability = 'manage_options'; if (!current_user_can('manage_options') && App::isProActive()) { $capability = PermissionManager::ADMIN_CAP; } if (!current_user_can($capability)) { return; } global $submenu; $adminMenuTitle = apply_filters('fluent_cart/admin_menu_title', 'FluentCart', []); add_menu_page( $adminMenuTitle, $adminMenuTitle, $capability, 'fluent-cart', [$this, 'renderAdmin'], $this->getMenuIcon(), apply_filters('fluent_cart/admin_menu_position', 3) ); $submenu['fluent-cart']['dashboard'] = array( __('Dashboard', 'fluent-cart'), $capability, 'admin.php?page=fluent-cart#/', '', 'fluent_cart_dashboard' ); if (PermissionManager::hasPermission(['orders/view'])) { $submenu['fluent-cart']['orders'] = array( __('Orders', 'fluent-cart'), $capability, 'admin.php?page=fluent-cart#/orders', '', 'fluent_cart_orders' ); } if (PermissionManager::hasPermission(['customers/view', 'customers/manage'])) { $submenu['fluent-cart']['customers'] = array( __('Customers', 'fluent-cart'), $capability, 'admin.php?page=fluent-cart#/customers', '', 'fluent_cart_customers' ); } if (PermissionManager::hasPermission(['products/view'])) { $submenu['fluent-cart']['products'] = array( __('Products', 'fluent-cart'), $capability, 'admin.php?page=fluent-cart#/products', '', 'fluent_cart_products' ); } if (PermissionManager::hasPermission(['subscriptions/view'])) { $submenu['fluent-cart']['subscriptions'] = array( __('Subscriptions', 'fluent-cart'), $capability, 'admin.php?page=fluent-cart#/subscriptions', '', 'fluent_cart_subscriptions' ); } if (PermissionManager::hasPermission(['reports/view'])) { $submenu['fluent-cart']['reports'] = array( __('Reports', 'fluent-cart'), $capability, 'admin.php?page=fluent-cart#/reports/overview', '', 'fluent_cart_reports' ); } if (PermissionManager::userCan('is_super_admin')) { $submenu['fluent-cart']['integrations'] = array( __('Integrations', 'fluent-cart'), $capability, 'admin.php?page=fluent-cart#/integrations', '', 'fluent_cart_integrations' ); } $hasSensitiveAccess = PermissionManager::hasPermission(['store/settings', 'store/sensitive']); if ($hasSensitiveAccess) { $submenu['fluent-cart']['settings'] = array( __('Settings', 'fluent-cart'), $capability, 'admin.php?page=fluent-cart#/settings/store-settings/', '', 'fluent_cart_settings' ); } if (PermissionManager::hasPermission(['coupons/manage', 'coupons/view'])) { $submenu['fluent-cart']['coupons'] = array( __('Coupons', 'fluent-cart'), $capability, 'admin.php?page=fluent-cart#/coupons', '', 'fluent_cart_coupons' ); } if ($hasSensitiveAccess && TaxModule::isTaxEnabled()) { $submenu['fluent-cart']['taxes'] = array( __('Taxes', 'fluent-cart'), $capability, 'admin.php?page=fluent-cart#/taxes', '', 'fluent_cart_taxes' ); } if (PermissionManager::hasPermission(['products/create', 'products/edit'])) { $taxonomies = get_taxonomies([ 'object_type' => [FluentProducts::CPT_NAME], 'public' => true, ], 'object'); foreach ($taxonomies as $key => $taxonomy) { $menuUrl = 'edit-tags.php?taxonomy=' . $taxonomy->name . '&post_type=' . FluentProducts::CPT_NAME; $submenu['fluent-cart'][$key] = [ $taxonomy->label, $capability, $menuUrl, '', $taxonomy->name ]; } } if (PermissionManager::userCan('is_super_admin')) { $submenu['fluent-cart']['logs'] = array( __('Logs', 'fluent-cart'), $capability, 'admin.php?page=fluent-cart#/logs', '', 'fluent_cart_logs' ); } do_action('fluent_cart/admin_submenu_added', $submenu); } public function renderAdmin() { $isCustomDashboardSlugChanged = (new StoreSettings())->getCustomerDashboardPageSlug() != (new StoreSettings())->get('customer_profile_page_slug'); if ($isCustomDashboardSlugChanged) { $allSettings = (new StoreSettings())->get(); (new StoreSettings())->save($allSettings); // we are just resaving to flash the settings cache } if (function_exists('wp_enqueue_editor')) { wp_enqueue_editor(); wp_tinymce_inline_scripts(); wp_enqueue_media(); } $this->enqueueAssets(); $config = App::getInstance('config'); $name = $config->get('app.name'); $slug = $config->get('app.slug'); $baseUrl = apply_filters('fluent_connector_base_url', admin_url('admin.php?page=newproject#/')); $app = App::getInstance(); $assets = $app['url.assets']; App::make('view')->render('admin.admin_app', [ 'name' => $name, 'slug' => $slug, 'baseUrl' => $baseUrl, 'logo' => $assets . 'images/logo.svg', ]); } public function maybeRenderAdminMenu() { $postType = $_GET['post_type'] ?? ''; if ($postType == FluentProducts::CPT_NAME && is_admin()) { AdminHelper::getAdminMenu(true); AdminHelper::pushGlobalAdminAssets(); } } public function renderAdminMenu() { if (!apply_filters('fluent_cart/show_admin_top_bar', true)) { return; } AdminHelper::getAdminMenu(true); } public function pushProductNav($post) { if (!$post || $post->post_type != FluentProducts::CPT_NAME) { return; } AdminHelper::getProductMenu($post->ID, true, 'product_edit'); AdminHelper::pushGlobalAdminAssets(); } public function enqueueAssets() { $app = App::getInstance(); $slug = $app->config->get('app.slug'); do_action('fluent_cart/loading_app', $app); //This should be done before enqueueing the global script. Vite::enqueueScript($slug . '_admin_app_start', 'admin/bootstrap/app.js', [$slug . '_global_admin_hooks']); //Don't register this script using vite. if (!wp_script_is('wp-hooks', 'registered')) { $suffix = (defined('SCRIPT_DEBUG') && SCRIPT_DEBUG) ? '' : '.min'; wp_register_script('wp-hooks', includes_url('js/dist/hooks' . $suffix . '.js'), ['wp-polyfill'], FLUENTCART_VERSION, true); } if (!wp_script_is('wp-hooks', 'enqueued')) { wp_enqueue_script('wp-hooks'); } wp_enqueue_script($slug . '_global_admin_hooks', Vite::getEnqueuePath('admin/admin_hooks.js'), ['wp-hooks'], FLUENTCART_VERSION, true); $manager = GatewayManager::getInstance(); $payment_routes = $manager->getRoutes(); // $payment_routes = apply_filters('fluent_cart/payments/payment_method_settings_routes', []); $storage_driver_routes = apply_filters('fluent_cart/storage/storage_driver_settings_routes', [], []); $settings = new StoreSettings(); $checkoutUrl = add_query_arg(Helper::INSTANT_CHECKOUT_URL_PARAM, '=', $settings->getCheckoutPage()); $restVars = Helper::getRestInfo(); $hasDataMigrations = current_user_can('manage_options') && DataBackfills::hasPending(); $filterOptions = [ 'order_filter_options' => OrderFilter::getTableFilterOptions(), 'customer_filter_options' => CustomerFilter::getTableFilterOptions(), 'product_filter_options' => ProductFilter::getTableFilterOptions(), 'license_filter_options' => LicenseFilter::getTableFilterOptions(), 'license_site_filter_options' => LicenseSiteFilter::getTableFilterOptions(), 'tax_filter_options' => TaxFilter::getTableFilterOptions(), ]; $filterOptions = apply_filters('fluent_cart/admin_filter_options', $filterOptions, []); // Structured table config keyed by table name (used by Table.js base class) $tableConfig = [ 'order_table' => ['filters' => Arr::get($filterOptions, 'order_filter_options', [])], 'customers' => ['filters' => Arr::get($filterOptions, 'customer_filter_options', [])], 'product_table' => ['filters' => Arr::get($filterOptions, 'product_filter_options', [])], 'licenses' => ['filters' => Arr::get($filterOptions, 'license_filter_options', [])], 'license_sites' => ['filters' => Arr::get($filterOptions, 'license_site_filter_options', [])], 'taxes_table' => ['filters' => Arr::get($filterOptions, 'tax_filter_options', [])], 'subscriptions' => ['filters' => Arr::get($filterOptions, 'subscription_filter_options', [])], 'shipping_zone_table' => ['filters' => Arr::get($filterOptions, 'shipping_zone_filter_options', [])], ]; $tableConfig = apply_filters('fluent_cart/admin_table_saved_views', $tableConfig, [ 'filterOptions' => $filterOptions ]); $currentUser = get_user_by('ID', get_current_user_id()); // Get app config and merge additional properties into it $appConfig = $app->config->get('app'); $appConfig['version'] = FLUENTCART_VERSION; $appConfig['permissions'] = PermissionManager::getUserPermissions(); $appConfig['isProActive'] = App::isProActive(); $appConfig['proVersion'] = defined('FLUENTCART_PRO_PLUGIN_VERSION') ? FLUENTCART_PRO_PLUGIN_VERSION : null; $appConfig['logos'] = [ 'dark' => Vite::getAssetUrl('images/logo/logo-full-dark.svg'), 'light' => Vite::getAssetUrl('images/logo/logo-full.svg'), ]; $appConfig['isModuleTabEnabled'] = $settings->isModuleTabEnabled(); $appConfig['upgrade_url'] = Helper::getUpgradeUrl(); $max_upload_size = wp_max_upload_size(); // Returns size in bytes $adminLocalizeData = apply_filters('fluent_cart/admin_app_data', [ 'app_config' => $appConfig, 'slug' => $app->config->get('app.slug'), 'admin_url' => admin_url('admin.php?page=fluent-cart#/'), 'wp_admin_url' => rtrim(admin_url(), '/'), 'frontend_url' => URL::getFrontEndUrl(''), 'nonce' => wp_create_nonce($slug), 'rest' => $restVars, 'brand_logo' => $this->getMenuIcon(), 'asset_url' => Vite::getAssetUrl(), 'me' => [ 'id' => $currentUser->ID, 'full_name' => trim($currentUser->display_name), 'email' => $currentUser->user_email, 'avatar' => get_avatar_url($currentUser->ID) ], 'shop' => Helper::shopConfig(), 'product_statuses' => Status::getProductStatuses(), 'total_products_count' => Product::query()->count(), 'payment_statuses' => Status::getEditableTransactionStatuses(true), 'payment_routes' => $payment_routes, 'storage_driver_routes' => $storage_driver_routes, 'editable_payment_statuses' => Status::getEditableTransactionStatuses(true), 'order_statuses' => Status::getOrderStatuses(), 'editable_order_statuses' => Status::getEditableOrderStatuses(), 'editable_customer_statuses' => Status::getEditableCustomerStatuses(), // Backward compat: keep the old typo'd keys for existing frontend code 'order_statues' => Status::getOrderStatuses(), 'editable_order_statues' => Status::getEditableOrderStatuses(), 'editable_customer_statues' => Status::getEditableCustomerStatuses(), 'shipping_statuses' => Status::getShippingStatuses(), // Attribute library powering the Advanced Variation feature. 'variation_attributes' => AttributeGroup::with(['terms'])->get(), 'variation_terms' => AttributeTerm::query()->get()->keyBy('id'), 'product_image_base_uri' => Helper::getProductImageBaseUri(), 'add_on_modules' => AddOnModule::showAddOns(), 'stock_statuses' => Status::getStockStatuses(), 'fulfillment_types' => Helper::getFulfilmentTypes(), 'variation_types' => Helper::getVariationTypes(), 'trans' => TransStrings::getStrings(), 'dashboard_url' => admin_url('admin.php?page=fluent-cart#'), 'checkout_url' => $checkoutUrl, 'dummy_product_info' => apply_filters('fluent_cart/dummy_product_info', []) ?: [], 'currency_signs' => CurrenciesHelper::getCurrencySigns(), 'filter_options' => $filterOptions, 'table_config' => $tableConfig, 'receipt_page_url' => $settings->getReceiptPage(), 'payment_logos' => PaymentMethods::getIcons(), 'is_admin_bar_showing' => is_admin_bar_showing(), 'max_upload_size' => size_format($max_upload_size), 'available_shipping_method_count' => ShippingMethod::query()->where('is_enabled', '1')->count(), 'is_tax_enabled' => TaxModule::isTaxEnabled(), 'eu_vat_county_options' => TaxModule::euVatCountyOptions(), 'country_tax_titles' => TaxModule::taxTitleLists(), 'site_url' => site_url(), 'modules_settings' => ModuleSettings::getAllSettings(), 'purchase_fluent_cart_link' => 'https://fluentcart.com/', 'admin_notices' => apply_filters('fluent_cart/admin_notices', []), // POSTs data-backfills/run until done; endpoint requires manage_options 'has_data_migrations' => $hasDataMigrations, 'subscription_intervals' => Helper::getAvailableSubscriptionIntervalOptions(), 'datei18' => TransStrings::dateTimeStrings(), 'el_strings' => TransStrings::elStrings(), 'wp_locale' => get_locale(), 'is_full_name_required' => CheckoutFieldsSchema::isFullNameRequired(), 'business_details' => [ 'company_name' => [ 'enabled' => CheckoutFieldsSchema::isCompanyNameEnabled(), 'required' => CheckoutFieldsSchema::isCompanyNameRequired(), ], 'vat_number' => [ 'enabled' => CheckoutFieldsSchema::isVatNumberEnabled(), 'required' => CheckoutFieldsSchema::isVatNumberRequired(), ], 'legal_registration_id' => [ 'enabled' => CheckoutFieldsSchema::isLegalRegistrationIdEnabled(), 'required' => CheckoutFieldsSchema::isLegalRegistrationIdRequired(), ], ], 'fct_editor_frame' => '', ]); wp_localize_script($slug . '_admin_app_start', 'fluentCartAdminApp', $adminLocalizeData); wp_localize_script($slug . '_admin_app_start', 'fluentCartRestVars', [ 'rest' => $restVars, ]); do_action('fluent_cart/admin_js_loaded', $app); } public function globalEnqueueAssets($adminBar) { if (function_exists('get_current_screen')) { $screen = get_current_screen(); } else { $screen = null; } if ($screen && $screen->base !== 'user-edit') { return; } $app = App::getInstance(); $slug = $app->config->get('app.slug'); if (is_admin()) { wp_enqueue_script($slug . '_edit_wp_user_admin_global_js', Vite::getEnqueuePath('admin/utils/edit-wp-user-global.js'), ['jquery'], FLUENTCART_VERSION, true); } $baseUrl = apply_filters('fluent_cart/admin_base_url', admin_url('admin.php?page=fluent-cart#/'), []); $editingUserVars = null; if (function_exists('get_current_screen')) { $currentScreen = get_current_screen(); if ($currentScreen && $currentScreen->id == 'user-edit') { $userId = (int)($_GET['user_id'] ?? 0); $user = get_user_by('ID', $userId); if ($userId && $user) { $fluentcartProfile = Customer::query()->where('email', $user->user_email) ->orWhere('user_id', $user->ID) ->first(); if ($fluentcartProfile) { $fluentcartProfileUrl = $baseUrl . 'customers/' . $fluentcartProfile->id . '/view'; $editingUserVars = [ 'user_id' => $userId, 'fct_profile_id' => $fluentcartProfile->id, 'fct_profile_url' => $fluentcartProfileUrl ]; } } } } wp_localize_script('fluent-cart_edit_wp_user_admin_global_js', 'fluentcart_edit_user_global_bar_vars', [ 'customer_base' => $baseUrl . 'customers/', 'edit_user_vars' => $editingUserVars ]); } protected function getMenuIcon(): string { $svg = ''; return 'data:image/svg+xml;base64,' . base64_encode($svg); } }