PluginProbe
ShopBuilder – WooCommerce Builder For Elementor / 2.1.13
ShopBuilder – WooCommerce Builder For Elementor v2.1.13
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 +70 -144 3.4.22.1.13 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;
13 12 use RadiusTheme\SB\Traits\SingletonTrait;
14 13 use RadiusTheme\SB\Controllers\Builder\BuilderCpt;
15 14 use RadiusTheme\SB\Controllers\Hooks\BuilderHooks;
16 15 use RadiusTheme\SB\Elementor\Controls\ImageSelectorControl;
17 16 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,18 +54,22 @@
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 +
58 59 if ( ! is_admin() ) {
59 60 BuilderHooks::instance();
60 61 }
61 62
62 63 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 - }
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 +
68 72 // RT Select2 Ajax.
69 73 add_action( 'wp_ajax_rtsb_select2_object_search', [ $this, 'select2_ajax_posts_filter_autocomplete' ] );
70 74 add_action( 'wp_ajax_nopriv_rtsb_select2_object_search', [ $this, 'select2_ajax_posts_filter_autocomplete' ] );
71 75 // Select2 ajax save data.
@@ -88,20 +92,13 @@
88 92 *
89 93 * @return void
90 94 */
91 95 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 - );
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' ] );
104 101 }
105 102
106 103 /**
107 104 * Register Category
@@ -115,9 +112,9 @@
115 112 $builder_id = get_queried_object_id();
116 113 $id = Fns::wpml_object_id( $builder_id, BuilderFns::$post_type_tb, 'default' );
117 114 $type = BuilderFns::builder_type( $id );
118 115
119 - if ( $type && 'popup-builder' !== $type ) {
116 + if ( $type ) {
120 117 $builder_type = ! empty( BuilderFns::builder_page_types()[ $type ] ) ? BuilderFns::builder_page_types()[ $type ] : '';
121 118 $builder_type = str_replace( [ 'My Account - ', 'Endpoint: ' ], '', $builder_type );
122 119 $categories['rtsb-shopbuilder'] = [
123 120 'title' => esc_html__( 'ShopBuilder', 'shopbuilder' ) . ' - ' . ucfirst( $builder_type ),
@@ -138,10 +135,10 @@
138 135 $categories,
139 136 array_slice( $other_categories, 1 )
140 137 );
141 138
142 - $set_categories = function ( $categories ) use ( $elements_manager ) {
143 - $elements_manager->categories = $categories;
139 + $set_categories = function ( $categories ) {
140 + $this->categories = $categories;
144 141 };
145 142
146 143 $set_categories->call( $elements_manager, $categories );
147 144 }
@@ -162,14 +159,10 @@
162 159
163 160 /**
164 161 * Init Widgets
165 162 *
166 - * Include widget files and register them
163 + * Include widgets files and register them
167 164 *
168 - * @param object $widgets_manager Widgets Manager.
169 - *
170 - * @return void
171 - *
172 165 * @since 1.0.0
173 166 */
174 167 public function init_widgets( $widgets_manager ) {
175 168
@@ -187,24 +180,45 @@
187 180 continue;
188 181 }
189 182
190 183 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 ) ) {
184 + $widget = false;
185 + $import = apply_filters( 'rtsb_import_status', false );
186 + switch ( $element['category'] ) {
187 + case 'product':
188 + if ( BuilderFns::is_product() || $import ) {
189 + $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':
196 213 $widget = new $element['base_class']();
197 - }
214 + break;
215 + default:
216 + }
217 + $widget = apply_filters( 'rtsb/element/list/init/widgets', $widget, $element );
198 218
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;
219 + if ( $widget && is_object( $widget ) ) {
220 + $widgets_manager->register( $widget );
207 221 }
208 222 }
209 223 }
210 224 }
@@ -209,48 +223,8 @@
209 223 }
210 224 }
211 225
212 226 /**
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 227 * Adding custom icons in Elementor
254 228 *
255 229 * @param array $tabs Tabs.
256 230 *
@@ -315,26 +289,18 @@
315 289 *
316 290 * @since 2.0.0
317 291 */
318 292 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
293 + do_action( 'elementor/page_templates/header-footer/before_content' );
320 294 }
321 295
322 296 $parent_class = apply_filters( 'rtsb/builder/content/parent_class', [] );
323 297
324 298 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 -
299 + $product_id = Fns::get_prepared_product_id();
334 300 $parent_class = wc_get_product_class( $parent_class, $product_id );
335 -
336 - if ( function_exists( 'rtwpvs' ) && $_product instanceof \WC_Product ) {
301 + if ( function_exists( 'rtwpvs' ) ) {
302 + $_product = Fns::get_product();
337 303 if ( $_product->is_type( 'variable' ) ) {
338 304 $parent_class[] = 'rtwpvs-product';
339 305 $beside_label = function_exists( 'rtwpvsp' ) && rtwpvs()->get_option( 'attribute_on_click_behavior' );
340 306 if ( $beside_label ) {
@@ -363,34 +329,10 @@
363 329 if ( BuilderFns::is_checkout() ) {
364 330 if ( ! apply_filters( 'rtsb/multi/step/checkout/widget', true ) ) {
365 331 return;
366 332 }
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 333 ?>
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">
334 + <form name="checkout" method="post" class="rtsb-woocommerce-checkout checkout" action="<?php echo esc_url( wc_get_checkout_url() ); ?>" enctype="multipart/form-data">
393 335 <?php
394 336 }
395 337 }
396 338
@@ -407,9 +349,9 @@
407 349 *
408 350 * @since 2.0.0
409 351 */
410 352 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
353 + do_action( 'elementor/page_templates/header-footer/after_content' );
412 354 }
413 355
414 356 if ( BuilderFns::is_checkout() ) {
415 357 if ( ! apply_filters( 'rtsb/multi/step/checkout/widget', true ) ) {
@@ -417,9 +359,8 @@
417 359 }
418 360 ?>
419 361 </form>
420 362 <?php
421 - do_action( 'woocommerce_after_checkout_form', WC()->checkout() );
422 363 }
423 364 ?>
424 365 </div>
425 366 <!-- After Content end -->
@@ -439,20 +380,17 @@
439 380 $post_type = 'post';
440 381 $source_name = 'post_type';
441 382 $paged = absint( $_POST['page'] ?? 1 );
442 383 if ( ! empty( $_POST['post_type'] ) ) {
443 - // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash
444 384 $post_type = sanitize_text_field( $_POST['post_type'] );
445 385 }
446 386
447 387 if ( ! empty( $_POST['source_name'] ) ) {
448 - // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash
449 388 $source_name = sanitize_text_field( $_POST['source_name'] );
450 389 }
451 390
452 - // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash
453 391 $search = ! empty( $_POST['search'] ) ? sanitize_text_field( $_POST['search'] ) : '';
454 - $results = $post_list = []; // phpcs:ignore Squiz.PHP.DisallowMultipleAssignments.Found
392 + $results = $post_list = [];
455 393 switch ( $source_name ) {
456 394 case 'taxonomy':
457 395 $args = [
458 396 'hide_empty' => false,
@@ -457,13 +395,13 @@
457 395 $args = [
458 396 'hide_empty' => false,
459 397 'orderby' => 'name',
460 398 'order' => 'ASC',
461 - 'name__like' => $search,
399 + 'search' => $search,
462 400 'number' => '5',
463 401 ];
464 402
465 - if ( 'all' !== $post_type ) {
403 + if ( $post_type !== 'all' ) {
466 404 $args['taxonomy'] = $post_type;
467 405 }
468 406
469 407 $post_list = wp_list_pluck( get_terms( $args ), 'name', 'term_id' );
@@ -518,14 +456,13 @@
518 456 if ( empty( $_POST['id'] ) ) {
519 457 wp_send_json_error( [] );
520 458 }
521 459
522 - // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
523 460 if ( empty( array_filter( $_POST['id'] ) ) ) {
524 461 wp_send_json_error( [] );
525 462 }
526 463 $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
464 + $source_name = ! empty( $_POST['source_name'] ) ? sanitize_text_field( $_POST['source_name'] ) : '';
528 465
529 466 switch ( $source_name ) {
530 467 case 'taxonomy':
531 468 $args = [
@@ -534,11 +471,9 @@
534 471 'order' => 'ASC',
535 472 'include' => implode( ',', $ids ),
536 473 ];
537 474
538 - // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotValidated
539 - if ( 'all' !== $_POST['post_type'] ) {
540 - // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotValidated, WordPress.Security.ValidatedSanitizedInput.MissingUnslash
475 + if ( $_POST['post_type'] !== 'all' ) {
541 476 $args['taxonomy'] = sanitize_text_field( $_POST['post_type'] );
542 477 }
543 478
544 479 $response = wp_list_pluck( get_terms( $args ), 'name', 'term_id' );
@@ -556,9 +491,9 @@
556 491 break;
557 492 default:
558 493 $post_info = get_posts(
559 494 [
560 - 'post_type' => sanitize_text_field( $_POST['post_type'] ), // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotValidated
495 + 'post_type' => sanitize_text_field( $_POST['post_type'] ),
561 496 'include' => implode( ',', $ids ),
562 497 ]
563 498 );
564 499 $response = wp_list_pluck( $post_info, 'post_title', 'ID' );
@@ -574,12 +509,12 @@
574 509
575 510 /**
576 511 * Ajax callback for rt-select2
577 512 *
578 - * @param string $post_type Post type.
579 - * @param int $limit Limit.
580 - * @param string $search Search.
581 - * @param int $paged Paged.
513 + * @param $post_type
514 + * @param $limit
515 + * @param $search
516 + * @param $paged
582 517 *
583 518 * @return array
584 519 */
585 520 public function get_query_data( $post_type = 'any', $limit = 10, $search = '', $paged = 1 ) {
@@ -614,17 +549,8 @@
614 549 }
615 550
616 551 if ( ! empty( $search ) ) {
617 552 $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 553 }
628 554
629 555 $query = "select post_title,ID from $wpdb->posts where post_status = 'publish' {$where} {$limit}";
630 556 $results = $wpdb->get_results( $query ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.NoCaching