| @@ -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,19 @@ | ||
| 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\Services\Filter\ReviewFilter; | |
| 36 | +use FluentCart\App\Modules\Shipping\Services\Filter\ShippingClassFilter; | |
| 37 | +use FluentCart\App\Modules\Shipping\Services\Filter\ShippingZoneFilter; | |
| 30 | 38 | use FluentCart\App\Modules\Integrations\AddOnModule; |
| 39 | +use FluentCart\App\Services\DateTime\DayjsFormatter; | |
| 31 | 40 | use FluentCart\App\Services\Translations\TransStrings; |
| 32 | 41 | use FluentCart\App\Services\Permission\PermissionManager; |
| 42 | +use FluentCart\Database\DataBackfills; | |
| 33 | 43 | use FluentCart\App\Modules\PaymentMethods\Core\GatewayManager; |
| 34 | 44 | |
| 35 | 45 | class MenuHandler |
| 36 | 46 | { |
| @@ -43,8 +53,9 @@ | ||
| 43 | 53 | |
| 44 | 54 | if ($page == 'fluent-cart') { |
| 45 | 55 | |
| 46 | 56 | \FluentCart\App\Events\FirstTimePluginActivation::handle(); |
| 57 | + (new AdminFooter())->register(); | |
| 47 | 58 | add_action('admin_enqueue_scripts', function () { |
| 48 | 59 | Vite::enqueueStyle('fluent_cart_admin_app_css', |
| 49 | 60 | 'styles/tailwind/style.css', |
| 50 | 61 | ); |
| @@ -78,8 +89,9 @@ | ||
| 78 | 89 | $targetKeys = [ |
| 79 | 90 | 'checkout_page_id' => __('Checkout Page', 'fluent-cart'), |
| 80 | 91 | 'cart_page_id' => __('Cart Page', 'fluent-cart'), |
| 81 | 92 | 'receipt_page_id' => __('Receipt Page', 'fluent-cart'), |
| 93 | + 'order_review_page_id' => __('Order Review Page', 'fluent-cart'), | |
| 82 | 94 | 'shop_page_id' => __('Shop Page', 'fluent-cart'), |
| 83 | 95 | 'customer_profile_page_id' => __('Customer Profile Page', 'fluent-cart'), |
| 84 | 96 | ]; |
| 85 | 97 | |
| @@ -438,9 +450,10 @@ | ||
| 438 | 450 | |
| 439 | 451 | do_action('fluent_cart/loading_app', $app); |
| 440 | 452 | |
| 441 | 453 | //This should be done before enqueueing the global script. |
| 442 | - Vite::enqueueScript($slug . '_admin_app_start', 'admin/bootstrap/app.js', [$slug . '_global_admin_hooks']); | |
| 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']); | |
| 443 | 456 | |
| 444 | 457 | //Don't register this script using vite. |
| 445 | 458 | if (!wp_script_is('wp-hooks', 'registered')) { |
| 446 | 459 | $suffix = (defined('SCRIPT_DEBUG') && SCRIPT_DEBUG) ? '' : '.min'; |
| @@ -460,8 +473,9 @@ | ||
| 460 | 473 | |
| 461 | 474 | $settings = new StoreSettings(); |
| 462 | 475 | $checkoutUrl = add_query_arg(Helper::INSTANT_CHECKOUT_URL_PARAM, '=', $settings->getCheckoutPage()); |
| 463 | 476 | $restVars = Helper::getRestInfo(); |
| 477 | + $hasDataMigrations = current_user_can('manage_options') && DataBackfills::hasPending(); | |
| 464 | 478 | |
| 465 | 479 | $filterOptions = [ |
| 466 | 480 | 'order_filter_options' => OrderFilter::getTableFilterOptions(), |
| 467 | 481 | 'customer_filter_options' => CustomerFilter::getTableFilterOptions(), |
| @@ -468,8 +482,9 @@ | ||
| 468 | 482 | 'product_filter_options' => ProductFilter::getTableFilterOptions(), |
| 469 | 483 | 'license_filter_options' => LicenseFilter::getTableFilterOptions(), |
| 470 | 484 | 'license_site_filter_options' => LicenseSiteFilter::getTableFilterOptions(), |
| 471 | 485 | 'tax_filter_options' => TaxFilter::getTableFilterOptions(), |
| 486 | + 'review_filter_options' => ReviewFilter::getTableFilterOptions(), | |
| 472 | 487 | ]; |
| 473 | 488 | $filterOptions = apply_filters('fluent_cart/admin_filter_options', $filterOptions, []); |
| 474 | 489 | |
| 475 | 490 | // Structured table config keyed by table name (used by Table.js base class) |
| @@ -481,10 +496,31 @@ | ||
| 481 | 496 | 'license_sites' => ['filters' => Arr::get($filterOptions, 'license_site_filter_options', [])], |
| 482 | 497 | 'taxes_table' => ['filters' => Arr::get($filterOptions, 'tax_filter_options', [])], |
| 483 | 498 | 'subscriptions' => ['filters' => Arr::get($filterOptions, 'subscription_filter_options', [])], |
| 484 | 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', [])], | |
| 485 | 504 | ]; |
| 486 | 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 | + | |
| 487 | 523 | $tableConfig = apply_filters('fluent_cart/admin_table_saved_views', $tableConfig, [ |
| 488 | 524 | 'filterOptions' => $filterOptions |
| 489 | 525 | ]); |
| 490 | 526 | |
| @@ -495,8 +531,9 @@ | ||
| 495 | 531 | $appConfig['version'] = FLUENTCART_VERSION; |
| 496 | 532 | $appConfig['permissions'] = PermissionManager::getUserPermissions(); |
| 497 | 533 | $appConfig['isProActive'] = App::isProActive(); |
| 498 | 534 | $appConfig['proVersion'] = defined('FLUENTCART_PRO_PLUGIN_VERSION') ? FLUENTCART_PRO_PLUGIN_VERSION : null; |
| 535 | + $appConfig['fluentPlayer'] = FluentPlayerBridge::adminAppConfig(); | |
| 499 | 536 | |
| 500 | 537 | $appConfig['logos'] = [ |
| 501 | 538 | 'dark' => Vite::getAssetUrl('images/logo/logo-full-dark.svg'), |
| 502 | 539 | 'light' => Vite::getAssetUrl('images/logo/logo-full.svg'), |
| @@ -501,9 +538,9 @@ | ||
| 501 | 538 | 'dark' => Vite::getAssetUrl('images/logo/logo-full-dark.svg'), |
| 502 | 539 | 'light' => Vite::getAssetUrl('images/logo/logo-full.svg'), |
| 503 | 540 | ]; |
| 504 | 541 | $appConfig['isModuleTabEnabled'] = $settings->isModuleTabEnabled(); |
| 505 | - $appConfig['upgrade_url'] = 'https://fluentcart.com/pricing/'; | |
| 542 | + $appConfig['upgrade_url'] = Helper::getUpgradeUrl(); | |
| 506 | 543 | |
| 507 | 544 | $max_upload_size = wp_max_upload_size(); // Returns size in bytes |
| 508 | 545 | $adminLocalizeData = apply_filters('fluent_cart/admin_app_data', [ |
| 509 | 546 | 'app_config' => $appConfig, |
| @@ -508,8 +545,9 @@ | ||
| 508 | 545 | $adminLocalizeData = apply_filters('fluent_cart/admin_app_data', [ |
| 509 | 546 | 'app_config' => $appConfig, |
| 510 | 547 | 'slug' => $app->config->get('app.slug'), |
| 511 | 548 | 'admin_url' => admin_url('admin.php?page=fluent-cart#/'), |
| 549 | + 'wp_admin_url' => rtrim(admin_url(), '/'), | |
| 512 | 550 | 'frontend_url' => URL::getFrontEndUrl(''), |
| 513 | 551 | 'nonce' => wp_create_nonce($slug), |
| 514 | 552 | 'rest' => $restVars, |
| 515 | 553 | 'brand_logo' => $this->getMenuIcon(), |
| @@ -534,9 +572,8 @@ | ||
| 534 | 572 | 'order_statues' => Status::getOrderStatuses(), |
| 535 | 573 | 'editable_order_statues' => Status::getEditableOrderStatuses(), |
| 536 | 574 | 'editable_customer_statues' => Status::getEditableCustomerStatuses(), |
| 537 | 575 | 'shipping_statuses' => Status::getShippingStatuses(), |
| 538 | - 'allow_bulk_payment_status_change' => true, | |
| 539 | 576 | // Attribute library powering the Advanced Variation feature. |
| 540 | 577 | 'variation_attributes' => AttributeGroup::with(['terms'])->get(), |
| 541 | 578 | 'variation_terms' => AttributeTerm::query()->get()->keyBy('id'), |
| 542 | 579 | 'product_image_base_uri' => Helper::getProductImageBaseUri(), |
| @@ -559,14 +596,17 @@ | ||
| 559 | 596 | 'is_tax_enabled' => TaxModule::isTaxEnabled(), |
| 560 | 597 | 'eu_vat_county_options' => TaxModule::euVatCountyOptions(), |
| 561 | 598 | 'country_tax_titles' => TaxModule::taxTitleLists(), |
| 562 | 599 | 'site_url' => site_url(), |
| 600 | + 'store_logo' => (new \FluentCart\Api\StoreSettings())->get('store_logo.url', ''), | |
| 563 | 601 | 'modules_settings' => ModuleSettings::getAllSettings(), |
| 564 | 602 | 'purchase_fluent_cart_link' => 'https://fluentcart.com/', |
| 565 | 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, | |
| 566 | 606 | 'subscription_intervals' => Helper::getAvailableSubscriptionIntervalOptions(), |
| 567 | 607 | |
| 568 | - 'datei18' => TransStrings::dateTimeStrings(), | |
| 608 | + 'datei18' => DayjsFormatter::localizedStrings(), | |
| 569 | 609 | 'el_strings' => TransStrings::elStrings(), |
| 570 | 610 | 'wp_locale' => get_locale(), |
| 571 | 611 | 'is_full_name_required' => CheckoutFieldsSchema::isFullNameRequired(), |
| 572 | 612 | 'business_details' => [ |