PluginProbe
ShopBuilder – WooCommerce Builder For Elementor / 3.4.2
ShopBuilder – WooCommerce Builder For Elementor v3.4.2
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
shopbuilder / app / Helpers / BuilderFns.php

BuilderFns.php in ShopBuilder – WooCommerce Builder For Elementor 3.4.2, at app/Helpers/BuilderFns.php

625 lines 17.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * BuilderFns class
4 *
5 * The builder.
6 *
7 * @package RadiusTheme\SB
8 * @since 1.0.0
9 */
10
11 namespace RadiusTheme\SB\Helpers;
12
13 // Do not allow directly accessing this file.
14 use RadiusTheme\SB\Models\TemplateSettings;
15
16 if ( ! defined( 'ABSPATH' ) ) {
17 exit( 'This script cannot be accessed directly.' );
18 }
19
20 /**
21 * BuilderFns class
22 */
23 class BuilderFns {
24 /**
25 * Local Cache.
26 *
27 * @var array
28 */
29 private static $cache = [];
30
31 /**
32 * Template builder post type
33 *
34 * @var string
35 */
36 public static $post_type_tb = 'rtsb_builder';
37 /**
38 * Template builder
39 *
40 * @var string
41 */
42 public static $template_meta = 'rtsb_tb_template';
43 /**
44 * Template builder
45 *
46 * @var string
47 */
48 public static $product_template_meta = 'rtsb_selected_product_template';
49 /**
50 * Template builder
51 *
52 * @var string
53 */
54 public static $view_template_for_products_meta = 'rtsb_template_for_selected_products';
55 /**
56 * Template builder
57 *
58 * @var string
59 */
60 public static $view_template_for_archive_meta = 'rtsb_template_for_selected_category';
61
62 /**
63 * Template builder
64 *
65 * @var string
66 */
67 public static $categories_product_page_template = 'rtsb_categories_product_page_template';
68 /**
69 * Template builder
70 *
71 * @var string
72 */
73 public static $tags_product_page_template = 'rtsb_tags_product_page_template';
74 /**
75 * Term-meta key used on `product_brand` terms to point at the
76 * Product-Page template that targets that brand. Mirrors
77 * $categories_product_page_template / $tags_product_page_template.
78 *
79 * @var string
80 */
81 public static $brands_product_page_template = 'rtsb_brands_product_page_template';
82 /**
83 * Get template ID based on page type.
84 *
85 * @param string $type Page type (product, archive, etc.).
86 * @return int Template ID or 0.
87 */
88 public static function builder_page_id_by_type( $type ) { // phpcs:ignore Generic.Metrics.CyclomaticComplexity
89 global $post;
90
91 if ( ! array_key_exists( $type, self::builder_page_types() ) ) {
92 return 0;
93 }
94 // Wpml Supported.
95 $options = self::option_name( $type );
96 $post_id = TemplateSettings::instance()->get_option( $options );
97 if ( empty( $post ) ) {
98 return 0;
99 }
100 if ( empty( $post_id ) ) {
101 $options = self::option_name( $type, true );
102 $post_id = TemplateSettings::instance()->get_option( $options );
103 }
104
105 $cache_key = 'rtsb_builder_page_id_by_type_' . $type;
106 if ( isset( self::$cache[ $cache_key ] ) ) {
107 return self::$cache[ $cache_key ];
108 }
109
110 switch ( $type ) {
111 case 'product':
112 if ( ! $post instanceof \WP_Post || 'product' !== $post->post_type ) {
113 break;
114 }
115 $cache_key_product = 'template_for_product_page_' . get_the_ID();
116 $template = get_transient( $cache_key_product );
117 if ( $template && 'publish' === get_post_status( $template ) ) {
118 $post_id = $template;
119 break;
120 }
121 $builder_id = get_post_meta( get_the_ID(), self::$view_template_for_products_meta, true );
122
123 if ( self::get_specific_product_as_default( $builder_id ) && 'publish' === get_post_status( $builder_id ) ) {
124 $post_id = $builder_id;
125 set_transient( $cache_key_product, $post_id, 12 * HOUR_IN_SECONDS ); // Cache duration: 12 hours.
126 break;
127 }
128
129 $terms = get_the_terms( get_the_ID(), 'product_cat' );
130 if ( ! is_wp_error( $terms ) && ! empty( $terms ) ) {
131 foreach ( $terms as $term ) {
132 $template_id = get_term_meta( $term->term_id, self::$categories_product_page_template, true );
133 if ( empty( $template_id ) || 'publish' !== get_post_status( $template_id ) ) {
134 continue;
135 }
136 $set_default_option_name = self::option_name_product_page_specific_cat_set_default( $template_id );
137 if ( TemplateSettings::instance()->get_option( $set_default_option_name ) ) {
138 $post_id = $template_id;
139 set_transient( $cache_key_product, $post_id, 12 * HOUR_IN_SECONDS ); // Cache duration: 12 hours.
140 break 2;
141 }
142 }
143 }
144 // Brand check (between Category and Tag). Requires the `product_brand`
145 // taxonomy (WooCommerce 9.4+ native, or a brand plugin that registers it).
146 $brands = taxonomy_exists( 'product_brand' ) ? get_the_terms( get_the_ID(), 'product_brand' ) : false;
147 if ( ! is_wp_error( $brands ) && ! empty( $brands ) ) {
148 foreach ( $brands as $brand_term ) {
149 $template_id = get_term_meta( $brand_term->term_id, self::$brands_product_page_template, true );
150 if ( empty( $template_id ) || 'publish' !== get_post_status( $template_id ) ) {
151 continue;
152 }
153 $set_default_option_name = self::option_name_product_page_specific_brand_set_default( $template_id );
154 if ( TemplateSettings::instance()->get_option( $set_default_option_name ) ) {
155 $post_id = $template_id;
156 set_transient( $cache_key_product, $post_id, 12 * HOUR_IN_SECONDS ); // Cache duration: 12 hours.
157 break 2;
158 }
159 }
160 }
161 $tags = get_the_terms( get_the_ID(), 'product_tag' );
162 if ( ! is_wp_error( $tags ) && ! empty( $tags ) ) {
163 foreach ( $tags as $term ) {
164 $template_id = get_term_meta( $term->term_id, self::$tags_product_page_template, true );
165 if ( empty( $template_id ) || 'publish' !== get_post_status( $template_id ) ) {
166 continue;
167 }
168 $set_default_option_name = self::option_name_product_page_specific_tag_set_default( $template_id );
169 if ( TemplateSettings::instance()->get_option( $set_default_option_name ) ) {
170 $post_id = $template_id;
171 set_transient( $cache_key_product, $post_id, 12 * HOUR_IN_SECONDS ); // Cache duration: 12 hours.
172 break 2;
173 }
174 }
175 }
176 set_transient( $cache_key_product, $post_id, 12 * HOUR_IN_SECONDS );
177 break;
178 case 'archive':
179 $queried_object = get_queried_object();
180 if ( ! empty( $queried_object->taxonomy ) && 'product_cat' === $queried_object->taxonomy ) {
181 $cache_key_archive = 'template_for_archive_page_' . $queried_object->term_id;
182 $template = get_transient( $cache_key_archive );
183 if ( $template && 'publish' === get_post_status( $template ) ) {
184 $post_id = $template;
185 break;
186 }
187 $builder_id = get_term_meta( $queried_object->term_id, self::$view_template_for_archive_meta, true );
188 if ( self::get_specific_category_as_default( $builder_id ) && 'publish' === get_post_status( $builder_id ) ) {
189 $post_id = $builder_id;
190 set_transient( $cache_key_archive, $post_id, 12 * HOUR_IN_SECONDS ); // Cache duration: 12 hours.
191 }
192 }
193 break;
194
195 default:
196 $post_id = (int) apply_filters( 'rtsb/builder/page/id/by/type/resolve', $post_id, $type );
197 break;
198 }
199 if ( 'publish' === get_post_status( $post_id ) && self::builder_type( $post_id ) === $type ) {
200 self::$cache[ $cache_key ] = $post_id;
201 return $post_id;
202 }
203
204 // Fallback: use shop template for archive pages when no archive template exists.
205 // Filterable so other archive-like types (e.g. brand / tag archives) can opt in.
206 $fallback_to_shop = apply_filters( 'rtsb/builder/archive/fallback_to_shop', 'archive' === $type, $type );
207 if ( $fallback_to_shop ) {
208 $shop_options = self::option_name( 'shop' );
209 $shop_post_id = TemplateSettings::instance()->get_option( $shop_options );
210
211 if ( empty( $shop_post_id ) ) {
212 $shop_options = self::option_name( 'shop', true );
213 $shop_post_id = TemplateSettings::instance()->get_option( $shop_options );
214 }
215
216 if ( $shop_post_id && 'publish' === get_post_status( $shop_post_id ) && 'shop' === self::builder_type( $shop_post_id ) ) {
217 self::$cache[ $cache_key ] = $shop_post_id;
218 return $shop_post_id;
219 }
220 }
221
222 return 0;
223 }
224
225 /**
226 * Get current page builder ID via filter.
227 *
228 * @return int Template ID or 0.
229 */
230 public static function builder_page_id_by_page() {
231 $type = apply_filters( 'rtsb/builder/set/current/page/type', '' );
232 if ( ! $type ) {
233 return 0;
234 }
235
236 return self::builder_page_id_by_type( $type );
237 }
238
239 /**
240 * Page builder Page for.
241 * No need translatable Text and textdomain.
242 *
243 * @return array
244 */
245 public static function builder_page_types() {
246 $page_types = [
247 'shop' => 'Shop/Archive',
248 'archive' => 'Category Archive',
249 'product' => 'Product Page',
250 'cart' => 'Cart',
251 'checkout' => 'Checkout',
252 ];
253
254 return apply_filters( 'rtsb/builder/register/page/types', $page_types );
255 }
256
257 /**
258 * Get option key for template storage.
259 *
260 * @param string $type Template type.
261 * @param bool $default_lang Use default language.
262 * @return string Option key.
263 */
264 public static function option_name( $type, $default_lang = false ) {
265
266 $type = str_replace( [ '-', ' ' ], '_', $type );
267 $suffix = $type;
268
269 if ( $default_lang ) {
270 return self::$template_meta . '_default_' . $suffix;
271 }
272 $current_lang = Fns::wpml_current_language();
273
274 if ( ! empty( $current_lang ) ) {
275 $suffix = $type . '_' . $current_lang;
276 }
277
278 return self::$template_meta . '_default_' . $suffix;
279 }
280
281 /**
282 * Option name to mark product template as default.
283 *
284 * @param int $post_id Template ID.
285 * @return string|null
286 */
287 public static function option_name_for_specific_product_set_default( $post_id ) {
288 if ( ! $post_id ) {
289 return;
290 }
291
292 return 'rtsb_template_specific_product_set_default_' . $post_id;
293 }
294
295 /**
296 * Check if a specific product template is default.
297 *
298 * @param int $post_id Template ID.
299 * @return mixed
300 */
301 public static function get_specific_product_as_default( $post_id ) {
302 if ( ! $post_id ) {
303 return;
304 }
305 $options = self::option_name_for_specific_product_set_default( $post_id );
306
307 return TemplateSettings::instance()->get_option( $options );
308 }
309
310 /**
311 * Option name for default category template.
312 *
313 * @param int $post_id Template ID.
314 * @return string|null
315 */
316 public static function option_name_for_specific_category_set_default( $post_id ) {
317 if ( ! $post_id ) {
318 return;
319 }
320
321 return 'rtsb_template_specific_category_set_default_' . $post_id;
322 }
323
324 /**
325 * Check if a specific category template is default.
326 *
327 * @param int $post_id Template ID.
328 * @return mixed
329 */
330 public static function get_specific_category_as_default( $post_id ) {
331 if ( ! $post_id ) {
332 return;
333 }
334 $options = self::option_name_for_specific_category_set_default( $post_id );
335 return TemplateSettings::instance()->get_option( $options );
336 }
337
338 /**
339 * Get meta key by template ID for products.
340 *
341 * @param int $template_id Template ID.
342 * @return string
343 */
344 public static function option_name_by_template_id( $template_id ) {
345 $_suff = null;
346 if ( $template_id ) {
347 $_suff = '_' . $template_id;
348 }
349
350 return self::$view_template_for_products_meta . $_suff;
351 }
352
353 /**
354 * Get option name for the selected product category template.
355 *
356 * @param int|string $template_id Template ID for the category.
357 *
358 * @return string Generated option name.
359 */
360 public static function option_name_product_page_selected_cat( $template_id ) {
361 $_suff = null;
362 if ( $template_id ) {
363 $_suff = '_' . $template_id;
364 }
365
366 return self::$categories_product_page_template . $_suff;
367 }
368
369 /**
370 * Get option name for setting a specific product category template as default.
371 *
372 * @param int|string $post_id Template or post ID.
373 *
374 * @return string|null Option name or null if post ID is invalid.
375 */
376 public static function option_name_product_page_specific_cat_set_default( $post_id ) {
377 if ( ! $post_id ) {
378 return;
379 }
380
381 return 'rtsb_template_product_page_specific_category_set_default_' . $post_id;
382 }
383
384 /**
385 * Get option name for the selected product tag template.
386 *
387 * @param int|string $template_id Template ID for the tag.
388 *
389 * @return string Generated option name.
390 */
391 public static function option_name_product_page_selected_tag( $template_id ) {
392 $_suff = null;
393 if ( $template_id ) {
394 $_suff = '_' . $template_id;
395 }
396
397 return self::$tags_product_page_template . $_suff;
398 }
399 /**
400 * Get option name for setting a specific product tag template as default.
401 *
402 * @param int|string $post_id Template or post ID.
403 *
404 * @return string|null Option name or null if post ID is not provided.
405 */
406 public static function option_name_product_page_specific_tag_set_default( $post_id ) {
407 if ( ! $post_id ) {
408 return;
409 }
410
411 return 'rtsb_template_product_page_specific_tag_set_default_' . $post_id;
412 }
413 /**
414 * Get option name for the selected product brand template.
415 *
416 * @param int|string $template_id Template ID for the brand.
417 *
418 * @return string Generated option name.
419 */
420 public static function option_name_product_page_selected_brand( $template_id ) {
421 $_suff = null;
422 if ( $template_id ) {
423 $_suff = '_' . $template_id;
424 }
425
426 return self::$brands_product_page_template . $_suff;
427 }
428 /**
429 * Get option name for setting a specific product brand template as default.
430 *
431 * @param int|string $post_id Template or post ID.
432 *
433 * @return string|null Option name or null if post ID is not provided.
434 */
435 public static function option_name_product_page_specific_brand_set_default( $post_id ) {
436 if ( ! $post_id ) {
437 return;
438 }
439
440 return 'rtsb_template_product_page_specific_brand_set_default_' . $post_id;
441 }
442 /**
443 * Get option name for the selected archive (category) template.
444 *
445 * @param int|string $template_id Template ID.
446 *
447 * @return string Generated option name.
448 */
449 public static function archive_option_name_by_template_id( $template_id ) {
450 $_suff = null;
451 if ( $template_id ) {
452 $_suff = '_' . $template_id;
453 }
454
455 return self::$view_template_for_archive_meta . $_suff;
456 }
457
458 /**
459 * Returns meta key used to store builder type.
460 *
461 * @return string
462 */
463 public static function template_type_meta_key() {
464 return self::$template_meta . '_type';
465 }
466
467 /**
468 * Get builder type.
469 *
470 * @param [type] $post_id Post id.
471 *
472 * @return string
473 */
474 public static function builder_type( $post_id ) {
475 $post_id = Fns::wpml_object_id( $post_id, self::$post_type_tb, 'default' );
476
477 if ( ! $post_id ) {
478 return;
479 }
480
481 $cache_key = 'rtsb_template_type_' . $post_id;
482 if ( ! empty( self::$cache[ $cache_key ] ) ) {
483 return self::$cache[ $cache_key ];
484 }
485
486 $type = get_post_meta( $post_id, self::template_type_meta_key(), true );
487
488 // Cache the results in a static variable for the next call.
489 self::$cache[ $cache_key ] = $type;
490
491 return $type;
492 }
493
494 /**
495 * Check if current page is builder preview.
496 *
497 * @return bool
498 */
499 public static function is_builder_preview() {
500 return is_singular( self::$post_type_tb );
501 }
502
503 /**
504 * Check if archive template should load.
505 *
506 * @return bool
507 */
508 public static function is_archive() {
509 return self::is_page_builder( 'archive', is_product_taxonomy() );
510 }
511
512 /**
513 * Check if shop template should load.
514 *
515 * @return bool
516 */
517 public static function is_shop() {
518 return self::is_page_builder( 'shop', is_shop() );
519 }
520
521 /**
522 * Check if cart template should load.
523 *
524 * @return bool
525 */
526 public static function is_cart() {
527 return self::is_page_builder( 'cart', is_cart() );
528 }
529
530 /**
531 * Check if checkout template should load.
532 *
533 * @return bool
534 */
535 public static function is_checkout() {
536 return self::is_page_builder( 'checkout', is_checkout() && ! is_wc_endpoint_url() && ! is_order_received_page() );
537 }
538
539 /**
540 * Single Page builder Detection
541 *
542 * @return boolean
543 */
544 public static function is_product() {
545 return self::is_page_builder( 'product', is_product() );
546 }
547
548 /**
549 * Check if quick view page template should load.
550 *
551 * @param bool $is_quick_view True if quick view.
552 * @return bool
553 */
554 public static function is_quick_views_page( $is_quick_view = false ) {
555 return rtsb()->has_pro() && self::is_page_builder( 'quick-view', $is_quick_view );
556 }
557
558
559 /**
560 * Check if a template should replace default WooCommerce page.
561 *
562 * @param string $type Page type.
563 * @param bool $is_page Current page status.
564 * @param bool $is_require_auth Require login.
565 * @return bool
566 */
567 public static function is_page_builder( $type, $is_page, $is_require_auth = false ) {
568 $current_builder_type = self::builder_type( get_the_ID() );
569 $post_type = get_post_type( get_the_ID() );
570 if ( $post_type === self::$post_type_tb ) {
571 if ( $current_builder_type === $type ) {
572 return true;
573 } else {
574 return false;
575 }
576 }
577 if ( $is_require_auth && ! is_user_logged_in() ) {
578 $type = 'myaccount-auth';
579 }
580 $builder_id = self::builder_page_id_by_type( $type );
581 if ( ! $builder_id ) {
582 return false;
583 }
584 $builder_type = self::builder_type( $builder_id );
585 if ( $type === $builder_type && $is_page ) {
586 return true;
587 }
588
589 // Allow shop template as fallback for archive pages.
590 if ( 'archive' === $type && 'shop' === $builder_type && $is_page ) {
591 return true;
592 }
593
594 return false;
595 }
596
597 /**
598 * Get builder content function
599 *
600 * @param [type] $template_id builder Template id.
601 * @param boolean $with_css with css.
602 *
603 * @return mixed
604 */
605 public static function get_builder_content( $template_id, $with_css = false ) {
606 // Don't Use cache: tickets ID -> 75376.
607 if ( ! defined( 'ELEMENTOR_VERSION' ) || ! class_exists( '\Elementor\Plugin' ) ) {
608 return '';
609 }
610
611 try {
612 $plugin = \Elementor\Plugin::instance();
613
614 if ( ! $plugin || ! isset( $plugin->frontend ) ) {
615 return '';
616 }
617
618 return $plugin->frontend->get_builder_content_for_display( $template_id, $with_css );
619 } catch ( \Throwable $e ) {
620 error_log( 'ShopBuilder content render error: ' . $e->getMessage() ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
621 return '';
622 }
623 }
624 }
625