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