PluginProbe
ShopBuilder – WooCommerce Builder For Elementor / 3.4.0
ShopBuilder – WooCommerce Builder For Elementor v3.4.0
3.4.2 3.4.1 3.4.0 2.0.1 2.0.2 2.0.3 2.1.0 2.1.1 2.1.10 2.1.11 2.1.12 2.1.13 2.1.14 2.1.15 2.1.2 2.1.3 2.1.4 2.1.5 2.1.6 2.1.7 2.1.8 2.1.9 2.2.0 2.2.1 2.2.2 All 63 releases
shopbuilder / app / Controllers / BuilderController.php

BuilderController.php in ShopBuilder – WooCommerce Builder For Elementor 3.4.0, at app/Controllers/BuilderController.php

710 lines 20.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Main BuilderController class.
4 *
5 * @package RadiusTheme\SB
6 */
7
8 namespace RadiusTheme\SB\Controllers;
9
10 use RadiusTheme\SB\Helpers\Fns;
11 use RadiusTheme\SB\Helpers\BuilderFns;
12 use RadiusTheme\SB\Models\ElementList;
13 use RadiusTheme\SB\Traits\SingletonTrait;
14 use RadiusTheme\SB\Controllers\Builder\BuilderCpt;
15 use RadiusTheme\SB\Controllers\Hooks\BuilderHooks;
16 use RadiusTheme\SB\Elementor\Controls\ImageSelectorControl;
17 use RadiusTheme\SB\Elementor\Controls\Select2AjaxControl;
18
19 // Do not allow directly accessing this file.
20 if ( ! defined( 'ABSPATH' ) ) {
21 exit( 'This script cannot be accessed directly.' );
22 }
23
24 /**
25 * Builder Controller
26 */
27 class BuilderController {
28 /**
29 * @var array
30 */
31 private static $cache = [];
32
33 /**
34 * Builder page id.
35 *
36 * @var integer
37 */
38 private $builder_page_id = 0;
39
40 /**
41 * Page Edit By.
42 *
43 * @var string
44 */
45 private $page_edit_with = '';
46
47 /**
48 * Singleton Trait
49 */
50 use SingletonTrait;
51
52 /**
53 * Construct function
54 */
55 private function __construct() {
56 $this->builder_page_id = BuilderFns::builder_page_id_by_page();
57 $this->page_edit_with = Fns::page_edit_with( $this->builder_page_id );
58 if ( ! is_admin() ) {
59 BuilderHooks::instance();
60 }
61
62 BuilderCpt::instance();
63 if ( defined( 'ELEMENTOR_VERSION' ) ) {
64 $this->elementor_init();
65 $this->both_builder_frontend();
66 add_action( 'elementor/editor/before_enqueue_scripts', [ $this, 'editor_scripts' ] );
67 }
68 // RT Select2 Ajax.
69 add_action( 'wp_ajax_rtsb_select2_object_search', [ $this, 'select2_ajax_posts_filter_autocomplete' ] );
70 add_action( 'wp_ajax_nopriv_rtsb_select2_object_search', [ $this, 'select2_ajax_posts_filter_autocomplete' ] );
71 // Select2 ajax save data.
72 add_action( 'wp_ajax_rtsb_select2_get_title', [ $this, 'select2_ajax_get_posts_value_titles' ] );
73 add_action( 'wp_ajax_nopriv_rtsb_select2_get_title', [ $this, 'select2_ajax_get_posts_value_titles' ] );
74 }
75
76 /**
77 * Apply for frontend.
78 *
79 * @return void
80 */
81 public function both_builder_frontend() {
82 add_action( 'rtsb/builder/template/before/content', [ $this, 'builder_template_before_content' ] );
83 add_action( 'rtsb/builder/template/after/content', [ $this, 'builder_template_after_content' ] );
84 }
85
86 /**
87 * Register Category
88 *
89 * @return void
90 */
91 public function elementor_init() {
92 add_action(
93 'init',
94 function () {
95 if ( Fns::should_load_elementor_scripts() ) {
96 add_action( 'elementor/elements/categories_registered', [ $this, 'add_elementor_widget_categories' ] );
97 add_action( 'elementor/widgets/register', [ $this, 'init_widgets' ] );
98 add_action( 'elementor/controls/register', [ $this, 'init_controls' ] );
99 add_filter( 'elementor/editor/localize_settings', [ $this, 'promotePremiumWidgets' ] );
100 add_action( 'elementor/icons_manager/additional_tabs', [ $this, 'rtsb_icons' ] );
101 }
102 }
103 );
104 }
105
106 /**
107 * Register Category
108 *
109 * @param object $elements_manager Category hooks.
110 *
111 * @return void
112 */
113 public function add_elementor_widget_categories( $elements_manager ) {
114 $categories = [];
115 $builder_id = get_queried_object_id();
116 $id = Fns::wpml_object_id( $builder_id, BuilderFns::$post_type_tb, 'default' );
117 $type = BuilderFns::builder_type( $id );
118
119 if ( $type && 'popup-builder' !== $type ) {
120 $builder_type = ! empty( BuilderFns::builder_page_types()[ $type ] ) ? BuilderFns::builder_page_types()[ $type ] : '';
121 $builder_type = str_replace( [ 'My Account - ', 'Endpoint: ' ], '', $builder_type );
122 $categories['rtsb-shopbuilder'] = [
123 'title' => esc_html__( 'ShopBuilder', 'shopbuilder' ) . ' - ' . ucfirst( $builder_type ),
124 'icon' => 'fa fa-plug',
125 ];
126 }
127 if ( 'quick-view' !== $type ) {
128 $categories['rtsb-shopbuilder-general'] = [
129 'title' => esc_html__( 'Shopbuilder - General', 'shopbuilder' ),
130 'icon' => 'fa fa-plug',
131 ];
132 }
133 $categories = apply_filters( 'rtsb_elementor_widgets_category_lists', $categories );
134
135 $other_categories = $elements_manager->get_categories();
136 $categories = array_merge(
137 array_slice( $other_categories, 0, 1 ),
138 $categories,
139 array_slice( $other_categories, 1 )
140 );
141
142 $set_categories = function ( $categories ) use ( $elements_manager ) {
143 $elements_manager->categories = $categories;
144 };
145
146 $set_categories->call( $elements_manager, $categories );
147 }
148
149 /**
150 * Init Controls
151 *
152 * Include controls files and register them
153 *
154 * @param object $controls_manager Controls Manager.
155 *
156 * @since 1.0.0
157 */
158 public function init_controls( $controls_manager ) {
159 $controls_manager->register( new ImageSelectorControl() );
160 $controls_manager->register( new Select2AjaxControl() );
161 }
162
163 /**
164 * Init Widgets
165 *
166 * Include widget files and register them
167 *
168 * @param object $widgets_manager Widgets Manager.
169 *
170 * @return void
171 *
172 * @since 1.0.0
173 */
174 public function init_widgets( $widgets_manager ) {
175
176 $get_list = ElementList::instance()->get_list( true, 'active' );
177 foreach ( $get_list as $element ) {
178 if ( isset( $element['active'] ) && 'on' !== $element['active'] ) {
179 continue;
180 }
181
182 if ( ! empty( $element['package'] ) && 'pro-disabled' === $element['package'] ) {
183 continue;
184 }
185
186 if ( empty( $element['base_class'] ) || ! class_exists( $element['base_class'] ) ) {
187 continue;
188 }
189
190 if ( ! empty( $element['category'] ) ) {
191 try {
192 $widget = false;
193 $import = apply_filters( 'rtsb_import_status', false );
194
195 if ( $this->should_register_widget( $element['category'], $import ) ) {
196 $widget = new $element['base_class']();
197 }
198
199 $widget = apply_filters( 'rtsb/element/list/init/widgets', $widget, $element );
200
201 if ( $widget && is_object( $widget ) ) {
202 $widgets_manager->register( $widget );
203 }
204 } catch ( \Throwable $e ) {
205 error_log( 'ShopBuilder widget error (' . $element['base_class'] . '): ' . $e->getMessage() ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
206 continue;
207 }
208 }
209 }
210 }
211
212 /**
213 * Determine whether a widget for the given category should be registered
214 * in the current request context.
215 *
216 * @param string $category Element category.
217 * @param bool $import Whether an import is in progress.
218 *
219 * @return bool
220 */
221 protected function should_register_widget( $category, $import ) {
222 switch ( $category ) {
223 case 'product':
224 return BuilderFns::is_product() || $import;
225 case 'shop':
226 return BuilderFns::is_archive() || BuilderFns::is_shop() || $import;
227 case 'archive':
228 return BuilderFns::is_archive() || $import;
229 case 'cart':
230 return BuilderFns::is_cart() || $import;
231 case 'checkout':
232 return BuilderFns::is_checkout() || $import;
233 case 'general':
234 return true;
235 default:
236 return false;
237 }
238 }
239
240 /**
241 * Adding custom icons in Elementor
242 *
243 * @param array $tabs Tabs.
244 *
245 * @return array
246 */
247 public function rtsb_icons( $tabs = [] ) {
248 $custom_icons = Fns::get_custom_icon_names();
249
250 $tabs['shopbuilder-icons'] = [
251 'name' => 'rtsb-fonts',
252 'label' => esc_html__( 'ShopBuilder Icons', 'shopbuilder' ),
253 'labelIcon' => 'fab fa-elementor',
254 'prefix' => 'rtsb-icon-',
255 'displayPrefix' => 'rtsb-icon',
256 'url' => rtsb()->get_assets_uri( 'css/frontend/rtsb-fonts.css' ),
257 'icons' => $custom_icons,
258 'ver' => '1.0',
259 ];
260
261 return $tabs;
262 }
263
264 /**
265 * Editor JS.
266 *
267 * @return void
268 */
269 public function editor_scripts() {
270 $version = ( defined( 'WP_DEBUG' ) && WP_DEBUG ) ? time() : RTSB_VERSION;
271
272 wp_enqueue_script(
273 'rtsb-editor-script',
274 rtsb()->get_assets_uri( 'js/backend/editor.js' ),
275 [
276 'jquery',
277 'elementor-editor',
278 'jquery-elementor-select2',
279 ],
280 $version,
281 true
282 );
283 $params = [
284 'isEditorForBuilder' => false,
285 ];
286 if ( BuilderFns::is_builder_preview() ) {
287 $params['isEditorForBuilder'] = true;
288 }
289 wp_localize_script( 'rtsb-editor-script', 'rtsbTemplateBuilderEditorScript', $params );
290 wp_enqueue_style( 'rtsb-el-editor-style', rtsb()->get_assets_uri( 'css/backend/elementor-editor.css' ), [], $version );
291 }
292
293 /**
294 * Before Content for Elementor.
295 *
296 * @return void
297 */
298 public function builder_template_before_content() {
299 /**
300 * Before Header-Footer page template content.
301 *
302 * Fires before the content of Elementor Header-Footer page template.
303 *
304 * @since 2.0.0
305 */
306 if ( did_action( 'elementor/loaded' ) && 'elementor' === $this->page_edit_with ) {
307 do_action( 'elementor/page_templates/header-footer/before_content' ); // phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores
308 }
309
310 $parent_class = apply_filters( 'rtsb/builder/content/parent_class', [] );
311
312 if ( BuilderFns::is_product() ) {
313 $product_id = Fns::get_prepared_product_id();
314
315 // Ensure the WordPress global $product is a valid WC_Product before
316 // wc_get_product_class() fires the `woocommerce_post_class` filter.
317 // Some themes (e.g. Blocksy) read the global $product directly inside
318 // that filter and call methods like get_type() on it, which throws a
319 // fatal error when the global is still an unresolved string.
320 $_product = Fns::get_product();
321
322 $parent_class = wc_get_product_class( $parent_class, $product_id );
323
324 if ( function_exists( 'rtwpvs' ) && $_product instanceof \WC_Product ) {
325 if ( $_product->is_type( 'variable' ) ) {
326 $parent_class[] = 'rtwpvs-product';
327 $beside_label = function_exists( 'rtwpvsp' ) && rtwpvs()->get_option( 'attribute_on_click_behavior' );
328 if ( $beside_label ) {
329 $parent_class[] = 'rtwpvs-selected-term-beside-label';
330 }
331 }
332 }
333 }
334
335 if ( BuilderFns::is_shop() ) {
336 $parent_class[] = 'shop';
337 }
338
339 if ( BuilderFns::is_archive() ) {
340 $parent_class[] = 'archive';
341 }
342
343 if ( BuilderFns::is_checkout() ) {
344 $parent_class[] = 'checkout-page ';
345 }
346
347 ?>
348 <!-- Before Content start -->
349 <div class="<?php echo esc_attr( implode( ' ', $parent_class ) ); ?>">
350 <?php
351 if ( BuilderFns::is_checkout() ) {
352 if ( ! apply_filters( 'rtsb/multi/step/checkout/widget', true ) ) {
353 return;
354 }
355
356 $checkout = WC()->checkout();
357
358 // Temporarily remove callbacks that Elementor checkout
359 // handles via separate widgets to prevent duplicates.
360 remove_action( 'woocommerce_before_checkout_form', [ Hooks\ActionHooks::class, 'woocommerce_checkout_login_form' ], 10 );
361 remove_action( 'woocommerce_before_checkout_form', [ Hooks\ActionHooks::class, 'woocommerce_checkout_coupon_form' ], 10 );
362 remove_action( 'woocommerce_before_checkout_form', [ Fns::class, 'woocommerce_output_all_notices' ], 10 );
363
364 do_action( 'woocommerce_before_checkout_form', $checkout );
365
366 // Restore callbacks for non-Elementor contexts.
367 add_action( 'woocommerce_before_checkout_form', [ Hooks\ActionHooks::class, 'woocommerce_checkout_login_form' ], 10 );
368 add_action( 'woocommerce_before_checkout_form', [ Hooks\ActionHooks::class, 'woocommerce_checkout_coupon_form' ], 10 );
369 add_action( 'woocommerce_before_checkout_form', [ Fns::class, 'woocommerce_output_all_notices' ], 10 );
370
371 // If checkout registration is disabled and not logged in, the user cannot checkout.
372 if ( ! $checkout->is_registration_enabled() && $checkout->is_registration_required() && ! is_user_logged_in() ) {
373 echo esc_html( apply_filters( 'woocommerce_checkout_must_be_logged_in_message', __( 'You must be logged in to checkout.', 'shopbuilder' ) ) );
374 return;
375 }
376 ?>
377 <!--
378 woocommerce-checkout added for fix issue with payment method ( Revolut Pay )
379 -->
380 <form name="checkout" method="post" class="rtsb-woocommerce-checkout woocommerce-checkout checkout" action="<?php echo esc_url( wc_get_checkout_url() ); ?>" enctype="multipart/form-data">
381 <?php
382 }
383 }
384
385 /**
386 * After Content for Elementor.
387 *
388 * @return void
389 */
390 public function builder_template_after_content() {
391 /**
392 * After Header-Footer page template content.
393 *
394 * Fires after the content of Elementor Header-Footer page template.
395 *
396 * @since 2.0.0
397 */
398 if ( did_action( 'elementor/loaded' ) && 'elementor' === $this->page_edit_with ) {
399 do_action( 'elementor/page_templates/header-footer/after_content' ); // phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores
400 }
401
402 if ( BuilderFns::is_checkout() ) {
403 if ( ! apply_filters( 'rtsb/multi/step/checkout/widget', true ) ) {
404 return;
405 }
406 ?>
407 </form>
408 <?php
409 do_action( 'woocommerce_after_checkout_form', WC()->checkout() );
410 }
411 ?>
412 </div>
413 <!-- After Content end -->
414 <?php
415 }
416
417 /**
418 * Ajax callback for rt-select2
419 *
420 * @return void
421 */
422 public function select2_ajax_posts_filter_autocomplete() {
423 if ( ! wp_verify_nonce( Fns::get_nonce(), rtsb()->nonceText ) ) {
424 wp_send_json_error( [] );
425 }
426 $query_per_page = 15;
427 $post_type = 'post';
428 $source_name = 'post_type';
429 $paged = absint( $_POST['page'] ?? 1 );
430 if ( ! empty( $_POST['post_type'] ) ) {
431 // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash
432 $post_type = sanitize_text_field( $_POST['post_type'] );
433 }
434
435 if ( ! empty( $_POST['source_name'] ) ) {
436 // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash
437 $source_name = sanitize_text_field( $_POST['source_name'] );
438 }
439
440 // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash
441 $search = ! empty( $_POST['search'] ) ? sanitize_text_field( $_POST['search'] ) : '';
442 $results = $post_list = []; // phpcs:ignore Squiz.PHP.DisallowMultipleAssignments.Found
443 switch ( $source_name ) {
444 case 'taxonomy':
445 $args = [
446 'hide_empty' => false,
447 'orderby' => 'name',
448 'order' => 'ASC',
449 'name__like' => $search,
450 'number' => '5',
451 ];
452
453 if ( 'all' !== $post_type ) {
454 $args['taxonomy'] = $post_type;
455 }
456
457 $post_list = wp_list_pluck( get_terms( $args ), 'name', 'term_id' );
458 break;
459 case 'user':
460 $users = [];
461
462 foreach ( get_users( [ 'search' => "*{$search}*" ] ) as $user ) {
463 $user_id = $user->ID;
464 $user_name = $user->display_name;
465 $users[ $user_id ] = $user_name;
466 }
467
468 $post_list = $users;
469 break;
470 default:
471 $post_list = $this->get_query_data( $post_type, $query_per_page, $search, $paged );
472 }
473
474 $pagination = true;
475 if ( count( $post_list ) < $query_per_page ) {
476 $pagination = false;
477 }
478 if ( ! empty( $post_list ) ) {
479 foreach ( $post_list as $key => $item ) {
480 $results[] = [
481 'text' => $item,
482 'id' => $key,
483 ];
484 }
485 }
486 wp_send_json(
487 [
488 'results' => $results,
489 'pagination' => [ 'more' => $pagination ],
490 ]
491 );
492 }
493
494
495 /**
496 * Ajax callback for rt-select2
497 *
498 * @return void
499 */
500 public function select2_ajax_get_posts_value_titles() {
501
502 if ( ! wp_verify_nonce( Fns::get_nonce(), rtsb()->nonceText ) ) {
503 wp_send_json_error( [] );
504 }
505
506 if ( empty( $_POST['id'] ) ) {
507 wp_send_json_error( [] );
508 }
509
510 // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
511 if ( empty( array_filter( $_POST['id'] ) ) ) {
512 wp_send_json_error( [] );
513 }
514 $ids = array_map( 'intval', $_POST['id'] );
515 $source_name = ! empty( $_POST['source_name'] ) ? sanitize_text_field( $_POST['source_name'] ) : ''; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash
516
517 switch ( $source_name ) {
518 case 'taxonomy':
519 $args = [
520 'hide_empty' => false,
521 'orderby' => 'name',
522 'order' => 'ASC',
523 'include' => implode( ',', $ids ),
524 ];
525
526 // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotValidated
527 if ( 'all' !== $_POST['post_type'] ) {
528 // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotValidated, WordPress.Security.ValidatedSanitizedInput.MissingUnslash
529 $args['taxonomy'] = sanitize_text_field( $_POST['post_type'] );
530 }
531
532 $response = wp_list_pluck( get_terms( $args ), 'name', 'term_id' );
533 break;
534 case 'user':
535 $users = [];
536
537 foreach ( get_users( [ 'include' => $ids ] ) as $user ) {
538 $user_id = $user->ID;
539 $user_name = $user->display_name . '-' . $user->ID;
540 $users[ $user_id ] = $user_name;
541 }
542
543 $response = $users;
544 break;
545 default:
546 $post_info = get_posts(
547 [
548 'post_type' => sanitize_text_field( $_POST['post_type'] ), // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotValidated
549 'include' => implode( ',', $ids ),
550 ]
551 );
552 $response = wp_list_pluck( $post_info, 'post_title', 'ID' );
553 }
554
555 if ( ! empty( $response ) ) {
556 wp_send_json_success( [ 'results' => $response ] );
557 } else {
558 wp_send_json_error( [] );
559 }
560 }
561
562
563 /**
564 * Ajax callback for rt-select2
565 *
566 * @param string $post_type Post type.
567 * @param int $limit Limit.
568 * @param string $search Search.
569 * @param int $paged Paged.
570 *
571 * @return array
572 */
573 public function get_query_data( $post_type = 'any', $limit = 10, $search = '', $paged = 1 ) {
574 global $wpdb;
575 $where = '';
576 $data = [];
577
578 if ( - 1 == $limit ) {
579 $limit = '';
580 } elseif ( 0 == $limit ) {
581 $limit = 'limit 0,1';
582 } else {
583 $offset = 0;
584 if ( $paged ) {
585 $offset = ( $paged - 1 ) * $limit;
586 }
587 $limit = $wpdb->prepare( ' limit %d, %d', esc_sql( $offset ), esc_sql( $limit ) );
588 }
589
590 if ( 'any' === $post_type ) {
591 $in_search_post_types = get_post_types( [ 'exclude_from_search' => false ] );
592 if ( empty( $in_search_post_types ) ) {
593 $where .= ' AND 1=0 ';
594 } else {
595 $where .= " AND {$wpdb->posts}.post_type IN ('" . join(
596 "', '",
597 array_map( 'esc_sql', $in_search_post_types )
598 ) . "')";
599 }
600 } elseif ( ! empty( $post_type ) ) {
601 $where .= $wpdb->prepare( " AND {$wpdb->posts}.post_type = %s", esc_sql( $post_type ) );
602 }
603
604 if ( ! empty( $search ) ) {
605 $where .= $wpdb->prepare( " AND {$wpdb->posts}.post_title LIKE %s", '%' . esc_sql( $search ) . '%' );
606 }
607
608 // Add a query for shop_coupon post-type to check 'show on frontend' meta.
609 if ( 'shop_coupon' === $post_type ) {
610 $where .= " AND {$wpdb->posts}.ID IN (
611 SELECT post_id FROM {$wpdb->postmeta}
612 WHERE meta_key = 'rtsb_show_on_frontend'
613 AND meta_value = 'on'
614 )";
615 }
616
617 $query = "select post_title,ID from $wpdb->posts where post_status = 'publish' {$where} {$limit}";
618 $results = $wpdb->get_results( $query ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.NoCaching
619
620 if ( ! empty( $results ) ) {
621 foreach ( $results as $row ) {
622 $data[ $row->ID ] = $row->post_title . ' [#' . $row->ID . ']';
623 }
624 }
625
626 return $data;
627 }
628
629 /**
630 * Promotion.
631 *
632 * @param array $config Config.
633 * @return array
634 */
635 public function promotePremiumWidgets( $config ) {
636 if ( rtsb()->has_pro() ) {
637 return $config;
638 }
639
640 if ( ! empty( $config['initial_document']['panel']['elements_categories']['rtsb-shopbuilder']['title'] ) ) {
641 $title = $config['initial_document']['panel']['elements_categories']['rtsb-shopbuilder']['title'];
642
643 if ( 'ShopBuilder - Shop' === $title || 'ShopBuilder - Archive' === $title ) {
644 if ( ! isset( $config['promotionWidgets'] ) || ! is_array( $config['promotionWidgets'] ) ) {
645 $config['promotionWidgets'] = [];
646 }
647
648 $pro_widgets = [
649 [
650 'name' => 'rtsb-ajax-product-filters',
651 'title' => esc_html__( 'Ajax Product Filters', 'shopbuilder' ),
652 'description' => esc_html__( 'Ajax Product Filters', 'shopbuilder' ),
653 'icon' => 'rtsb-el-custom rtsb-element icon-rtsb-ajax-product-filters rtsb-promotional-element',
654 'categories' => '[ "rtsb-shopbuilder" ]',
655 ],
656 ];
657
658 $config['promotionWidgets'] = array_merge( $config['promotionWidgets'], $pro_widgets );
659
660 return $config;
661 }
662 }
663
664 return $config;
665 }
666
667 /**
668 * Get Icons.
669 *
670 * @return array
671 */
672 public function get_icons() {
673 return [
674 'heart-empty',
675 'heart',
676 'eye',
677 'exchange',
678 'plus',
679 'minus',
680 'avatar',
681 'pay',
682 'share',
683 'clock',
684 'check-alt',
685 'check',
686 'delete',
687 'marker',
688 'list',
689 'list-2',
690 'power',
691 'cart',
692 'cart-2',
693 'cart-3',
694 'downloads',
695 'zoom',
696 'user-edit',
697 'grid',
698 'filter',
699 'billing',
700 'login',
701 'payment',
702 'search',
703 'edit',
704 'coupon',
705 'arrows-cw',
706 'trash-empty',
707 ];
708 }
709 }
710