PluginProbe
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler / 1.6.6
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler v1.6.6
1.6.6 1.6.5 1.6.4 1.6.3 1.6.2 1.6.1 1.6.0 1.5.4 1.5.5 1.5.3 1.5.2 1.5.1 1.5.0 1.4.2 1.4.1 1.4.0 1.3.28 1.3.27 1.3.26 1.3.25 1.3.23 1.3.22 1.3.21 1.3.20 1.3.19 All 49 releases
← All changes | app/Hooks/Handlers/MenuHandler.php +127 -5 1.3.28 → 1.6.6 View file →
@@ -19,8 +19,10 @@
19 19 use FluentCart\App\Models\AttributeTerm;
20 20 use FluentCart\App\Models\AttributeGroup;
21 21 use FluentCart\App\Models\ShippingMethod;
22 22 use FluentCart\App\Modules\Tax\TaxModule;
23 +use FluentCart\App\Modules\FluentPlayer\FluentPlayerBridge;
24 +use FluentCart\App\Modules\AdminFooter\AdminFooter;
23 25 use FluentCart\App\Helpers\CurrenciesHelper;
24 26 use FluentCart\App\Services\Filter\TaxFilter;
25 27 use FluentCart\App\Services\Filter\OrderFilter;
26 28 use FluentCart\App\Services\Filter\LicenseFilter;
@@ -26,11 +28,18 @@
26 28 use FluentCart\App\Services\Filter\LicenseFilter;
27 29 use FluentCart\App\Services\Filter\LicenseSiteFilter;
28 30 use FluentCart\App\Services\Filter\ProductFilter;
29 31 use FluentCart\App\Services\Filter\CustomerFilter;
32 +use FluentCart\App\Services\Filter\CouponFilter;
33 +use FluentCart\App\Services\Filter\LogFilter;
34 +use FluentCart\App\Services\Filter\OrderBumpFilter;
35 +use FluentCart\App\Modules\Shipping\Services\Filter\ShippingClassFilter;
36 +use FluentCart\App\Modules\Shipping\Services\Filter\ShippingZoneFilter;
30 37 use FluentCart\App\Modules\Integrations\AddOnModule;
38 +use FluentCart\App\Services\DateTime\DayjsFormatter;
31 39 use FluentCart\App\Services\Translations\TransStrings;
32 40 use FluentCart\App\Services\Permission\PermissionManager;
41 +use FluentCart\Database\DataBackfills;
33 42 use FluentCart\App\Modules\PaymentMethods\Core\GatewayManager;
34 43
35 44 class MenuHandler
36 45 {
@@ -43,8 +52,9 @@
43 52
44 53 if ($page == 'fluent-cart') {
45 54
46 55 \FluentCart\App\Events\FirstTimePluginActivation::handle();
56 + (new AdminFooter())->register();
47 57 add_action('admin_enqueue_scripts', function () {
48 58 Vite::enqueueStyle('fluent_cart_admin_app_css',
49 59 'styles/tailwind/style.css',
50 60 );
@@ -55,8 +65,14 @@
55 65
56 66 }
57 67 });
58 68
69 + // Inline dark mode init script for all FluentCart admin pages (prevents flicker)
70 + add_action('admin_head', [$this, 'outputFluentCartDarkModeScript']);
71 +
72 + // Enqueue dark mode toggle JS for taxonomy pages
73 + add_action('admin_head', [$this, 'enqueueDarkModeToggleForTaxonomy']);
74 +
59 75 // Add a post display state for special WC pages.
60 76 add_filter('display_post_states', array($this, 'addDisplayPostStates'), 10, 2);
61 77
62 78 }
@@ -107,8 +123,66 @@
107 123 return $states;
108 124
109 125 }
110 126
127 + public function outputFluentCartDarkModeScript()
128 + {
129 + global $pagenow;
130 + $page = $_GET['page'] ?? '';
131 + $postType = $_GET['post_type'] ?? '';
132 +
133 + // post.php?post=ID&action=edit omits post_type; resolve it from the post ID.
134 + if ($pagenow === 'post.php' && empty($postType)) {
135 + $postId = (int) App::request()->get('post', 0);
136 + $postType = $postId ? (string) get_post_type($postId) : '';
137 + }
138 +
139 + $isFluentCartPage = $page === 'fluent-cart';
140 + $isTaxonomyList = $pagenow === 'edit-tags.php' && $postType === FluentProducts::CPT_NAME;
141 + $isTermEditPage = $pagenow === 'term.php' && $postType === FluentProducts::CPT_NAME;
142 + $isProductEditPage = ($pagenow === 'post.php' || $pagenow === 'edit.php') && $postType === FluentProducts::CPT_NAME;
143 +
144 + if (!$isFluentCartPage && !$isTaxonomyList && !$isTermEditPage && !$isProductEditPage) {
145 + return;
146 + }
147 +
148 + // Runs synchronously in <head> before any paint — applies the dark class and
149 + // data-fct-theme attribute to <html> so logos and the theme icon render correctly
150 + // from the very first frame, with no light-to-dark flash.
151 + echo '<script>' . $this->getDarkModeInitScript() . '</script>';
152 + }
153 +
154 + public function enqueueDarkModeToggleForTaxonomy()
155 + {
156 + global $pagenow;
157 + $postType = $_GET['post_type'] ?? '';
158 +
159 + $isTaxonomyList = $pagenow === 'edit-tags.php' && $postType === FluentProducts::CPT_NAME;
160 + $isTermEditPage = $pagenow === 'term.php' && $postType === FluentProducts::CPT_NAME;
161 +
162 + if ($isTaxonomyList || $isTermEditPage) {
163 + Vite::enqueueScript(
164 + 'fluent_cart_dark_mode_toggle',
165 + 'admin/dark-mode-toggle.js',
166 + [],
167 + FLUENTCART_VERSION,
168 + true
169 + );
170 + }
171 + }
172 +
173 + private function getDarkModeInitScript(): string
174 + {
175 + return "(function(){" .
176 + "var k='fluent_theme_mode',c='fluent_theme_dark'," .
177 + "s=localStorage.getItem(k)||localStorage.getItem('fcart_admin_theme')," .
178 + "t=s==='dark'?'dark':s==='light'?'light':'system'," .
179 + "d=s==='dark'||s==='system:dark'||((!s||s==='system')&&window.matchMedia&&window.matchMedia('(prefers-color-scheme: dark)').matches);" .
180 + "document.documentElement.setAttribute('data-fct-theme',t);" .
181 + "if(d)document.documentElement.classList.add(c);" .
182 + "})();";
183 + }
184 +
111 185 public function init()
112 186 {
113 187
114 188 add_action('admin_menu', array($this, 'addAdminMenu'));
@@ -374,13 +448,22 @@
374 448
375 449 do_action('fluent_cart/loading_app', $app);
376 450
377 451 //This should be done before enqueueing the global script.
378 - Vite::enqueueScript($slug . '_admin_app_start', 'admin/bootstrap/app.js', [$slug . '_global_admin_hooks']);
452 + // wp-i18n backs the admin translator (resources/admin/utils/translator/Translator.js).
453 + Vite::enqueueScript($slug . '_admin_app_start', 'admin/bootstrap/app.js', [$slug . '_global_admin_hooks', 'wp-i18n']);
379 454
380 455 //Don't register this script using vite.
381 - wp_enqueue_script($slug . '_global_admin_hooks', Vite::getEnqueuePath('admin/admin_hooks.js'), [], FLUENTCART_VERSION, true);
456 + if (!wp_script_is('wp-hooks', 'registered')) {
457 + $suffix = (defined('SCRIPT_DEBUG') && SCRIPT_DEBUG) ? '' : '.min';
458 + wp_register_script('wp-hooks', includes_url('js/dist/hooks' . $suffix . '.js'), ['wp-polyfill'], FLUENTCART_VERSION, true);
459 + }
460 + if (!wp_script_is('wp-hooks', 'enqueued')) {
461 + wp_enqueue_script('wp-hooks');
462 + }
382 463
464 + wp_enqueue_script($slug . '_global_admin_hooks', Vite::getEnqueuePath('admin/admin_hooks.js'), ['wp-hooks'], FLUENTCART_VERSION, true);
465 +
383 466 $manager = GatewayManager::getInstance();
384 467 $payment_routes = $manager->getRoutes();
385 468 // $payment_routes = apply_filters('fluent_cart/payments/payment_method_settings_routes', []);
386 469
@@ -388,8 +471,9 @@
388 471
389 472 $settings = new StoreSettings();
390 473 $checkoutUrl = add_query_arg(Helper::INSTANT_CHECKOUT_URL_PARAM, '=', $settings->getCheckoutPage());
391 474 $restVars = Helper::getRestInfo();
475 + $hasDataMigrations = current_user_can('manage_options') && DataBackfills::hasPending();
392 476
393 477 $filterOptions = [
394 478 'order_filter_options' => OrderFilter::getTableFilterOptions(),
395 479 'customer_filter_options' => CustomerFilter::getTableFilterOptions(),
@@ -409,10 +493,30 @@
409 493 'license_sites' => ['filters' => Arr::get($filterOptions, 'license_site_filter_options', [])],
410 494 'taxes_table' => ['filters' => Arr::get($filterOptions, 'tax_filter_options', [])],
411 495 'subscriptions' => ['filters' => Arr::get($filterOptions, 'subscription_filter_options', [])],
412 496 'shipping_zone_table' => ['filters' => Arr::get($filterOptions, 'shipping_zone_filter_options', [])],
497 + // The Order Sources report filters orders, so its advanced-filter UI
498 + // reuses the Orders filter vocabulary rather than defining its own.
499 + 'source_report' => ['filters' => Arr::get($filterOptions, 'order_filter_options', [])],
413 500 ];
414 501
502 + // Tables that declare sort options on their filter class but carry no
503 + // filter-options entry above: the Sort popover still needs them, and
504 + // they are what `fluent_cart/{filterName}_table_sorts` feeds.
505 + $sortOnlyTables = [
506 + 'coupon_table' => CouponFilter::class,
507 + 'log_table' => LogFilter::class,
508 + 'order_bump_table' => OrderBumpFilter::class,
509 + 'shipping_class_table' => ShippingClassFilter::class,
510 + 'shipping_zone_table' => ShippingZoneFilter::class,
511 + ];
512 +
513 + foreach ($sortOnlyTables as $tableName => $filterClass) {
514 + if (empty($tableConfig[$tableName]['filters']['sorts'])) {
515 + $tableConfig[$tableName]['filters']['sorts'] = call_user_func([$filterClass, 'getSortOptions']);
516 + }
517 + }
518 +
415 519 $tableConfig = apply_filters('fluent_cart/admin_table_saved_views', $tableConfig, [
416 520 'filterOptions' => $filterOptions
417 521 ]);
418 522
@@ -423,8 +527,9 @@
423 527 $appConfig['version'] = FLUENTCART_VERSION;
424 528 $appConfig['permissions'] = PermissionManager::getUserPermissions();
425 529 $appConfig['isProActive'] = App::isProActive();
426 530 $appConfig['proVersion'] = defined('FLUENTCART_PRO_PLUGIN_VERSION') ? FLUENTCART_PRO_PLUGIN_VERSION : null;
531 + $appConfig['fluentPlayer'] = FluentPlayerBridge::adminAppConfig();
427 532
428 533 $appConfig['logos'] = [
429 534 'dark' => Vite::getAssetUrl('images/logo/logo-full-dark.svg'),
430 535 'light' => Vite::getAssetUrl('images/logo/logo-full.svg'),
@@ -429,9 +534,9 @@
429 534 'dark' => Vite::getAssetUrl('images/logo/logo-full-dark.svg'),
430 535 'light' => Vite::getAssetUrl('images/logo/logo-full.svg'),
431 536 ];
432 537 $appConfig['isModuleTabEnabled'] = $settings->isModuleTabEnabled();
433 - $appConfig['upgrade_url'] = 'https://fluentcart.com/pricing/';
538 + $appConfig['upgrade_url'] = Helper::getUpgradeUrl();
434 539
435 540 $max_upload_size = wp_max_upload_size(); // Returns size in bytes
436 541 $adminLocalizeData = apply_filters('fluent_cart/admin_app_data', [
437 542 'app_config' => $appConfig,
@@ -436,8 +541,9 @@
436 541 $adminLocalizeData = apply_filters('fluent_cart/admin_app_data', [
437 542 'app_config' => $appConfig,
438 543 'slug' => $app->config->get('app.slug'),
439 544 'admin_url' => admin_url('admin.php?page=fluent-cart#/'),
545 + 'wp_admin_url' => rtrim(admin_url(), '/'),
440 546 'frontend_url' => URL::getFrontEndUrl(''),
441 547 'nonce' => wp_create_nonce($slug),
442 548 'rest' => $restVars,
443 549 'brand_logo' => $this->getMenuIcon(),
@@ -462,9 +568,9 @@
462 568 'order_statues' => Status::getOrderStatuses(),
463 569 'editable_order_statues' => Status::getEditableOrderStatuses(),
464 570 'editable_customer_statues' => Status::getEditableCustomerStatuses(),
465 571 'shipping_statuses' => Status::getShippingStatuses(),
466 - 'allow_bulk_payment_status_change' => true,
572 + // Attribute library powering the Advanced Variation feature.
467 573 'variation_attributes' => AttributeGroup::with(['terms'])->get(),
468 574 'variation_terms' => AttributeTerm::query()->get()->keyBy('id'),
469 575 'product_image_base_uri' => Helper::getProductImageBaseUri(),
470 576 'add_on_modules' => AddOnModule::showAddOns(),
@@ -489,14 +595,30 @@
489 595 'site_url' => site_url(),
490 596 'modules_settings' => ModuleSettings::getAllSettings(),
491 597 'purchase_fluent_cart_link' => 'https://fluentcart.com/',
492 598 'admin_notices' => apply_filters('fluent_cart/admin_notices', []),
599 + // POSTs data-backfills/run until done; endpoint requires manage_options
600 + 'has_data_migrations' => $hasDataMigrations,
493 601 'subscription_intervals' => Helper::getAvailableSubscriptionIntervalOptions(),
494 602
495 - 'datei18' => TransStrings::dateTimeStrings(),
603 + 'datei18' => DayjsFormatter::localizedStrings(),
496 604 'el_strings' => TransStrings::elStrings(),
497 605 'wp_locale' => get_locale(),
498 606 'is_full_name_required' => CheckoutFieldsSchema::isFullNameRequired(),
607 + 'business_details' => [
608 + 'company_name' => [
609 + 'enabled' => CheckoutFieldsSchema::isCompanyNameEnabled(),
610 + 'required' => CheckoutFieldsSchema::isCompanyNameRequired(),
611 + ],
612 + 'vat_number' => [
613 + 'enabled' => CheckoutFieldsSchema::isVatNumberEnabled(),
614 + 'required' => CheckoutFieldsSchema::isVatNumberRequired(),
615 + ],
616 + 'legal_registration_id' => [
617 + 'enabled' => CheckoutFieldsSchema::isLegalRegistrationIdEnabled(),
618 + 'required' => CheckoutFieldsSchema::isLegalRegistrationIdRequired(),
619 + ],
620 + ],
499 621 'fct_editor_frame' => '',
500 622 ]);
501 623
502 624 wp_localize_script($slug . '_admin_app_start', 'fluentCartAdminApp', $adminLocalizeData);