PluginProbe
StoreEngine — Complete eCommerce Solution with Memberships, Licensing, Affiliates & More / 2.1.0
StoreEngine — Complete eCommerce Solution with Memberships, Licensing, Affiliates & More v2.1.0
2.3.0 2.2.0 2.1.1 2.1.0 2.0.0 1.10.0 1.9.1 1.9.0 1.2.1 1.2.2 1.3.0 1.3.1 1.3.2 1.3.3 1.4.0 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 1.5.5 1.5.6 1.5.7 1.5.8 1.6.0 All 59 releases
storeengine / includes / assets.php

assets.php in StoreEngine — Complete eCommerce Solution with Memberships, Licensing, Affiliates & More 2.1.0, at includes/assets.php

641 lines 23.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace StoreEngine;
4
5 use StoreEngine\Admin\Notices;
6 use StoreEngine\Classes\Countries;
7 use StoreEngine\Classes\Order;
8 use StoreEngine\Classes\Product\VariableProduct;
9 use StoreEngine\Utils\ArrayUtil;
10 use StoreEngine\Utils\Formatting;
11 use StoreEngine\Utils\Helper;
12 use StoreEngine\Utils\PaymentUtil;
13 use StoreEngine\Utils\Pixel;
14
15 if ( ! defined( 'ABSPATH' ) ) {
16 exit(); // Exit if accessed directly.
17 }
18
19 class Assets {
20
21 public static function init() {
22 $self = new self();
23 add_action( 'admin_enqueue_scripts', array( $self, 'enqueue_admin_menu_css' ) );
24 add_action( 'admin_enqueue_scripts', [ $self, 'backend_scripts' ] );
25 add_action( 'admin_enqueue_scripts', [ $self, 'backend_inline_style' ] );
26 add_action( 'wp_enqueue_scripts', [ $self, 'frontend_scripts' ] );
27 add_action( 'enqueue_block_editor_assets', [ $self, 'block_editor_assets' ] );
28 add_action( 'wp_footer', [ $self, 'display_price_placeholder' ] );
29 }
30
31 public function web_fonts_url( $font ): string {
32 $font_url = add_query_arg( 'family', rawurlencode( $font ), '//fonts.googleapis.com/css2' );
33
34 return add_query_arg( 'display', 'swap', $font_url );
35 }
36
37 public function enqueue_admin_menu_css( $hook ) {
38 wp_enqueue_style( 'storeengine-admin-menu', STOREENGINE_ASSETS_URI . 'css/menu.css', [], STOREENGINE_VERSION, 'all' );
39
40 if ( strpos( $hook, '_page_' . STOREENGINE_PLUGIN_SLUG ) !== false ) {
41 return;
42 }
43
44 Notices::init()->dispatch_notices();
45 if ( ! empty( Admin\Notices::get_notices() ) ) {
46 wp_enqueue_style( 'storeengine-admin-notice', STOREENGINE_ASSETS_URI . 'css/notices.css', [], STOREENGINE_VERSION, 'all' );
47 wp_add_inline_style( 'storeengine-admin-notice', $this->get_dynamic_css() );
48 wp_enqueue_style(
49 'storeengine-frontend-icon',
50 STOREENGINE_ASSETS_URI . 'library/icons/storeengine-icons.css',
51 [],
52 filemtime( STOREENGINE_ASSETS_DIR_PATH . 'library/icons/storeengine-icons.css' )
53 );
54 }
55 }
56
57 public function frontend_scripts() {
58 // Icon Library.
59 wp_enqueue_style(
60 'storeengine-frontend-icon',
61 STOREENGINE_ASSETS_URI . 'library/icons/storeengine-icons.css',
62 [ 'wp-components' ],
63 filemtime(
64 STOREENGINE_ASSETS_DIR_PATH .
65 'library/icons/storeengine-icons.css'
66 ),
67 'all'
68 );
69
70 // Main Stylesheet.
71 wp_enqueue_style(
72 'storeengine-frontend-style',
73 STOREENGINE_ASSETS_URI . 'build/frontend.css',
74 [],
75 filemtime( STOREENGINE_ASSETS_DIR_PATH . 'build/frontend.css' ),
76 'all'
77 );
78
79 // Add dynamic CSS variables.
80 wp_add_inline_style( 'storeengine-frontend-style', $this->get_dynamic_css() );
81
82 wp_enqueue_style( 'storeengine-web-font', $this->web_fonts_url( 'Poppins:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900' ) ); // phpcs:ignore WordPress.WP.EnqueuedResourceParameters.MissingVersion
83
84 // Add Flickity CSS.
85 if ( Helper::is_product() ) {
86 wp_enqueue_style(
87 'flickity',
88 STOREENGINE_ASSETS_URI . 'library/flickity/flickity.min.css',
89 [],
90 STOREENGINE_VERSION,
91 null
92 );
93 }
94
95 // JS — use `include` (not `include_once`) so a second hook invocation in
96 // the same request still gets the array; `*_once` returns int(1) after
97 // the first include and breaks the array_merge below.
98 $asset_file = STOREENGINE_ASSETS_DIR_PATH . sprintf( 'build/frontend.%s.asset.php', STOREENGINE_VERSION );
99 $dependencies = is_file( $asset_file ) ? include $asset_file : null;
100 if ( ! is_array( $dependencies ) ) {
101 $dependencies = [ 'dependencies' => [], 'version' => STOREENGINE_VERSION ];
102 }
103
104 do_action( 'storeengine/enqueue_frontend_scripts' );
105
106 wp_enqueue_script(
107 'storeengine-frontend-scripts',
108 STOREENGINE_ASSETS_URI .
109 sprintf( 'build/frontend.%s.js', STOREENGINE_VERSION ),
110 array_merge( [ 'jquery', 'wp-util' ], (array) ( $dependencies['dependencies'] ?? [] ) ),
111 $dependencies['version'] ?? STOREENGINE_VERSION,
112 true
113 );
114
115 if ( Helper::is_product() ) {
116 global $product;
117
118 if ( $product instanceof VariableProduct && 'variable' === $product->get_type() ) {
119 wp_localize_script(
120 'storeengine-frontend-scripts',
121 'StoreEngineProductVariations',
122 self::get_product_variations( $product )
123 );
124 }
125
126 }
127
128 $analytics = (array) Helper::get_settings( 'analytics', [] );
129 if ( ArrayUtil::any( $analytics, fn( $stat ) => true === $stat ) ) {
130 $data = [];
131 if ( Helper::is_product() ) {
132 $data = Pixel::get_single_product_data();
133 }
134 if ( Helper::is_shop() ) {
135 $data = Pixel::get_product_archive_data();
136 }
137 if ( Helper::is_cart() || Helper::is_checkout() ) {
138 $data = [ 'cart_info' => Pixel::get_cart_info() ];
139 }
140 if ( Helper::is_thank_you() ) {
141 // Provide the completed order so the GA4 `purchase` event can
142 // fire on the thank-you page (see google.ts), attributing the
143 // conversion + revenue to this URL instead of the checkout page.
144 $data = $this->get_thankyou_pixel_data();
145 }
146 wp_localize_script(
147 'storeengine-frontend-scripts',
148 'SEPixelData',
149 array_merge(
150 [
151 'page_title' => wp_get_document_title(),
152 'currency' => Formatting::get_currency(),
153 ],
154 $data
155 )
156 );
157 }
158
159 wp_localize_script(
160 'storeengine-frontend-scripts',
161 'StoreEngineGlobal',
162 $this->get_frontend_script_data()
163 );
164
165 wp_set_script_translations(
166 'storeengine-frontend-scripts',
167 'storeengine',
168 STOREENGINE_ROOT_DIR_PATH . 'languages'
169 );
170
171 // Add Flickity JS
172 if ( Helper::is_product() ) {
173 wp_enqueue_script(
174 'flickity',
175 STOREENGINE_ASSETS_URI . 'library/flickity/flickity.pkgd.min.js',
176 [],
177 STOREENGINE_VERSION,
178 true
179 );
180 }
181
182 do_action( 'storeengine/assets/after_frontend_scripts' );
183 }
184
185 /**
186 * Completed-order data for the thank-you page GA4 `purchase` event.
187 *
188 * Returned under an `order` key inside SEPixelData and consumed by
189 * dev_storeengine/pixel-integrations/google.ts. The shape mirrors the
190 * checkout REST response's `order`, limited to the fields the analytics
191 * integration reads. Building it here (rather than re-running the checkout
192 * response pipeline) avoids re-firing payment-success side effects.
193 *
194 * @return array Either [ 'order' => [...] ] or [] when no valid order.
195 */
196 private function get_thankyou_pixel_data(): array {
197 // phpcs:ignore WordPress.Security.NonceVerification.Recommended
198 $order_hash = isset( $_GET['order_hash'] ) ? sanitize_text_field( wp_unslash( $_GET['order_hash'] ) ) : '';
199 if ( '' === $order_hash ) {
200 return [];
201 }
202
203 try {
204 $order = Helper::get_order_by_key( $order_hash );
205 } catch ( \Throwable $e ) {
206 return [];
207 }
208
209 if ( ! $order instanceof Order || is_wp_error( $order ) || ! $order->get_id() ) {
210 return [];
211 }
212
213 $line_items = [];
214 foreach ( $order->get_items( 'line_item' ) as $item ) {
215 $meta = [];
216 foreach ( (array) $item->get_meta_data() as $m ) {
217 if ( is_object( $m ) && isset( $m->key ) ) {
218 $meta[] = [
219 'key' => $m->key,
220 'value' => $m->value ?? '',
221 ];
222 }
223 }
224
225 $line_items[] = [
226 'product_id' => $item->get_product_id(),
227 'price_id' => $item->get_price_id(),
228 'name' => $item->get_name(),
229 'price' => $item->get_price(),
230 'quantity' => $item->get_quantity(),
231 'subtotal' => $item->get_subtotal(),
232 'total' => $item->get_total(),
233 'variation_id' => $item->get_variation_id(),
234 'price_type' => $item->get_price_type(),
235 'meta' => $meta,
236 ];
237 }
238
239 $coupon_lines = array_map(
240 static function ( $code ) {
241 return [ 'code' => $code ];
242 },
243 array_values( array_filter( (array) $order->get_coupon_codes() ) )
244 );
245
246 return [
247 'order' => [
248 'transaction_id' => $order->get_transaction_id(),
249 'order_key' => $order->get_order_key(),
250 'currency' => $order->get_currency(),
251 'total' => $order->get_total(),
252 'total_tax' => $order->get_total_tax(),
253 'shipping_total_amount' => $order->get_shipping_total(),
254 'discount_total_amount' => $order->get_discount_total(),
255 'coupon_lines' => $coupon_lines,
256 'line_items' => $line_items,
257 ],
258 ];
259 }
260
261 /**
262 * Enqueue Block Editor Assets
263 *
264 * @since 1.3.3
265 */
266 public function block_editor_assets() {
267 // Check if the aBlocks plugin is active before enqueuing styles.
268 if ( ! Helper::is_plugin_active( 'ablocks/ablocks.php' ) ) {
269 return;
270 }
271
272 // Icon Library.
273 wp_enqueue_style(
274 'storeengine-frontend-icon',
275 STOREENGINE_ASSETS_URI . 'library/icons/storeengine-icons.css',
276 [ 'wp-components' ],
277 filemtime(
278 STOREENGINE_ASSETS_DIR_PATH .
279 'library/icons/storeengine-icons.css'
280 ),
281 'all'
282 );
283
284 // Main Stylesheet.
285 wp_enqueue_style(
286 'storeengine-frontend-style',
287 STOREENGINE_ASSETS_URI . 'build/frontend.css',
288 [],
289 filemtime( STOREENGINE_ASSETS_DIR_PATH . 'build/frontend.css' ),
290 'all'
291 );
292
293 // Add dynamic CSS variables.
294 wp_add_inline_style( 'storeengine-frontend-style', $this->get_dynamic_css() );
295
296 wp_enqueue_style( 'storeengine-web-font', $this->web_fonts_url( 'Poppins:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900' ) ); // phpcs:ignore WordPress.WP.EnqueuedResourceParameters.MissingVersion
297
298 // Add Flickity CSS.
299 wp_enqueue_style(
300 'flickity',
301 STOREENGINE_ASSETS_URI . 'library/flickity/flickity.min.css',
302 [],
303 STOREENGINE_VERSION,
304 null
305 );
306 }
307
308 public static function get_product_variations( VariableProduct $product ): array {
309 $pricing = [];
310 $taxonomies = [];
311 $variations = array_map( function ( $variant ) use ( &$taxonomies ) {
312 $attributes = [];
313 foreach ( $variant->get_attributes() as $attribute ) {
314 $attributes[ $attribute->taxonomy ] = $attribute->slug;
315 $taxonomies[] = $attribute->taxonomy;
316 }
317
318 return [
319 'id' => $variant->get_id(),
320 'name' => $variant->get_name(),
321 'price' => $variant->get_price(),
322 'sku' => $variant->get_sku(),
323 'pricing_id' => (int) $variant->get_pricing_id(),
324 'featured_image_url' => wp_get_attachment_image_url( $variant->get_featured_image() ),
325 'attributes' => $attributes,
326 // Per-variation stock so the picker can disable Add to Cart /
327 // relabel "Out of stock" for the selected variation.
328 'is_in_stock' => method_exists( $variant, 'is_in_stock' ) ? $variant->is_in_stock() : true,
329 'stock_status' => method_exists( $variant, 'get_stock_status' ) ? $variant->get_stock_status() : 'instock',
330 ];
331 }, $product->get_available_variants() );
332
333 foreach ( $product->get_prices() as $price ) {
334 $pricing[ $price->get_id() ] = $price->get_price();
335 }
336
337 return [
338 'taxonomies' => array_values( array_unique( $taxonomies ) ),
339 'pricing' => $pricing,
340 'variations' => $variations,
341 ];
342 }
343
344 public function get_frontend_script_data() {
345 $data = [];
346
347 if ( Helper::is_checkout() || Helper::is_edit_address_page() ) {
348 $state_labels = array_filter( array_map( fn( $data ) => [
349 'label' => $data['state']['label'] ?? '',
350 'required' => $data['state']['required'] ?? false,
351 ], Countries::init()->get_country_locale() ) );
352 $states = array_merge( Countries::init()->get_allowed_country_states(), Countries::init()->get_shipping_country_states() );
353 $data = [
354 'states' => $states,
355 'state_labels' => $state_labels,
356 'state_label' => __( 'State / County', 'storeengine' ),
357 'is_required' => '&nbsp;<abbr class="storeengine-required" title="' . esc_attr__( 'Required', 'storeengine' ) . '">*</abbr>',
358 'i18n_select_state_text' => esc_attr__( 'Select an option&hellip;', 'storeengine' ),
359 'i18n_no_matches' => _x( 'No matches found', 'enhanced select', 'storeengine' ),
360 'i18n_ajax_error' => _x( 'Loading failed', 'enhanced select', 'storeengine' ),
361 'i18n_input_too_short_1' => _x( 'Please enter 1 or more characters', 'enhanced select', 'storeengine' ),
362 'i18n_input_too_short_n' => _x( 'Please enter %qty% or more characters', 'enhanced select', 'storeengine' ),
363 'i18n_input_too_long_1' => _x( 'Please delete 1 character', 'enhanced select', 'storeengine' ),
364 'i18n_input_too_long_n' => _x( 'Please delete %qty% characters', 'enhanced select', 'storeengine' ),
365 'i18n_selection_too_long_1' => _x( 'You can only select 1 item', 'enhanced select', 'storeengine' ),
366 'i18n_selection_too_long_n' => _x( 'You can only select %qty% items', 'enhanced select', 'storeengine' ),
367 'i18n_load_more' => _x( 'Loading more results&hellip;', 'enhanced select', 'storeengine' ),
368 'i18n_searching' => _x( 'Searching&hellip;', 'enhanced select', 'storeengine' ),
369 ];
370 }
371
372 $analytics = (array) Helper::get_settings( 'analytics', [] );
373 $hasAnalytics = ArrayUtil::any( $analytics, fn( $stat ) => true === $stat );
374
375 return apply_filters(
376 'storeengine/frontend_scripts_data',
377 array_merge(
378 $this->_get_script_data(),
379 [
380 'checkout_page_url' => esc_url( Helper::get_checkout_url() ),
381 'thankyou_page_url' => esc_url( Helper::get_thankyou_page_url() ),
382 'payment_gateways' => $this->get_payment_method_script_data(),
383 'payment_data' => [],
384 'checkout_with_order_pay' => Formatting::string_to_bool( get_query_var( 'order_pay' ) ),
385 'page' => [
386 'dashboard' => esc_url( Helper::get_dashboard_url() ),
387 'checkout' => esc_url( Helper::get_checkout_url() ),
388 'thankyou' => esc_url( Helper::get_thankyou_page_url() ),
389 'terms' => esc_url( Helper::get_terms_page_url() ),
390 'privacy' => esc_url( Helper::get_privacy_page_url() ),
391 ],
392 'is_page' => [
393 'is_product' => Helper::is_product(),
394 'is_shop' => Helper::is_shop(),
395 'is_cart' => Helper::is_cart(),
396 'is_dashboard' => Helper::is_dashboard_index(),
397 'is_address_edit' => Helper::is_edit_address_page(),
398 'is_checkout' => Helper::is_checkout(),
399 'is_order_pay' => Helper::is_checkout() && PaymentUtil::is_valid_order_pay_page(),
400 'is_add_payment_method' => Helper::is_add_payment_method_page(),
401 ],
402 'settings' => [
403 'analytics' => $hasAnalytics ? $analytics : false,
404 ]
405 ],
406 $data
407 )
408 );
409 }
410
411 public function _get_script_data(): array {
412 global $storeengine_addons;
413
414 $current_user = wp_get_current_user();
415 $user_name = ! is_email( $current_user->display_name ) ? $current_user->display_name : trim( $current_user->first_name . ' ' . $current_user->last_name );
416 $user_name = $user_name ?: $current_user->user_login;
417
418 // Brand logo for barcode labels etc. — StoreEngine store logo, then the
419 // theme custom logo, then the site icon.
420 $store_logo = Helper::get_settings( 'store_logo' );
421 if ( is_numeric( $store_logo ) && (int) $store_logo > 0 ) {
422 $store_logo = wp_get_attachment_image_url( (int) $store_logo, 'medium' );
423 }
424 if ( empty( $store_logo ) && get_theme_mod( 'custom_logo' ) ) {
425 $store_logo = wp_get_attachment_image_url( (int) get_theme_mod( 'custom_logo' ), 'medium' );
426 }
427 if ( empty( $store_logo ) ) {
428 $store_logo = get_site_icon_url( 128 );
429 }
430
431 return [
432 'is_admin' => is_admin(),
433 'nonce' => wp_create_nonce( 'wp_rest' ),
434 'storeengine_nonce' => wp_create_nonce( 'storeengine_nonce' ),
435 'rest_url' => esc_url_raw( rest_url() ),
436 'locale' => get_locale(),
437 'user_locale' => function_exists( 'get_user_locale' ) ? get_user_locale() : get_locale(),
438 'namespace' => STOREENGINE_PLUGIN_SLUG . '/v1/',
439 'plugin_root_url' => STOREENGINE_PLUGIN_ROOT_URI,
440 'plugin_root_path' => STOREENGINE_ROOT_DIR_PATH,
441 'root_path' => STOREENGINE_ROOT_DIR_PATH,
442 'root_url' => STOREENGINE_PLUGIN_ROOT_URI,
443 'assets_url' => STOREENGINE_ASSETS_URI,
444 'ajaxurl' => esc_url( admin_url( 'admin-ajax.php' ) ),
445 'admin_url' => admin_url(),
446 'site_url' => site_url(),
447 'route_path' => wp_parse_url( admin_url(), PHP_URL_PATH ),
448 'admin_menu_lists' => wp_json_encode( Admin\Menu::get_menu_lists() ),
449 'current_user_id' => $current_user->ID,
450 'current_user_name' => $user_name,
451 'store_email' => Helper::get_settings( 'store_email' ),
452 'store_name' => get_bloginfo( 'name' ),
453 'store_logo' => $store_logo ? $store_logo : '',
454 'is_rtl' => is_rtl(),
455 'addons' => $storeengine_addons,
456 // Addon cards injected by other plugins (e.g. storeengine-payments
457 // gateways) for the Add-ons screen. Each entry mirrors the card shape
458 // in the React Addons utils (name, label, details, tags, svgIcon, …).
459 'extra_addons' => apply_filters( 'storeengine/admin/extra_addons', [] ),
460 'timezone' => wp_timezone_string(),
461 'current_user_can' => [
462 'manage_options' => current_user_can( 'manage_options' ),
463 ],
464 'currency_options' => Helper::get_currency_options(),
465 'localeConv' => localeconv(),
466 'is_tax_enabled' => Helper::get_settings( 'enable_product_tax' ),
467 'enable_product_tax' => Helper::get_settings( 'enable_product_tax' ),
468 'is_pro' => Helper::is_active_storeengine_pro(),
469 'ablocks_status' => Helper::is_plugin_installed( 'ablocks/ablocks.php' ) ? ( Helper::is_plugin_active( 'ablocks/ablocks.php' ) ? 'active' : 'not-active' ) : 'not-installed',
470 ];
471 }
472
473 public function get_payment_method_script_data() {
474 $data = apply_filters( 'storeengine/frontend_scripts_payment_method_data', [] );
475
476 // Also walk every available gateway through the unified per-gateway
477 // data filter — `storeengine/checkout/gateway/{id}/data` — so third-
478 // party gateways that only hook the new public API still populate the
479 // legacy `payment_gateways.{id}` global that the /checkout/ page
480 // shells read from. The same filter feeds React Quick Checkout's
481 // snapshot, so one hook covers both surfaces.
482 try {
483 $gateways = Helper::get_payment_gateways()->get_available_payment_gateways();
484 } catch ( \Throwable $e ) {
485 $gateways = [];
486 }
487 foreach ( $gateways as $gateway ) {
488 $existing = isset( $data[ $gateway->id ] ) && is_array( $data[ $gateway->id ] ) ? $data[ $gateway->id ] : [];
489 $merged = apply_filters( "storeengine/checkout/gateway/{$gateway->id}/data", $existing, $gateway );
490 if ( is_array( $merged ) && ! empty( $merged ) ) {
491 $data[ $gateway->id ] = $merged;
492 }
493 }
494
495 return $data;
496 }
497
498 /**
499 * Enqueue Files on Start Plugin
500 *
501 * @param string $hook
502 *
503 * @function backend_scripts
504 */
505 public function backend_scripts( string $hook ) {
506 if ( ! strpos( $hook, '_page_' . STOREENGINE_PLUGIN_SLUG ) !== false ) {
507 return;
508 }
509
510 remove_all_actions( 'admin_notices' );
511
512 wp_enqueue_style(
513 'storeengine-admin-icon',
514 STOREENGINE_ASSETS_URI . 'library/icons/storeengine-icons.css',
515 [ 'wp-components' ],
516 filemtime(
517 STOREENGINE_ASSETS_DIR_PATH .
518 'library/icons/storeengine-icons.css'
519 ),
520 );
521
522 wp_enqueue_style(
523 'storeengine-admin-style',
524 STOREENGINE_ASSETS_URI . 'build/backend.css',
525 [ 'wp-components' ],
526 filemtime( STOREENGINE_ASSETS_DIR_PATH . 'build/backend.css' ),
527 'all'
528 );
529
530 wp_add_inline_style( 'storeengine-admin-style', $this->get_dynamic_css() );
531
532 if ( ! did_action( 'wp_enqueue_media' ) ) {
533 wp_enqueue_media();
534 }
535
536 // js — see note on the frontend equivalent above (use `include` so a
537 // second invocation in the same request still returns the array).
538 $asset_file = STOREENGINE_ASSETS_DIR_PATH . sprintf( 'build/backend.%s.asset.php', STOREENGINE_VERSION );
539 $dependencies = is_file( $asset_file ) ? include $asset_file : null;
540 if ( ! is_array( $dependencies ) ) {
541 $dependencies = [ 'dependencies' => [], 'version' => STOREENGINE_VERSION ];
542 }
543
544 wp_enqueue_script(
545 'storeengine-admin-scripts',
546 STOREENGINE_ASSETS_URI .
547 sprintf( 'build/backend.%s.js', STOREENGINE_VERSION ),
548 (array) ( $dependencies['dependencies'] ?? [] ),
549 $dependencies['version'] ?? STOREENGINE_VERSION,
550 true
551 );
552 wp_localize_script(
553 'storeengine-admin-scripts',
554 'StoreEngineGlobal',
555 $this->get_backend_script_data()
556 );
557 wp_set_script_translations(
558 'storeengine-admin-scripts',
559 'storeengine',
560 STOREENGINE_ROOT_DIR_PATH . 'i18n/languages'
561 );
562 }
563
564 public function get_backend_script_data(): array {
565 $currencies = [];
566
567 foreach ( Helper::get_currencies() as $code => $label ) {
568 $currencies[] = [
569 'code' => $code,
570 'name' => $label,
571 'symbol' => Helper::get_currency_symbol( $code ),
572 ];
573 }
574
575 return apply_filters(
576 'storeengine/backend_scripts_data',
577 array_merge(
578 $this->_get_script_data(),
579 [
580 'first_order' => Helper::get_first_order_date( 'Y-m-d' ),
581 'currency_options' => Helper::get_currency_options(),
582 'localeConv' => localeconv(),
583 'countries' => Countries::init()->get_countries(),
584 'currencies' => $currencies,
585 'enable_after_purchase_redirect' => Helper::get_settings( 'enable_after_purchase_redirect', false ),
586 // Store-wide default for new products. Settings → Products
587 // exposes a radio that writes this; the product editor's
588 // initial-values builder reads it for new products only.
589 'default_product_shipping_type' => in_array( Helper::get_settings( 'default_product_shipping_type', 'digital' ), [ 'digital', 'physical' ], true ) ? Helper::get_settings( 'default_product_shipping_type', 'digital' ) : 'digital',
590 'is_debug' => defined( 'WP_DEBUG' ) && WP_DEBUG,
591 ]
592 )
593 );
594 }
595
596 public function get_dynamic_css(): string {
597 global $storeengine_settings;
598
599 /**
600 * Filter css properties
601 */
602 $css = apply_filters( 'storeengine/dynamic_css_root_properties', [
603 '--storeengine-primary-color' => esc_attr( $storeengine_settings->global_primary_color ?? '' ),
604 '--storeengine-secondary-color' => esc_attr( $storeengine_settings->global_secondary_color ?? '' ),
605 '--storeengine-text-color' => esc_attr( $storeengine_settings->global_text_color ?? '' ),
606 '--storeengine-subtitle-color' => esc_attr( $storeengine_settings->global_subtitle_color ?? '' ),
607 '--storeengine-input-text-color' => esc_attr( $storeengine_settings->global_input_text_color ?? '' ),
608 '--storeengine-placeholder-color' => esc_attr( $storeengine_settings->global_placeholder_color ?? '' ),
609 '--storeengine-border-color' => esc_attr( $storeengine_settings->global_border_color ?? '' ),
610 '--storeengine-background-color' => esc_attr( $storeengine_settings->global_background_color ?? '' ),
611 ] );
612
613 // Filter out empty values to avoid invalid CSS.
614 $filtered_css = array_filter( $css, fn( $value ) => trim( ltrim( rtrim( $value, ';' ), ':' ) ) !== '' );
615
616 return ':root {' . PHP_EOL . implode( PHP_EOL, array_map( fn( $key, $value ) => "\t$key:$value;", array_keys( $filtered_css ), $filtered_css ) ) . PHP_EOL . '}';
617 }
618
619 public function display_price_placeholder() {
620 ?>
621 <script type="text/html" id="tmpl-storeengine-price">
622 <p class="storeengine-product__price-amount">
623 {{{ data.price }}}
624 </p>
625 </script>
626 <?php
627 }
628
629 public function backend_inline_style() {
630 $custom_css = '
631 a[href*="page=storeengine-get-pro"] {
632 background: #FFA500 !important;
633 color: #000000 !important;
634 font-weight: 600;
635 box-shadow: none !important;
636 }
637 ';
638 wp_add_inline_style( 'admin-bar', $custom_css );
639 }
640 }
641