PluginProbe
ShopBuilder – WooCommerce Builder For Elementor / 3.4.2
ShopBuilder – WooCommerce Builder For Elementor v3.4.2
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.2, at app/Controllers/BuilderController.php

722 lines 20.7 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 // On the frontend the Elementor Widgets Manager can initialise at an
223 // unpredictable time — e.g. Elementor Pro's Theme Builder boots it on
224 // template_redirect — when WooCommerce query conditionals such as
225 // is_shop()/is_archive() are not yet reliable. Widget registration is
226 // cached for the whole request, so gating it by those conditionals can
227 // permanently skip ShopBuilder widgets, leaving the builder template to
228 // render empty container shells. Register unconditionally on the
229 // frontend; keep the per-category gate only for the editor widget panel.
230 if ( ! is_admin() ) {
231 return true;
232 }
233
234 switch ( $category ) {
235 case 'product':
236 return BuilderFns::is_product() || $import;
237 case 'shop':
238 return BuilderFns::is_archive() || BuilderFns::is_shop() || $import;
239 case 'archive':
240 return BuilderFns::is_archive() || $import;
241 case 'cart':
242 return BuilderFns::is_cart() || $import;
243 case 'checkout':
244 return BuilderFns::is_checkout() || $import;
245 case 'general':
246 return true;
247 default:
248 return false;
249 }
250 }
251
252 /**
253 * Adding custom icons in Elementor
254 *
255 * @param array $tabs Tabs.
256 *
257 * @return array
258 */
259 public function rtsb_icons( $tabs = [] ) {
260 $custom_icons = Fns::get_custom_icon_names();
261
262 $tabs['shopbuilder-icons'] = [
263 'name' => 'rtsb-fonts',
264 'label' => esc_html__( 'ShopBuilder Icons', 'shopbuilder' ),
265 'labelIcon' => 'fab fa-elementor',
266 'prefix' => 'rtsb-icon-',
267 'displayPrefix' => 'rtsb-icon',
268 'url' => rtsb()->get_assets_uri( 'css/frontend/rtsb-fonts.css' ),
269 'icons' => $custom_icons,
270 'ver' => '1.0',
271 ];
272
273 return $tabs;
274 }
275
276 /**
277 * Editor JS.
278 *
279 * @return void
280 */
281 public function editor_scripts() {
282 $version = ( defined( 'WP_DEBUG' ) && WP_DEBUG ) ? time() : RTSB_VERSION;
283
284 wp_enqueue_script(
285 'rtsb-editor-script',
286 rtsb()->get_assets_uri( 'js/backend/editor.js' ),
287 [
288 'jquery',
289 'elementor-editor',
290 'jquery-elementor-select2',
291 ],
292 $version,
293 true
294 );
295 $params = [
296 'isEditorForBuilder' => false,
297 ];
298 if ( BuilderFns::is_builder_preview() ) {
299 $params['isEditorForBuilder'] = true;
300 }
301 wp_localize_script( 'rtsb-editor-script', 'rtsbTemplateBuilderEditorScript', $params );
302 wp_enqueue_style( 'rtsb-el-editor-style', rtsb()->get_assets_uri( 'css/backend/elementor-editor.css' ), [], $version );
303 }
304
305 /**
306 * Before Content for Elementor.
307 *
308 * @return void
309 */
310 public function builder_template_before_content() {
311 /**
312 * Before Header-Footer page template content.
313 *
314 * Fires before the content of Elementor Header-Footer page template.
315 *
316 * @since 2.0.0
317 */
318 if ( did_action( 'elementor/loaded' ) && 'elementor' === $this->page_edit_with ) {
319 do_action( 'elementor/page_templates/header-footer/before_content' ); // phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores
320 }
321
322 $parent_class = apply_filters( 'rtsb/builder/content/parent_class', [] );
323
324 if ( BuilderFns::is_product() ) {
325 $product_id = Fns::get_prepared_product_id();
326
327 // Ensure the WordPress global $product is a valid WC_Product before
328 // wc_get_product_class() fires the `woocommerce_post_class` filter.
329 // Some themes (e.g. Blocksy) read the global $product directly inside
330 // that filter and call methods like get_type() on it, which throws a
331 // fatal error when the global is still an unresolved string.
332 $_product = Fns::get_product();
333
334 $parent_class = wc_get_product_class( $parent_class, $product_id );
335
336 if ( function_exists( 'rtwpvs' ) && $_product instanceof \WC_Product ) {
337 if ( $_product->is_type( 'variable' ) ) {
338 $parent_class[] = 'rtwpvs-product';
339 $beside_label = function_exists( 'rtwpvsp' ) && rtwpvs()->get_option( 'attribute_on_click_behavior' );
340 if ( $beside_label ) {
341 $parent_class[] = 'rtwpvs-selected-term-beside-label';
342 }
343 }
344 }
345 }
346
347 if ( BuilderFns::is_shop() ) {
348 $parent_class[] = 'shop';
349 }
350
351 if ( BuilderFns::is_archive() ) {
352 $parent_class[] = 'archive';
353 }
354
355 if ( BuilderFns::is_checkout() ) {
356 $parent_class[] = 'checkout-page ';
357 }
358
359 ?>
360 <!-- Before Content start -->
361 <div class="<?php echo esc_attr( implode( ' ', $parent_class ) ); ?>">
362 <?php
363 if ( BuilderFns::is_checkout() ) {
364 if ( ! apply_filters( 'rtsb/multi/step/checkout/widget', true ) ) {
365 return;
366 }
367
368 $checkout = WC()->checkout();
369
370 // Temporarily remove callbacks that Elementor checkout
371 // handles via separate widgets to prevent duplicates.
372 remove_action( 'woocommerce_before_checkout_form', [ Hooks\ActionHooks::class, 'woocommerce_checkout_login_form' ], 10 );
373 remove_action( 'woocommerce_before_checkout_form', [ Hooks\ActionHooks::class, 'woocommerce_checkout_coupon_form' ], 10 );
374 remove_action( 'woocommerce_before_checkout_form', [ Fns::class, 'woocommerce_output_all_notices' ], 10 );
375
376 do_action( 'woocommerce_before_checkout_form', $checkout );
377
378 // Restore callbacks for non-Elementor contexts.
379 add_action( 'woocommerce_before_checkout_form', [ Hooks\ActionHooks::class, 'woocommerce_checkout_login_form' ], 10 );
380 add_action( 'woocommerce_before_checkout_form', [ Hooks\ActionHooks::class, 'woocommerce_checkout_coupon_form' ], 10 );
381 add_action( 'woocommerce_before_checkout_form', [ Fns::class, 'woocommerce_output_all_notices' ], 10 );
382
383 // If checkout registration is disabled and not logged in, the user cannot checkout.
384 if ( ! $checkout->is_registration_enabled() && $checkout->is_registration_required() && ! is_user_logged_in() ) {
385 echo esc_html( apply_filters( 'woocommerce_checkout_must_be_logged_in_message', __( 'You must be logged in to checkout.', 'shopbuilder' ) ) );
386 return;
387 }
388 ?>
389 <!--
390 woocommerce-checkout added for fix issue with payment method ( Revolut Pay )
391 -->
392 <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">
393 <?php
394 }
395 }
396
397 /**
398 * After Content for Elementor.
399 *
400 * @return void
401 */
402 public function builder_template_after_content() {
403 /**
404 * After Header-Footer page template content.
405 *
406 * Fires after the content of Elementor Header-Footer page template.
407 *
408 * @since 2.0.0
409 */
410 if ( did_action( 'elementor/loaded' ) && 'elementor' === $this->page_edit_with ) {
411 do_action( 'elementor/page_templates/header-footer/after_content' ); // phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores
412 }
413
414 if ( BuilderFns::is_checkout() ) {
415 if ( ! apply_filters( 'rtsb/multi/step/checkout/widget', true ) ) {
416 return;
417 }
418 ?>
419 </form>
420 <?php
421 do_action( 'woocommerce_after_checkout_form', WC()->checkout() );
422 }
423 ?>
424 </div>
425 <!-- After Content end -->
426 <?php
427 }
428
429 /**
430 * Ajax callback for rt-select2
431 *
432 * @return void
433 */
434 public function select2_ajax_posts_filter_autocomplete() {
435 if ( ! wp_verify_nonce( Fns::get_nonce(), rtsb()->nonceText ) ) {
436 wp_send_json_error( [] );
437 }
438 $query_per_page = 15;
439 $post_type = 'post';
440 $source_name = 'post_type';
441 $paged = absint( $_POST['page'] ?? 1 );
442 if ( ! empty( $_POST['post_type'] ) ) {
443 // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash
444 $post_type = sanitize_text_field( $_POST['post_type'] );
445 }
446
447 if ( ! empty( $_POST['source_name'] ) ) {
448 // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash
449 $source_name = sanitize_text_field( $_POST['source_name'] );
450 }
451
452 // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash
453 $search = ! empty( $_POST['search'] ) ? sanitize_text_field( $_POST['search'] ) : '';
454 $results = $post_list = []; // phpcs:ignore Squiz.PHP.DisallowMultipleAssignments.Found
455 switch ( $source_name ) {
456 case 'taxonomy':
457 $args = [
458 'hide_empty' => false,
459 'orderby' => 'name',
460 'order' => 'ASC',
461 'name__like' => $search,
462 'number' => '5',
463 ];
464
465 if ( 'all' !== $post_type ) {
466 $args['taxonomy'] = $post_type;
467 }
468
469 $post_list = wp_list_pluck( get_terms( $args ), 'name', 'term_id' );
470 break;
471 case 'user':
472 $users = [];
473
474 foreach ( get_users( [ 'search' => "*{$search}*" ] ) as $user ) {
475 $user_id = $user->ID;
476 $user_name = $user->display_name;
477 $users[ $user_id ] = $user_name;
478 }
479
480 $post_list = $users;
481 break;
482 default:
483 $post_list = $this->get_query_data( $post_type, $query_per_page, $search, $paged );
484 }
485
486 $pagination = true;
487 if ( count( $post_list ) < $query_per_page ) {
488 $pagination = false;
489 }
490 if ( ! empty( $post_list ) ) {
491 foreach ( $post_list as $key => $item ) {
492 $results[] = [
493 'text' => $item,
494 'id' => $key,
495 ];
496 }
497 }
498 wp_send_json(
499 [
500 'results' => $results,
501 'pagination' => [ 'more' => $pagination ],
502 ]
503 );
504 }
505
506
507 /**
508 * Ajax callback for rt-select2
509 *
510 * @return void
511 */
512 public function select2_ajax_get_posts_value_titles() {
513
514 if ( ! wp_verify_nonce( Fns::get_nonce(), rtsb()->nonceText ) ) {
515 wp_send_json_error( [] );
516 }
517
518 if ( empty( $_POST['id'] ) ) {
519 wp_send_json_error( [] );
520 }
521
522 // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
523 if ( empty( array_filter( $_POST['id'] ) ) ) {
524 wp_send_json_error( [] );
525 }
526 $ids = array_map( 'intval', $_POST['id'] );
527 $source_name = ! empty( $_POST['source_name'] ) ? sanitize_text_field( $_POST['source_name'] ) : ''; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash
528
529 switch ( $source_name ) {
530 case 'taxonomy':
531 $args = [
532 'hide_empty' => false,
533 'orderby' => 'name',
534 'order' => 'ASC',
535 'include' => implode( ',', $ids ),
536 ];
537
538 // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotValidated
539 if ( 'all' !== $_POST['post_type'] ) {
540 // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotValidated, WordPress.Security.ValidatedSanitizedInput.MissingUnslash
541 $args['taxonomy'] = sanitize_text_field( $_POST['post_type'] );
542 }
543
544 $response = wp_list_pluck( get_terms( $args ), 'name', 'term_id' );
545 break;
546 case 'user':
547 $users = [];
548
549 foreach ( get_users( [ 'include' => $ids ] ) as $user ) {
550 $user_id = $user->ID;
551 $user_name = $user->display_name . '-' . $user->ID;
552 $users[ $user_id ] = $user_name;
553 }
554
555 $response = $users;
556 break;
557 default:
558 $post_info = get_posts(
559 [
560 'post_type' => sanitize_text_field( $_POST['post_type'] ), // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotValidated
561 'include' => implode( ',', $ids ),
562 ]
563 );
564 $response = wp_list_pluck( $post_info, 'post_title', 'ID' );
565 }
566
567 if ( ! empty( $response ) ) {
568 wp_send_json_success( [ 'results' => $response ] );
569 } else {
570 wp_send_json_error( [] );
571 }
572 }
573
574
575 /**
576 * Ajax callback for rt-select2
577 *
578 * @param string $post_type Post type.
579 * @param int $limit Limit.
580 * @param string $search Search.
581 * @param int $paged Paged.
582 *
583 * @return array
584 */
585 public function get_query_data( $post_type = 'any', $limit = 10, $search = '', $paged = 1 ) {
586 global $wpdb;
587 $where = '';
588 $data = [];
589
590 if ( - 1 == $limit ) {
591 $limit = '';
592 } elseif ( 0 == $limit ) {
593 $limit = 'limit 0,1';
594 } else {
595 $offset = 0;
596 if ( $paged ) {
597 $offset = ( $paged - 1 ) * $limit;
598 }
599 $limit = $wpdb->prepare( ' limit %d, %d', esc_sql( $offset ), esc_sql( $limit ) );
600 }
601
602 if ( 'any' === $post_type ) {
603 $in_search_post_types = get_post_types( [ 'exclude_from_search' => false ] );
604 if ( empty( $in_search_post_types ) ) {
605 $where .= ' AND 1=0 ';
606 } else {
607 $where .= " AND {$wpdb->posts}.post_type IN ('" . join(
608 "', '",
609 array_map( 'esc_sql', $in_search_post_types )
610 ) . "')";
611 }
612 } elseif ( ! empty( $post_type ) ) {
613 $where .= $wpdb->prepare( " AND {$wpdb->posts}.post_type = %s", esc_sql( $post_type ) );
614 }
615
616 if ( ! empty( $search ) ) {
617 $where .= $wpdb->prepare( " AND {$wpdb->posts}.post_title LIKE %s", '%' . esc_sql( $search ) . '%' );
618 }
619
620 // Add a query for shop_coupon post-type to check 'show on frontend' meta.
621 if ( 'shop_coupon' === $post_type ) {
622 $where .= " AND {$wpdb->posts}.ID IN (
623 SELECT post_id FROM {$wpdb->postmeta}
624 WHERE meta_key = 'rtsb_show_on_frontend'
625 AND meta_value = 'on'
626 )";
627 }
628
629 $query = "select post_title,ID from $wpdb->posts where post_status = 'publish' {$where} {$limit}";
630 $results = $wpdb->get_results( $query ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.NoCaching
631
632 if ( ! empty( $results ) ) {
633 foreach ( $results as $row ) {
634 $data[ $row->ID ] = $row->post_title . ' [#' . $row->ID . ']';
635 }
636 }
637
638 return $data;
639 }
640
641 /**
642 * Promotion.
643 *
644 * @param array $config Config.
645 * @return array
646 */
647 public function promotePremiumWidgets( $config ) {
648 if ( rtsb()->has_pro() ) {
649 return $config;
650 }
651
652 if ( ! empty( $config['initial_document']['panel']['elements_categories']['rtsb-shopbuilder']['title'] ) ) {
653 $title = $config['initial_document']['panel']['elements_categories']['rtsb-shopbuilder']['title'];
654
655 if ( 'ShopBuilder - Shop' === $title || 'ShopBuilder - Archive' === $title ) {
656 if ( ! isset( $config['promotionWidgets'] ) || ! is_array( $config['promotionWidgets'] ) ) {
657 $config['promotionWidgets'] = [];
658 }
659
660 $pro_widgets = [
661 [
662 'name' => 'rtsb-ajax-product-filters',
663 'title' => esc_html__( 'Ajax Product Filters', 'shopbuilder' ),
664 'description' => esc_html__( 'Ajax Product Filters', 'shopbuilder' ),
665 'icon' => 'rtsb-el-custom rtsb-element icon-rtsb-ajax-product-filters rtsb-promotional-element',
666 'categories' => '[ "rtsb-shopbuilder" ]',
667 ],
668 ];
669
670 $config['promotionWidgets'] = array_merge( $config['promotionWidgets'], $pro_widgets );
671
672 return $config;
673 }
674 }
675
676 return $config;
677 }
678
679 /**
680 * Get Icons.
681 *
682 * @return array
683 */
684 public function get_icons() {
685 return [
686 'heart-empty',
687 'heart',
688 'eye',
689 'exchange',
690 'plus',
691 'minus',
692 'avatar',
693 'pay',
694 'share',
695 'clock',
696 'check-alt',
697 'check',
698 'delete',
699 'marker',
700 'list',
701 'list-2',
702 'power',
703 'cart',
704 'cart-2',
705 'cart-3',
706 'downloads',
707 'zoom',
708 'user-edit',
709 'grid',
710 'filter',
711 'billing',
712 'login',
713 'payment',
714 'search',
715 'edit',
716 'coupon',
717 'arrows-cw',
718 'trash-empty',
719 ];
720 }
721 }
722