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

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