PluginProbe
ShopBuilder – WooCommerce Builder For Elementor / 1.1.4
ShopBuilder – WooCommerce Builder For Elementor v1.1.4
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 +297 -721 3.4.21.1.4 View file →
@@ -1,721 +1,297 @@
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 -
195 - if ( $this->should_register_widget( $element['category'], $import ) ) {
196 - $widget = new $element['base_class']();
197 - }
198 -
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;
207 - }
208 - }
209 - }
210 - }
211 -
212 - /**
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 - * Adding custom icons in Elementor
254 - *
255 - * @param array $tabs Tabs.
256 - *
257 - * @return array
258 - */
259 - public function rtsb_icons( $tabs = [] ) {
260 - $custom_icons = Fns::get_custom_icon_names();
261 -
262 - $tabs['shopbuilder-icons'] = [
263 - 'name' => 'rtsb-fonts',
264 - 'label' => esc_html__( 'ShopBuilder Icons', 'shopbuilder' ),
265 - 'labelIcon' => 'fab fa-elementor',
266 - 'prefix' => 'rtsb-icon-',
267 - 'displayPrefix' => 'rtsb-icon',
268 - 'url' => rtsb()->get_assets_uri( 'css/frontend/rtsb-fonts.css' ),
269 - 'icons' => $custom_icons,
270 - 'ver' => '1.0',
271 - ];
272 -
273 - return $tabs;
274 - }
275 -
276 - /**
277 - * Editor JS.
278 - *
279 - * @return void
280 - */
281 - public function editor_scripts() {
282 - $version = ( defined( 'WP_DEBUG' ) && WP_DEBUG ) ? time() : RTSB_VERSION;
283 -
284 - wp_enqueue_script(
285 - 'rtsb-editor-script',
286 - rtsb()->get_assets_uri( 'js/backend/editor.js' ),
287 - [
288 - 'jquery',
289 - 'elementor-editor',
290 - 'jquery-elementor-select2',
291 - ],
292 - $version,
293 - true
294 - );
295 - $params = [
296 - 'isEditorForBuilder' => false,
297 - ];
298 - if ( BuilderFns::is_builder_preview() ) {
299 - $params['isEditorForBuilder'] = true;
300 - }
301 - wp_localize_script( 'rtsb-editor-script', 'rtsbTemplateBuilderEditorScript', $params );
302 - wp_enqueue_style( 'rtsb-el-editor-style', rtsb()->get_assets_uri( 'css/backend/elementor-editor.css' ), [], $version );
303 - }
304 -
305 - /**
306 - * Before Content for Elementor.
307 - *
308 - * @return void
309 - */
310 - public function builder_template_before_content() {
311 - /**
312 - * Before Header-Footer page template content.
313 - *
314 - * Fires before the content of Elementor Header-Footer page template.
315 - *
316 - * @since 2.0.0
317 - */
318 - 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
320 - }
321 -
322 - $parent_class = apply_filters( 'rtsb/builder/content/parent_class', [] );
323 -
324 - 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 -
334 - $parent_class = wc_get_product_class( $parent_class, $product_id );
335 -
336 - if ( function_exists( 'rtwpvs' ) && $_product instanceof \WC_Product ) {
337 - if ( $_product->is_type( 'variable' ) ) {
338 - $parent_class[] = 'rtwpvs-product';
339 - $beside_label = function_exists( 'rtwpvsp' ) && rtwpvs()->get_option( 'attribute_on_click_behavior' );
340 - if ( $beside_label ) {
341 - $parent_class[] = 'rtwpvs-selected-term-beside-label';
342 - }
343 - }
344 - }
345 - }
346 -
347 - if ( BuilderFns::is_shop() ) {
348 - $parent_class[] = 'shop';
349 - }
350 -
351 - if ( BuilderFns::is_archive() ) {
352 - $parent_class[] = 'archive';
353 - }
354 -
355 - if ( BuilderFns::is_checkout() ) {
356 - $parent_class[] = 'checkout-page ';
357 - }
358 -
359 - ?>
360 - <!-- Before Content start -->
361 - <div class="<?php echo esc_attr( implode( ' ', $parent_class ) ); ?>">
362 - <?php
363 - if ( BuilderFns::is_checkout() ) {
364 - if ( ! apply_filters( 'rtsb/multi/step/checkout/widget', true ) ) {
365 - return;
366 - }
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 - ?>
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">
393 - <?php
394 - }
395 - }
396 -
397 - /**
398 - * After Content for Elementor.
399 - *
400 - * @return void
401 - */
402 - public function builder_template_after_content() {
403 - /**
404 - * After Header-Footer page template content.
405 - *
406 - * Fires after the content of Elementor Header-Footer page template.
407 - *
408 - * @since 2.0.0
409 - */
410 - 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
412 - }
413 -
414 - if ( BuilderFns::is_checkout() ) {
415 - if ( ! apply_filters( 'rtsb/multi/step/checkout/widget', true ) ) {
416 - return;
417 - }
418 - ?>
419 - </form>
420 - <?php
421 - do_action( 'woocommerce_after_checkout_form', WC()->checkout() );
422 - }
423 - ?>
424 - </div>
425 - <!-- After Content end -->
426 - <?php
427 - }
428 -
429 - /**
430 - * Ajax callback for rt-select2
431 - *
432 - * @return void
433 - */
434 - public function select2_ajax_posts_filter_autocomplete() {
435 - if ( ! wp_verify_nonce( Fns::get_nonce(), rtsb()->nonceText ) ) {
436 - wp_send_json_error( [] );
437 - }
438 - $query_per_page = 15;
439 - $post_type = 'post';
440 - $source_name = 'post_type';
441 - $paged = absint( $_POST['page'] ?? 1 );
442 - if ( ! empty( $_POST['post_type'] ) ) {
443 - // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash
444 - $post_type = sanitize_text_field( $_POST['post_type'] );
445 - }
446 -
447 - if ( ! empty( $_POST['source_name'] ) ) {
448 - // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash
449 - $source_name = sanitize_text_field( $_POST['source_name'] );
450 - }
451 -
452 - // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash
453 - $search = ! empty( $_POST['search'] ) ? sanitize_text_field( $_POST['search'] ) : '';
454 - $results = $post_list = []; // phpcs:ignore Squiz.PHP.DisallowMultipleAssignments.Found
455 - switch ( $source_name ) {
456 - case 'taxonomy':
457 - $args = [
458 - 'hide_empty' => false,
459 - 'orderby' => 'name',
460 - 'order' => 'ASC',
461 - 'name__like' => $search,
462 - 'number' => '5',
463 - ];
464 -
465 - if ( 'all' !== $post_type ) {
466 - $args['taxonomy'] = $post_type;
467 - }
468 -
469 - $post_list = wp_list_pluck( get_terms( $args ), 'name', 'term_id' );
470 - break;
471 - case 'user':
472 - $users = [];
473 -
474 - foreach ( get_users( [ 'search' => "*{$search}*" ] ) as $user ) {
475 - $user_id = $user->ID;
476 - $user_name = $user->display_name;
477 - $users[ $user_id ] = $user_name;
478 - }
479 -
480 - $post_list = $users;
481 - break;
482 - default:
483 - $post_list = $this->get_query_data( $post_type, $query_per_page, $search, $paged );
484 - }
485 -
486 - $pagination = true;
487 - if ( count( $post_list ) < $query_per_page ) {
488 - $pagination = false;
489 - }
490 - if ( ! empty( $post_list ) ) {
491 - foreach ( $post_list as $key => $item ) {
492 - $results[] = [
493 - 'text' => $item,
494 - 'id' => $key,
495 - ];
496 - }
497 - }
498 - wp_send_json(
499 - [
500 - 'results' => $results,
501 - 'pagination' => [ 'more' => $pagination ],
502 - ]
503 - );
504 - }
505 -
506 -
507 - /**
508 - * Ajax callback for rt-select2
509 - *
510 - * @return void
511 - */
512 - public function select2_ajax_get_posts_value_titles() {
513 -
514 - if ( ! wp_verify_nonce( Fns::get_nonce(), rtsb()->nonceText ) ) {
515 - wp_send_json_error( [] );
516 - }
517 -
518 - if ( empty( $_POST['id'] ) ) {
519 - wp_send_json_error( [] );
520 - }
521 -
522 - // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
523 - if ( empty( array_filter( $_POST['id'] ) ) ) {
524 - wp_send_json_error( [] );
525 - }
526 - $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
528 -
529 - switch ( $source_name ) {
530 - case 'taxonomy':
531 - $args = [
532 - 'hide_empty' => false,
533 - 'orderby' => 'name',
534 - 'order' => 'ASC',
535 - 'include' => implode( ',', $ids ),
536 - ];
537 -
538 - // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotValidated
539 - if ( 'all' !== $_POST['post_type'] ) {
540 - // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotValidated, WordPress.Security.ValidatedSanitizedInput.MissingUnslash
541 - $args['taxonomy'] = sanitize_text_field( $_POST['post_type'] );
542 - }
543 -
544 - $response = wp_list_pluck( get_terms( $args ), 'name', 'term_id' );
545 - break;
546 - case 'user':
547 - $users = [];
548 -
549 - foreach ( get_users( [ 'include' => $ids ] ) as $user ) {
550 - $user_id = $user->ID;
551 - $user_name = $user->display_name . '-' . $user->ID;
552 - $users[ $user_id ] = $user_name;
553 - }
554 -
555 - $response = $users;
556 - break;
557 - default:
558 - $post_info = get_posts(
559 - [
560 - 'post_type' => sanitize_text_field( $_POST['post_type'] ), // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotValidated
561 - 'include' => implode( ',', $ids ),
562 - ]
563 - );
564 - $response = wp_list_pluck( $post_info, 'post_title', 'ID' );
565 - }
566 -
567 - if ( ! empty( $response ) ) {
568 - wp_send_json_success( [ 'results' => $response ] );
569 - } else {
570 - wp_send_json_error( [] );
571 - }
572 - }
573 -
574 -
575 - /**
576 - * Ajax callback for rt-select2
577 - *
578 - * @param string $post_type Post type.
579 - * @param int $limit Limit.
580 - * @param string $search Search.
581 - * @param int $paged Paged.
582 - *
583 - * @return array
584 - */
585 - public function get_query_data( $post_type = 'any', $limit = 10, $search = '', $paged = 1 ) {
586 - global $wpdb;
587 - $where = '';
588 - $data = [];
589 -
590 - if ( - 1 == $limit ) {
591 - $limit = '';
592 - } elseif ( 0 == $limit ) {
593 - $limit = 'limit 0,1';
594 - } else {
595 - $offset = 0;
596 - if ( $paged ) {
597 - $offset = ( $paged - 1 ) * $limit;
598 - }
599 - $limit = $wpdb->prepare( ' limit %d, %d', esc_sql( $offset ), esc_sql( $limit ) );
600 - }
601 -
602 - if ( 'any' === $post_type ) {
603 - $in_search_post_types = get_post_types( [ 'exclude_from_search' => false ] );
604 - if ( empty( $in_search_post_types ) ) {
605 - $where .= ' AND 1=0 ';
606 - } else {
607 - $where .= " AND {$wpdb->posts}.post_type IN ('" . join(
608 - "', '",
609 - array_map( 'esc_sql', $in_search_post_types )
610 - ) . "')";
611 - }
612 - } elseif ( ! empty( $post_type ) ) {
613 - $where .= $wpdb->prepare( " AND {$wpdb->posts}.post_type = %s", esc_sql( $post_type ) );
614 - }
615 -
616 - if ( ! empty( $search ) ) {
617 - $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 - }
628 -
629 - $query = "select post_title,ID from $wpdb->posts where post_status = 'publish' {$where} {$limit}";
630 - $results = $wpdb->get_results( $query ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.NoCaching
631 -
632 - if ( ! empty( $results ) ) {
633 - foreach ( $results as $row ) {
634 - $data[ $row->ID ] = $row->post_title . ' [#' . $row->ID . ']';
635 - }
636 - }
637 -
638 - return $data;
639 - }
640 -
641 - /**
642 - * Promotion.
643 - *
644 - * @param array $config Config.
645 - * @return array
646 - */
647 - public function promotePremiumWidgets( $config ) {
648 - if ( rtsb()->has_pro() ) {
649 - return $config;
650 - }
651 -
652 - if ( ! empty( $config['initial_document']['panel']['elements_categories']['rtsb-shopbuilder']['title'] ) ) {
653 - $title = $config['initial_document']['panel']['elements_categories']['rtsb-shopbuilder']['title'];
654 -
655 - if ( 'ShopBuilder - Shop' === $title || 'ShopBuilder - Archive' === $title ) {
656 - if ( ! isset( $config['promotionWidgets'] ) || ! is_array( $config['promotionWidgets'] ) ) {
657 - $config['promotionWidgets'] = [];
658 - }
659 -
660 - $pro_widgets = [
661 - [
662 - 'name' => 'rtsb-ajax-product-filters',
663 - 'title' => esc_html__( 'Ajax Product Filters', 'shopbuilder' ),
664 - 'description' => esc_html__( 'Ajax Product Filters', 'shopbuilder' ),
665 - 'icon' => 'rtsb-el-custom rtsb-element icon-rtsb-ajax-product-filters rtsb-promotional-element',
666 - 'categories' => '[ "rtsb-shopbuilder" ]',
667 - ],
668 - ];
669 -
670 - $config['promotionWidgets'] = array_merge( $config['promotionWidgets'], $pro_widgets );
671 -
672 - return $config;
673 - }
674 - }
675 -
676 - return $config;
677 - }
678 -
679 - /**
680 - * Get Icons.
681 - *
682 - * @return array
683 - */
684 - public function get_icons() {
685 - return [
686 - 'heart-empty',
687 - 'heart',
688 - 'eye',
689 - 'exchange',
690 - 'plus',
691 - 'minus',
692 - 'avatar',
693 - 'pay',
694 - 'share',
695 - 'clock',
696 - 'check-alt',
697 - 'check',
698 - 'delete',
699 - 'marker',
700 - 'list',
701 - 'list-2',
702 - 'power',
703 - 'cart',
704 - 'cart-2',
705 - 'cart-3',
706 - 'downloads',
707 - 'zoom',
708 - 'user-edit',
709 - 'grid',
710 - 'filter',
711 - 'billing',
712 - 'login',
713 - 'payment',
714 - 'search',
715 - 'edit',
716 - 'coupon',
717 - 'arrows-cw',
718 - 'trash-empty',
719 - ];
720 - }
721 -}
1 +<?php
2 +/**
3 + * Main BuilderController class.
4 + *
5 + * @package RadiusTheme\SB
6 + */
7 +
8 +namespace RadiusTheme\SB\Controllers;
9 +
10 +use Elementor\Plugin;
11 +use RadiusTheme\SB\Helpers\Fns;
12 +use RadiusTheme\SB\Helpers\BuilderFns;
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\Models\ElementList;
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 + * Builder page id.
30 + *
31 + * @var integer
32 + */
33 + private $builder_page_id = 0;
34 +
35 + /**
36 + * Page Edit By.
37 + *
38 + * @var string
39 + */
40 + private $page_edit_with = '';
41 +
42 + /**
43 + * Singleton Trait
44 + */
45 + use SingletonTrait;
46 +
47 + /**
48 + * Construct function
49 + */
50 + private function __construct() {
51 + $this->builder_page_id = BuilderFns::builder_page_id_by_page();
52 + $this->page_edit_with = Fns::page_edit_with( $this->builder_page_id );
53 +
54 + if ( ! is_admin() ) {
55 + BuilderHooks::instance();
56 + }
57 +
58 + BuilderCpt::instance();
59 +
60 + add_action( 'elementor/init', [ $this, 'elementor_init' ] );
61 + add_action( 'elementor/editor/before_enqueue_scripts', [ $this, 'editor_scripts' ] );
62 + add_action( 'template_redirect', [ $this, 'both_builder_frontend' ], 99 );
63 + }
64 +
65 + /**
66 + * Apply for frontend.
67 + *
68 + * @return void
69 + */
70 + public function both_builder_frontend() {
71 + add_action( 'rtsb/builder/template/before/content', [ $this, 'builder_template_before_content' ] );
72 + add_action( 'rtsb/builder/template/after/content', [ $this, 'builder_template_after_content' ] );
73 + }
74 +
75 + /**
76 + * Register Category
77 + *
78 + * @return void
79 + */
80 + public function elementor_init() {
81 + add_action( 'elementor/elements/categories_registered', [ $this, 'add_elementor_widget_categories' ] );
82 + add_action( 'elementor/widgets/register', [ $this, 'init_widgets' ] );
83 + add_action( 'elementor/controls/register', [ $this, 'init_controls' ] );
84 + }
85 +
86 + /**
87 + * Register Category
88 + *
89 + * @param object $elements_manager Category hooks.
90 + *
91 + * @return void
92 + */
93 + public function add_elementor_widget_categories( $elements_manager ) {
94 + $type = BuilderFns::builder_type( get_the_ID() );
95 + $builder_type = ! empty( BuilderFns::builder_page_types()[ $type ] ) ? BuilderFns::builder_page_types()[ $type ] : null;
96 + $categories['rtsb-shopbuilder'] = [
97 + 'title' => esc_html__( 'ShopBuilder', 'shopbuilder' ) . ' - ' . ucfirst( $builder_type ),
98 + 'icon' => 'fa fa-plug',
99 + ];
100 + $categories['rtsb-shopbuilder-general'] = [
101 + 'title' => esc_html__( 'Shopbuilder - General', 'shopbuilder' ),
102 + 'icon' => 'fa fa-plug',
103 + ];
104 +
105 + $categories = apply_filters( 'rtsb_elementor_widgets_category_lists', $categories );
106 + $other_categories = $elements_manager->get_categories();
107 + $categories = array_merge(
108 + array_slice( $other_categories, 0, 1 ),
109 + $categories,
110 + array_slice( $other_categories, 1 )
111 + );
112 +
113 + $set_categories = function ( $categories ) {
114 + $this->categories = $categories;
115 + };
116 +
117 + $set_categories->call( $elements_manager, $categories );
118 + }
119 +
120 + /**
121 + * Init Controls
122 + *
123 + * Include controls files and register them
124 + *
125 + * @param object $controls_manager Controls Manager.
126 + *
127 + * @since 1.0.0
128 + */
129 + public function init_controls( $controls_manager ) {
130 + $controls_manager->register( new ImageSelectorControl() );
131 + }
132 +
133 + /**
134 + * Init Widgets
135 + *
136 + * Include widgets files and register them
137 + *
138 + * @since 1.0.0
139 + */
140 + public function init_widgets( $widgets_manager ) {
141 + foreach ( ElementList::instance()->get_list( true, 'active' ) as $element ) {
142 + if ( isset( $element['active'] ) && $element['active'] !== 'on' ) {
143 + continue;
144 + }
145 +
146 + if ( ! empty( $element['package'] ) && $element['package'] === 'pro-disabled' ) {
147 + continue;
148 + }
149 +
150 + if ( isset( $element['base_class'] ) && ! class_exists( $element['base_class'] ) ) {
151 + continue;
152 + }
153 +
154 + if ( ! empty( $element['category'] ) ) {
155 + $widget = false;
156 + switch ( $element['category'] ) {
157 + case 'product':
158 + if ( BuilderFns::is_product() ) {
159 + $widget = new $element['base_class']();
160 + }
161 + break;
162 + case 'shop':
163 + if ( BuilderFns::is_archive() || BuilderFns::is_shop() ) {
164 + $widget = new $element['base_class']();
165 + }
166 + break;
167 + case 'archive':
168 + if ( BuilderFns::is_archive() ) {
169 + $widget = new $element['base_class']();
170 + }
171 + break;
172 + case 'cart':
173 + if ( BuilderFns::is_cart() ) {
174 + $widget = new $element['base_class']();
175 + }
176 + break;
177 + case 'checkout':
178 + if ( BuilderFns::is_checkout() ) {
179 + $widget = new $element['base_class']();
180 + }
181 + break;
182 + case 'general':
183 + $widget = new $element['base_class']();
184 + break;
185 + default:
186 + }
187 + $widget = apply_filters( 'rtsb/element/list/init/widgets', $widget, $element );
188 +
189 + if ( $widget && is_object( $widget ) ) {
190 + $widgets_manager->register( $widget );
191 + }
192 + }
193 + }
194 + }
195 +
196 + /**
197 + * Editor JS.
198 + *
199 + * @return void
200 + */
201 + public function editor_scripts() {
202 + $version = ( defined( 'WP_DEBUG' ) && WP_DEBUG ) ? time() : RTSB_VERSION;
203 +
204 + wp_enqueue_script(
205 + 'rtsb-editor-script',
206 + rtsb()->get_assets_uri( 'js/backend/editor.js' ),
207 + [
208 + 'jquery',
209 + 'elementor-editor',
210 + ],
211 + $version,
212 + true
213 + );
214 + $params = [
215 + 'isEditorForBuilder' => false,
216 + ];
217 + if ( BuilderFns::is_builder_preview() ) {
218 + $params['isEditorForBuilder'] = true;
219 + }
220 + wp_localize_script( 'rtsb-editor-script', 'rtsbTemplateBuilderEditorScript', $params );
221 + wp_enqueue_style( 'rtsb-el-editor-style', rtsb()->get_assets_uri( 'css/backend/elementor-editor.css' ), [], $version );
222 + }
223 +
224 + /**
225 + * Before Content for Elementor.
226 + *
227 + * @return void
228 + */
229 + public function builder_template_before_content() {
230 + /**
231 + * Before Header-Footer page template content.
232 + *
233 + * Fires before the content of Elementor Header-Footer page template.
234 + *
235 + * @since 2.0.0
236 + */
237 + if ( did_action( 'elementor/loaded' ) && 'elementor' === $this->page_edit_with ) {
238 + do_action( 'elementor/page_templates/header-footer/before_content' );
239 + }
240 +
241 + $parent_class = apply_filters( 'rtsb/builder/content/parent_class', [] );
242 +
243 + if ( BuilderFns::is_product() ) {
244 + $product_id = Fns::get_prepared_product_id();
245 + $parent_class = wc_get_product_class( $parent_class, $product_id );
246 + }
247 +
248 + if ( BuilderFns::is_shop() ) {
249 + $parent_class[] = 'shop';
250 + }
251 +
252 + if ( BuilderFns::is_archive() ) {
253 + $parent_class[] = 'archive';
254 + }
255 +
256 + if ( BuilderFns::is_checkout() ) {
257 + $parent_class[] = 'checkout-page ';
258 + }
259 +
260 + ?>
261 + <!-- Before Content start -->
262 + <div class="<?php echo esc_attr( implode( ' ', $parent_class ) ); ?>">
263 + <?php if ( BuilderFns::is_checkout() ) { ?>
264 + <form name="checkout" method="post" class="rtsb-woocommerce-checkout checkout" action="<?php echo esc_url( wc_get_checkout_url() ); ?>" enctype="multipart/form-data">
265 + <?php
266 + }
267 +
268 + }
269 +
270 + /**
271 + * After Content for Elementor.
272 + *
273 + * @return void
274 + */
275 + public function builder_template_after_content() {
276 + /**
277 + * After Header-Footer page template content.
278 + *
279 + * Fires after the content of Elementor Header-Footer page template.
280 + *
281 + * @since 2.0.0
282 + */
283 + if ( did_action( 'elementor/loaded' ) && 'elementor' === $this->page_edit_with ) {
284 + do_action( 'elementor/page_templates/header-footer/after_content' );
285 + }
286 +
287 + if ( BuilderFns::is_checkout() ) {
288 + ?>
289 + </form>
290 + <?php
291 + }
292 + ?>
293 + </div>
294 + <!-- After Content end -->
295 + <?php
296 + }
297 +}