PluginProbe
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler / 1.7.0
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler v1.7.0
1.7.0 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 All 50 releases
fluent-cart / app / Hooks / Handlers / MenuHandler.php

MenuHandler.php in FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler 1.7.0, at app/Hooks/Handlers/MenuHandler.php

706 lines 30.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace FluentCart\App\Hooks\Handlers;
4
5 use FluentCart\Api\ModuleSettings;
6 use FluentCart\App\App;
7 use FluentCart\App\Services\Renderer\CheckoutFieldsSchema;
8 use FluentCart\App\Vite;
9 use FluentCart\App\Services\URL;
10 use FluentCart\Api\StoreSettings;
11 use FluentCart\Api\PaymentMethods;
12 use FluentCart\App\Helpers\Helper;
13 use FluentCart\App\Helpers\Status;
14 use FluentCart\App\Models\Product;
15 use FluentCart\App\Models\Customer;
16 use FluentCart\Framework\Support\Arr;
17 use FluentCart\App\CPT\FluentProducts;
18 use FluentCart\App\Helpers\AdminHelper;
19 use FluentCart\App\Models\AttributeTerm;
20 use FluentCart\App\Models\AttributeGroup;
21 use FluentCart\App\Models\ShippingMethod;
22 use FluentCart\App\Modules\Tax\TaxModule;
23 use FluentCart\App\Modules\FluentPlayer\FluentPlayerBridge;
24 use FluentCart\App\Modules\AdminFooter\AdminFooter;
25 use FluentCart\App\Helpers\CurrenciesHelper;
26 use FluentCart\App\Services\Filter\TaxFilter;
27 use FluentCart\App\Services\Filter\OrderFilter;
28 use FluentCart\App\Services\Filter\LicenseFilter;
29 use FluentCart\App\Services\Filter\LicenseSiteFilter;
30 use FluentCart\App\Services\Filter\ProductFilter;
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\Services\Filter\ReviewFilter;
36 use FluentCart\App\Modules\Shipping\Services\Filter\ShippingClassFilter;
37 use FluentCart\App\Modules\Shipping\Services\Filter\ShippingZoneFilter;
38 use FluentCart\App\Modules\Integrations\AddOnModule;
39 use FluentCart\App\Services\DateTime\DayjsFormatter;
40 use FluentCart\App\Services\Translations\TransStrings;
41 use FluentCart\App\Services\Permission\PermissionManager;
42 use FluentCart\Database\DataBackfills;
43 use FluentCart\App\Modules\PaymentMethods\Core\GatewayManager;
44
45 class MenuHandler
46 {
47 public function register()
48 {
49 add_action('init', [$this, 'init']);
50
51 add_action('admin_init', function () {
52 $page = $_GET['page'] ?? '';
53
54 if ($page == 'fluent-cart') {
55
56 \FluentCart\App\Events\FirstTimePluginActivation::handle();
57 (new AdminFooter())->register();
58 add_action('admin_enqueue_scripts', function () {
59 Vite::enqueueStyle('fluent_cart_admin_app_css',
60 'styles/tailwind/style.css',
61 );
62 Vite::enqueueScript('fluent_cart_admin_global_js',
63 'admin/global.js',
64 );
65 });
66
67 }
68 });
69
70 // Inline dark mode init script for all FluentCart admin pages (prevents flicker)
71 add_action('admin_head', [$this, 'outputFluentCartDarkModeScript']);
72
73 // Enqueue dark mode toggle JS for taxonomy pages
74 add_action('admin_head', [$this, 'enqueueDarkModeToggleForTaxonomy']);
75
76 // Add a post display state for special WC pages.
77 add_filter('display_post_states', array($this, 'addDisplayPostStates'), 10, 2);
78
79 }
80
81
82 public function addDisplayPostStates($states, $post)
83 {
84 if (!$post || $post->post_type != 'page') {
85 return $states;
86 }
87
88
89 $targetKeys = [
90 'checkout_page_id' => __('Checkout Page', 'fluent-cart'),
91 'cart_page_id' => __('Cart Page', 'fluent-cart'),
92 'receipt_page_id' => __('Receipt Page', 'fluent-cart'),
93 'order_review_page_id' => __('Order Review Page', 'fluent-cart'),
94 'shop_page_id' => __('Shop Page', 'fluent-cart'),
95 'customer_profile_page_id' => __('Customer Profile Page', 'fluent-cart'),
96 ];
97
98 $pagesConfig = (new StoreSettings())->getPagesSettings();
99 $pagesConfig = Arr::only($pagesConfig, array_keys($targetKeys));
100
101 if (!is_array($pagesConfig)) {
102 return $states;
103 }
104 $pagesConfig = array_filter($pagesConfig);
105
106 if (empty($pagesConfig)) {
107 return $states;
108 }
109
110
111 $pagesConfig = array_flip($pagesConfig);
112 $targetKey = Arr::get($pagesConfig, $post->ID);
113
114 if ($targetKey && isset($targetKeys[$targetKey])) {
115
116 $logo = '<svg style="vertical-align: middle; height: 18px; width: 18px;" width="18" height="18" viewBox="0 0 300 300" fill="none" xmlns="http://www.w3.org/2000/svg">
117 <rect width="300" height="300" rx="30" fill="white"/>
118 <path d="M136.561 205.944H47.1367L61.1704 173.491C65.2906 163.963 74.6784 157.795 85.0589 157.795H191.584L184.338 174.551C176.098 193.607 157.322 205.944 136.561 205.944Z" fill="#00009F"/>
119 <path d="M210.643 142.439H84.8574L92.1035 125.683C100.344 106.627 119.12 94.2905 139.881 94.2905H248.565L234.531 126.743C230.411 136.271 221.023 142.439 210.643 142.439Z" fill="#00009F"/>
120 </svg>';
121
122 $states['fluent_cart'] = '<span>' . $logo . '<span>' . $targetKeys[$targetKey] . '</span></span>';
123 }
124
125 return $states;
126
127 }
128
129 public function outputFluentCartDarkModeScript()
130 {
131 global $pagenow;
132 $page = $_GET['page'] ?? '';
133 $postType = $_GET['post_type'] ?? '';
134
135 // post.php?post=ID&action=edit omits post_type; resolve it from the post ID.
136 if ($pagenow === 'post.php' && empty($postType)) {
137 $postId = (int) App::request()->get('post', 0);
138 $postType = $postId ? (string) get_post_type($postId) : '';
139 }
140
141 $isFluentCartPage = $page === 'fluent-cart';
142 $isTaxonomyList = $pagenow === 'edit-tags.php' && $postType === FluentProducts::CPT_NAME;
143 $isTermEditPage = $pagenow === 'term.php' && $postType === FluentProducts::CPT_NAME;
144 $isProductEditPage = ($pagenow === 'post.php' || $pagenow === 'edit.php') && $postType === FluentProducts::CPT_NAME;
145
146 if (!$isFluentCartPage && !$isTaxonomyList && !$isTermEditPage && !$isProductEditPage) {
147 return;
148 }
149
150 // Runs synchronously in <head> before any paint — applies the dark class and
151 // data-fct-theme attribute to <html> so logos and the theme icon render correctly
152 // from the very first frame, with no light-to-dark flash.
153 echo '<script>' . $this->getDarkModeInitScript() . '</script>';
154 }
155
156 public function enqueueDarkModeToggleForTaxonomy()
157 {
158 global $pagenow;
159 $postType = $_GET['post_type'] ?? '';
160
161 $isTaxonomyList = $pagenow === 'edit-tags.php' && $postType === FluentProducts::CPT_NAME;
162 $isTermEditPage = $pagenow === 'term.php' && $postType === FluentProducts::CPT_NAME;
163
164 if ($isTaxonomyList || $isTermEditPage) {
165 Vite::enqueueScript(
166 'fluent_cart_dark_mode_toggle',
167 'admin/dark-mode-toggle.js',
168 [],
169 FLUENTCART_VERSION,
170 true
171 );
172 }
173 }
174
175 private function getDarkModeInitScript(): string
176 {
177 return "(function(){" .
178 "var k='fluent_theme_mode',c='fluent_theme_dark'," .
179 "s=localStorage.getItem(k)||localStorage.getItem('fcart_admin_theme')," .
180 "t=s==='dark'?'dark':s==='light'?'light':'system'," .
181 "d=s==='dark'||s==='system:dark'||((!s||s==='system')&&window.matchMedia&&window.matchMedia('(prefers-color-scheme: dark)').matches);" .
182 "document.documentElement.setAttribute('data-fct-theme',t);" .
183 "if(d)document.documentElement.classList.add(c);" .
184 "})();";
185 }
186
187 public function init()
188 {
189
190 add_action('admin_menu', array($this, 'addAdminMenu'));
191
192 /*
193 * Disable Gutenberg for Products
194 */
195 add_filter('parent_file', function ($parent_file) {
196 global $submenu_file, $current_screen, $pagenow;
197
198 $postType = $_GET['post_type'] ?? '';
199 if ($postType == FluentProducts::CPT_NAME && $current_screen->post_type == FluentProducts::CPT_NAME) {
200 if ($pagenow == 'post.php') {
201 $submenu_file = 'edit.php?post_type=' . $current_screen->post_type;
202 }
203
204 if ($pagenow == 'edit-tags.php') {
205 $taxonomy = $_GET['taxonomy'] ?? '';
206 $submenu_file = 'edit-tags.php?taxonomy=' . esc_attr($taxonomy) . '&post_type=' . $current_screen->post_type;
207 }
208
209 $parent_file = 'fluent-cart';
210 }
211
212 return $parent_file;
213 });
214
215 add_action('fluent_cart/admin_menu', array($this, 'renderAdminMenu'));
216 // add_action('in_admin_header', array($this, 'maybeRenderAdminMenu'));
217
218 add_action('edit_form_top', array($this, 'pushProductNav'));
219
220 add_action('admin_bar_menu', [$this, 'globalEnqueueAssets'], 10, 1);
221 }
222
223 public function addAdminMenu()
224 {
225 $capability = 'manage_options';
226
227 if (!current_user_can('manage_options') && App::isProActive()) {
228 $capability = PermissionManager::ADMIN_CAP;
229 }
230
231 if (!current_user_can($capability)) {
232 return;
233 }
234
235 global $submenu;
236
237 $adminMenuTitle = apply_filters('fluent_cart/admin_menu_title', 'FluentCart', []);
238
239 add_menu_page(
240 $adminMenuTitle,
241 $adminMenuTitle,
242 $capability,
243 'fluent-cart',
244 [$this, 'renderAdmin'],
245 $this->getMenuIcon(),
246 apply_filters('fluent_cart/admin_menu_position', 3)
247 );
248
249 $submenu['fluent-cart']['dashboard'] = array(
250 __('Dashboard', 'fluent-cart'),
251 $capability,
252 'admin.php?page=fluent-cart#/',
253 '',
254 'fluent_cart_dashboard'
255 );
256
257 if (PermissionManager::hasPermission(['orders/view'])) {
258 $submenu['fluent-cart']['orders'] = array(
259 __('Orders', 'fluent-cart'),
260 $capability,
261 'admin.php?page=fluent-cart#/orders',
262 '',
263 'fluent_cart_orders'
264 );
265 }
266
267 if (PermissionManager::hasPermission(['customers/view', 'customers/manage'])) {
268 $submenu['fluent-cart']['customers'] = array(
269 __('Customers', 'fluent-cart'),
270 $capability,
271 'admin.php?page=fluent-cart#/customers',
272 '',
273 'fluent_cart_customers'
274 );
275 }
276
277 if (PermissionManager::hasPermission(['products/view'])) {
278 $submenu['fluent-cart']['products'] = array(
279 __('Products', 'fluent-cart'),
280 $capability,
281 'admin.php?page=fluent-cart#/products',
282 '',
283 'fluent_cart_products'
284 );
285 }
286
287 if (PermissionManager::hasPermission(['subscriptions/view'])) {
288 $submenu['fluent-cart']['subscriptions'] = array(
289 __('Subscriptions', 'fluent-cart'),
290 $capability,
291 'admin.php?page=fluent-cart#/subscriptions',
292 '',
293 'fluent_cart_subscriptions'
294 );
295 }
296
297 if (PermissionManager::hasPermission(['reports/view'])) {
298 $submenu['fluent-cart']['reports'] = array(
299 __('Reports', 'fluent-cart'),
300 $capability,
301 'admin.php?page=fluent-cart#/reports/overview',
302 '',
303 'fluent_cart_reports'
304 );
305 }
306
307 if (PermissionManager::userCan('is_super_admin')) {
308 $submenu['fluent-cart']['integrations'] = array(
309 __('Integrations', 'fluent-cart'),
310 $capability,
311 'admin.php?page=fluent-cart#/integrations',
312 '',
313 'fluent_cart_integrations'
314 );
315 }
316
317
318 $hasSensitiveAccess = PermissionManager::hasPermission(['store/settings', 'store/sensitive']);
319
320 if ($hasSensitiveAccess) {
321 $submenu['fluent-cart']['settings'] = array(
322 __('Settings', 'fluent-cart'),
323 $capability,
324 'admin.php?page=fluent-cart#/settings/store-settings/',
325 '',
326 'fluent_cart_settings'
327 );
328 }
329
330 if (PermissionManager::hasPermission(['coupons/manage', 'coupons/view'])) {
331 $submenu['fluent-cart']['coupons'] = array(
332 __('Coupons', 'fluent-cart'),
333 $capability,
334 'admin.php?page=fluent-cart#/coupons',
335 '',
336 'fluent_cart_coupons'
337 );
338 }
339
340 if ($hasSensitiveAccess && TaxModule::isTaxEnabled()) {
341 $submenu['fluent-cart']['taxes'] = array(
342 __('Taxes', 'fluent-cart'),
343 $capability,
344 'admin.php?page=fluent-cart#/taxes',
345 '',
346 'fluent_cart_taxes'
347 );
348 }
349
350
351 if (PermissionManager::hasPermission(['products/create', 'products/edit'])) {
352 $taxonomies = get_taxonomies([
353 'object_type' => [FluentProducts::CPT_NAME],
354 'public' => true,
355 ], 'object');
356
357 foreach ($taxonomies as $key => $taxonomy) {
358 $menuUrl = 'edit-tags.php?taxonomy=' . $taxonomy->name . '&post_type=' . FluentProducts::CPT_NAME;
359 $submenu['fluent-cart'][$key] = [
360 $taxonomy->label,
361 $capability,
362 $menuUrl,
363 '',
364 $taxonomy->name
365 ];
366 }
367 }
368
369 if (PermissionManager::userCan('is_super_admin')) {
370 $submenu['fluent-cart']['logs'] = array(
371 __('Logs', 'fluent-cart'),
372 $capability,
373 'admin.php?page=fluent-cart#/logs',
374 '',
375 'fluent_cart_logs'
376 );
377 }
378
379 do_action('fluent_cart/admin_submenu_added', $submenu);
380 }
381
382 public function renderAdmin()
383 {
384 $isCustomDashboardSlugChanged = (new StoreSettings())->getCustomerDashboardPageSlug() != (new StoreSettings())->get('customer_profile_page_slug');
385
386 if ($isCustomDashboardSlugChanged) {
387 $allSettings = (new StoreSettings())->get();
388 (new StoreSettings())->save($allSettings); // we are just resaving to flash the settings cache
389 }
390
391 if (function_exists('wp_enqueue_editor')) {
392 wp_enqueue_editor();
393 wp_tinymce_inline_scripts();
394 wp_enqueue_media();
395 }
396
397 $this->enqueueAssets();
398
399 $config = App::getInstance('config');
400
401 $name = $config->get('app.name');
402
403 $slug = $config->get('app.slug');
404
405 $baseUrl = apply_filters('fluent_connector_base_url', admin_url('admin.php?page=newproject#/'));
406
407 $app = App::getInstance();
408 $assets = $app['url.assets'];
409
410 App::make('view')->render('admin.admin_app', [
411 'name' => $name,
412 'slug' => $slug,
413 'baseUrl' => $baseUrl,
414 'logo' => $assets . 'images/logo.svg',
415 ]);
416 }
417
418 public function maybeRenderAdminMenu()
419 {
420 $postType = $_GET['post_type'] ?? '';
421 if ($postType == FluentProducts::CPT_NAME && is_admin()) {
422 AdminHelper::getAdminMenu(true);
423 AdminHelper::pushGlobalAdminAssets();
424 }
425 }
426
427 public function renderAdminMenu()
428 {
429 if (!apply_filters('fluent_cart/show_admin_top_bar', true)) {
430 return;
431 }
432 AdminHelper::getAdminMenu(true);
433 }
434
435 public function pushProductNav($post)
436 {
437 if (!$post || $post->post_type != FluentProducts::CPT_NAME) {
438 return;
439 }
440
441 AdminHelper::getProductMenu($post->ID, true, 'product_edit');
442 AdminHelper::pushGlobalAdminAssets();
443 }
444
445 public function enqueueAssets()
446 {
447 $app = App::getInstance();
448
449 $slug = $app->config->get('app.slug');
450
451 do_action('fluent_cart/loading_app', $app);
452
453 //This should be done before enqueueing the global script.
454 // wp-i18n backs the admin translator (resources/admin/utils/translator/Translator.js).
455 Vite::enqueueScript($slug . '_admin_app_start', 'admin/bootstrap/app.js', [$slug . '_global_admin_hooks', 'wp-i18n']);
456
457 //Don't register this script using vite.
458 if (!wp_script_is('wp-hooks', 'registered')) {
459 $suffix = (defined('SCRIPT_DEBUG') && SCRIPT_DEBUG) ? '' : '.min';
460 wp_register_script('wp-hooks', includes_url('js/dist/hooks' . $suffix . '.js'), ['wp-polyfill'], FLUENTCART_VERSION, true);
461 }
462 if (!wp_script_is('wp-hooks', 'enqueued')) {
463 wp_enqueue_script('wp-hooks');
464 }
465
466 wp_enqueue_script($slug . '_global_admin_hooks', Vite::getEnqueuePath('admin/admin_hooks.js'), ['wp-hooks'], FLUENTCART_VERSION, true);
467
468 $manager = GatewayManager::getInstance();
469 $payment_routes = $manager->getRoutes();
470 // $payment_routes = apply_filters('fluent_cart/payments/payment_method_settings_routes', []);
471
472 $storage_driver_routes = apply_filters('fluent_cart/storage/storage_driver_settings_routes', [], []);
473
474 $settings = new StoreSettings();
475 $checkoutUrl = add_query_arg(Helper::INSTANT_CHECKOUT_URL_PARAM, '=', $settings->getCheckoutPage());
476 $restVars = Helper::getRestInfo();
477 $hasDataMigrations = current_user_can('manage_options') && DataBackfills::hasPending();
478
479 $filterOptions = [
480 'order_filter_options' => OrderFilter::getTableFilterOptions(),
481 'customer_filter_options' => CustomerFilter::getTableFilterOptions(),
482 'product_filter_options' => ProductFilter::getTableFilterOptions(),
483 'license_filter_options' => LicenseFilter::getTableFilterOptions(),
484 'license_site_filter_options' => LicenseSiteFilter::getTableFilterOptions(),
485 'tax_filter_options' => TaxFilter::getTableFilterOptions(),
486 'review_filter_options' => ReviewFilter::getTableFilterOptions(),
487 ];
488 $filterOptions = apply_filters('fluent_cart/admin_filter_options', $filterOptions, []);
489
490 // Structured table config keyed by table name (used by Table.js base class)
491 $tableConfig = [
492 'order_table' => ['filters' => Arr::get($filterOptions, 'order_filter_options', [])],
493 'customers' => ['filters' => Arr::get($filterOptions, 'customer_filter_options', [])],
494 'product_table' => ['filters' => Arr::get($filterOptions, 'product_filter_options', [])],
495 'licenses' => ['filters' => Arr::get($filterOptions, 'license_filter_options', [])],
496 'license_sites' => ['filters' => Arr::get($filterOptions, 'license_site_filter_options', [])],
497 'taxes_table' => ['filters' => Arr::get($filterOptions, 'tax_filter_options', [])],
498 'subscriptions' => ['filters' => Arr::get($filterOptions, 'subscription_filter_options', [])],
499 'shipping_zone_table' => ['filters' => Arr::get($filterOptions, 'shipping_zone_filter_options', [])],
500 'review_table' => ['filters' => Arr::get($filterOptions, 'review_filter_options', [])],
501 // The Order Sources report filters orders, so its advanced-filter UI
502 // reuses the Orders filter vocabulary rather than defining its own.
503 'source_report' => ['filters' => Arr::get($filterOptions, 'order_filter_options', [])],
504 ];
505
506 // Tables that declare sort options on their filter class but carry no
507 // filter-options entry above: the Sort popover still needs them, and
508 // they are what `fluent_cart/{filterName}_table_sorts` feeds.
509 $sortOnlyTables = [
510 'coupon_table' => CouponFilter::class,
511 'log_table' => LogFilter::class,
512 'order_bump_table' => OrderBumpFilter::class,
513 'shipping_class_table' => ShippingClassFilter::class,
514 'shipping_zone_table' => ShippingZoneFilter::class,
515 ];
516
517 foreach ($sortOnlyTables as $tableName => $filterClass) {
518 if (empty($tableConfig[$tableName]['filters']['sorts'])) {
519 $tableConfig[$tableName]['filters']['sorts'] = call_user_func([$filterClass, 'getSortOptions']);
520 }
521 }
522
523 $tableConfig = apply_filters('fluent_cart/admin_table_saved_views', $tableConfig, [
524 'filterOptions' => $filterOptions
525 ]);
526
527 $currentUser = get_user_by('ID', get_current_user_id());
528
529 // Get app config and merge additional properties into it
530 $appConfig = $app->config->get('app');
531 $appConfig['version'] = FLUENTCART_VERSION;
532 $appConfig['permissions'] = PermissionManager::getUserPermissions();
533 $appConfig['isProActive'] = App::isProActive();
534 $appConfig['proVersion'] = defined('FLUENTCART_PRO_PLUGIN_VERSION') ? FLUENTCART_PRO_PLUGIN_VERSION : null;
535 $appConfig['fluentPlayer'] = FluentPlayerBridge::adminAppConfig();
536
537 $appConfig['logos'] = [
538 'dark' => Vite::getAssetUrl('images/logo/logo-full-dark.svg'),
539 'light' => Vite::getAssetUrl('images/logo/logo-full.svg'),
540 ];
541 $appConfig['isModuleTabEnabled'] = $settings->isModuleTabEnabled();
542 $appConfig['upgrade_url'] = Helper::getUpgradeUrl();
543
544 $max_upload_size = wp_max_upload_size(); // Returns size in bytes
545 $adminLocalizeData = apply_filters('fluent_cart/admin_app_data', [
546 'app_config' => $appConfig,
547 'slug' => $app->config->get('app.slug'),
548 'admin_url' => admin_url('admin.php?page=fluent-cart#/'),
549 'wp_admin_url' => rtrim(admin_url(), '/'),
550 'frontend_url' => URL::getFrontEndUrl(''),
551 'nonce' => wp_create_nonce($slug),
552 'rest' => $restVars,
553 'brand_logo' => $this->getMenuIcon(),
554 'asset_url' => Vite::getAssetUrl(),
555 'me' => [
556 'id' => $currentUser->ID,
557 'full_name' => trim($currentUser->display_name),
558 'email' => $currentUser->user_email,
559 'avatar' => get_avatar_url($currentUser->ID)
560 ],
561 'shop' => Helper::shopConfig(),
562 'product_statuses' => Status::getProductStatuses(),
563 'total_products_count' => Product::query()->count(),
564 'payment_statuses' => Status::getEditableTransactionStatuses(true),
565 'payment_routes' => $payment_routes,
566 'storage_driver_routes' => $storage_driver_routes,
567 'editable_payment_statuses' => Status::getEditableTransactionStatuses(true),
568 'order_statuses' => Status::getOrderStatuses(),
569 'editable_order_statuses' => Status::getEditableOrderStatuses(),
570 'editable_customer_statuses' => Status::getEditableCustomerStatuses(),
571 // Backward compat: keep the old typo'd keys for existing frontend code
572 'order_statues' => Status::getOrderStatuses(),
573 'editable_order_statues' => Status::getEditableOrderStatuses(),
574 'editable_customer_statues' => Status::getEditableCustomerStatuses(),
575 'shipping_statuses' => Status::getShippingStatuses(),
576 // Attribute library powering the Advanced Variation feature.
577 'variation_attributes' => AttributeGroup::with(['terms'])->get(),
578 'variation_terms' => AttributeTerm::query()->get()->keyBy('id'),
579 'product_image_base_uri' => Helper::getProductImageBaseUri(),
580 'add_on_modules' => AddOnModule::showAddOns(),
581 'stock_statuses' => Status::getStockStatuses(),
582 'fulfillment_types' => Helper::getFulfilmentTypes(),
583 'variation_types' => Helper::getVariationTypes(),
584 'trans' => TransStrings::getStrings(),
585 'dashboard_url' => admin_url('admin.php?page=fluent-cart#'),
586 'checkout_url' => $checkoutUrl,
587 'dummy_product_info' => apply_filters('fluent_cart/dummy_product_info', []) ?: [],
588 'currency_signs' => CurrenciesHelper::getCurrencySigns(),
589 'filter_options' => $filterOptions,
590 'table_config' => $tableConfig,
591 'receipt_page_url' => $settings->getReceiptPage(),
592 'payment_logos' => PaymentMethods::getIcons(),
593 'is_admin_bar_showing' => is_admin_bar_showing(),
594 'max_upload_size' => size_format($max_upload_size),
595 'available_shipping_method_count' => ShippingMethod::query()->where('is_enabled', '1')->count(),
596 'is_tax_enabled' => TaxModule::isTaxEnabled(),
597 'eu_vat_county_options' => TaxModule::euVatCountyOptions(),
598 'country_tax_titles' => TaxModule::taxTitleLists(),
599 'site_url' => site_url(),
600 'store_logo' => (new \FluentCart\Api\StoreSettings())->get('store_logo.url', ''),
601 'modules_settings' => ModuleSettings::getAllSettings(),
602 'purchase_fluent_cart_link' => 'https://fluentcart.com/',
603 'admin_notices' => apply_filters('fluent_cart/admin_notices', []),
604 // POSTs data-backfills/run until done; endpoint requires manage_options
605 'has_data_migrations' => $hasDataMigrations,
606 'subscription_intervals' => Helper::getAvailableSubscriptionIntervalOptions(),
607
608 'datei18' => DayjsFormatter::localizedStrings(),
609 'el_strings' => TransStrings::elStrings(),
610 'wp_locale' => get_locale(),
611 'is_full_name_required' => CheckoutFieldsSchema::isFullNameRequired(),
612 'business_details' => [
613 'company_name' => [
614 'enabled' => CheckoutFieldsSchema::isCompanyNameEnabled(),
615 'required' => CheckoutFieldsSchema::isCompanyNameRequired(),
616 ],
617 'vat_number' => [
618 'enabled' => CheckoutFieldsSchema::isVatNumberEnabled(),
619 'required' => CheckoutFieldsSchema::isVatNumberRequired(),
620 ],
621 'legal_registration_id' => [
622 'enabled' => CheckoutFieldsSchema::isLegalRegistrationIdEnabled(),
623 'required' => CheckoutFieldsSchema::isLegalRegistrationIdRequired(),
624 ],
625 ],
626 'fct_editor_frame' => '',
627 ]);
628
629 wp_localize_script($slug . '_admin_app_start', 'fluentCartAdminApp', $adminLocalizeData);
630
631 wp_localize_script($slug . '_admin_app_start', 'fluentCartRestVars', [
632 'rest' => $restVars,
633 ]);
634
635 do_action('fluent_cart/admin_js_loaded', $app);
636 }
637
638 public function globalEnqueueAssets($adminBar)
639 {
640 if (function_exists('get_current_screen')) {
641 $screen = get_current_screen();
642 } else {
643 $screen = null;
644 }
645
646 if ($screen && $screen->base !== 'user-edit') {
647 return;
648 }
649
650 $app = App::getInstance();
651
652 $slug = $app->config->get('app.slug');
653 if (is_admin()) {
654 wp_enqueue_script($slug . '_edit_wp_user_admin_global_js', Vite::getEnqueuePath('admin/utils/edit-wp-user-global.js'), ['jquery'], FLUENTCART_VERSION, true);
655 }
656
657
658 $baseUrl = apply_filters('fluent_cart/admin_base_url', admin_url('admin.php?page=fluent-cart#/'), []);
659
660 $editingUserVars = null;
661
662 if (function_exists('get_current_screen')) {
663 $currentScreen = get_current_screen();
664 if ($currentScreen && $currentScreen->id == 'user-edit') {
665 $userId = (int)($_GET['user_id'] ?? 0);
666 $user = get_user_by('ID', $userId);
667
668 if ($userId && $user) {
669 $fluentcartProfile = Customer::query()->where('email', $user->user_email)
670 ->orWhere('user_id', $user->ID)
671 ->first();
672 if ($fluentcartProfile) {
673 $fluentcartProfileUrl = $baseUrl . 'customers/' . $fluentcartProfile->id . '/view';
674 $editingUserVars = [
675 'user_id' => $userId,
676 'fct_profile_id' => $fluentcartProfile->id,
677 'fct_profile_url' => $fluentcartProfileUrl
678 ];
679 }
680 }
681 }
682 }
683 wp_localize_script('fluent-cart_edit_wp_user_admin_global_js', 'fluentcart_edit_user_global_bar_vars', [
684 'customer_base' => $baseUrl . 'customers/',
685 'edit_user_vars' => $editingUserVars
686 ]);
687 }
688
689 protected function getMenuIcon(): string
690 {
691 $svg = '<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100" viewBox="0 0 100 100" fill="none">
692 <g clip-path="url(#clip0_394_8994)">
693 <path d="M90 0C95.5229 0 100 4.47715 100 10V90C100 95.5229 95.5229 100 90 100H10C4.47715 100 0 95.5229 0 90V10C0 4.47715 4.47715 0 10 0H90ZM28.3525 52.5986C24.8927 52.5988 21.7641 54.6544 20.3906 57.8301L15.7119 68.6484H45.5205C52.4408 68.6484 58.6996 64.5355 61.4463 58.1836L63.8613 52.5986H28.3525ZM46.6748 31.333C39.7545 31.333 33.4959 35.4459 30.749 41.7979L28.333 47.3828H70.2617C73.7217 47.3828 76.8513 45.3264 78.2246 42.1504L82.9023 31.333H46.6748Z" fill="#9CA1A8"/>
694 </g>
695 <defs>
696 <clipPath id="clip0_394_8994">
697 <rect width="100" height="100" fill="white"/>
698 </clipPath>
699 </defs>
700 </svg>';
701
702 return 'data:image/svg+xml;base64,' . base64_encode($svg);
703 }
704
705 }
706