PluginProbe
Ultimate Store Kit – Store Builder Addons for Elementor, WooCommerce Store Builder, EDD Store Builder / 3.1.4
Ultimate Store Kit – Store Builder Addons for Elementor, WooCommerce Store Builder, EDD Store Builder v3.1.4
3.1.4 3.0.8 3.0.9 3.1.0 3.1.2 3.1.3 3.0.7 3.0.5 3.0.4 3.0.3 3.0.2 trunk 1.5.0 1.5.1 1.5.2 1.6.1 1.6.2 1.6.3 1.6.4 2.0.0 2.0.1 2.0.2 2.0.3 2.0.4 2.0.5 All 93 releases
← All changes | includes/builder/builder-integration.php +289 -93 2.0.13.1.4 View file →
@@ -1,7 +1,15 @@
1 1 <?php
2 2
3 -if ( ! defined( 'WPINC' ) ) {
3 +namespace UltimateStoreKit\Builder;
4 +
5 +if (! defined('ABSPATH')) {
6 + exit; // Exit if accessed directly
7 +}
8 +
9 +// phpcs:disable WordPress.NamingConventions.PrefixAllGlobals -- BDTUSK_ / ultimate_store_kit_ / ultimate-store-kit- are this plugin's established public prefixes.
10 +
11 +if (! defined('WPINC')) {
4 12 die;
5 13 }
6 14
7 15 use Elementor\Controls_Manager;
@@ -19,21 +27,120 @@
19 27 private $current_template = null;
20 28 public $current_template_id = null;
21 29
22 30 function __construct() {
23 - add_filter( 'template_include', [ $this, 'set_builder_template' ], 9999 );
24 - add_action( 'elementor/editor/init', [ $this, 'set_sample_post' ], 999 );
31 + add_filter('template_include', [$this, 'set_builder_template'], 9999);
32 + add_action('elementor/editor/init', [$this, 'set_sample_post'], 999);
25 33
26 - add_action( 'print_default_editor_scripts', array( $this, 'my_custom_fonts' ) );
34 + add_action('print_default_editor_scripts', array($this, 'my_custom_fonts'));
35 + add_filter("elementor/document/urls/wp_preview", [$this, 'change_preview_editor_url'], 999, 2);
27 36
28 - add_action( 'elementor/documents/register_controls', [ $this, 'register_document_controls' ] );
37 + add_action('elementor/documents/register_controls', [$this, 'register_document_controls']);
38 +
39 + // The template preview used to accept the literal string "verified" in place
40 + // of a nonce whenever $_SERVER['HTTP_HOST'] contained one of a list of demo
41 + // hostnames. Because Host is attacker-controlled and the check was a substring
42 + // match, any unauthenticated visitor could render the Elementor content of an
43 + // arbitrary post id -- including drafts and private posts -- on any site whose
44 + // Host reached PHP as localhost/127.0.0.1 (common behind a reverse proxy) or
45 + // whose domain merely contained one of those strings. Preview is now gated on
46 + // the real per-post nonce plus an edit_post capability check; see get_template_id().
29 47 }
30 48
49 + public function change_preview_editor_url($url, $document) {
50 + $post_id = $document->get_main_id();
51 + $template_type = get_post_meta($post_id, Meta::TEMPLATE_TYPE, true);
52 +
53 + if (empty($template_type) || get_post_type($post_id) !== Meta::POST_TYPE) {
54 + return $url;
55 + }
56 +
57 + $template_data = explode(Builder_Template_Helper::separator(), $template_type);
58 + if (count($template_data) < 2) {
59 + return $url;
60 + }
61 +
62 + $post_type = $template_data[0];
63 + $template_slug = $template_data[1];
64 +
65 + // Get template URL based on template type
66 + $template_url = '';
67 +
68 + // Check for product category first
69 + if ($template_slug === 'product-category') {
70 + $product_cats = get_terms([
71 + 'taxonomy' => 'product_cat',
72 + 'hide_empty' => true,
73 + 'number' => 1,
74 + ]);
75 +
76 + if (!empty($product_cats) && !is_wp_error($product_cats)) {
77 + $template_url = get_term_link($product_cats[0]);
78 + }
79 + }
80 +
81 + // Check for product tag
82 + elseif ($template_slug === 'product-tag') {
83 + $product_tags = get_terms([
84 + 'taxonomy' => 'product_tag',
85 + 'hide_empty' => true,
86 + 'number' => 1,
87 + ]);
88 +
89 + if (!empty($product_tags) && !is_wp_error($product_tags)) {
90 + $template_url = get_term_link($product_tags[0]);
91 + }
92 + } elseif ($template_slug === 'shop' || $template_slug === 'archive') {
93 + $template_url = get_permalink(wc_get_page_id('shop'));
94 + } elseif ($template_slug === 'single' && $post_type === 'product') {
95 + $page_settings_manager = \Elementor\Core\Settings\Manager::get_settings_managers('page');
96 + $page_settings_model = $page_settings_manager->get_model($post_id);
97 + $sample_product = $page_settings_model->get_settings('usk_builder_sample_post_id');
98 +
99 + $template_url = !empty($sample_product) ?
100 + get_permalink($sample_product) :
101 + $this->get_default_product_url();
102 + } elseif ($template_slug === 'cart') {
103 + $template_url = wc_get_cart_url();
104 + } elseif ($template_slug === 'checkout') {
105 + $template_url = wc_get_checkout_url();
106 + } elseif (
107 + $template_slug === 'myaccount'
108 + || $template_slug === 'login'
109 + || strpos($template_slug, 'myaccount-') === 0
110 + ) {
111 + $template_url = get_permalink(wc_get_page_id('myaccount'));
112 + } elseif ($template_slug === 'order-received') {
113 + $orders = wc_get_orders(['limit' => 1]);
114 + if (!empty($orders)) {
115 + $order = $orders[0];
116 + $order_id = $order->get_id();
117 + $template_url = add_query_arg('order-received', $order_id, wc_get_checkout_url());
118 + }
119 + }
120 +
121 + if (empty($template_url)) {
122 + return $url;
123 + }
124 +
125 + $param = [
126 + 'ultimate_store_kit_template_id' => $post_id,
127 + 'ultimate_store_kit_preview_nonce' => wp_create_nonce('ultimate_store_kit_template_preview_' . $post_id),
128 + 'preview' => true
129 + ];
130 +
131 + // Add parameters two URL
132 + $url = add_query_arg($param, $template_url);
133 +
134 + return $url;
135 + }
136 +
31 137 public function my_custom_fonts() {
32 - if ( is_admin() && Plugin::instance()->editor->is_edit_mode() ) {
33 - if ( isset( $_REQUEST['usk-template'] ) ) {
34 - wp_register_style( 'usk-template-builder-hide-preview-btn-inline', false ); // phpcs:ignore
35 - wp_enqueue_style( 'usk-template-builder-hide-preview-btn-inline' );
138 + if (is_admin() && Plugin::instance()->editor->is_edit_mode()) {
139 + // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only check on whether a builder template is open; only enqueues a style.
140 + if (isset($_REQUEST['usk-template'])) {
141 + wp_register_style('usk-template-builder-hide-preview-btn-inline', false); // phpcs:ignore
142 + wp_enqueue_style('usk-template-builder-hide-preview-btn-inline');
36 143 wp_add_inline_style(
37 144 'usk-template-builder-hide-preview-btn-inline',
38 145 '#elementor-panel-footer-saver-preview {display:none!important}'
39 146 );
@@ -40,50 +147,52 @@
40 147 }
41 148 }
42 149 }
43 150 function set_sample_post() {
44 - if ( Builder_Template_Helper::isTemplateEditMode() ) {
151 + if (Builder_Template_Helper::isTemplateEditMode()) {
45 152 $object = \UltimateStoreKit\Includes\Builder\Builder_Post_Singleton::instance();
46 153 $object::set_sample_post();
47 154 }
48 155 }
49 156
50 - function register_document_controls( $document ) {
51 - if ( ! $document instanceof \Elementor\Core\DocumentTypes\PageBase
52 - || ! $document::get_property( 'has_elements' ) ) {
157 + function register_document_controls($document) {
158 + if (
159 + ! $document instanceof \Elementor\Core\DocumentTypes\PageBase
160 + || ! $document::get_property('has_elements')
161 + ) {
53 162 return;
54 163 }
55 164
56 - if ( Plugin::instance()->preview->is_preview_mode() )
165 + if (Plugin::instance()->preview->is_preview_mode())
57 166 return;
58 167
59 - if ( ! Builder_Template_Helper::isTemplateEditMode() ) {
168 + if (! Builder_Template_Helper::isTemplateEditMode()) {
60 169 return;
61 170 }
62 171
63 172 global $post;
64 173
65 - if ( ! isset( $post->ID ) ) {
174 + if (! isset($post->ID)) {
66 175 return;
67 176 }
68 - $meta = get_post_meta( $post->ID );
177 + $meta = get_post_meta($post->ID);
69 178
70 - $templateMeta = optional( $meta )[ Meta::TEMPLATE_TYPE ];
71 - if ( ! isset( $templateMeta[0] ) ) {
179 + $templateMeta = ultimate_store_kit_optional($meta)[Meta::TEMPLATE_TYPE];
180 + if (! isset($templateMeta[0])) {
72 181 return;
73 182 }
74 183 $postMeta = $templateMeta[0];
75 - $postMeta = explode( '|', $postMeta );
184 + $postMeta = explode('|', $postMeta);
76 185 $postType = $postMeta[0];
77 186
78 - if ( $postMeta[1] != 'single' ) {
187 + if ($postMeta[1] != 'single') {
79 188 return;
80 189 }
81 190
82 191 $document->start_controls_section(
83 192 'usk_page_setting_preview',
84 - [
85 - 'label' => esc_html__( 'Builder Settings', 'ultimate-store-kit' ),
193 + [
194 + 'label' => esc_html__('Builder Settings', 'ultimate-store-kit'),
86 195 'tab' => Controls_Manager::TAB_SETTINGS,
87 196 ]
88 197 );
89 198
@@ -88,27 +197,27 @@
88 197 );
89 198
90 199 $document->add_control(
91 200 'usk_builder_sample_post_id',
92 - [
93 - 'label' => __( 'Builder Post', 'ultimate-store-kit' ),
201 + [
202 + 'label' => __('Builder Post', 'ultimate-store-kit'),
94 203 'type' => Dynamic_Select::TYPE,
95 204 'multiple' => false,
96 205 'label_block' => true,
97 - 'query_args' => [
98 - 'post_type' => $postType
99 - ],
206 + 'query_args' => [
207 + 'post_type' => $postType
208 + ],
100 209 ]
101 210 );
102 211
103 212 $document->add_control(
104 213 'usk_builder_sample_apply_preview',
105 - [
214 + [
106 215 'type' => Controls_Manager::BUTTON,
107 - 'label' => esc_html__( 'Apply & Preview', 'ultimate-store-kit' ),
216 + 'label' => esc_html__('Apply & Preview', 'ultimate-store-kit'),
108 217 'label_block' => true,
109 218 'show_label' => false,
110 - 'text' => esc_html__( 'Apply & Preview', 'ultimate-store-kit' ),
219 + 'text' => esc_html__('Apply & Preview', 'ultimate-store-kit'),
111 220 'separator' => 'none',
112 221 'event' => 'ultimateStoreKitBuilderSetting:applySinglePagePostOnPreview',
113 222 ]
114 223 );
@@ -119,73 +228,84 @@
119 228 /**
120 229 * Rewrite default template
121 230 *
122 231 */
123 - function set_builder_template( $template ) {
124 - if ( Builder_Template_Helper::isTemplateEditMode() ) {
125 - return $this->setBackendTemplate( $template );
232 + function set_builder_template($template) {
233 + if (Builder_Template_Helper::isTemplateEditMode()) {
234 + return $this->setBackendTemplate($template);
126 235 } else {
127 - return $this->setFrontendTemplate( $template );
236 + return $this->setFrontendTemplate($template);
128 237 }
129 238 }
130 239
131 240
132 - protected function setBackendTemplate( $template ) {
241 + protected function setBackendTemplate($template) {
133 242 return $template;
134 243 }
135 244
136 245
137 - protected function setFrontendTemplate( $template ) {
246 + protected function setFrontendTemplate($template) {
138 247
139 - if ( get_post_type() == 'product' ) {
248 + if (get_post_type() == 'product') {
140 249 global $product;
141 250 $product = wc_get_product();
142 251 }
143 252
144 - if ( defined( 'ELEMENTOR_PATH' ) ) {
253 + if (defined('ELEMENTOR_PATH')) {
145 254 $elementorTem = ELEMENTOR_PATH . "modules/page-templates/templates/";
146 - $elementorTem = explode( $elementorTem, $template );
147 - if ( count( $elementorTem ) == 2 ) {
255 + $elementorTem = explode($elementorTem, $template);
256 + if (count($elementorTem) == 2) {
148 257 return $template;
149 258 }
150 259 }
151 260
152 - if ( is_post_type_archive( 'product' ) || is_page( wc_get_page_id( 'shop' ) ) || is_product_taxonomy() ) {
153 - if ( $custom_template = $this->get_template_id( 'shop' ) ) {
261 +
262 + if (is_post_type_archive('product') || is_page(wc_get_page_id('shop')) || is_product_taxonomy()) {
263 + $template_type = 'shop';
264 +
265 + if (is_tax('product_cat')) {
266 + $template_type = 'category';
267 + } elseif (is_tax('product_tag')) {
268 + $template_type = 'tag';
269 + }
270 +
271 + if ($custom_template = $this->get_template_id($template_type)) {
154 272 $this->current_template_id = $custom_template;
155 - return $this->getTemplatePath( 'woocommerce/archive-product', $template );
273 + return $this->getTemplatePath('woocommerce/archive-product', $template);
156 274 }
157 275 }
158 276
277 +
159 278 if ( is_cart() ) {
160 - if ( $custom_template = $this->get_template_id( 'cart', 'product' ) ) {
161 - $this->current_template_id = $custom_template;
162 - return $this->getTemplatePath( 'woocommerce/cart', $template );
279 + $cart_template = $this->resolve_cart_template( $template );
280 +
281 + if ( $cart_template ) {
282 + return $cart_template;
163 283 }
164 284 }
165 285
166 - if ( is_order_received_page() ) {
167 - if ( $custom_template = $this->get_template_id( 'order-received', 'product' ) ) {
286 + if (is_order_received_page()) {
287 + if ($custom_template = $this->get_template_id('order-received', 'product')) {
168 288 $this->current_template_id = $custom_template;
169 - return $this->getTemplatePath( 'woocommerce/order-received', $template );
289 + return $this->getTemplatePath('woocommerce/order-received', $template);
170 290 }
171 291 }
172 292
173 - if ( is_checkout() ) {
174 - if ( $custom_template = $this->get_template_id( 'checkout', 'product' ) ) {
293 + if (is_checkout()) {
294 + if ($custom_template = $this->get_template_id('checkout', 'product')) {
175 295 $this->current_template_id = $custom_template;
176 - return $this->getTemplatePath( 'woocommerce/checkout', $template );
296 + return $this->getTemplatePath('woocommerce/checkout', $template);
177 297 }
178 298 }
179 299
180 - if ( is_single() && get_post_type() == 'product' ) {
181 - if ( $custom_template = $this->get_template_id( 'single', 'product' ) ) {
300 + if (is_single() && get_post_type() == 'product') {
301 + if ($custom_template = $this->get_template_id('single', 'product')) {
182 302 $this->current_template_id = $custom_template;
183 - return $this->getTemplatePath( 'woocommerce/single-product', $template );
303 + return $this->getTemplatePath('woocommerce/single-product', $template);
184 304 }
185 305 }
186 306
187 - if ( is_account_page() ) {
307 + if (is_account_page()) {
188 308 global $wp;
189 309 $query_vars = WC()->query->get_query_vars();
190 310
191 311 /**
@@ -192,61 +312,79 @@
192 312 * Add wishlist endpoint
193 313 */
194 314 $query_vars['wishlist'] = 'wishlist';
195 315
196 - if ( $endpoint = array_intersect_key( $wp->query_vars, $query_vars ) ) {
197 - $endpoint = array_key_first( $endpoint );
316 + $endpoint_match = array_intersect_key($wp->query_vars, $query_vars);
198 317
199 - if ( $endpoint && $custom_template = $this->get_template_id( $endpoint, 'account' ) ) {
318 + // Logged-out visitors landing on /my-account/ (no endpoint) see the
319 + // single Login & Register template, which is responsible for both
320 + // authentication flows. WooCommerce's own form-login.php renders
321 + // the login and registration forms on the same URL, so one
322 + // template covers both intents.
323 + if (! is_user_logged_in() && empty($endpoint_match)) {
324 + if ($custom_template = $this->get_template_id('login', 'account')) {
200 325 $this->current_template_id = $custom_template;
201 326
202 - if ( $newTemplate = $this->getTemplatePath( "woocommerce/{$endpoint}" ) ) {
327 + if ($newTemplate = $this->getTemplatePath('woocommerce/login')) {
203 328 return $newTemplate;
204 329 }
205 330
206 - return $this->getTemplatePath( "woocommerce/my-account", '' );
331 + return $this->getTemplatePath('woocommerce/my-account', $template);
207 332 }
333 + }
208 334
209 - if ( $custom_template = $this->get_template_id( 'myaccount-orders', 'account' ) ) {
335 + if ($endpoint = $endpoint_match) {
336 + $endpoint = array_key_first($endpoint);
337 +
338 + if ($endpoint && $custom_template = $this->get_template_id($endpoint, 'account')) {
210 339 $this->current_template_id = $custom_template;
211 - return $this->getTemplatePath( 'woocommerce/my-account', $template );
340 +
341 + if ($newTemplate = $this->getTemplatePath("woocommerce/{$endpoint}")) {
342 + return $newTemplate;
343 + }
344 +
345 + return $this->getTemplatePath("woocommerce/my-account", '');
212 346 }
213 347
348 + if ($custom_template = $this->get_template_id('myaccount-orders', 'account')) {
349 + $this->current_template_id = $custom_template;
350 + return $this->getTemplatePath('woocommerce/my-account', $template);
351 + }
214 352 } else {
215 - if ( $custom_template = $this->get_template_id( 'myaccount', 'account' ) ) {
353 + if ($custom_template = $this->get_template_id('myaccount', 'account')) {
216 354 $this->current_template_id = $custom_template;
217 - return $this->getTemplatePath( 'woocommerce/my-account', $template );
355 + return $this->getTemplatePath('woocommerce/my-account', $template);
218 356 }
219 357 }
220 358 }
221 359
222 360
223 - if ( is_single() ) {
224 - if ( $custom_template = $this->get_template_id( 'single', 'post' ) ) {
361 + if (is_single()) {
362 + if ($custom_template = $this->get_template_id('single', 'post')) {
225 363 $this->current_template_id = $custom_template;
226 - return $this->getTemplatePath( 'single-post', $template );
364 + return $this->getTemplatePath('single-post', $template);
227 365 }
228 366 }
229 367
230 - if ( is_archive() ) {
231 - if ( $custom_template = $this->get_template_id( 'archive', 'post' ) ) {
368 + if (is_archive()) {
369 + if ($custom_template = $this->get_template_id('archive', 'post')) {
232 370 $this->current_template_id = $custom_template;
233 - return $this->getTemplatePath( 'archive-post', $template );
371 + return $this->getTemplatePath('archive-post', $template);
234 372 }
235 373 }
236 374
237 - if ( is_home() ) {
238 - if ( $custom_template = $this->get_template_id( 'home', 'post' ) ) {
375 + if (is_home()) {
376 + if ($custom_template = $this->get_template_id('home', 'post')) {
239 377 $this->current_template_id = $custom_template;
240 - return $this->getTemplatePath( 'home', $template );
378 + return $this->getTemplatePath('home', $template);
241 379 }
242 380 }
243 381
244 - if ( $page_Id = intval( get_option( 'bdt_usk_compare_products_page_id' ) ) ) {
245 - if ( is_page( $page_Id ) ) {
246 - if ( $custom_template = $this->get_template_id( 'compare-products', 'product' ) ) {
382 + if ($page_Id = ultimate_store_kit_get_compare_page_option()) {
383 + if (is_page($page_Id)) {
384 + if ($custom_template = $this->get_template_id('compare-products', 'product')) {
247 385 $this->current_template_id = $custom_template;
248 - return $this->getTemplatePath( 'home', $template );
386 + return $this->getTemplatePath('home', $template);
249 387 }
250 388 }
251 389 }
252 390
@@ -253,20 +391,20 @@
253 391 return $template;
254 392 }
255 393
256 394
257 - public function getThemeTemplatePath( $slug ) {
395 + public function getThemeTemplatePath($slug) {
258 396
259 397 $fullPath = get_template_directory() . "/ultimate-store-kit/$slug";
260 - if ( file_exists( $fullPath ) ) {
398 + if (file_exists($fullPath)) {
261 399 return $fullPath;
262 400 }
263 401 }
264 402
265 - public function getPluginTemplatePath( $slug ) {
403 + public function getPluginTemplatePath($slug) {
266 404
267 405 $fullPath = BDTUSK_PATH . "includes/builder/templates/$slug";
268 - if ( file_exists( $fullPath ) ) {
406 + if (file_exists($fullPath)) {
269 407 return $fullPath;
270 408 }
271 409 }
272 410
@@ -278,16 +416,41 @@
278 416 * @param $postType
279 417 *
280 418 * @return mixed|void|null
281 419 */
282 - public function get_template_id( $slug, $postType = false ) {
420 + public function get_template_id($slug, $postType = false) {
421 + // If we already have a template ID for this request, return it
422 + if (null !== $this->current_template_id) {
423 + return $this->current_template_id;
424 + }
283 425
284 - if ( null !== $this->current_template_id ) {
285 - return $this->current_template_id;
426 + // Handle template preview from URL parameters.
427 + if (!empty($_GET['preview']) && !empty($_GET['ultimate_store_kit_template_id']) && !empty($_GET['ultimate_store_kit_preview_nonce'])) {
428 + $usk_template_id = absint(wp_unslash($_GET['ultimate_store_kit_template_id']));
429 + $nonce = sanitize_text_field(wp_unslash($_GET['ultimate_store_kit_preview_nonce']));
430 +
431 + // The nonce is bound to the specific template and to the user who
432 + // generated it, and the capability check makes sure a leaked preview
433 + // URL cannot be replayed by someone who may not edit the template.
434 + $nonce_verified = $usk_template_id
435 + && wp_verify_nonce($nonce, 'ultimate_store_kit_template_preview_' . $usk_template_id)
436 + && current_user_can('edit_post', $usk_template_id);
437 +
438 + if ($nonce_verified && get_post_type($usk_template_id) === Meta::POST_TYPE) {
439 + $template_type = get_post_meta($usk_template_id, Meta::TEMPLATE_TYPE, true);
440 + if (!empty($template_type)) {
441 + $template_data = explode(Builder_Template_Helper::separator(), $template_type);
442 + if (count($template_data) >= 2 && $template_data[1] === $slug && ($postType === false || $template_data[0] === $postType)) {
443 + $this->current_template_id = $usk_template_id;
444 + return $this->current_template_id;
445 + }
446 + }
447 + }
286 448 }
287 449
288 - $templateId = Builder_Template_Helper::getTemplate( $slug, $postType );
289 - $this->current_template_id = apply_filters( 'ultimate-store-kit-builder/custom-shop-template', $templateId );
450 + // Regular template retrieval
451 + $templateId = Builder_Template_Helper::getTemplate($slug, $postType);
452 + $this->current_template_id = apply_filters('ultimate-store-kit-builder/custom-shop-template', $templateId);
290 453
291 454 return $this->current_template_id;
292 455 }
293 456
@@ -299,16 +462,16 @@
299 462 * @param $default
300 463 *
301 464 * @return mixed|string|void
302 465 */
303 - protected function getTemplatePath( $slug, $default = '' ) {
466 + protected function getTemplatePath($slug, $default = '') {
304 467 $phpSlug = "{$slug}.php";
305 468
306 - if ( $template = $this->getThemeTemplatePath( $phpSlug ) ) {
469 + if ($template = $this->getThemeTemplatePath($phpSlug)) {
307 470 return $template;
308 471 }
309 472
310 - if ( $template = $this->getPluginTemplatePath( $phpSlug ) ) {
473 + if ($template = $this->getPluginTemplatePath($phpSlug)) {
311 474 return $template;
312 475 }
313 476
314 477 return $default;
@@ -313,10 +476,43 @@
313 476
314 477 return $default;
315 478 }
316 479
480 + /**
481 + * Resolve the plugin cart template for WooCommerce cart requests.
482 + *
483 + * @param string $template Default WordPress template path.
484 + * @return string|false
485 + */
486 + protected function resolve_cart_template( $template ) {
487 + if ( ! Cart_Render::is_available() ) {
488 + return false;
489 + }
490 +
491 + $custom_template = $this->get_template_id( 'cart', 'product' );
492 + $this->current_template_id = $custom_template ? absint( $custom_template ) : null;
493 +
494 + return $this->getTemplatePath( 'woocommerce/cart', $template );
495 + }
496 +
497 + /**
498 + * Get default product URL with proper error checking
499 + *
500 + * @return string
501 + */
502 + protected function get_default_product_url() {
503 + $products = wc_get_products(['status' => 'publish', 'limit' => 1]);
504 +
505 + if (!empty($products) && isset($products[0]) && is_object($products[0])) {
506 + $product = $products[0];
507 + if (method_exists($product, 'get_id')) {
508 + return get_permalink($product->get_id());
509 + }
510 + }
511 +
512 + // Fallback to shop page if no products found
513 + return get_permalink(wc_get_page_id('shop'));
514 + }
317 515 }
318 516
319 517
320 518 Builder_Integration::instance();
321 -
322 -