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

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

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