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 +119 -67 2.1.123.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,22 +54,18 @@
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 69 add_action( 'wp_ajax_rtsb_select2_object_search', [ $this, 'select2_ajax_posts_filter_autocomplete' ] );
74 70 add_action( 'wp_ajax_nopriv_rtsb_select2_object_search', [ $this, 'select2_ajax_posts_filter_autocomplete' ] );
75 71 // Select2 ajax save data.
@@ -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
@@ -112,9 +115,9 @@
112 115 $builder_id = get_queried_object_id();
113 116 $id = Fns::wpml_object_id( $builder_id, BuilderFns::$post_type_tb, 'default' );
114 117 $type = BuilderFns::builder_type( $id );
115 118
116 - if ( $type ) {
119 + if ( $type && 'popup-builder' !== $type ) {
117 120 $builder_type = ! empty( BuilderFns::builder_page_types()[ $type ] ) ? BuilderFns::builder_page_types()[ $type ] : '';
118 121 $builder_type = str_replace( [ 'My Account - ', 'Endpoint: ' ], '', $builder_type );
119 122 $categories['rtsb-shopbuilder'] = [
120 123 'title' => esc_html__( 'ShopBuilder', 'shopbuilder' ) . ' - ' . ucfirst( $builder_type ),
@@ -135,10 +138,10 @@
135 138 $categories,
136 139 array_slice( $other_categories, 1 )
137 140 );
138 141
139 - $set_categories = function ( $categories ) {
140 - $this->categories = $categories;
142 + $set_categories = function ( $categories ) use ( $elements_manager ) {
143 + $elements_manager->categories = $categories;
141 144 };
142 145
143 146 $set_categories->call( $elements_manager, $categories );
144 147 }
@@ -159,10 +162,14 @@
159 162
160 163 /**
161 164 * Init Widgets
162 165 *
163 - * Include widgets files and register them
166 + * Include widget files and register them
164 167 *
168 + * @param object $widgets_manager Widgets Manager.
169 + *
170 + * @return void
171 + *
165 172 * @since 1.0.0
166 173 */
167 174 public function init_widgets( $widgets_manager ) {
168 175
@@ -180,45 +187,50 @@
180 187 continue;
181 188 }
182 189
183 190 if ( ! empty( $element['category'] ) ) {
184 - $widget = false;
185 - $import = apply_filters( 'rtsb_import_status', false );
186 - switch ( $element['category'] ) {
187 - case 'product':
188 - 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':
189 221 $widget = new $element['base_class']();
190 - }
191 - break;
192 - case 'shop':
193 - if ( BuilderFns::is_archive() || BuilderFns::is_shop() || $import ) {
194 - $widget = new $element['base_class']();
195 - }
196 - break;
197 - case 'archive':
198 - if ( BuilderFns::is_archive() || $import ) {
199 - $widget = new $element['base_class']();
200 - }
201 - break;
202 - case 'cart':
203 - if ( BuilderFns::is_cart() || $import ) {
204 - $widget = new $element['base_class']();
205 - }
206 - break;
207 - case 'checkout':
208 - if ( BuilderFns::is_checkout() || $import ) {
209 - $widget = new $element['base_class']();
210 - }
211 - break;
212 - case 'general':
213 - $widget = new $element['base_class']();
214 - break;
215 - default:
216 - }
217 - $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 );
218 226
219 - if ( $widget && is_object( $widget ) ) {
220 - $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;
221 233 }
222 234 }
223 235 }
224 236 }
@@ -289,9 +301,9 @@
289 301 *
290 302 * @since 2.0.0
291 303 */
292 304 if ( did_action( 'elementor/loaded' ) && 'elementor' === $this->page_edit_with ) {
293 - 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
294 306 }
295 307
296 308 $parent_class = apply_filters( 'rtsb/builder/content/parent_class', [] );
297 309
@@ -329,10 +341,34 @@
329 341 if ( BuilderFns::is_checkout() ) {
330 342 if ( ! apply_filters( 'rtsb/multi/step/checkout/widget', true ) ) {
331 343 return;
332 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 + }
333 366 ?>
334 - <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">
335 371 <?php
336 372 }
337 373 }
338 374
@@ -349,9 +385,9 @@
349 385 *
350 386 * @since 2.0.0
351 387 */
352 388 if ( did_action( 'elementor/loaded' ) && 'elementor' === $this->page_edit_with ) {
353 - 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
354 390 }
355 391
356 392 if ( BuilderFns::is_checkout() ) {
357 393 if ( ! apply_filters( 'rtsb/multi/step/checkout/widget', true ) ) {
@@ -359,8 +395,9 @@
359 395 }
360 396 ?>
361 397 </form>
362 398 <?php
399 + do_action( 'woocommerce_after_checkout_form', WC()->checkout() );
363 400 }
364 401 ?>
365 402 </div>
366 403 <!-- After Content end -->
@@ -380,17 +417,20 @@
380 417 $post_type = 'post';
381 418 $source_name = 'post_type';
382 419 $paged = absint( $_POST['page'] ?? 1 );
383 420 if ( ! empty( $_POST['post_type'] ) ) {
421 + // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash
384 422 $post_type = sanitize_text_field( $_POST['post_type'] );
385 423 }
386 424
387 425 if ( ! empty( $_POST['source_name'] ) ) {
426 + // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash
388 427 $source_name = sanitize_text_field( $_POST['source_name'] );
389 428 }
390 429
430 + // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash
391 431 $search = ! empty( $_POST['search'] ) ? sanitize_text_field( $_POST['search'] ) : '';
392 - $results = $post_list = [];
432 + $results = $post_list = []; // phpcs:ignore Squiz.PHP.DisallowMultipleAssignments.Found
393 433 switch ( $source_name ) {
394 434 case 'taxonomy':
395 435 $args = [
396 436 'hide_empty' => false,
@@ -395,13 +435,13 @@
395 435 $args = [
396 436 'hide_empty' => false,
397 437 'orderby' => 'name',
398 438 'order' => 'ASC',
399 - 'search' => $search,
439 + 'name__like' => $search,
400 440 'number' => '5',
401 441 ];
402 442
403 - if ( $post_type !== 'all' ) {
443 + if ( 'all' !== $post_type ) {
404 444 $args['taxonomy'] = $post_type;
405 445 }
406 446
407 447 $post_list = wp_list_pluck( get_terms( $args ), 'name', 'term_id' );
@@ -456,13 +496,14 @@
456 496 if ( empty( $_POST['id'] ) ) {
457 497 wp_send_json_error( [] );
458 498 }
459 499
500 + // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
460 501 if ( empty( array_filter( $_POST['id'] ) ) ) {
461 502 wp_send_json_error( [] );
462 503 }
463 504 $ids = array_map( 'intval', $_POST['id'] );
464 - $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
465 506
466 507 switch ( $source_name ) {
467 508 case 'taxonomy':
468 509 $args = [
@@ -471,9 +512,11 @@
471 512 'order' => 'ASC',
472 513 'include' => implode( ',', $ids ),
473 514 ];
474 515
475 - 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
476 519 $args['taxonomy'] = sanitize_text_field( $_POST['post_type'] );
477 520 }
478 521
479 522 $response = wp_list_pluck( get_terms( $args ), 'name', 'term_id' );
@@ -491,9 +534,9 @@
491 534 break;
492 535 default:
493 536 $post_info = get_posts(
494 537 [
495 - '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
496 539 'include' => implode( ',', $ids ),
497 540 ]
498 541 );
499 542 $response = wp_list_pluck( $post_info, 'post_title', 'ID' );
@@ -509,12 +552,12 @@
509 552
510 553 /**
511 554 * Ajax callback for rt-select2
512 555 *
513 - * @param $post_type
514 - * @param $limit
515 - * @param $search
516 - * @param $paged
556 + * @param string $post_type Post type.
557 + * @param int $limit Limit.
558 + * @param string $search Search.
559 + * @param int $paged Paged.
517 560 *
518 561 * @return array
519 562 */
520 563 public function get_query_data( $post_type = 'any', $limit = 10, $search = '', $paged = 1 ) {
@@ -549,8 +592,17 @@
549 592 }
550 593
551 594 if ( ! empty( $search ) ) {
552 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 + )";
553 605 }
554 606
555 607 $query = "select post_title,ID from $wpdb->posts where post_status = 'publish' {$where} {$limit}";
556 608 $results = $wpdb->get_results( $query ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.NoCaching