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
← All changes | app/Controllers/BuilderController.php +164 -90 2.1.23.3.0 View file →
@@ -8,15 +8,14 @@
8 8 namespace RadiusTheme\SB\Controllers;
9 9
10 10 use RadiusTheme\SB\Helpers\Fns;
11 11 use RadiusTheme\SB\Helpers\BuilderFns;
12 +use RadiusTheme\SB\Models\ElementList;
12 13 use RadiusTheme\SB\Traits\SingletonTrait;
13 14 use RadiusTheme\SB\Controllers\Builder\BuilderCpt;
14 15 use RadiusTheme\SB\Controllers\Hooks\BuilderHooks;
15 16 use RadiusTheme\SB\Elementor\Controls\ImageSelectorControl;
16 17 use RadiusTheme\SB\Elementor\Controls\Select2AjaxControl;
17 -use RadiusTheme\SB\Models\ElementList;
18 -use RadiusTheme\SBPRO\Helpers\FnsPro;
19 18
20 19 // Do not allow directly accessing this file.
21 20 if ( ! defined( 'ABSPATH' ) ) {
22 21 exit( 'This script cannot be accessed directly.' );
@@ -55,28 +54,24 @@
55 54 */
56 55 private function __construct() {
57 56 $this->builder_page_id = BuilderFns::builder_page_id_by_page();
58 57 $this->page_edit_with = Fns::page_edit_with( $this->builder_page_id );
59 -
60 58 if ( ! is_admin() ) {
61 59 BuilderHooks::instance();
62 60 }
63 61
64 62 BuilderCpt::instance();
65 -
66 - $this->elementor_init();
67 - $this->both_builder_frontend();
68 -
69 - // add_action( 'elementor/init', [ $this, 'elementor_init' ] );
70 - add_action( 'elementor/editor/before_enqueue_scripts', [ $this, 'editor_scripts' ] );
71 - // add_action( 'template_redirect', [ $this, 'both_builder_frontend' ], 99 );
72 -
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 + }
73 68 // RT Select2 Ajax.
74 - add_action( 'wp_ajax_rt_select2_object_search', [ $this, 'select2_ajax_posts_filter_autocomplete' ] );
75 - add_action( 'wp_ajax_nopriv_rt_select2_object_search', [ $this, 'select2_ajax_posts_filter_autocomplete' ] );
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' ] );
76 71 // Select2 ajax save data.
77 - add_action( 'wp_ajax_rt_select2_get_title', [ $this, 'select2_ajax_get_posts_value_titles' ] );
78 - add_action( 'wp_ajax_nopriv_rt_select2_get_title', [ $this, 'select2_ajax_get_posts_value_titles' ] );
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' ] );
79 74 }
80 75
81 76 /**
82 77 * Apply for frontend.
@@ -93,13 +88,20 @@
93 88 *
94 89 * @return void
95 90 */
96 91 public function elementor_init() {
97 - add_action( 'elementor/elements/categories_registered', [ $this, 'add_elementor_widget_categories' ] );
98 - add_action( 'elementor/widgets/register', [ $this, 'init_widgets' ] );
99 - add_action( 'elementor/controls/register', [ $this, 'init_controls' ] );
100 - add_filter( 'elementor/editor/localize_settings', [ $this, 'promotePremiumWidgets' ] );
101 - add_action( 'elementor/icons_manager/additional_tabs', [ $this, 'rtsb_icons' ] );
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 + );
102 104 }
103 105
104 106 /**
105 107 * Register Category
@@ -108,21 +110,29 @@
108 110 *
109 111 * @return void
110 112 */
111 113 public function add_elementor_widget_categories( $elements_manager ) {
112 - $type = BuilderFns::builder_type( get_the_ID() );
113 - $builder_type = ! empty( BuilderFns::builder_page_types()[ $type ] ) ? BuilderFns::builder_page_types()[ $type ] : '';
114 - $builder_type = str_replace( 'My Account - ', '', $builder_type );
115 - $categories['rtsb-shopbuilder'] = [
116 - 'title' => esc_html__( 'ShopBuilder', 'shopbuilder' ) . ' - ' . ucfirst( $builder_type ),
117 - 'icon' => 'fa fa-plug',
118 - ];
119 - $categories['rtsb-shopbuilder-general'] = [
120 - 'title' => esc_html__( 'Shopbuilder - General', 'shopbuilder' ),
121 - 'icon' => 'fa fa-plug',
122 - ];
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 );
123 118
124 - $categories = apply_filters( 'rtsb_elementor_widgets_category_lists', $categories );
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 +
125 135 $other_categories = $elements_manager->get_categories();
126 136 $categories = array_merge(
127 137 array_slice( $other_categories, 0, 1 ),
128 138 $categories,
@@ -128,10 +138,10 @@
128 138 $categories,
129 139 array_slice( $other_categories, 1 )
130 140 );
131 141
132 - $set_categories = function ( $categories ) {
133 - $this->categories = $categories;
142 + $set_categories = function ( $categories ) use ( $elements_manager ) {
143 + $elements_manager->categories = $categories;
134 144 };
135 145
136 146 $set_categories->call( $elements_manager, $categories );
137 147 }
@@ -152,10 +162,14 @@
152 162
153 163 /**
154 164 * Init Widgets
155 165 *
156 - * Include widgets files and register them
166 + * Include widget files and register them
157 167 *
168 + * @param object $widgets_manager Widgets Manager.
169 + *
170 + * @return void
171 + *
158 172 * @since 1.0.0
159 173 */
160 174 public function init_widgets( $widgets_manager ) {
161 175
@@ -173,45 +187,50 @@
173 187 continue;
174 188 }
175 189
176 190 if ( ! empty( $element['category'] ) ) {
177 - $widget = false;
178 - $import = apply_filters( 'rtsb_import_status', false );
179 - switch ( $element['category'] ) {
180 - case 'product':
181 - if ( BuilderFns::is_product() || $import ) {
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':
182 221 $widget = new $element['base_class']();
183 - }
184 - break;
185 - case 'shop':
186 - if ( BuilderFns::is_archive() || BuilderFns::is_shop() || $import ) {
187 - $widget = new $element['base_class']();
188 - }
189 - break;
190 - case 'archive':
191 - if ( BuilderFns::is_archive() || $import ) {
192 - $widget = new $element['base_class']();
193 - }
194 - break;
195 - case 'cart':
196 - if ( BuilderFns::is_cart() || $import ) {
197 - $widget = new $element['base_class']();
198 - }
199 - break;
200 - case 'checkout':
201 - if ( BuilderFns::is_checkout() || $import ) {
202 - $widget = new $element['base_class']();
203 - }
204 - break;
205 - case 'general':
206 - $widget = new $element['base_class']();
207 - break;
208 - default:
209 - }
210 - $widget = apply_filters( 'rtsb/element/list/init/widgets', $widget, $element );
222 + break;
223 + default:
224 + }
225 + $widget = apply_filters( 'rtsb/element/list/init/widgets', $widget, $element );
211 226
212 - if ( $widget && is_object( $widget ) ) {
213 - $widgets_manager->register( $widget );
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;
214 233 }
215 234 }
216 235 }
217 236 }
@@ -223,9 +242,9 @@
223 242 *
224 243 * @return array
225 244 */
226 245 public function rtsb_icons( $tabs = [] ) {
227 - $custom_icons = $this->get_icons();
246 + $custom_icons = Fns::get_custom_icon_names();
228 247
229 248 $tabs['shopbuilder-icons'] = [
230 249 'name' => 'rtsb-fonts',
231 250 'label' => esc_html__( 'ShopBuilder Icons', 'shopbuilder' ),
@@ -282,9 +301,9 @@
282 301 *
283 302 * @since 2.0.0
284 303 */
285 304 if ( did_action( 'elementor/loaded' ) && 'elementor' === $this->page_edit_with ) {
286 - do_action( 'elementor/page_templates/header-footer/before_content' );
305 + do_action( 'elementor/page_templates/header-footer/before_content' ); // phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores
287 306 }
288 307
289 308 $parent_class = apply_filters( 'rtsb/builder/content/parent_class', [] );
290 309
@@ -290,8 +309,18 @@
290 309
291 310 if ( BuilderFns::is_product() ) {
292 311 $product_id = Fns::get_prepared_product_id();
293 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 + }
294 323 }
295 324
296 325 if ( BuilderFns::is_shop() ) {
297 326 $parent_class[] = 'shop';
@@ -312,10 +341,34 @@
312 341 if ( BuilderFns::is_checkout() ) {
313 342 if ( ! apply_filters( 'rtsb/multi/step/checkout/widget', true ) ) {
314 343 return;
315 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 + }
316 366 ?>
317 - <form name="checkout" method="post" class="rtsb-woocommerce-checkout checkout" action="<?php echo esc_url( wc_get_checkout_url() ); ?>" enctype="multipart/form-data">
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">
318 371 <?php
319 372 }
320 373 }
321 374
@@ -332,9 +385,9 @@
332 385 *
333 386 * @since 2.0.0
334 387 */
335 388 if ( did_action( 'elementor/loaded' ) && 'elementor' === $this->page_edit_with ) {
336 - do_action( 'elementor/page_templates/header-footer/after_content' );
389 + do_action( 'elementor/page_templates/header-footer/after_content' ); // phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores
337 390 }
338 391
339 392 if ( BuilderFns::is_checkout() ) {
340 393 if ( ! apply_filters( 'rtsb/multi/step/checkout/widget', true ) ) {
@@ -342,8 +395,9 @@
342 395 }
343 396 ?>
344 397 </form>
345 398 <?php
399 + do_action( 'woocommerce_after_checkout_form', WC()->checkout() );
346 400 }
347 401 ?>
348 402 </div>
349 403 <!-- After Content end -->
@@ -355,24 +409,28 @@
355 409 *
356 410 * @return void
357 411 */
358 412 public function select2_ajax_posts_filter_autocomplete() {
359 -
413 + if ( ! wp_verify_nonce( Fns::get_nonce(), rtsb()->nonceText ) ) {
414 + wp_send_json_error( [] );
415 + }
360 416 $query_per_page = 15;
361 417 $post_type = 'post';
362 418 $source_name = 'post_type';
363 - $paged = $_POST['page'] ?? 1;
364 -
419 + $paged = absint( $_POST['page'] ?? 1 );
365 420 if ( ! empty( $_POST['post_type'] ) ) {
421 + // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash
366 422 $post_type = sanitize_text_field( $_POST['post_type'] );
367 423 }
368 424
369 425 if ( ! empty( $_POST['source_name'] ) ) {
426 + // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash
370 427 $source_name = sanitize_text_field( $_POST['source_name'] );
371 428 }
372 429
430 + // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash
373 431 $search = ! empty( $_POST['search'] ) ? sanitize_text_field( $_POST['search'] ) : '';
374 - $results = $post_list = [];
432 + $results = $post_list = []; // phpcs:ignore Squiz.PHP.DisallowMultipleAssignments.Found
375 433 switch ( $source_name ) {
376 434 case 'taxonomy':
377 435 $args = [
378 436 'hide_empty' => false,
@@ -377,13 +435,13 @@
377 435 $args = [
378 436 'hide_empty' => false,
379 437 'orderby' => 'name',
380 438 'order' => 'ASC',
381 - 'search' => $search,
439 + 'name__like' => $search,
382 440 'number' => '5',
383 441 ];
384 442
385 - if ( $post_type !== 'all' ) {
443 + if ( 'all' !== $post_type ) {
386 444 $args['taxonomy'] = $post_type;
387 445 }
388 446
389 447 $post_list = wp_list_pluck( get_terms( $args ), 'name', 'term_id' );
@@ -430,17 +488,22 @@
430 488 * @return void
431 489 */
432 490 public function select2_ajax_get_posts_value_titles() {
433 491
492 + if ( ! wp_verify_nonce( Fns::get_nonce(), rtsb()->nonceText ) ) {
493 + wp_send_json_error( [] );
494 + }
495 +
434 496 if ( empty( $_POST['id'] ) ) {
435 497 wp_send_json_error( [] );
436 498 }
437 499
500 + // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
438 501 if ( empty( array_filter( $_POST['id'] ) ) ) {
439 502 wp_send_json_error( [] );
440 503 }
441 504 $ids = array_map( 'intval', $_POST['id'] );
442 - $source_name = ! empty( $_POST['source_name'] ) ? sanitize_text_field( $_POST['source_name'] ) : '';
505 + $source_name = ! empty( $_POST['source_name'] ) ? sanitize_text_field( $_POST['source_name'] ) : ''; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash
443 506
444 507 switch ( $source_name ) {
445 508 case 'taxonomy':
446 509 $args = [
@@ -449,9 +512,11 @@
449 512 'order' => 'ASC',
450 513 'include' => implode( ',', $ids ),
451 514 ];
452 515
453 - if ( $_POST['post_type'] !== 'all' ) {
516 + // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotValidated
517 + if ( 'all' !== $_POST['post_type'] ) {
518 + // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotValidated, WordPress.Security.ValidatedSanitizedInput.MissingUnslash
454 519 $args['taxonomy'] = sanitize_text_field( $_POST['post_type'] );
455 520 }
456 521
457 522 $response = wp_list_pluck( get_terms( $args ), 'name', 'term_id' );
@@ -469,9 +534,9 @@
469 534 break;
470 535 default:
471 536 $post_info = get_posts(
472 537 [
473 - 'post_type' => sanitize_text_field( $_POST['post_type'] ),
538 + 'post_type' => sanitize_text_field( $_POST['post_type'] ), // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotValidated
474 539 'include' => implode( ',', $ids ),
475 540 ]
476 541 );
477 542 $response = wp_list_pluck( $post_info, 'post_title', 'ID' );
@@ -487,12 +552,12 @@
487 552
488 553 /**
489 554 * Ajax callback for rt-select2
490 555 *
491 - * @param $post_type
492 - * @param $limit
493 - * @param $search
494 - * @param $paged
556 + * @param string $post_type Post type.
557 + * @param int $limit Limit.
558 + * @param string $search Search.
559 + * @param int $paged Paged.
495 560 *
496 561 * @return array
497 562 */
498 563 public function get_query_data( $post_type = 'any', $limit = 10, $search = '', $paged = 1 ) {
@@ -529,10 +594,19 @@
529 594 if ( ! empty( $search ) ) {
530 595 $where .= $wpdb->prepare( " AND {$wpdb->posts}.post_title LIKE %s", '%' . esc_sql( $search ) . '%' );
531 596 }
532 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 +
533 607 $query = "select post_title,ID from $wpdb->posts where post_status = 'publish' {$where} {$limit}";
534 - $results = $wpdb->get_results( $query );
608 + $results = $wpdb->get_results( $query ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.NoCaching
535 609
536 610 if ( ! empty( $results ) ) {
537 611 foreach ( $results as $row ) {
538 612 $data[ $row->ID ] = $row->post_title . ' [#' . $row->ID . ']';
@@ -563,10 +637,10 @@
563 637
564 638 $pro_widgets = [
565 639 [
566 640 'name' => 'rtsb-ajax-product-filters',
567 - 'title' => esc_html__( 'Ajax Product Filters', 'testimonial-slider-showcase' ),
568 - 'description' => esc_html__( 'Ajax Product Filters', 'testimonial-slider-showcase' ),
641 + 'title' => esc_html__( 'Ajax Product Filters', 'shopbuilder' ),
642 + 'description' => esc_html__( 'Ajax Product Filters', 'shopbuilder' ),
569 643 'icon' => 'rtsb-el-custom rtsb-element icon-rtsb-ajax-product-filters rtsb-promotional-element',
570 644 'categories' => '[ "rtsb-shopbuilder" ]',
571 645 ],
572 646 ];