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

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

576 lines 23.5 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\Helpers\CurrenciesHelper;
24 use FluentCart\App\Services\Filter\TaxFilter;
25 use FluentCart\App\Services\Filter\OrderFilter;
26 use FluentCart\App\Services\Filter\LicenseFilter;
27 use FluentCart\App\Services\Filter\LicenseSiteFilter;
28 use FluentCart\App\Services\Filter\ProductFilter;
29 use FluentCart\App\Services\Filter\CustomerFilter;
30 use FluentCart\App\Modules\Integrations\AddOnModule;
31 use FluentCart\App\Services\Translations\TransStrings;
32 use FluentCart\App\Services\Permission\PermissionManager;
33 use FluentCart\App\Modules\PaymentMethods\Core\GatewayManager;
34
35 class MenuHandler
36 {
37 public function register()
38 {
39 add_action('init', [$this, 'init']);
40
41 add_action('admin_init', function () {
42 $page = $_GET['page'] ?? '';
43
44 if ($page == 'fluent-cart') {
45
46 \FluentCart\App\Events\FirstTimePluginActivation::handle();
47 add_action('admin_enqueue_scripts', function () {
48 Vite::enqueueStyle('fluent_cart_admin_app_css',
49 'styles/tailwind/style.css',
50 );
51 Vite::enqueueScript('fluent_cart_admin_global_js',
52 'admin/global.js',
53 );
54 });
55
56 }
57 });
58
59 // Add a post display state for special WC pages.
60 add_filter('display_post_states', array($this, 'addDisplayPostStates'), 10, 2);
61
62 }
63
64
65 public function addDisplayPostStates($states, $post)
66 {
67 if (!$post || $post->post_type != 'page') {
68 return $states;
69 }
70
71
72 $targetKeys = [
73 'checkout_page_id' => __('Checkout Page', 'fluent-cart'),
74 'cart_page_id' => __('Cart Page', 'fluent-cart'),
75 'receipt_page_id' => __('Receipt Page', 'fluent-cart'),
76 'shop_page_id' => __('Shop Page', 'fluent-cart'),
77 'customer_profile_page_id' => __('Customer Profile Page', 'fluent-cart'),
78 ];
79
80 $pagesConfig = (new StoreSettings())->getPagesSettings();
81 $pagesConfig = Arr::only($pagesConfig, array_keys($targetKeys));
82
83 if (!is_array($pagesConfig)) {
84 return $states;
85 }
86 $pagesConfig = array_filter($pagesConfig);
87
88 if (empty($pagesConfig)) {
89 return $states;
90 }
91
92
93 $pagesConfig = array_flip($pagesConfig);
94 $targetKey = Arr::get($pagesConfig, $post->ID);
95
96 if ($targetKey && isset($targetKeys[$targetKey])) {
97
98 $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">
99 <rect width="300" height="300" rx="30" fill="white"/>
100 <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"/>
101 <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"/>
102 </svg>';
103
104 $states['fluent_cart'] = '<span>' . $logo . '<span>' . $targetKeys[$targetKey] . '</span></span>';
105 }
106
107 return $states;
108
109 }
110
111 public function init()
112 {
113
114 add_action('admin_menu', array($this, 'addAdminMenu'));
115
116 /*
117 * Disable Gutenberg for Products
118 */
119 add_filter('parent_file', function ($parent_file) {
120 global $submenu_file, $current_screen, $pagenow;
121
122 $postType = $_GET['post_type'] ?? '';
123 if ($postType == FluentProducts::CPT_NAME && $current_screen->post_type == FluentProducts::CPT_NAME) {
124 if ($pagenow == 'post.php') {
125 $submenu_file = 'edit.php?post_type=' . $current_screen->post_type;
126 }
127
128 if ($pagenow == 'edit-tags.php') {
129 $taxonomy = $_GET['taxonomy'] ?? '';
130 $submenu_file = 'edit-tags.php?taxonomy=' . esc_attr($taxonomy) . '&post_type=' . $current_screen->post_type;
131 }
132
133 $parent_file = 'fluent-cart';
134 }
135
136 return $parent_file;
137 });
138
139 add_action('fluent_cart/admin_menu', array($this, 'renderAdminMenu'));
140 // add_action('in_admin_header', array($this, 'maybeRenderAdminMenu'));
141
142 add_action('edit_form_top', array($this, 'pushProductNav'));
143
144 add_action('admin_bar_menu', [$this, 'globalEnqueueAssets'], 10, 1);
145 }
146
147 public function addAdminMenu()
148 {
149 $capability = 'manage_options';
150
151 if (!current_user_can('manage_options') && App::isProActive()) {
152 $capability = PermissionManager::ADMIN_CAP;
153 }
154
155 if (!current_user_can($capability)) {
156 return;
157 }
158
159 global $submenu;
160
161 $adminMenuTitle = apply_filters('fluent_cart/admin_menu_title', 'FluentCart', []);
162
163 add_menu_page(
164 $adminMenuTitle,
165 $adminMenuTitle,
166 $capability,
167 'fluent-cart',
168 [$this, 'renderAdmin'],
169 $this->getMenuIcon(),
170 apply_filters('fluent_cart/admin_menu_position', 3)
171 );
172
173 $submenu['fluent-cart']['dashboard'] = array(
174 __('Dashboard', 'fluent-cart'),
175 $capability,
176 'admin.php?page=fluent-cart#/',
177 '',
178 'fluent_cart_dashboard'
179 );
180
181 if (PermissionManager::hasPermission(['orders/view'])) {
182 $submenu['fluent-cart']['orders'] = array(
183 __('Orders', 'fluent-cart'),
184 $capability,
185 'admin.php?page=fluent-cart#/orders',
186 '',
187 'fluent_cart_orders'
188 );
189 }
190
191 if (PermissionManager::hasPermission(['customers/view', 'customers/manage'])) {
192 $submenu['fluent-cart']['customers'] = array(
193 __('Customers', 'fluent-cart'),
194 $capability,
195 'admin.php?page=fluent-cart#/customers',
196 '',
197 'fluent_cart_customers'
198 );
199 }
200
201 if (PermissionManager::hasPermission(['products/view'])) {
202 $submenu['fluent-cart']['products'] = array(
203 __('Products', 'fluent-cart'),
204 $capability,
205 'admin.php?page=fluent-cart#/products',
206 '',
207 'fluent_cart_products'
208 );
209 }
210
211 if (PermissionManager::hasPermission(['subscriptions/view'])) {
212 $submenu['fluent-cart']['subscriptions'] = array(
213 __('Subscriptions', 'fluent-cart'),
214 $capability,
215 'admin.php?page=fluent-cart#/subscriptions',
216 '',
217 'fluent_cart_subscriptions'
218 );
219 }
220
221 if (PermissionManager::hasPermission(['reports/view'])) {
222 $submenu['fluent-cart']['reports'] = array(
223 __('Reports', 'fluent-cart'),
224 $capability,
225 'admin.php?page=fluent-cart#/reports/overview',
226 '',
227 'fluent_cart_reports'
228 );
229 }
230
231 if (PermissionManager::userCan('is_super_admin')) {
232 $submenu['fluent-cart']['integrations'] = array(
233 __('Integrations', 'fluent-cart'),
234 $capability,
235 'admin.php?page=fluent-cart#/integrations',
236 '',
237 'fluent_cart_integrations'
238 );
239 }
240
241
242 $hasSensitiveAccess = PermissionManager::hasPermission(['store/settings', 'store/sensitive']);
243
244 if ($hasSensitiveAccess) {
245 $submenu['fluent-cart']['settings'] = array(
246 __('Settings', 'fluent-cart'),
247 $capability,
248 'admin.php?page=fluent-cart#/settings/store-settings/',
249 '',
250 'fluent_cart_settings'
251 );
252 }
253
254 if (PermissionManager::hasPermission(['coupons/manage', 'coupons/view'])) {
255 $submenu['fluent-cart']['coupons'] = array(
256 __('Coupons', 'fluent-cart'),
257 $capability,
258 'admin.php?page=fluent-cart#/coupons',
259 '',
260 'fluent_cart_coupons'
261 );
262 }
263
264 if ($hasSensitiveAccess && TaxModule::isTaxEnabled()) {
265 $submenu['fluent-cart']['taxes'] = array(
266 __('Taxes', 'fluent-cart'),
267 $capability,
268 'admin.php?page=fluent-cart#/taxes',
269 '',
270 'fluent_cart_taxes'
271 );
272 }
273
274
275 if (PermissionManager::hasPermission(['products/create', 'products/edit'])) {
276 $taxonomies = get_taxonomies([
277 'object_type' => [FluentProducts::CPT_NAME],
278 'public' => true,
279 ], 'object');
280
281 foreach ($taxonomies as $key => $taxonomy) {
282 $menuUrl = 'edit-tags.php?taxonomy=' . $taxonomy->name . '&post_type=' . FluentProducts::CPT_NAME;
283 $submenu['fluent-cart'][$key] = [
284 $taxonomy->label,
285 $capability,
286 $menuUrl,
287 '',
288 $taxonomy->name
289 ];
290 }
291 }
292
293 if (PermissionManager::userCan('is_super_admin')) {
294 $submenu['fluent-cart']['logs'] = array(
295 __('Logs', 'fluent-cart'),
296 $capability,
297 'admin.php?page=fluent-cart#/logs',
298 '',
299 'fluent_cart_logs'
300 );
301 }
302
303 do_action('fluent_cart/admin_submenu_added', $submenu);
304 }
305
306 public function renderAdmin()
307 {
308 $isCustomDashboardSlugChanged = (new StoreSettings())->getCustomerDashboardPageSlug() != (new StoreSettings())->get('customer_profile_page_slug');
309
310 if ($isCustomDashboardSlugChanged) {
311 $allSettings = (new StoreSettings())->get();
312 (new StoreSettings())->save($allSettings); // we are just resaving to flash the settings cache
313 }
314
315 if (function_exists('wp_enqueue_editor')) {
316 wp_enqueue_editor();
317 wp_tinymce_inline_scripts();
318 wp_enqueue_media();
319 }
320
321 $this->enqueueAssets();
322
323 $config = App::getInstance('config');
324
325 $name = $config->get('app.name');
326
327 $slug = $config->get('app.slug');
328
329 $baseUrl = apply_filters('fluent_connector_base_url', admin_url('admin.php?page=newproject#/'));
330
331 $app = App::getInstance();
332 $assets = $app['url.assets'];
333
334 App::make('view')->render('admin.admin_app', [
335 'name' => $name,
336 'slug' => $slug,
337 'baseUrl' => $baseUrl,
338 'logo' => $assets . 'images/logo.svg',
339 ]);
340 }
341
342 public function maybeRenderAdminMenu()
343 {
344 $postType = $_GET['post_type'] ?? '';
345 if ($postType == FluentProducts::CPT_NAME && is_admin()) {
346 AdminHelper::getAdminMenu(true);
347 AdminHelper::pushGlobalAdminAssets();
348 }
349 }
350
351 public function renderAdminMenu()
352 {
353 AdminHelper::getAdminMenu(true);
354 }
355
356 public function pushProductNav($post)
357 {
358 if (!$post || $post->post_type != FluentProducts::CPT_NAME) {
359 return;
360 }
361
362 AdminHelper::getProductMenu($post->ID, true, 'product_edit');
363 AdminHelper::pushGlobalAdminAssets();
364 }
365
366 public function enqueueAssets()
367 {
368 $app = App::getInstance();
369
370 $slug = $app->config->get('app.slug');
371
372 do_action('fluent_cart/loading_app', $app);
373
374 //This should be done before enqueueing the global script.
375 Vite::enqueueScript($slug . '_admin_app_start', 'admin/bootstrap/app.js', [$slug . '_global_admin_hooks']);
376
377 //Don't register this script using vite.
378 wp_enqueue_script($slug . '_global_admin_hooks', Vite::getEnqueuePath('admin/admin_hooks.js'), [], FLUENTCART_VERSION, true);
379
380 $manager = GatewayManager::getInstance();
381 $payment_routes = $manager->getRoutes();
382 // $payment_routes = apply_filters('fluent_cart/payments/payment_method_settings_routes', []);
383
384 $storage_driver_routes = apply_filters('fluent_cart/storage/storage_driver_settings_routes', [], []);
385
386 $settings = new StoreSettings();
387 $checkoutUrl = add_query_arg(Helper::INSTANT_CHECKOUT_URL_PARAM, '=', $settings->getCheckoutPage());
388 $restVars = Helper::getRestInfo();
389
390 $filterOptions = [
391 'order_filter_options' => OrderFilter::getTableFilterOptions(),
392 'customer_filter_options' => CustomerFilter::getTableFilterOptions(),
393 'product_filter_options' => ProductFilter::getTableFilterOptions(),
394 'license_filter_options' => LicenseFilter::getTableFilterOptions(),
395 'license_site_filter_options' => LicenseSiteFilter::getTableFilterOptions(),
396 'tax_filter_options' => TaxFilter::getTableFilterOptions(),
397 ];
398 $filterOptions = apply_filters('fluent_cart/admin_filter_options', $filterOptions, []);
399
400 // Structured table config keyed by table name (used by Table.js base class)
401 $tableConfig = [
402 'order_table' => ['filters' => Arr::get($filterOptions, 'order_filter_options', [])],
403 'customers' => ['filters' => Arr::get($filterOptions, 'customer_filter_options', [])],
404 'product_table' => ['filters' => Arr::get($filterOptions, 'product_filter_options', [])],
405 'licenses' => ['filters' => Arr::get($filterOptions, 'license_filter_options', [])],
406 'license_sites' => ['filters' => Arr::get($filterOptions, 'license_site_filter_options', [])],
407 'taxes_table' => ['filters' => Arr::get($filterOptions, 'tax_filter_options', [])],
408 'subscriptions' => ['filters' => Arr::get($filterOptions, 'subscription_filter_options', [])],
409 'shipping_zone_table' => ['filters' => Arr::get($filterOptions, 'shipping_zone_filter_options', [])],
410 ];
411
412 $tableConfig = apply_filters('fluent_cart/admin_table_saved_views', $tableConfig, [
413 'filterOptions' => $filterOptions
414 ]);
415
416 $currentUser = get_user_by('ID', get_current_user_id());
417
418 // Get app config and merge additional properties into it
419 $appConfig = $app->config->get('app');
420 $appConfig['version'] = FLUENTCART_VERSION;
421 $appConfig['permissions'] = PermissionManager::getUserPermissions();
422 $appConfig['isProActive'] = App::isProActive();
423 $appConfig['proVersion'] = defined('FLUENTCART_PRO_PLUGIN_VERSION') ? FLUENTCART_PRO_PLUGIN_VERSION : null;
424
425 $appConfig['logos'] = [
426 'dark' => Vite::getAssetUrl('images/logo/logo-full-dark.svg'),
427 'light' => Vite::getAssetUrl('images/logo/logo-full.svg'),
428 ];
429 $appConfig['isModuleTabEnabled'] = $settings->isModuleTabEnabled();
430 $appConfig['upgrade_url'] = 'https://fluentcart.com/pricing/';
431
432 $max_upload_size = wp_max_upload_size(); // Returns size in bytes
433 $adminLocalizeData = apply_filters('fluent_cart/admin_app_data', [
434 'app_config' => $appConfig,
435 'slug' => $app->config->get('app.slug'),
436 'admin_url' => admin_url('admin.php?page=fluent-cart#/'),
437 'frontend_url' => URL::getFrontEndUrl(''),
438 'nonce' => wp_create_nonce($slug),
439 'rest' => $restVars,
440 'brand_logo' => $this->getMenuIcon(),
441 'asset_url' => Vite::getAssetUrl(),
442 'me' => [
443 'id' => $currentUser->ID,
444 'full_name' => trim($currentUser->display_name),
445 'email' => $currentUser->user_email,
446 'avatar' => get_avatar_url($currentUser->ID)
447 ],
448 'shop' => Helper::shopConfig(),
449 'product_statuses' => Status::getProductStatuses(),
450 'total_products_count' => Product::query()->count(),
451 'payment_statuses' => Status::getEditableTransactionStatuses(true),
452 'payment_routes' => $payment_routes,
453 'storage_driver_routes' => $storage_driver_routes,
454 'editable_payment_statuses' => Status::getEditableTransactionStatuses(true),
455 'order_statuses' => Status::getOrderStatuses(),
456 'editable_order_statuses' => Status::getEditableOrderStatuses(),
457 'editable_customer_statuses' => Status::getEditableCustomerStatuses(),
458 // Backward compat: keep the old typo'd keys for existing frontend code
459 'order_statues' => Status::getOrderStatuses(),
460 'editable_order_statues' => Status::getEditableOrderStatuses(),
461 'editable_customer_statues' => Status::getEditableCustomerStatuses(),
462 'shipping_statuses' => Status::getShippingStatuses(),
463 'allow_bulk_payment_status_change' => true,
464 'variation_attributes' => AttributeGroup::with(['terms'])->get(),
465 'variation_terms' => AttributeTerm::query()->get()->keyBy('id'),
466 'product_image_base_uri' => Helper::getProductImageBaseUri(),
467 'add_on_modules' => AddOnModule::showAddOns(),
468 'stock_statuses' => Status::getStockStatuses(),
469 'fulfillment_types' => Helper::getFulfilmentTypes(),
470 'variation_types' => Helper::getVariationTypes(),
471 'trans' => TransStrings::getStrings(),
472 'dashboard_url' => admin_url('admin.php?page=fluent-cart#'),
473 'checkout_url' => $checkoutUrl,
474 'dummy_product_info' => apply_filters('fluent_cart/dummy_product_info', []) ?: [],
475 'currency_signs' => CurrenciesHelper::getCurrencySigns(),
476 'filter_options' => $filterOptions,
477 'table_config' => $tableConfig,
478 'receipt_page_url' => $settings->getReceiptPage(),
479 'payment_logos' => PaymentMethods::getIcons(),
480 'is_admin_bar_showing' => is_admin_bar_showing(),
481 'max_upload_size' => size_format($max_upload_size),
482 'available_shipping_method_count' => ShippingMethod::query()->where('is_enabled', '1')->count(),
483 'is_tax_enabled' => TaxModule::isTaxEnabled(),
484 'eu_vat_county_options' => TaxModule::euVatCountyOptions(),
485 'country_tax_titles' => TaxModule::taxTitleLists(),
486 'site_url' => site_url(),
487 'modules_settings' => ModuleSettings::getAllSettings(),
488 'purchase_fluent_cart_link' => 'https://fluentcart.com/',
489 'admin_notices' => apply_filters('fluent_cart/admin_notices', []),
490 'subscription_intervals' => Helper::getAvailableSubscriptionIntervalOptions(),
491
492 'datei18' => TransStrings::dateTimeStrings(),
493 'el_strings' => TransStrings::elStrings(),
494 'wp_locale' => get_locale(),
495 'is_full_name_required' => CheckoutFieldsSchema::isFullNameRequired(),
496 'fct_editor_frame' => '',
497 ]);
498
499 wp_localize_script($slug . '_admin_app_start', 'fluentCartAdminApp', $adminLocalizeData);
500
501 wp_localize_script($slug . '_admin_app_start', 'fluentCartRestVars', [
502 'rest' => $restVars,
503 ]);
504
505 do_action('fluent_cart/admin_js_loaded', $app);
506 }
507
508 public function globalEnqueueAssets($adminBar)
509 {
510 if (function_exists('get_current_screen')) {
511 $screen = get_current_screen();
512 } else {
513 $screen = null;
514 }
515
516 if ($screen && $screen->base !== 'user-edit') {
517 return;
518 }
519
520 $app = App::getInstance();
521
522 $slug = $app->config->get('app.slug');
523 if (is_admin()) {
524 wp_enqueue_script($slug . '_edit_wp_user_admin_global_js', Vite::getEnqueuePath('admin/utils/edit-wp-user-global.js'), ['jquery'], FLUENTCART_VERSION, true);
525 }
526
527
528 $baseUrl = apply_filters('fluent_cart/admin_base_url', admin_url('admin.php?page=fluent-cart#/'), []);
529
530 $editingUserVars = null;
531
532 if (function_exists('get_current_screen')) {
533 $currentScreen = get_current_screen();
534 if ($currentScreen && $currentScreen->id == 'user-edit') {
535 $userId = (int)($_GET['user_id'] ?? 0);
536 $user = get_user_by('ID', $userId);
537
538 if ($userId && $user) {
539 $fluentcartProfile = Customer::query()->where('email', $user->user_email)
540 ->orWhere('user_id', $user->ID)
541 ->first();
542 if ($fluentcartProfile) {
543 $fluentcartProfileUrl = $baseUrl . 'customers/' . $fluentcartProfile->id . '/view';
544 $editingUserVars = [
545 'user_id' => $userId,
546 'fct_profile_id' => $fluentcartProfile->id,
547 'fct_profile_url' => $fluentcartProfileUrl
548 ];
549 }
550 }
551 }
552 }
553 wp_localize_script('fluent-cart_edit_wp_user_admin_global_js', 'fluentcart_edit_user_global_bar_vars', [
554 'customer_base' => $baseUrl . 'customers/',
555 'edit_user_vars' => $editingUserVars
556 ]);
557 }
558
559 protected function getMenuIcon(): string
560 {
561 $svg = '<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100" viewBox="0 0 100 100" fill="none">
562 <g clip-path="url(#clip0_394_8994)">
563 <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"/>
564 </g>
565 <defs>
566 <clipPath id="clip0_394_8994">
567 <rect width="100" height="100" fill="white"/>
568 </clipPath>
569 </defs>
570 </svg>';
571
572 return 'data:image/svg+xml;base64,' . base64_encode($svg);
573 }
574
575 }
576