Completed
Pull Request — master (#11455)
by
unknown
11:10
created

wc-template-functions.php ➔ woocommerce_get_product_schema()   B

Complexity

Conditions 4
Paths 4

Size

Total Lines 22
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
dl 0
loc 22
rs 8.9197
c 0
b 0
f 0
eloc 15
nc 4
nop 0

1 Method

Rating   Name   Duplication   Size   Complexity  
A wc-template-functions.php ➔ woocommerce_get_product_thumbnail() 0 14 3
1
<?php
2
/**
3
 * WooCommerce Template
4
 *
5
 * Functions for the templating system.
6
 *
7
 * @author   WooThemes
8
 * @category Core
9
 * @package  WooCommerce/Functions
10
 * @version  2.5.0
11
 */
12
13
if ( ! defined( 'ABSPATH' ) ) {
14
	exit; // Exit if accessed directly
15
}
16
17
/**
18
 * Handle redirects before content is output - hooked into template_redirect so is_page works.
19
 */
20
function wc_template_redirect() {
21
	global $wp_query, $wp;
22
23
	if ( ! empty( $_GET['page_id'] ) && '' === get_option( 'permalink_structure' ) && wc_get_page_id( 'shop' ) == $_GET['page_id'] ) {
24
25
		// When default permalinks are enabled, redirect shop page to post type archive url
26
		wp_safe_redirect( get_post_type_archive_link( 'product' ) );
27
		exit;
28
29
	} elseif ( is_page( wc_get_page_id( 'checkout' ) ) && wc_get_page_id( 'checkout' ) !== wc_get_page_id( 'cart' ) && WC()->cart->is_empty() && empty( $wp->query_vars['order-pay'] ) && ! isset( $wp->query_vars['order-received'] ) ) {
30
31
		// When on the checkout with an empty cart, redirect to cart page
32
		wc_add_notice( __( 'Checkout is not available whilst your cart is empty.', 'woocommerce' ), 'notice' );
33
		wp_redirect( wc_get_page_permalink( 'cart' ) );
34
		exit;
35
36
	} elseif ( isset( $wp->query_vars['customer-logout'] ) ) {
37
38
		// Logout
39
		wp_redirect( str_replace( '&amp;', '&', wp_logout_url( wc_get_page_permalink( 'myaccount' ) ) ) );
40
		exit;
41
42
	} elseif ( is_search() && is_post_type_archive( 'product' ) && apply_filters( 'woocommerce_redirect_single_search_result', true ) && 1 === absint( $wp_query->found_posts ) ) {
43
44
		// Redirect to the product page if we have a single product
45
		$product = wc_get_product( $wp_query->post );
46
47
		if ( $product && $product->is_visible() ) {
48
			wp_safe_redirect( get_permalink( $product->id ), 302 );
49
			exit;
50
		}
51
	} elseif ( is_add_payment_method_page() ) {
52
53
		// Ensure payment gateways are loaded early
54
		WC()->payment_gateways();
55
56
	} elseif ( is_checkout() ) {
57
58
		// Checkout pages handling
59
		// Buffer the checkout page
60
		ob_start();
61
62
		// Ensure gateways and shipping methods are loaded early
63
		WC()->payment_gateways();
64
		WC()->shipping();
65
66
	}
67
}
68
add_action( 'template_redirect', 'wc_template_redirect' );
69
70
/**
71
 * When loading sensitive checkout or account pages, send a HTTP header to limit rendering of pages to same origin iframes for security reasons.
72
 *
73
 * Can be disabled with: remove_action( 'template_redirect', 'wc_send_frame_options_header' );
74
 *
75
 * @since  2.3.10
76
 */
77
function wc_send_frame_options_header() {
78
	if ( is_checkout() || is_account_page() ) {
79
		send_frame_options_header();
80
	}
81
}
82
add_action( 'template_redirect', 'wc_send_frame_options_header' );
83
84
/**
85
 * No index our endpoints.
86
 * Prevent indexing pages like order-received.
87
 *
88
 * @since 2.5.3
89
 */
90
function wc_prevent_endpoint_indexing() {
91
	if ( is_wc_endpoint_url() || isset( $_GET['download_file'] ) ) {
92
		@header( 'X-Robots-Tag: noindex' );
93
	}
94
}
95
add_action( 'template_redirect', 'wc_prevent_endpoint_indexing' );
96
97
/**
98
 * Remove adjacent_posts_rel_link_wp_head - pointless for products.
99
 *
100
 * @since 2.7.0
101
 */
102
function wc_prevent_adjacent_posts_rel_link_wp_head() {
103
	if ( is_singular( 'product' ) ) {
104
		remove_action( 'wp_head', 'adjacent_posts_rel_link_wp_head', 10, 0 );
105
	}
106
}
107
add_action( 'template_redirect', 'wc_prevent_adjacent_posts_rel_link_wp_head' );
108
109
/**
110
 * When the_post is called, put product data into a global.
111
 *
112
 * @param mixed $post
113
 * @return WC_Product
114
 */
115
function wc_setup_product_data( $post ) {
116
	unset( $GLOBALS['product'] );
117
118
	if ( is_int( $post ) )
119
		$post = get_post( $post );
120
121
	if ( empty( $post->post_type ) || ! in_array( $post->post_type, array( 'product', 'product_variation' ) ) )
122
		return;
123
124
	$GLOBALS['product'] = wc_get_product( $post );
125
126
	return $GLOBALS['product'];
127
}
128
add_action( 'the_post', 'wc_setup_product_data' );
129
130
if ( ! function_exists( 'woocommerce_reset_loop' ) ) {
131
132
	/**
133
	 * Reset the loop's index and columns when we're done outputting a product loop.
134
	 * @subpackage	Loop
135
	 */
136
	function woocommerce_reset_loop() {
137
		$GLOBALS['woocommerce_loop'] = array(
138
			'loop'    => '',
139
			'columns' => '',
140
			'name'    => '',
141
		);
142
	}
143
}
144
add_filter( 'loop_end', 'woocommerce_reset_loop' );
145
146
/**
147
 * Products RSS Feed.
148
 * @deprecated 2.6
149
 * @access public
150
 */
151
function wc_products_rss_feed() {
152
	// Product RSS
153
	if ( is_post_type_archive( 'product' ) || is_singular( 'product' ) ) {
154
155
		$feed = get_post_type_archive_feed_link( 'product' );
156
157
		echo '<link rel="alternate" type="application/rss+xml"  title="' . esc_attr__( 'New products', 'woocommerce' ) . '" href="' . esc_url( $feed ) . '" />';
158
159
	} elseif ( is_tax( 'product_cat' ) ) {
160
161
		$term = get_term_by( 'slug', esc_attr( get_query_var( 'product_cat' ) ), 'product_cat' );
162
163 View Code Duplication
		if ( $term ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
164
			$feed = add_query_arg( 'product_cat', $term->slug, get_post_type_archive_feed_link( 'product' ) );
165
			echo '<link rel="alternate" type="application/rss+xml"  title="' . esc_attr( sprintf( __( 'New products added to %s', 'woocommerce' ), $term->name ) ) . '" href="' . esc_url( $feed ) . '" />';
166
		}
167
	} elseif ( is_tax( 'product_tag' ) ) {
168
169
		$term = get_term_by( 'slug', esc_attr( get_query_var( 'product_tag' ) ), 'product_tag' );
170
171 View Code Duplication
		if ( $term ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
172
			$feed = add_query_arg( 'product_tag', $term->slug, get_post_type_archive_feed_link( 'product' ) );
173
			echo '<link rel="alternate" type="application/rss+xml"  title="' . sprintf( __( 'New products tagged %s', 'woocommerce' ), urlencode( $term->name ) ) . '" href="' . esc_url( $feed ) . '" />';
174
		}
175
	}
176
}
177
178
/**
179
 * Output generator tag to aid debugging.
180
 *
181
 * @access public
182
 */
183
function wc_generator_tag( $gen, $type ) {
184
	switch ( $type ) {
185
		case 'html':
186
			$gen .= "\n" . '<meta name="generator" content="WooCommerce ' . esc_attr( WC_VERSION ) . '">';
187
			break;
188
		case 'xhtml':
189
			$gen .= "\n" . '<meta name="generator" content="WooCommerce ' . esc_attr( WC_VERSION ) . '" />';
190
			break;
191
	}
192
	return $gen;
193
}
194
195
/**
196
 * Add body classes for WC pages.
197
 *
198
 * @param  array $classes
199
 * @return array
200
 */
201
function wc_body_class( $classes ) {
202
	$classes = (array) $classes;
203
204
	if ( is_woocommerce() ) {
205
206
		$classes[] = 'woocommerce';
207
		$classes[] = 'woocommerce-page';
208
209
	} elseif ( is_checkout() ) {
210
211
		$classes[] = 'woocommerce-checkout';
212
		$classes[] = 'woocommerce-page';
213
214
	} elseif ( is_cart() ) {
215
216
		$classes[] = 'woocommerce-cart';
217
		$classes[] = 'woocommerce-page';
218
219
	} elseif ( is_account_page() ) {
220
221
		$classes[] = 'woocommerce-account';
222
		$classes[] = 'woocommerce-page';
223
224
	}
225
226
	if ( is_store_notice_showing() ) {
227
		$classes[] = 'woocommerce-demo-store';
228
	}
229
230
	foreach ( WC()->query->query_vars as $key => $value ) {
231
		if ( is_wc_endpoint_url( $key ) ) {
232
			$classes[] = 'woocommerce-' . sanitize_html_class( $key );
233
		}
234
	}
235
236
	return array_unique( $classes );
237
}
238
239
/**
240
 * Display the classes for the product cat div.
241
 *
242
 * @since 2.4.0
243
 * @param string|array $class One or more classes to add to the class list.
244
 * @param object $category object Optional.
245
 */
246
function wc_product_cat_class( $class = '', $category = null ) {
247
	// Separates classes with a single space, collates classes for post DIV
248
	echo 'class="' . esc_attr( join( ' ', wc_get_product_cat_class( $class, $category ) ) ) . '"';
249
}
250
251
/**
252
 * Get classname for loops based on $woocommerce_loop global.
253
 * @since 2.6.0
254
 * @return string
255
 */
256
function wc_get_loop_class() {
257
	global $woocommerce_loop;
258
259
	$woocommerce_loop['loop']    = ! empty( $woocommerce_loop['loop'] ) ? $woocommerce_loop['loop'] + 1   : 1;
260
	$woocommerce_loop['columns'] = ! empty( $woocommerce_loop['columns'] ) ? $woocommerce_loop['columns'] : apply_filters( 'loop_shop_columns', 4 );
261
262
	if ( 0 === ( $woocommerce_loop['loop'] - 1 ) % $woocommerce_loop['columns'] || 1 === $woocommerce_loop['columns'] ) {
263
		return 'first';
264
	} elseif ( 0 === $woocommerce_loop['loop'] % $woocommerce_loop['columns'] ) {
265
		return 'last';
266
	} else {
267
		return '';
268
	}
269
}
270
271
/**
272
 * Get the classes for the product cat div.
273
 *
274
 * @since 2.4.0
275
 * @param string|array $class One or more classes to add to the class list.
276
 * @param object $category object Optional.
277
 */
278
function wc_get_product_cat_class( $class = '', $category = null ) {
279
	$classes   = is_array( $class ) ? $class : array_map( 'trim', explode( ' ', $class ) );
280
	$classes[] = 'product-category';
281
	$classes[] = 'product';
282
	$classes[] = wc_get_loop_class();
283
	$classes   = apply_filters( 'product_cat_class', $classes, $class, $category );
284
285
	return array_unique( array_filter( $classes ) );
286
}
287
288
/**
289
 * Adds extra post classes for products.
290
 *
291
 * @since 2.1.0
292
 * @param array $classes
293
 * @param string|array $class
294
 * @param int $post_id
295
 * @return array
296
 */
297
function wc_product_post_class( $classes, $class = '', $post_id = '' ) {
0 ignored issues
show
Unused Code introduced by
The parameter $class is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
298
	if ( ! $post_id || 'product' !== get_post_type( $post_id ) ) {
299
		return $classes;
300
	}
301
302
	$product = wc_get_product( $post_id );
303
304
	if ( $product ) {
305
		$classes[] = wc_get_loop_class();
306
		$classes[] = $product->stock_status;
307
308
		if ( $product->is_on_sale() ) {
309
			$classes[] = 'sale';
310
		}
311
		if ( $product->is_featured() ) {
312
			$classes[] = 'featured';
313
		}
314
		if ( $product->is_downloadable() ) {
315
			$classes[] = 'downloadable';
316
		}
317
		if ( $product->is_virtual() ) {
318
			$classes[] = 'virtual';
319
		}
320
		if ( $product->is_sold_individually() ) {
321
			$classes[] = 'sold-individually';
322
		}
323
		if ( $product->is_taxable() ) {
324
			$classes[] = 'taxable';
325
		}
326
		if ( $product->is_shipping_taxable() ) {
327
			$classes[] = 'shipping-taxable';
328
		}
329
		if ( $product->is_purchasable() ) {
330
			$classes[] = 'purchasable';
331
		}
332
		if ( $product->get_type() ) {
333
			$classes[] = "product-type-" . $product->get_type();
334
		}
335
		if ( $product->is_type( 'variable' ) ) {
336
			if ( $product->has_default_attributes() ) {
337
				$classes[] = 'has-default-attributes';
338
			}
339
			if ( $product->has_child() ) {
340
				$classes[] = 'has-children';
341
			}
342
		}
343
	}
344
345
	if ( false !== ( $key = array_search( 'hentry', $classes ) ) ) {
346
		unset( $classes[ $key ] );
347
	}
348
349
	return $classes;
350
}
351
352
/**
353
 * Outputs hidden form inputs for each query string variable.
354
 * @since 2.7.0
355
 * @param array $values Name value pairs.
356
 * @param array $exclude Keys to exclude.
357
 * @param string $current_key Current key we are outputting.
358
 */
359
function wc_query_string_form_fields( $values = null, $exclude = array(), $current_key = '', $return = false ) {
360
	if ( is_null( $values ) ) {
361
		$values = $_GET;
362
	}
363
	$html = '';
364
365
	foreach ( $values as $key => $value ) {
366
		if ( in_array( $key, $exclude, true ) ) {
367
			continue;
368
		}
369
		if ( $current_key ) {
370
			$key = $current_key . '[' . $key . ']';
371
		}
372
		if ( is_array( $value ) ) {
373
			$html .= wc_query_string_form_fields( $value, $exclude, $key, true );
374
		} else {
375
			$html .= '<input type="hidden" name="' . esc_attr( $key ) . '" value="' . esc_attr( $value ) . '" />';
376
		}
377
	}
378
379
	if ( $return ) {
380
		return $html;
381
	} else {
382
		echo $html;
383
	}
384
}
385
386
/** Template pages ********************************************************/
387
388
if ( ! function_exists( 'woocommerce_content' ) ) {
389
390
	/**
391
	 * Output WooCommerce content.
392
	 *
393
	 * This function is only used in the optional 'woocommerce.php' template.
394
	 * which people can add to their themes to add basic woocommerce support.
395
	 * without hooks or modifying core templates.
396
	 *
397
	 */
398
	function woocommerce_content() {
399
400
		if ( is_singular( 'product' ) ) {
401
402
			while ( have_posts() ) : the_post();
403
404
				wc_get_template_part( 'content', 'single-product' );
405
406
			endwhile;
407
408
		} else { ?>
409
410
			<?php if ( apply_filters( 'woocommerce_show_page_title', true ) ) : ?>
411
412
				<h1 class="page-title"><?php woocommerce_page_title(); ?></h1>
413
414
			<?php endif; ?>
415
416
			<?php do_action( 'woocommerce_archive_description' ); ?>
417
418 View Code Duplication
			<?php if ( have_posts() ) : ?>
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
419
420
				<?php do_action( 'woocommerce_before_shop_loop' ); ?>
421
422
				<?php woocommerce_product_loop_start(); ?>
423
424
					<?php woocommerce_product_subcategories(); ?>
425
426
					<?php while ( have_posts() ) : the_post(); ?>
427
428
						<?php wc_get_template_part( 'content', 'product' ); ?>
429
430
					<?php endwhile; // end of the loop. ?>
431
432
				<?php woocommerce_product_loop_end(); ?>
433
434
				<?php do_action( 'woocommerce_after_shop_loop' ); ?>
435
436
			<?php elseif ( ! woocommerce_product_subcategories( array( 'before' => woocommerce_product_loop_start( false ), 'after' => woocommerce_product_loop_end( false ) ) ) ) : ?>
437
438
				<?php do_action( 'woocommerce_no_products_found' ); ?>
439
440
			<?php endif;
441
442
		}
443
	}
444
}
445
446
/** Global ****************************************************************/
447
448
if ( ! function_exists( 'woocommerce_output_content_wrapper' ) ) {
449
450
	/**
451
	 * Output the start of the page wrapper.
452
	 *
453
	 */
454
	function woocommerce_output_content_wrapper() {
455
		wc_get_template( 'global/wrapper-start.php' );
456
	}
457
}
458
if ( ! function_exists( 'woocommerce_output_content_wrapper_end' ) ) {
459
460
	/**
461
	 * Output the end of the page wrapper.
462
	 *
463
	 */
464
	function woocommerce_output_content_wrapper_end() {
465
		wc_get_template( 'global/wrapper-end.php' );
466
	}
467
}
468
469
if ( ! function_exists( 'woocommerce_get_sidebar' ) ) {
470
471
	/**
472
	 * Get the shop sidebar template.
473
	 *
474
	 */
475
	function woocommerce_get_sidebar() {
476
		wc_get_template( 'global/sidebar.php' );
477
	}
478
}
479
480
if ( ! function_exists( 'woocommerce_demo_store' ) ) {
481
482
	/**
483
	 * Adds a demo store banner to the site if enabled.
484
	 *
485
	 */
486
	function woocommerce_demo_store() {
487
		if ( ! is_store_notice_showing() ) {
488
			return;
489
		}
490
491
		$notice = get_option( 'woocommerce_demo_store_notice' );
492
493
		if ( empty( $notice ) ) {
494
			$notice = __( 'This is a demo store for testing purposes &mdash; no orders shall be fulfilled.', 'woocommerce' );
495
		}
496
497
		echo apply_filters( 'woocommerce_demo_store', '<p class="demo_store">' . wp_kses_post( $notice ) . '</p>', $notice );
498
	}
499
}
500
501
/** Loop ******************************************************************/
502
503
if ( ! function_exists( 'woocommerce_page_title' ) ) {
504
505
	/**
506
	 * woocommerce_page_title function.
507
	 *
508
	 * @param  bool $echo
509
	 * @return string
510
	 */
511
	function woocommerce_page_title( $echo = true ) {
512
513
		if ( is_search() ) {
514
			$page_title = sprintf( __( 'Search Results: &ldquo;%s&rdquo;', 'woocommerce' ), get_search_query() );
515
516
			if ( get_query_var( 'paged' ) )
517
				$page_title .= sprintf( __( '&nbsp;&ndash; Page %s', 'woocommerce' ), get_query_var( 'paged' ) );
518
519
		} elseif ( is_tax() ) {
520
521
			$page_title = single_term_title( "", false );
522
523
		} else {
524
525
			$shop_page_id = wc_get_page_id( 'shop' );
526
			$page_title   = get_the_title( $shop_page_id );
527
528
		}
529
530
		$page_title = apply_filters( 'woocommerce_page_title', $page_title );
531
532
		if ( $echo )
533
			echo $page_title;
534
		else
535
			return $page_title;
536
	}
537
}
538
539
if ( ! function_exists( 'woocommerce_product_loop_start' ) ) {
540
541
	/**
542
	 * Output the start of a product loop. By default this is a UL.
543
	 *
544
	 * @param bool $echo
545
	 * @return string
546
	 */
547
	function woocommerce_product_loop_start( $echo = true ) {
548
		ob_start();
549
		$GLOBALS['woocommerce_loop']['loop'] = 0;
550
		wc_get_template( 'loop/loop-start.php' );
551
		if ( $echo )
552
			echo ob_get_clean();
553
		else
554
			return ob_get_clean();
555
	}
556
}
557
if ( ! function_exists( 'woocommerce_product_loop_end' ) ) {
558
559
	/**
560
	 * Output the end of a product loop. By default this is a UL.
561
	 *
562
	 * @param bool $echo
563
	 * @return string
564
	 */
565
	function woocommerce_product_loop_end( $echo = true ) {
566
		ob_start();
567
568
		wc_get_template( 'loop/loop-end.php' );
569
570
		if ( $echo )
571
			echo ob_get_clean();
572
		else
573
			return ob_get_clean();
574
	}
575
}
576
if ( ! function_exists( 'woocommerce_template_loop_product_title' ) ) {
577
578
	/**
579
	 * Show the product title in the product loop. By default this is an H3.
580
	 */
581
	function woocommerce_template_loop_product_title() {
582
		$tag = is_product_taxonomy() || is_shop() ? 'h2' : 'h3';
583
584
		echo '<' . $tag . ' class="woocommerce-loop-product__title">' . get_the_title() . '</' . $tag . '>';
585
	}
586
}
587
if ( ! function_exists( 'woocommerce_template_loop_category_title' ) ) {
588
589
	/**
590
	 * Show the subcategory title in the product loop.
591
	 */
592
	function woocommerce_template_loop_category_title( $category ) {
593
		?>
594
		<h2 class="woocommerce-loop-category__title">
595
			<?php
596
				echo $category->name;
597
598
				if ( $category->count > 0 )
599
					echo apply_filters( 'woocommerce_subcategory_count_html', ' <mark class="count">(' . $category->count . ')</mark>', $category );
600
			?>
601
		</h2>
602
		<?php
603
	}
604
}
605
/**
606
 * Insert the opening anchor tag for products in the loop.
607
 */
608
function woocommerce_template_loop_product_link_open() {
609
	echo '<a href="' . get_the_permalink() . '" class="woocommerce-LoopProduct-link">';
610
}
611
/**
612
 * Insert the opening anchor tag for products in the loop.
613
 */
614
function woocommerce_template_loop_product_link_close() {
615
	echo '</a>';
616
}
617
/**
618
 * Insert the opening anchor tag for categories in the loop.
619
 */
620
function woocommerce_template_loop_category_link_open( $category ) {
621
	echo '<a href="' . get_term_link( $category, 'product_cat' ) . '">';
622
}
623
/**
624
 * Insert the opening anchor tag for categories in the loop.
625
 */
626
function woocommerce_template_loop_category_link_close() {
627
	echo '</a>';
628
}
629
if ( ! function_exists( 'woocommerce_taxonomy_archive_description' ) ) {
630
631
	/**
632
	 * Show an archive description on taxonomy archives.
633
	 *
634
	 * @subpackage	Archives
635
	 */
636
	function woocommerce_taxonomy_archive_description() {
637
		if ( is_product_taxonomy() && 0 === absint( get_query_var( 'paged' ) ) ) {
638
			$description = wc_format_content( term_description() );
639
			if ( $description ) {
640
				echo '<div class="term-description">' . $description . '</div>';
641
			}
642
		}
643
	}
644
}
645
if ( ! function_exists( 'woocommerce_product_archive_description' ) ) {
646
647
	/**
648
	 * Show a shop page description on product archives.
649
	 *
650
	 * @subpackage	Archives
651
	 */
652
	function woocommerce_product_archive_description() {
653
		// Don't display the description on search results page
654
		if ( is_search() ) {
655
			return;
656
		}
657
658
		if ( is_post_type_archive( 'product' ) && 0 === absint( get_query_var( 'paged' ) ) ) {
659
			$shop_page   = get_post( wc_get_page_id( 'shop' ) );
660
			if ( $shop_page ) {
661
				$description = wc_format_content( $shop_page->post_content );
662
				if ( $description ) {
663
					echo '<div class="page-description">' . $description . '</div>';
664
				}
665
			}
666
		}
667
	}
668
}
669
670
if ( ! function_exists( 'woocommerce_template_loop_add_to_cart' ) ) {
671
672
	/**
673
	 * Get the add to cart template for the loop.
674
	 *
675
	 * @subpackage	Loop
676
	 */
677
	function woocommerce_template_loop_add_to_cart( $args = array() ) {
678
		global $product;
679
680
		if ( $product ) {
681
			$defaults = array(
682
				'quantity' => 1,
683
				'class'    => implode( ' ', array_filter( array(
684
						'button',
685
						'product_type_' . $product->product_type,
686
						$product->is_purchasable() && $product->is_in_stock() ? 'add_to_cart_button' : '',
687
						$product->supports( 'ajax_add_to_cart' ) ? 'ajax_add_to_cart' : '',
688
				) ) ),
689
			);
690
691
			$args = apply_filters( 'woocommerce_loop_add_to_cart_args', wp_parse_args( $args, $defaults ), $product );
692
693
			wc_get_template( 'loop/add-to-cart.php', $args );
694
		}
695
	}
696
}
697
if ( ! function_exists( 'woocommerce_template_loop_product_thumbnail' ) ) {
698
699
	/**
700
	 * Get the product thumbnail for the loop.
701
	 *
702
	 * @subpackage	Loop
703
	 */
704
	function woocommerce_template_loop_product_thumbnail() {
705
		echo woocommerce_get_product_thumbnail();
706
	}
707
}
708
if ( ! function_exists( 'woocommerce_template_loop_price' ) ) {
709
710
	/**
711
	 * Get the product price for the loop.
712
	 *
713
	 * @subpackage	Loop
714
	 */
715
	function woocommerce_template_loop_price() {
716
		wc_get_template( 'loop/price.php' );
717
	}
718
}
719
if ( ! function_exists( 'woocommerce_template_loop_rating' ) ) {
720
721
	/**
722
	 * Display the average rating in the loop.
723
	 *
724
	 * @subpackage	Loop
725
	 */
726
	function woocommerce_template_loop_rating() {
727
		wc_get_template( 'loop/rating.php' );
728
	}
729
}
730
if ( ! function_exists( 'woocommerce_show_product_loop_sale_flash' ) ) {
731
732
	/**
733
	 * Get the sale flash for the loop.
734
	 *
735
	 * @subpackage	Loop
736
	 */
737
	function woocommerce_show_product_loop_sale_flash() {
738
		wc_get_template( 'loop/sale-flash.php' );
739
	}
740
}
741
742
if ( ! function_exists( 'woocommerce_get_product_thumbnail' ) ) {
743
744
	/**
745
	 * Get the product thumbnail, or the placeholder if not set.
746
	 *
747
	 * @subpackage	Loop
748
	 * @param string $size (default: 'shop_catalog')
749
	 * @param int $deprecated1 Deprecated since WooCommerce 2.0 (default: 0)
750
	 * @param int $deprecated2 Deprecated since WooCommerce 2.0 (default: 0)
751
	 * @return string
752
	 */
753
	function woocommerce_get_product_thumbnail( $size = 'shop_catalog', $deprecated1 = 0, $deprecated2 = 0 ) {
0 ignored issues
show
Unused Code introduced by
The parameter $deprecated1 is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $deprecated2 is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
754
		global $post;
755
		$image_size = apply_filters( 'single_product_archive_thumbnail_size', $size );
756
757
		if ( has_post_thumbnail() ) {
758
			$props = wc_get_product_attachment_props( get_post_thumbnail_id(), $post );
759
			return get_the_post_thumbnail( $post->ID, $image_size, array(
760
				'title'	 => $props['title'],
761
				'alt'    => $props['alt'],
762
			) );
763
		} elseif ( wc_placeholder_img_src() ) {
764
			return wc_placeholder_img( $image_size );
765
		}
766
	}
767
}
768
769
if ( ! function_exists( 'woocommerce_result_count' ) ) {
770
771
	/**
772
	 * Output the result count text (Showing x - x of x results).
773
	 *
774
	 * @subpackage	Loop
775
	 */
776
	function woocommerce_result_count() {
777
		wc_get_template( 'loop/result-count.php' );
778
	}
779
}
780
781
if ( ! function_exists( 'woocommerce_catalog_ordering' ) ) {
782
783
	/**
784
	 * Output the product sorting options.
785
	 *
786
	 * @subpackage	Loop
787
	 */
788
	function woocommerce_catalog_ordering() {
789
		global $wp_query;
790
791
		if ( 1 === $wp_query->found_posts || ! woocommerce_products_will_display() ) {
792
			return;
793
		}
794
795
		$orderby                 = isset( $_GET['orderby'] ) ? wc_clean( $_GET['orderby'] ) : apply_filters( 'woocommerce_default_catalog_orderby', get_option( 'woocommerce_default_catalog_orderby' ) );
796
		$show_default_orderby    = 'menu_order' === apply_filters( 'woocommerce_default_catalog_orderby', get_option( 'woocommerce_default_catalog_orderby' ) );
797
		$catalog_orderby_options = apply_filters( 'woocommerce_catalog_orderby', array(
798
			'menu_order' => __( 'Default sorting', 'woocommerce' ),
799
			'popularity' => __( 'Sort by popularity', 'woocommerce' ),
800
			'rating'     => __( 'Sort by average rating', 'woocommerce' ),
801
			'date'       => __( 'Sort by newness', 'woocommerce' ),
802
			'price'      => __( 'Sort by price: low to high', 'woocommerce' ),
803
			'price-desc' => __( 'Sort by price: high to low', 'woocommerce' ),
804
		) );
805
806
		if ( ! $show_default_orderby ) {
807
			unset( $catalog_orderby_options['menu_order'] );
808
		}
809
810
		if ( 'no' === get_option( 'woocommerce_enable_review_rating' ) ) {
811
			unset( $catalog_orderby_options['rating'] );
812
		}
813
814
		wc_get_template( 'loop/orderby.php', array( 'catalog_orderby_options' => $catalog_orderby_options, 'orderby' => $orderby, 'show_default_orderby' => $show_default_orderby ) );
815
	}
816
}
817
818
if ( ! function_exists( 'woocommerce_pagination' ) ) {
819
820
	/**
821
	 * Output the pagination.
822
	 *
823
	 * @subpackage	Loop
824
	 */
825
	function woocommerce_pagination() {
826
		wc_get_template( 'loop/pagination.php' );
827
	}
828
}
829
830
/** Single Product ********************************************************/
831
832
if ( ! function_exists( 'woocommerce_show_product_images' ) ) {
833
834
	/**
835
	 * Output the product image before the single product summary.
836
	 *
837
	 * @subpackage	Product
838
	 */
839
	function woocommerce_show_product_images() {
840
		wc_get_template( 'single-product/product-image.php' );
841
	}
842
}
843
if ( ! function_exists( 'woocommerce_show_product_thumbnails' ) ) {
844
845
	/**
846
	 * Output the product thumbnails.
847
	 *
848
	 * @subpackage	Product
849
	 */
850
	function woocommerce_show_product_thumbnails() {
851
		wc_get_template( 'single-product/product-thumbnails.php' );
852
	}
853
}
854
if ( ! function_exists( 'woocommerce_output_product_data_tabs' ) ) {
855
856
	/**
857
	 * Output the product tabs.
858
	 *
859
	 * @subpackage	Product/Tabs
860
	 */
861
	function woocommerce_output_product_data_tabs() {
862
		wc_get_template( 'single-product/tabs/tabs.php' );
863
	}
864
}
865
if ( ! function_exists( 'woocommerce_template_single_title' ) ) {
866
867
	/**
868
	 * Output the product title.
869
	 *
870
	 * @subpackage	Product
871
	 */
872
	function woocommerce_template_single_title() {
873
		wc_get_template( 'single-product/title.php' );
874
	}
875
}
876
if ( ! function_exists( 'woocommerce_template_single_rating' ) ) {
877
878
	/**
879
	 * Output the product rating.
880
	 *
881
	 * @subpackage	Product
882
	 */
883
	function woocommerce_template_single_rating() {
884
		wc_get_template( 'single-product/rating.php' );
885
	}
886
}
887
if ( ! function_exists( 'woocommerce_template_single_price' ) ) {
888
889
	/**
890
	 * Output the product price.
891
	 *
892
	 * @subpackage	Product
893
	 */
894
	function woocommerce_template_single_price() {
895
		wc_get_template( 'single-product/price.php' );
896
	}
897
}
898
if ( ! function_exists( 'woocommerce_template_single_excerpt' ) ) {
899
900
	/**
901
	 * Output the product short description (excerpt).
902
	 *
903
	 * @subpackage	Product
904
	 */
905
	function woocommerce_template_single_excerpt() {
906
		wc_get_template( 'single-product/short-description.php' );
907
	}
908
}
909
if ( ! function_exists( 'woocommerce_template_single_meta' ) ) {
910
911
	/**
912
	 * Output the product meta.
913
	 *
914
	 * @subpackage	Product
915
	 */
916
	function woocommerce_template_single_meta() {
917
		wc_get_template( 'single-product/meta.php' );
918
	}
919
}
920
if ( ! function_exists( 'woocommerce_template_single_sharing' ) ) {
921
922
	/**
923
	 * Output the product sharing.
924
	 *
925
	 * @subpackage	Product
926
	 */
927
	function woocommerce_template_single_sharing() {
928
		wc_get_template( 'single-product/share.php' );
929
	}
930
}
931
if ( ! function_exists( 'woocommerce_show_product_sale_flash' ) ) {
932
933
	/**
934
	 * Output the product sale flash.
935
	 *
936
	 * @subpackage	Product
937
	 */
938
	function woocommerce_show_product_sale_flash() {
939
		wc_get_template( 'single-product/sale-flash.php' );
940
	}
941
}
942
943
if ( ! function_exists( 'woocommerce_template_single_add_to_cart' ) ) {
944
945
	/**
946
	 * Trigger the single product add to cart action.
947
	 *
948
	 * @subpackage	Product
949
	 */
950
	function woocommerce_template_single_add_to_cart() {
951
		global $product;
952
		do_action( 'woocommerce_' . $product->product_type . '_add_to_cart' );
953
	}
954
}
955
if ( ! function_exists( 'woocommerce_simple_add_to_cart' ) ) {
956
957
	/**
958
	 * Output the simple product add to cart area.
959
	 *
960
	 * @subpackage	Product
961
	 */
962
	function woocommerce_simple_add_to_cart() {
963
		wc_get_template( 'single-product/add-to-cart/simple.php' );
964
	}
965
}
966
if ( ! function_exists( 'woocommerce_grouped_add_to_cart' ) ) {
967
968
	/**
969
	 * Output the grouped product add to cart area.
970
	 *
971
	 * @subpackage	Product
972
	 */
973
	function woocommerce_grouped_add_to_cart() {
974
		global $product;
975
976
		wc_get_template( 'single-product/add-to-cart/grouped.php', array(
977
			'grouped_product'    => $product,
978
			'grouped_products'   => $product->get_children(),
979
			'quantites_required' => false,
980
		) );
981
	}
982
}
983
if ( ! function_exists( 'woocommerce_variable_add_to_cart' ) ) {
984
985
	/**
986
	 * Output the variable product add to cart area.
987
	 *
988
	 * @subpackage	Product
989
	 */
990
	function woocommerce_variable_add_to_cart() {
991
		global $product;
992
993
		// Enqueue variation scripts
994
		wp_enqueue_script( 'wc-add-to-cart-variation' );
995
996
		// Get Available variations?
997
		$get_variations = sizeof( $product->get_children() ) <= apply_filters( 'woocommerce_ajax_variation_threshold', 30, $product );
998
999
		// Load the template
1000
		wc_get_template( 'single-product/add-to-cart/variable.php', array(
1001
			'available_variations' => $get_variations ? $product->get_available_variations() : false,
1002
			'attributes'           => $product->get_variation_attributes(),
1003
			'selected_attributes'  => $product->get_variation_default_attributes(),
1004
		) );
1005
	}
1006
}
1007
if ( ! function_exists( 'woocommerce_external_add_to_cart' ) ) {
1008
1009
	/**
1010
	 * Output the external product add to cart area.
1011
	 *
1012
	 * @subpackage	Product
1013
	 */
1014
	function woocommerce_external_add_to_cart() {
1015
		global $product;
1016
1017
		if ( ! $product->add_to_cart_url() ) {
1018
			return;
1019
		}
1020
1021
		wc_get_template( 'single-product/add-to-cart/external.php', array(
1022
			'product_url' => $product->add_to_cart_url(),
1023
			'button_text' => $product->single_add_to_cart_text(),
1024
		) );
1025
	}
1026
}
1027
1028
if ( ! function_exists( 'woocommerce_quantity_input' ) ) {
1029
1030
	/**
1031
	 * Output the quantity input for add to cart forms.
1032
	 *
1033
	 * @param  array $args Args for the input
1034
	 * @param  WC_Product|null $product
1035
	 * @param  boolean $echo Whether to return or echo|string
1036
	 */
1037
	function woocommerce_quantity_input( $args = array(), $product = null, $echo = true ) {
1038
		if ( is_null( $product ) ) {
1039
			$product = $GLOBALS['product'];
1040
		}
1041
1042
		$defaults = array(
1043
			'input_name'  => 'quantity',
1044
			'input_value' => '1',
1045
			'max_value'   => apply_filters( 'woocommerce_quantity_input_max', '', $product ),
1046
			'min_value'   => apply_filters( 'woocommerce_quantity_input_min', '', $product ),
1047
			'step'        => apply_filters( 'woocommerce_quantity_input_step', '1', $product ),
1048
			'pattern'     => apply_filters( 'woocommerce_quantity_input_pattern', has_filter( 'woocommerce_stock_amount', 'intval' ) ? '[0-9]*' : '' ),
1049
			'inputmode'   => apply_filters( 'woocommerce_quantity_input_inputmode', has_filter( 'woocommerce_stock_amount', 'intval' ) ? 'numeric' : '' ),
1050
		);
1051
1052
		$args = apply_filters( 'woocommerce_quantity_input_args', wp_parse_args( $args, $defaults ), $product );
1053
1054
		// Set min and max value to empty string if not set.
1055
		$args['min_value'] = isset( $args['min_value'] ) ? $args['min_value'] : '';
1056
		$args['max_value'] = isset( $args['max_value'] ) ? $args['max_value'] : '';
1057
1058
		// Apply sanity to min/max args - min cannot be lower than 0
1059
		if ( '' !== $args['min_value'] && is_numeric( $args['min_value'] ) && $args['min_value'] < 0 ) {
1060
			$args['min_value'] = 0; // Cannot be lower than 0
1061
		}
1062
1063
		// Max cannot be lower than 0 or min
1064
		if ( '' !== $args['max_value'] && is_numeric( $args['max_value'] ) ) {
1065
			$args['max_value'] = $args['max_value'] < 0 ? 0 : $args['max_value'];
1066
			$args['max_value'] = $args['max_value'] < $args['min_value'] ? $args['min_value'] : $args['max_value'];
1067
		}
1068
1069
		ob_start();
1070
1071
		wc_get_template( 'global/quantity-input.php', $args );
1072
1073
		if ( $echo ) {
1074
			echo ob_get_clean();
1075
		} else {
1076
			return ob_get_clean();
1077
		}
1078
	}
1079
}
1080
1081
if ( ! function_exists( 'woocommerce_product_description_tab' ) ) {
1082
1083
	/**
1084
	 * Output the description tab content.
1085
	 *
1086
	 * @subpackage	Product/Tabs
1087
	 */
1088
	function woocommerce_product_description_tab() {
1089
		wc_get_template( 'single-product/tabs/description.php' );
1090
	}
1091
}
1092
if ( ! function_exists( 'woocommerce_product_additional_information_tab' ) ) {
1093
1094
	/**
1095
	 * Output the attributes tab content.
1096
	 *
1097
	 * @subpackage	Product/Tabs
1098
	 */
1099
	function woocommerce_product_additional_information_tab() {
1100
		wc_get_template( 'single-product/tabs/additional-information.php' );
1101
	}
1102
}
1103
if ( ! function_exists( 'woocommerce_product_reviews_tab' ) ) {
1104
1105
	/**
1106
	 * Output the reviews tab content.
1107
	 * @deprecated  2.4.0 Unused
1108
	 * @subpackage	Product/Tabs
1109
	 */
1110
	function woocommerce_product_reviews_tab() {
1111
		_deprecated_function( 'woocommerce_product_reviews_tab', '2.4', '' );
1112
	}
1113
}
1114
1115
if ( ! function_exists( 'woocommerce_default_product_tabs' ) ) {
1116
1117
	/**
1118
	 * Add default product tabs to product pages.
1119
	 *
1120
	 * @param array $tabs
1121
	 * @return array
1122
	 */
1123
	function woocommerce_default_product_tabs( $tabs = array() ) {
1124
		global $product, $post;
1125
1126
		// Description tab - shows product content
1127
		if ( $post->post_content ) {
1128
			$tabs['description'] = array(
1129
				'title'    => __( 'Description', 'woocommerce' ),
1130
				'priority' => 10,
1131
				'callback' => 'woocommerce_product_description_tab',
1132
			);
1133
		}
1134
1135
		// Additional information tab - shows attributes
1136
		if ( $product && ( $product->has_attributes() || $product->enable_dimensions_display() ) ) {
1137
			$tabs['additional_information'] = array(
1138
				'title'    => __( 'Additional Information', 'woocommerce' ),
1139
				'priority' => 20,
1140
				'callback' => 'woocommerce_product_additional_information_tab',
1141
			);
1142
		}
1143
1144
		// Reviews tab - shows comments
1145
		if ( comments_open() ) {
1146
			$tabs['reviews'] = array(
1147
				'title'    => sprintf( __( 'Reviews (%d)', 'woocommerce' ), $product->get_review_count() ),
1148
				'priority' => 30,
1149
				'callback' => 'comments_template',
1150
			);
1151
		}
1152
1153
		return $tabs;
1154
	}
1155
}
1156
1157
if ( ! function_exists( 'woocommerce_sort_product_tabs' ) ) {
1158
1159
	/**
1160
	 * Sort tabs by priority.
1161
	 *
1162
	 * @param array $tabs
1163
	 * @return array
1164
	 */
1165
	function woocommerce_sort_product_tabs( $tabs = array() ) {
1166
1167
		// Make sure the $tabs parameter is an array
1168
		if ( ! is_array( $tabs ) ) {
1169
			trigger_error( "Function woocommerce_sort_product_tabs() expects an array as the first parameter. Defaulting to empty array." );
1170
			$tabs = array();
1171
		}
1172
1173
		// Re-order tabs by priority
1174
		if ( ! function_exists( '_sort_priority_callback' ) ) {
1175
			function _sort_priority_callback( $a, $b ) {
1176
				if ( $a['priority'] === $b['priority'] )
1177
					return 0;
1178
				return ( $a['priority'] < $b['priority'] ) ? -1 : 1;
1179
			}
1180
		}
1181
1182
		uasort( $tabs, '_sort_priority_callback' );
1183
1184
		return $tabs;
1185
	}
1186
}
1187
1188
if ( ! function_exists( 'woocommerce_comments' ) ) {
1189
1190
	/**
1191
	 * Output the Review comments template.
1192
	 *
1193
	 * @subpackage	Product
1194
	 * @param WP_Comment $comment
1195
	 * @param array $args
1196
	 * @param int $depth
1197
	 */
1198
	function woocommerce_comments( $comment, $args, $depth ) {
1199
		$GLOBALS['comment'] = $comment;
1200
		wc_get_template( 'single-product/review.php', array( 'comment' => $comment, 'args' => $args, 'depth' => $depth ) );
1201
	}
1202
}
1203
1204
if ( ! function_exists( 'woocommerce_review_display_gravatar' ) ) {
1205
	/**
1206
	 * Display the review authors gravatar
1207
	 *
1208
	 * @param array $comment WP_Comment.
1209
	 * @return void
1210
	 */
1211
	function woocommerce_review_display_gravatar( $comment ) {
1212
		echo get_avatar( $comment, apply_filters( 'woocommerce_review_gravatar_size', '60' ), '' );
1213
	}
1214
}
1215
1216
if ( ! function_exists( 'woocommerce_review_display_rating' ) ) {
1217
	/**
1218
	 * Display the reviewers star rating
1219
	 *
1220
	 * @return void
1221
	 */
1222
	function woocommerce_review_display_rating() {
1223
		wc_get_template( 'single-product/review-rating.php' );
1224
	}
1225
}
1226
1227
if ( ! function_exists( 'woocommerce_review_display_meta' ) ) {
1228
	/**
1229
	 * Display the review authors meta (name, verified owner, review date)
1230
	 *
1231
	 * @return void
1232
	 */
1233
	function woocommerce_review_display_meta() {
1234
		wc_get_template( 'single-product/review-meta.php' );
1235
	}
1236
}
1237
1238
if ( ! function_exists( 'woocommerce_review_display_comment_text' ) ) {
1239
1240
	/**
1241
	 * Display the review content.
1242
	 */
1243
	function woocommerce_review_display_comment_text() {
1244
		echo '<div class="description">';
1245
		comment_text();
1246
		echo '</div>';
1247
	}
1248
}
1249
1250
if ( ! function_exists( 'woocommerce_output_related_products' ) ) {
1251
1252
	/**
1253
	 * Output the related products.
1254
	 *
1255
	 * @subpackage	Product
1256
	 */
1257
	function woocommerce_output_related_products() {
1258
1259
		$args = array(
1260
			'posts_per_page' 	=> 4,
1261
			'columns' 			=> 4,
1262
			'orderby' 			=> 'rand',
1263
		);
1264
1265
		woocommerce_related_products( apply_filters( 'woocommerce_output_related_products_args', $args ) );
1266
	}
1267
}
1268
1269
if ( ! function_exists( 'woocommerce_related_products' ) ) {
1270
1271
	/**
1272
	 * Output the related products.
1273
	 *
1274
	 * @param array Provided arguments
1275
	 * @param bool Columns argument for backwards compat
1276
	 * @param bool Order by argument for backwards compat
1277
	 */
1278
	function woocommerce_related_products( $args = array(), $columns = false, $orderby = false ) {
1279
		if ( ! is_array( $args ) ) {
1280
			_deprecated_argument( __FUNCTION__, '2.1', __( 'Use $args argument as an array instead. Deprecated argument will be removed in WC 2.2.', 'woocommerce' ) );
1281
1282
			$argsvalue = $args;
1283
1284
			$args = array(
1285
				'posts_per_page' => $argsvalue,
1286
				'columns'        => $columns,
1287
				'orderby'        => $orderby,
1288
			);
1289
		}
1290
1291
		$defaults = array(
1292
			'posts_per_page' => 2,
1293
			'columns'        => 2,
1294
			'orderby'        => 'rand',
1295
		);
1296
1297
		$args = wp_parse_args( $args, $defaults );
1298
1299
		wc_get_template( 'single-product/related.php', $args );
1300
	}
1301
}
1302
1303
if ( ! function_exists( 'woocommerce_upsell_display' ) ) {
1304
1305
	/**
1306
	 * Output product up sells.
1307
	 *
1308
	 * @param int $posts_per_page (default: -1)
1309
	 * @param int $columns (default: 4)
1310
	 * @param string $orderby (default: 'rand')
1311
	 */
1312
	function woocommerce_upsell_display( $posts_per_page = '-1', $columns = 4, $orderby = 'rand' ) {
1313
		$args = apply_filters( 'woocommerce_upsell_display_args', array(
1314
			'posts_per_page'	=> $posts_per_page,
1315
			'orderby'			=> apply_filters( 'woocommerce_upsells_orderby', $orderby ),
1316
			'columns'			=> $columns,
1317
		) );
1318
1319
		wc_get_template( 'single-product/up-sells.php', $args );
1320
	}
1321
}
1322
1323
/** Cart ******************************************************************/
1324
1325
if ( ! function_exists( 'woocommerce_shipping_calculator' ) ) {
1326
1327
	/**
1328
	 * Output the cart shipping calculator.
1329
	 *
1330
	 * @subpackage	Cart
1331
	 */
1332
	function woocommerce_shipping_calculator() {
1333
		wc_get_template( 'cart/shipping-calculator.php' );
1334
	}
1335
}
1336
1337
if ( ! function_exists( 'woocommerce_cart_totals' ) ) {
1338
1339
	/**
1340
	 * Output the cart totals.
1341
	 *
1342
	 * @subpackage	Cart
1343
	 */
1344
	function woocommerce_cart_totals() {
1345
		if ( is_checkout() ) {
1346
			return;
1347
		}
1348
		wc_get_template( 'cart/cart-totals.php' );
1349
	}
1350
}
1351
1352
if ( ! function_exists( 'woocommerce_cross_sell_display' ) ) {
1353
1354
	/**
1355
	 * Output the cart cross-sells.
1356
	 *
1357
	 * @param  int $posts_per_page (default: 2)
1358
	 * @param  int $columns (default: 2)
1359
	 * @param  string $orderby (default: 'rand')
1360
	 */
1361
	function woocommerce_cross_sell_display( $posts_per_page = 2, $columns = 2, $orderby = 'rand' ) {
1362
		if ( is_checkout() ) {
1363
			return;
1364
		}
1365
		wc_get_template( 'cart/cross-sells.php', array(
1366
			'posts_per_page' => $posts_per_page,
1367
			'orderby'        => $orderby,
1368
			'columns'        => $columns,
1369
		) );
1370
	}
1371
}
1372
1373
if ( ! function_exists( 'woocommerce_button_proceed_to_checkout' ) ) {
1374
1375
	/**
1376
	 * Output the proceed to checkout button.
1377
	 *
1378
	 * @subpackage	Cart
1379
	 */
1380
	function woocommerce_button_proceed_to_checkout() {
1381
		wc_get_template( 'cart/proceed-to-checkout-button.php' );
1382
	}
1383
}
1384
1385 View Code Duplication
if ( ! function_exists( 'woocommerce_widget_shopping_cart_button_view_cart' ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1386
1387
	/**
1388
	 * Output the proceed to checkout button.
1389
	 *
1390
	 * @subpackage	Cart
1391
	 */
1392
	function woocommerce_widget_shopping_cart_button_view_cart() {
1393
		echo '<a href="' . esc_url( wc_get_cart_url() ) . '" class="button wc-forward">' . __( 'View Cart', 'woocommerce' ) . '</a>';
1394
	}
1395
}
1396
1397 View Code Duplication
if ( ! function_exists( 'woocommerce_widget_shopping_cart_proceed_to_checkout' ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1398
1399
	/**
1400
	 * Output the proceed to checkout button.
1401
	 *
1402
	 * @subpackage	Cart
1403
	 */
1404
	function woocommerce_widget_shopping_cart_proceed_to_checkout() {
1405
		echo '<a href="' . esc_url( wc_get_checkout_url() ) . '" class="button checkout wc-forward">' . __( 'Checkout', 'woocommerce' ) . '</a>';
1406
	}
1407
}
1408
1409
/** Mini-Cart *************************************************************/
1410
1411
if ( ! function_exists( 'woocommerce_mini_cart' ) ) {
1412
1413
	/**
1414
	 * Output the Mini-cart - used by cart widget.
1415
	 *
1416
	 * @param array $args
1417
	 */
1418
	function woocommerce_mini_cart( $args = array() ) {
1419
1420
		$defaults = array(
1421
			'list_class' => '',
1422
		);
1423
1424
		$args = wp_parse_args( $args, $defaults );
1425
1426
		wc_get_template( 'cart/mini-cart.php', $args );
1427
	}
1428
}
1429
1430
/** Login *****************************************************************/
1431
1432
if ( ! function_exists( 'woocommerce_login_form' ) ) {
1433
1434
	/**
1435
	 * Output the WooCommerce Login Form.
1436
	 *
1437
	 * @subpackage	Forms
1438
	 * @param array $args
1439
	 */
1440
	function woocommerce_login_form( $args = array() ) {
1441
1442
		$defaults = array(
1443
			'message'  => '',
1444
			'redirect' => '',
1445
			'hidden'   => false,
1446
		);
1447
1448
		$args = wp_parse_args( $args, $defaults );
1449
1450
		wc_get_template( 'global/form-login.php', $args );
1451
	}
1452
}
1453
1454
if ( ! function_exists( 'woocommerce_checkout_login_form' ) ) {
1455
1456
	/**
1457
	 * Output the WooCommerce Checkout Login Form.
1458
	 *
1459
	 * @subpackage	Checkout
1460
	 */
1461
	function woocommerce_checkout_login_form() {
1462
		wc_get_template( 'checkout/form-login.php', array( 'checkout' => WC()->checkout() ) );
1463
	}
1464
}
1465
1466
if ( ! function_exists( 'woocommerce_breadcrumb' ) ) {
1467
1468
	/**
1469
	 * Output the WooCommerce Breadcrumb.
1470
	 *
1471
	 * @param array $args
1472
	 */
1473
	function woocommerce_breadcrumb( $args = array() ) {
1474
		$args = wp_parse_args( $args, apply_filters( 'woocommerce_breadcrumb_defaults', array(
1475
			'delimiter'   => '&nbsp;&#47;&nbsp;',
1476
			'wrap_before' => '<nav class="woocommerce-breadcrumb">',
1477
			'wrap_after'  => '</nav>',
1478
			'before'      => '',
1479
			'after'       => '',
1480
			'home'        => _x( 'Home', 'breadcrumb', 'woocommerce' ),
1481
		) ) );
1482
1483
		$breadcrumbs = new WC_Breadcrumb();
1484
1485
		if ( ! empty( $args['home'] ) ) {
1486
			$breadcrumbs->add_crumb( $args['home'], apply_filters( 'woocommerce_breadcrumb_home_url', home_url() ) );
1487
		}
1488
1489
		$args['breadcrumb'] = $breadcrumbs->generate();
1490
1491
		/**
1492
		 * @hooked WC_Structured_Data::generate_breadcrumblist_data() - 10
1493
		 */
1494
		do_action( 'woocommerce_breadcrumb', $breadcrumbs, $args );
1495
1496
		wc_get_template( 'global/breadcrumb.php', $args );
1497
	}
1498
}
1499
1500
if ( ! function_exists( 'woocommerce_order_review' ) ) {
1501
1502
	/**
1503
	 * Output the Order review table for the checkout.
1504
	 *
1505
	 * @subpackage	Checkout
1506
	 */
1507
	function woocommerce_order_review( $deprecated = false ) {
0 ignored issues
show
Unused Code introduced by
The parameter $deprecated is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1508
		wc_get_template( 'checkout/review-order.php', array( 'checkout' => WC()->checkout() ) );
1509
	}
1510
}
1511
1512
if ( ! function_exists( 'woocommerce_checkout_payment' ) ) {
1513
1514
	/**
1515
	 * Output the Payment Methods on the checkout.
1516
	 *
1517
	 * @subpackage	Checkout
1518
	 */
1519
	function woocommerce_checkout_payment() {
1520
		if ( WC()->cart->needs_payment() ) {
1521
			$available_gateways = WC()->payment_gateways()->get_available_payment_gateways();
1522
			WC()->payment_gateways()->set_current_gateway( $available_gateways );
1523
		} else {
1524
			$available_gateways = array();
1525
		}
1526
1527
		wc_get_template( 'checkout/payment.php', array(
1528
			'checkout'           => WC()->checkout(),
1529
			'available_gateways' => $available_gateways,
1530
			'order_button_text'  => apply_filters( 'woocommerce_order_button_text', __( 'Place order', 'woocommerce' ) ),
1531
		) );
1532
	}
1533
}
1534
1535
if ( ! function_exists( 'woocommerce_checkout_coupon_form' ) ) {
1536
1537
	/**
1538
	 * Output the Coupon form for the checkout.
1539
	 *
1540
	 * @subpackage	Checkout
1541
	 */
1542
	function woocommerce_checkout_coupon_form() {
1543
		wc_get_template( 'checkout/form-coupon.php', array( 'checkout' => WC()->checkout() ) );
1544
	}
1545
}
1546
1547
if ( ! function_exists( 'woocommerce_products_will_display' ) ) {
1548
1549
	/**
1550
	 * Check if we will be showing products or not (and not sub-categories only).
1551
	 * @subpackage	Loop
1552
	 * @return bool
1553
	 */
1554
	function woocommerce_products_will_display() {
1555
		global $wpdb;
1556
1557
		if ( is_shop() ) {
1558
			return 'subcategories' !== get_option( 'woocommerce_shop_page_display' ) || is_search();
1559
		}
1560
1561
		if ( ! is_product_taxonomy() ) {
1562
			return false;
1563
		}
1564
1565
		if ( is_search() || is_filtered() || is_paged() ) {
1566
			return true;
1567
		}
1568
1569
		$term = get_queried_object();
1570
1571
		if ( is_product_category() ) {
1572
			switch ( get_woocommerce_term_meta( $term->term_id, 'display_type', true ) ) {
1573
				case 'subcategories' :
1574
					// Nothing - we want to continue to see if there are products/subcats
1575
				break;
1576
				case 'products' :
1577
				case 'both' :
1578
					return true;
1579
				break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
1580
				default :
1581
					// Default - no setting
1582
					if ( get_option( 'woocommerce_category_archive_display' ) != 'subcategories' ) {
1583
						return true;
1584
					}
1585
				break;
1586
			}
1587
		}
1588
1589
		// Begin subcategory logic
1590
		if ( empty( $term->term_id ) || empty( $term->taxonomy ) ) {
1591
			return true;
1592
		}
1593
1594
		$transient_name = 'wc_products_will_display_' . $term->term_id . '_' . WC_Cache_Helper::get_transient_version( 'product_query' );
1595
1596
		if ( false === ( $products_will_display = get_transient( $transient_name ) ) ) {
1597
			$has_children = $wpdb->get_col( $wpdb->prepare( "SELECT term_id FROM {$wpdb->term_taxonomy} WHERE parent = %d AND taxonomy = %s", $term->term_id, $term->taxonomy ) );
1598
1599
			if ( $has_children ) {
1600
				// Check terms have products inside - parents first. If products are found inside, subcats will be shown instead of products so we can return false.
1601
				if ( sizeof( get_objects_in_term( $has_children, $term->taxonomy ) ) > 0 ) {
1602
					$products_will_display = false;
1603
				} else {
1604
					// If we get here, the parents were empty so we're forced to check children
1605
					foreach ( $has_children as $term_id ) {
1606
						$children = get_term_children( $term_id, $term->taxonomy );
1607
1608
						if ( sizeof( get_objects_in_term( $children, $term->taxonomy ) ) > 0 ) {
1609
							$products_will_display = false;
1610
							break;
1611
						}
1612
					}
1613
				}
1614
			} else {
1615
				$products_will_display = true;
1616
			}
1617
		}
1618
1619
		set_transient( $transient_name, $products_will_display, DAY_IN_SECONDS * 30 );
1620
1621
		return $products_will_display;
1622
	}
1623
}
1624
1625
if ( ! function_exists( 'woocommerce_product_subcategories' ) ) {
1626
1627
	/**
1628
	 * Display product sub categories as thumbnails.
1629
	 *
1630
	 * @subpackage	Loop
1631
	 * @param array $args
1632
	 * @return null|boolean
1633
	 */
1634
	function woocommerce_product_subcategories( $args = array() ) {
1635
		global $wp_query;
1636
1637
		$defaults = array(
1638
			'before'        => '',
1639
			'after'         => '',
1640
			'force_display' => false,
1641
		);
1642
1643
		$args = wp_parse_args( $args, $defaults );
1644
1645
		extract( $args );
1646
1647
		// Main query only
1648
		if ( ! is_main_query() && ! $force_display ) {
1649
			return;
1650
		}
1651
1652
		// Don't show when filtering, searching or when on page > 1 and ensure we're on a product archive
1653
		if ( is_search() || is_filtered() || is_paged() || ( ! is_product_category() && ! is_shop() ) ) {
1654
			return;
1655
		}
1656
1657
		// Check categories are enabled
1658
		if ( is_shop() && '' === get_option( 'woocommerce_shop_page_display' ) ) {
1659
			return;
1660
		}
1661
1662
		// Find the category + category parent, if applicable
1663
		$term 			= get_queried_object();
1664
		$parent_id 		= empty( $term->term_id ) ? 0 : $term->term_id;
1665
1666
		if ( is_product_category() ) {
1667
			$display_type = get_woocommerce_term_meta( $term->term_id, 'display_type', true );
1668
1669
			switch ( $display_type ) {
1670
				case 'products' :
1671
					return;
1672
				break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
1673
				case '' :
1674
					if ( '' === get_option( 'woocommerce_category_archive_display' ) ) {
1675
						return;
1676
					}
1677
				break;
1678
			}
1679
		}
1680
1681
		// NOTE: using child_of instead of parent - this is not ideal but due to a WP bug ( https://core.trac.wordpress.org/ticket/15626 ) pad_counts won't work
1682
		$product_categories = get_categories( apply_filters( 'woocommerce_product_subcategories_args', array(
1683
			'parent'       => $parent_id,
1684
			'menu_order'   => 'ASC',
1685
			'hide_empty'   => 0,
1686
			'hierarchical' => 1,
1687
			'taxonomy'     => 'product_cat',
1688
			'pad_counts'   => 1,
1689
		) ) );
1690
1691
		if ( ! apply_filters( 'woocommerce_product_subcategories_hide_empty', false ) ) {
1692
			$product_categories = wp_list_filter( $product_categories, array( 'count' => 0 ), 'NOT' );
1693
		}
1694
1695
		if ( $product_categories ) {
1696
			echo $before;
1697
1698
			foreach ( $product_categories as $category ) {
1699
				wc_get_template( 'content-product_cat.php', array(
1700
					'category' => $category,
1701
				) );
1702
			}
1703
1704
			// If we are hiding products disable the loop and pagination
1705
			if ( is_product_category() ) {
1706
				$display_type = get_woocommerce_term_meta( $term->term_id, 'display_type', true );
1707
1708
				switch ( $display_type ) {
1709
					case 'subcategories' :
1710
						$wp_query->post_count    = 0;
1711
						$wp_query->max_num_pages = 0;
1712
					break;
1713
					case '' :
1714
						if ( 'subcategories' === get_option( 'woocommerce_category_archive_display' ) ) {
1715
							$wp_query->post_count    = 0;
1716
							$wp_query->max_num_pages = 0;
1717
						}
1718
					break;
1719
				}
1720
			}
1721
1722
			if ( is_shop() && 'subcategories' === get_option( 'woocommerce_shop_page_display' ) ) {
1723
				$wp_query->post_count    = 0;
1724
				$wp_query->max_num_pages = 0;
1725
			}
1726
1727
			echo $after;
1728
1729
			return true;
1730
		}
1731
	}
1732
}
1733
1734
if ( ! function_exists( 'woocommerce_subcategory_thumbnail' ) ) {
1735
1736
	/**
1737
	 * Show subcategory thumbnails.
1738
	 *
1739
	 * @param mixed $category
1740
	 * @subpackage	Loop
1741
	 */
1742
	function woocommerce_subcategory_thumbnail( $category ) {
1743
		$small_thumbnail_size  	= apply_filters( 'subcategory_archive_thumbnail_size', 'shop_catalog' );
1744
		$dimensions    			= wc_get_image_size( $small_thumbnail_size );
1745
		$thumbnail_id  			= get_woocommerce_term_meta( $category->term_id, 'thumbnail_id', true );
1746
1747
		if ( $thumbnail_id ) {
1748
			$image        = wp_get_attachment_image_src( $thumbnail_id, $small_thumbnail_size );
1749
			$image        = $image[0];
1750
			$image_srcset = function_exists( 'wp_get_attachment_image_srcset' ) ? wp_get_attachment_image_srcset( $thumbnail_id, $small_thumbnail_size ) : false;
1751
			$image_sizes  = function_exists( 'wp_get_attachment_image_sizes' ) ? wp_get_attachment_image_sizes( $thumbnail_id, $small_thumbnail_size ) : false;
1752
		} else {
1753
			$image        = wc_placeholder_img_src();
1754
			$image_srcset = $image_sizes = false;
1755
		}
1756
1757
		if ( $image ) {
1758
			// Prevent esc_url from breaking spaces in urls for image embeds
1759
			// Ref: https://core.trac.wordpress.org/ticket/23605
1760
			$image = str_replace( ' ', '%20', $image );
1761
1762
			// Add responsive image markup if available
1763
			if ( $image_srcset && $image_sizes ) {
1764
				echo '<img src="' . esc_url( $image ) . '" alt="' . esc_attr( $category->name ) . '" width="' . esc_attr( $dimensions['width'] ) . '" height="' . esc_attr( $dimensions['height'] ) . '" srcset="' . esc_attr( $image_srcset ) . '" sizes="' . esc_attr( $image_sizes ) . '" />';
1765
			} else {
1766
				echo '<img src="' . esc_url( $image ) . '" alt="' . esc_attr( $category->name ) . '" width="' . esc_attr( $dimensions['width'] ) . '" height="' . esc_attr( $dimensions['height'] ) . '" />';
1767
			}
1768
		}
1769
	}
1770
}
1771
1772
if ( ! function_exists( 'woocommerce_order_details_table' ) ) {
1773
1774
	/**
1775
	 * Displays order details in a table.
1776
	 *
1777
	 * @param mixed $order_id
1778
	 * @subpackage	Orders
1779
	 */
1780
	function woocommerce_order_details_table( $order_id ) {
1781
		if ( ! $order_id ) return;
1782
1783
		wc_get_template( 'order/order-details.php', array(
1784
			'order_id' => $order_id,
1785
		) );
1786
	}
1787
}
1788
1789
1790
if ( ! function_exists( 'woocommerce_order_again_button' ) ) {
1791
1792
	/**
1793
	 * Display an 'order again' button on the view order page.
1794
	 *
1795
	 * @param object $order
1796
	 * @subpackage	Orders
1797
	 */
1798
	function woocommerce_order_again_button( $order ) {
1799
		if ( ! $order || ! $order->has_status( 'completed' ) || ! is_user_logged_in() ) {
1800
			return;
1801
		}
1802
1803
		wc_get_template( 'order/order-again.php', array(
1804
			'order' => $order,
1805
		) );
1806
	}
1807
}
1808
1809
/** Forms ****************************************************************/
1810
1811
if ( ! function_exists( 'woocommerce_form_field' ) ) {
1812
1813
	/**
1814
	 * Outputs a checkout/address form field.
1815
	 *
1816
	 * @subpackage	Forms
1817
	 * @param string $key
1818
	 * @param mixed $args
1819
	 * @param string $value (default: null)
1820
	 * @todo This function needs to be broken up in smaller pieces
1821
	 */
1822
	function woocommerce_form_field( $key, $args, $value = null ) {
1823
		$defaults = array(
1824
			'type'              => 'text',
1825
			'label'             => '',
1826
			'description'       => '',
1827
			'placeholder'       => '',
1828
			'maxlength'         => false,
1829
			'required'          => false,
1830
			'autocomplete'      => false,
1831
			'id'                => $key,
1832
			'class'             => array(),
1833
			'label_class'       => array(),
1834
			'input_class'       => array(),
1835
			'return'            => false,
1836
			'options'           => array(),
1837
			'custom_attributes' => array(),
1838
			'validate'          => array(),
1839
			'default'           => '',
1840
		);
1841
1842
		$args = wp_parse_args( $args, $defaults );
1843
		$args = apply_filters( 'woocommerce_form_field_args', $args, $key, $value );
1844
1845
		if ( $args['required'] ) {
1846
			$args['class'][] = 'validate-required';
1847
			$required = ' <abbr class="required" title="' . esc_attr__( 'required', 'woocommerce' ) . '">*</abbr>';
1848
		} else {
1849
			$required = '';
1850
		}
1851
1852
		$args['maxlength'] = ( $args['maxlength'] ) ? 'maxlength="' . absint( $args['maxlength'] ) . '"' : '';
1853
1854
		$args['autocomplete'] = ( $args['autocomplete'] ) ? 'autocomplete="' . esc_attr( $args['autocomplete'] ) . '"' : '';
1855
1856
		if ( is_string( $args['label_class'] ) ) {
1857
			$args['label_class'] = array( $args['label_class'] );
1858
		}
1859
1860
		if ( is_null( $value ) ) {
1861
			$value = $args['default'];
1862
		}
1863
1864
		// Custom attribute handling
1865
		$custom_attributes = array();
1866
1867 View Code Duplication
		if ( ! empty( $args['custom_attributes'] ) && is_array( $args['custom_attributes'] ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1868
			foreach ( $args['custom_attributes'] as $attribute => $attribute_value ) {
1869
				$custom_attributes[] = esc_attr( $attribute ) . '="' . esc_attr( $attribute_value ) . '"';
1870
			}
1871
		}
1872
1873
		if ( ! empty( $args['validate'] ) ) {
1874
			foreach ( $args['validate'] as $validate ) {
0 ignored issues
show
Bug introduced by
The expression $args['validate'] of type string|array is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
1875
				$args['class'][] = 'validate-' . $validate;
1876
			}
1877
		}
1878
1879
		$field = '';
1880
		$label_id = $args['id'];
1881
		$field_container = '<p class="form-row %1$s" id="%2$s">%3$s</p>';
1882
1883
		switch ( $args['type'] ) {
1884
			case 'country' :
1885
1886
				$countries = 'shipping_country' === $key ? WC()->countries->get_shipping_countries() : WC()->countries->get_allowed_countries();
1887
1888
				if ( 1 === sizeof( $countries ) ) {
1889
1890
					$field .= '<strong>' . current( array_values( $countries ) ) . '</strong>';
1891
1892
					$field .= '<input type="hidden" name="' . esc_attr( $key ) . '" id="' . esc_attr( $args['id'] ) . '" value="' . current( array_keys( $countries ) ) . '" ' . implode( ' ', $custom_attributes ) . ' class="country_to_state" />';
1893
1894
				} else {
1895
1896
					$field = '<select name="' . esc_attr( $key ) . '" id="' . esc_attr( $args['id'] ) . '" ' . $args['autocomplete'] . ' class="country_to_state country_select ' . esc_attr( implode( ' ', $args['input_class'] ) ) . '" ' . implode( ' ', $custom_attributes ) . '>' . '<option value="">' . __( 'Select a country&hellip;', 'woocommerce' ) . '</option>';
1897
1898 View Code Duplication
					foreach ( $countries as $ckey => $cvalue ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1899
						$field .= '<option value="' . esc_attr( $ckey ) . '" ' . selected( $value, $ckey, false ) . '>' . $cvalue . '</option>';
1900
					}
1901
1902
					$field .= '</select>';
1903
1904
					$field .= '<noscript><input type="submit" name="woocommerce_checkout_update_totals" value="' . esc_attr__( 'Update country', 'woocommerce' ) . '" /></noscript>';
1905
1906
				}
1907
1908
				break;
1909
			case 'state' :
1910
1911
				/* Get Country */
1912
				$country_key = 'billing_state' === $key ? 'billing_country' : 'shipping_country';
1913
				$current_cc  = WC()->checkout->get_value( $country_key );
1914
				$states      = WC()->countries->get_states( $current_cc );
1915
1916
				if ( is_array( $states ) && empty( $states ) ) {
1917
1918
					$field_container = '<p class="form-row %1$s" id="%2$s" style="display: none">%3$s</p>';
1919
1920
					$field .= '<input type="hidden" class="hidden" name="' . esc_attr( $key ) . '" id="' . esc_attr( $args['id'] ) . '" value="" ' . implode( ' ', $custom_attributes ) . ' placeholder="' . esc_attr( $args['placeholder'] ) . '" />';
1921
1922
				} elseif ( is_array( $states ) ) {
1923
1924
					$field .= '<select name="' . esc_attr( $key ) . '" id="' . esc_attr( $args['id'] ) . '" class="state_select ' . esc_attr( implode( ' ', $args['input_class'] ) ) . '" ' . implode( ' ', $custom_attributes ) . ' data-placeholder="' . esc_attr( $args['placeholder'] ) . '" ' . $args['autocomplete'] . '>
1925
						<option value="">' . __( 'Select a state&hellip;', 'woocommerce' ) . '</option>';
1926
1927 View Code Duplication
					foreach ( $states as $ckey => $cvalue ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1928
						$field .= '<option value="' . esc_attr( $ckey ) . '" ' . selected( $value, $ckey, false ) . '>' . $cvalue . '</option>';
1929
					}
1930
1931
					$field .= '</select>';
1932
1933
				} else {
1934
1935
					$field .= '<input type="text" class="input-text ' . esc_attr( implode( ' ', $args['input_class'] ) ) . '" value="' . esc_attr( $value ) . '"  placeholder="' . esc_attr( $args['placeholder'] ) . '" ' . $args['autocomplete'] . ' name="' . esc_attr( $key ) . '" id="' . esc_attr( $args['id'] ) . '" ' . implode( ' ', $custom_attributes ) . ' />';
1936
1937
				}
1938
1939
				break;
1940
			case 'textarea' :
1941
1942
				$field .= '<textarea name="' . esc_attr( $key ) . '" class="input-text ' . esc_attr( implode( ' ', $args['input_class'] ) ) . '" id="' . esc_attr( $args['id'] ) . '" placeholder="' . esc_attr( $args['placeholder'] ) . '" ' . $args['maxlength'] . ' ' . $args['autocomplete'] . ' ' . ( empty( $args['custom_attributes']['rows'] ) ? ' rows="2"' : '' ) . ( empty( $args['custom_attributes']['cols'] ) ? ' cols="5"' : '' ) . implode( ' ', $custom_attributes ) . '>' . esc_textarea( $value ) . '</textarea>';
1943
1944
				break;
1945 View Code Duplication
			case 'checkbox' :
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1946
1947
				$field = '<label class="checkbox ' . implode( ' ', $args['label_class'] ) . '" ' . implode( ' ', $custom_attributes ) . '>
1948
						<input type="' . esc_attr( $args['type'] ) . '" class="input-checkbox ' . esc_attr( implode( ' ', $args['input_class'] ) ) . '" name="' . esc_attr( $key ) . '" id="' . esc_attr( $args['id'] ) . '" value="1" ' . checked( $value, 1, false ) . ' /> '
1949
						 . $args['label'] . $required . '</label>';
1950
1951
				break;
1952
			case 'password' :
1953
			case 'text' :
1954
			case 'email' :
1955
			case 'tel' :
1956 View Code Duplication
			case 'number' :
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1957
1958
				$field .= '<input type="' . esc_attr( $args['type'] ) . '" class="input-text ' . esc_attr( implode( ' ', $args['input_class'] ) ) . '" name="' . esc_attr( $key ) . '" id="' . esc_attr( $args['id'] ) . '" placeholder="' . esc_attr( $args['placeholder'] ) . '" ' . $args['maxlength'] . ' ' . $args['autocomplete'] . ' value="' . esc_attr( $value ) . '" ' . implode( ' ', $custom_attributes ) . ' />';
1959
1960
				break;
1961
			case 'select' :
1962
1963
				$options = $field = '';
1964
1965
				if ( ! empty( $args['options'] ) ) {
1966
					foreach ( $args['options'] as $option_key => $option_text ) {
1967
						if ( '' === $option_key ) {
1968
							// If we have a blank option, select2 needs a placeholder
1969
							if ( empty( $args['placeholder'] ) ) {
1970
								$args['placeholder'] = $option_text ? $option_text : __( 'Choose an option', 'woocommerce' );
1971
							}
1972
							$custom_attributes[] = 'data-allow_clear="true"';
1973
						}
1974
						$options .= '<option value="' . esc_attr( $option_key ) . '" ' . selected( $value, $option_key, false ) . '>' . esc_attr( $option_text ) . '</option>';
1975
					}
1976
1977
					$field .= '<select name="' . esc_attr( $key ) . '" id="' . esc_attr( $args['id'] ) . '" class="select ' . esc_attr( implode( ' ', $args['input_class'] ) ) . '" ' . implode( ' ', $custom_attributes ) . ' data-placeholder="' . esc_attr( $args['placeholder'] ) . '" ' . $args['autocomplete'] . '>
1978
							' . $options . '
1979
						</select>';
1980
				}
1981
1982
				break;
1983
			case 'radio' :
1984
1985
				$label_id = current( array_keys( $args['options'] ) );
1986
1987
				if ( ! empty( $args['options'] ) ) {
1988
					foreach ( $args['options'] as $option_key => $option_text ) {
0 ignored issues
show
Bug introduced by
The expression $args['options'] of type string|array is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
1989
						$field .= '<input type="radio" class="input-radio ' . esc_attr( implode( ' ', $args['input_class'] ) ) . '" value="' . esc_attr( $option_key ) . '" name="' . esc_attr( $key ) . '" id="' . esc_attr( $args['id'] ) . '_' . esc_attr( $option_key ) . '"' . checked( $value, $option_key, false ) . ' />';
1990
						$field .= '<label for="' . esc_attr( $args['id'] ) . '_' . esc_attr( $option_key ) . '" class="radio ' . implode( ' ', $args['label_class'] ) . '">' . $option_text . '</label>';
1991
					}
1992
				}
1993
1994
				break;
1995
		}
1996
1997
		if ( ! empty( $field ) ) {
1998
			$field_html = '';
1999
2000
			if ( $args['label'] && 'checkbox' != $args['type'] ) {
2001
				$field_html .= '<label for="' . esc_attr( $label_id ) . '" class="' . esc_attr( implode( ' ', $args['label_class'] ) ) . '">' . $args['label'] . $required . '</label>';
2002
			}
2003
2004
			$field_html .= $field;
2005
2006
			if ( $args['description'] ) {
2007
				$field_html .= '<span class="description">' . esc_html( $args['description'] ) . '</span>';
2008
			}
2009
2010
			$container_class = 'form-row ' . esc_attr( implode( ' ', $args['class'] ) );
2011
			$container_id = esc_attr( $args['id'] ) . '_field';
2012
2013
			$after = ! empty( $args['clear'] ) ? '<div class="clear"></div>' : '';
2014
2015
			$field = sprintf( $field_container, $container_class, $container_id, $field_html ) . $after;
2016
		}
2017
2018
		$field = apply_filters( 'woocommerce_form_field_' . $args['type'], $field, $key, $args, $value );
2019
2020
		if ( $args['return'] ) {
2021
			return $field;
2022
		} else {
2023
			echo $field;
2024
		}
2025
	}
2026
}
2027
2028
if ( ! function_exists( 'get_product_search_form' ) ) {
2029
2030
	/**
2031
	 * Display product search form.
2032
	 *
2033
	 * Will first attempt to locate the product-searchform.php file in either the child or.
2034
	 * the parent, then load it. If it doesn't exist, then the default search form.
2035
	 * will be displayed.
2036
	 *
2037
	 * The default searchform uses html5.
2038
	 *
2039
	 * @subpackage	Forms
2040
	 * @param bool $echo (default: true)
2041
	 * @return string
2042
	 */
2043
	function get_product_search_form( $echo = true  ) {
2044
		global $product_search_form_index;
2045
2046
		ob_start();
2047
2048
		if ( empty( $product_search_form_index ) ) {
2049
			$product_search_form_index = 0;
2050
		}
2051
2052
		do_action( 'pre_get_product_search_form' );
2053
2054
		wc_get_template( 'product-searchform.php', array(
2055
			'index' => $product_search_form_index++,
2056
		) );
2057
2058
		$form = apply_filters( 'get_product_search_form', ob_get_clean() );
2059
2060
		if ( $echo ) {
2061
			echo $form;
2062
		} else {
2063
			return $form;
2064
		}
2065
	}
2066
}
2067
2068
if ( ! function_exists( 'woocommerce_output_auth_header' ) ) {
2069
2070
	/**
2071
	 * Output the Auth header.
2072
	 */
2073
	function woocommerce_output_auth_header() {
2074
		wc_get_template( 'auth/header.php' );
2075
	}
2076
}
2077
2078
if ( ! function_exists( 'woocommerce_output_auth_footer' ) ) {
2079
2080
	/**
2081
	 * Output the Auth footer.
2082
	 */
2083
	function woocommerce_output_auth_footer() {
2084
		wc_get_template( 'auth/footer.php' );
2085
	}
2086
}
2087
2088
if ( ! function_exists( 'woocommerce_single_variation' ) ) {
2089
2090
	/**
2091
	 * Output placeholders for the single variation.
2092
	 */
2093
	function woocommerce_single_variation() {
2094
		echo '<div class="woocommerce-variation single_variation"></div>';
2095
	}
2096
}
2097
2098
if ( ! function_exists( 'woocommerce_single_variation_add_to_cart_button' ) ) {
2099
2100
	/**
2101
	 * Output the add to cart button for variations.
2102
	 */
2103
	function woocommerce_single_variation_add_to_cart_button() {
2104
		wc_get_template( 'single-product/add-to-cart/variation-add-to-cart-button.php' );
2105
	}
2106
}
2107
2108
if ( ! function_exists( 'wc_dropdown_variation_attribute_options' ) ) {
2109
2110
	/**
2111
	 * Output a list of variation attributes for use in the cart forms.
2112
	 *
2113
	 * @param array $args
2114
	 * @since 2.4.0
2115
	 */
2116
	function wc_dropdown_variation_attribute_options( $args = array() ) {
2117
		$args = wp_parse_args( apply_filters( 'woocommerce_dropdown_variation_attribute_options_args', $args ), array(
2118
			'options'          => false,
2119
			'attribute'        => false,
2120
			'product'          => false,
2121
			'selected' 	       => false,
2122
			'name'             => '',
2123
			'id'               => '',
2124
			'class'            => '',
2125
			'show_option_none' => __( 'Choose an option', 'woocommerce' ),
2126
		) );
2127
2128
		$options   = $args['options'];
2129
		$product   = $args['product'];
2130
		$attribute = $args['attribute'];
2131
		$name      = $args['name'] ? $args['name'] : 'attribute_' . sanitize_title( $attribute );
2132
		$id        = $args['id'] ? $args['id'] : sanitize_title( $attribute );
2133
		$class     = $args['class'];
2134
2135
		if ( empty( $options ) && ! empty( $product ) && ! empty( $attribute ) ) {
2136
			$attributes = $product->get_variation_attributes();
2137
			$options    = $attributes[ $attribute ];
2138
		}
2139
2140
		$html = '<select id="' . esc_attr( $id ) . '" class="' . esc_attr( $class ) . '" name="' . esc_attr( $name ) . '" data-attribute_name="attribute_' . esc_attr( sanitize_title( $attribute ) ) . '">';
2141
2142
		if ( $args['show_option_none'] ) {
2143
			$html .= '<option value="">' . esc_html( $args['show_option_none'] ) . '</option>';
2144
		}
2145
2146
		if ( ! empty( $options ) ) {
2147
			if ( $product && taxonomy_exists( $attribute ) ) {
2148
				// Get terms if this is a taxonomy - ordered. We need the names too.
2149
				$terms = wc_get_product_terms( $product->id, $attribute, array( 'fields' => 'all' ) );
2150
2151 View Code Duplication
				foreach ( $terms as $term ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2152
					if ( in_array( $term->slug, $options ) ) {
2153
						$html .= '<option value="' . esc_attr( $term->slug ) . '" ' . selected( sanitize_title( $args['selected'] ), $term->slug, false ) . '>' . esc_html( apply_filters( 'woocommerce_variation_option_name', $term->name ) ) . '</option>';
2154
					}
2155
				}
2156
			} else {
2157
				foreach ( $options as $option ) {
2158
					// This handles < 2.4.0 bw compatibility where text attributes were not sanitized.
2159
					$selected = sanitize_title( $args['selected'] ) === $args['selected'] ? selected( $args['selected'], sanitize_title( $option ), false ) : selected( $args['selected'], $option, false );
2160
					$html .= '<option value="' . esc_attr( $option ) . '" ' . $selected . '>' . esc_html( apply_filters( 'woocommerce_variation_option_name', $option ) ) . '</option>';
2161
				}
2162
			}
2163
		}
2164
2165
		$html .= '</select>';
2166
2167
		echo apply_filters( 'woocommerce_dropdown_variation_attribute_options_html', $html, $args );
2168
	}
2169
}
2170
2171
if ( ! function_exists( 'woocommerce_account_content' ) ) {
2172
2173
	/**
2174
	 * My Account content output.
2175
	 */
2176
	function woocommerce_account_content() {
2177
		global $wp;
2178
2179
		foreach ( $wp->query_vars as $key => $value ) {
2180
			// Ignore pagename param.
2181
			if ( 'pagename' === $key ) {
2182
				continue;
2183
			}
2184
2185
			if ( has_action( 'woocommerce_account_' . $key . '_endpoint' ) ) {
2186
				do_action( 'woocommerce_account_' . $key . '_endpoint', $value );
2187
				return;
2188
			}
2189
		}
2190
2191
		// No endpoint found? Default to dashboard.
2192
		wc_get_template( 'myaccount/dashboard.php', array(
2193
			'current_user' => get_user_by( 'id', get_current_user_id() ),
2194
		) );
2195
	}
2196
}
2197
2198
if ( ! function_exists( 'woocommerce_account_navigation' ) ) {
2199
2200
	/**
2201
	 * My Account navigation template.
2202
	 */
2203
	function woocommerce_account_navigation() {
2204
		wc_get_template( 'myaccount/navigation.php' );
2205
	}
2206
}
2207
2208
if ( ! function_exists( 'woocommerce_account_orders' ) ) {
2209
2210
	/**
2211
	 * My Account > Orders template.
2212
	 *
2213
	 * @param int $current_page Current page number.
2214
	 */
2215
	function woocommerce_account_orders( $current_page ) {
2216
		$current_page    = empty( $current_page ) ? 1 : absint( $current_page );
2217
		$customer_orders = wc_get_orders( apply_filters( 'woocommerce_my_account_my_orders_query', array( 'customer' => get_current_user_id(), 'page' => $current_page, 'paginate' => true ) ) );
2218
2219
		wc_get_template(
2220
			'myaccount/orders.php',
2221
			array(
2222
				'current_page' => absint( $current_page ),
2223
				'customer_orders' => $customer_orders,
2224
				'has_orders' => 0 < $customer_orders->total,
2225
			)
2226
		);
2227
	}
2228
}
2229
2230
if ( ! function_exists( 'woocommerce_account_view_order' ) ) {
2231
2232
	/**
2233
	 * My Account > View order template.
2234
	 *
2235
	 * @param int $order_id Order ID.
2236
	 */
2237
	function woocommerce_account_view_order( $order_id ) {
2238
		WC_Shortcode_My_Account::view_order( absint( $order_id ) );
2239
	}
2240
}
2241
2242
if ( ! function_exists( 'woocommerce_account_downloads' ) ) {
2243
2244
	/**
2245
	 * My Account > Downloads template.
2246
	 */
2247
	function woocommerce_account_downloads() {
2248
		wc_get_template( 'myaccount/downloads.php' );
2249
	}
2250
}
2251
2252
if ( ! function_exists( 'woocommerce_account_edit_address' ) ) {
2253
2254
	/**
2255
	 * My Account > Edit address template.
2256
	 *
2257
	 * @param string $type Address type.
2258
	 */
2259
	function woocommerce_account_edit_address( $type ) {
2260
		$type = wc_edit_address_i18n( sanitize_title( $type ), true );
2261
2262
		WC_Shortcode_My_Account::edit_address( $type );
2263
	}
2264
}
2265
2266
if ( ! function_exists( 'woocommerce_account_payment_methods' ) ) {
2267
2268
	/**
2269
	 * My Account > Downloads template.
2270
	 */
2271
	function woocommerce_account_payment_methods() {
2272
		wc_get_template( 'myaccount/payment-methods.php' );
2273
	}
2274
}
2275
2276
if ( ! function_exists( 'woocommerce_account_add_payment_method' ) ) {
2277
2278
	/**
2279
	 * My Account > Add payment method template.
2280
	 */
2281
	function woocommerce_account_add_payment_method() {
2282
		WC_Shortcode_My_Account::add_payment_method();
2283
	}
2284
}
2285
2286
if ( ! function_exists( 'woocommerce_account_edit_account' ) ) {
2287
2288
	/**
2289
	 * My Account > Edit account template.
2290
	 */
2291
	function woocommerce_account_edit_account() {
2292
		WC_Shortcode_My_Account::edit_account();
2293
	}
2294
}
2295
2296
if ( ! function_exists( 'wc_no_products_found' ) ) {
2297
2298
	/**
2299
	 * Show no products found message.
2300
	 */
2301
	function wc_no_products_found() {
2302
		wc_get_template( 'loop/no-products-found.php' );
2303
	}
2304
}
2305
2306
2307
if ( ! function_exists( 'wc_get_email_order_items' ) ) {
2308
	/**
2309
	 * Get HTML for the order items to be shown in emails.
2310
	 * @param WC_Order $order
2311
	 * @param array $args
2312
	 * @since 2.7.0
2313
	 */
2314
	function wc_get_email_order_items( $order, $args = array() ) {
2315
		ob_start();
2316
2317
		$defaults = array(
2318
			'show_sku'      => false,
2319
			'show_image'    => false,
2320
			'image_size'    => array( 32, 32 ),
2321
			'plain_text'    => false,
2322
			'sent_to_admin' => false,
2323
		);
2324
2325
		$args     = wp_parse_args( $args, $defaults );
2326
		$template = $args['plain_text'] ? 'emails/plain/email-order-items.php' : 'emails/email-order-items.php';
2327
2328
		wc_get_template( $template, array(
2329
			'order'               => $order,
2330
			'items'               => $order->get_items(),
2331
			'show_download_links' => $order->is_download_permitted(),
2332
			'show_sku'            => $args['show_sku'],
2333
			'show_purchase_note'  => $order->is_paid(),
2334
			'show_image'          => $args['show_image'],
2335
			'image_size'          => $args['image_size'],
2336
			'plain_text'          => $args['plain_text'],
2337
			'sent_to_admin'       => $args['sent_to_admin'],
2338
		) );
2339
2340
		return apply_filters( 'woocommerce_email_order_items_table', ob_get_clean(), $order );
2341
	}
2342
}
2343
2344
if ( ! function_exists( 'wc_display_item_meta' ) ) {
2345
	/**
2346
	 * Display item meta data.
2347
	 * @since  2.7.0
2348
	 * @param  WC_Item $item
2349
	 * @param  array   $args
2350
	 * @return string|void
2351
	 */
2352
	function wc_display_item_meta( $item, $args = array() ) {
2353
		$strings = array();
2354
		$html    = '';
2355
		$args    = wp_parse_args( $args, array(
2356
			'before'    => '<ul class="wc-item-meta"><li>',
2357
			'after'     => '</li></ul>',
2358
			'separator' => '</li><li>',
2359
			'echo'      => true,
2360
			'autop'     => false,
2361
		) );
2362
2363
		foreach ( $item->get_formatted_meta_data() as $meta_id => $meta ) {
2364
			if ( '_' === substr( $meta->key, 0, 1 ) ) {
2365
				continue;
2366
			}
2367
			$value = $args['autop'] ? wp_kses_post( wpautop( make_clickable( $meta->display_value ) ) ) : wp_kses_post( make_clickable( $meta->display_value ) );
2368
			$strings[] = '<strong class="wc-item-meta-label">' . wp_kses_post( $meta->display_key ) . ':</strong> ' . $value;
2369
		}
2370
2371 View Code Duplication
		if ( $strings ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $strings of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2372
			$html = $args['before'] . implode( $args['separator'], $strings ) . $args['after'];
2373
		}
2374
2375
		$html = apply_filters( 'woocommerce_display_item_meta', $html, $item, $args );
2376
2377
		if ( $args['echo'] ) {
2378
			echo $html;
2379
		} else {
2380
			return $html;
2381
		}
2382
	}
2383
}
2384
2385
if ( ! function_exists( 'wc_display_item_downloads' ) ) {
2386
	/**
2387
	 * Display item download links.
2388
	 * @since  2.7.0
2389
	 * @param  WC_Item $item
2390
	 * @param  array   $args
2391
	 * @return string|void
2392
	 */
2393
	function wc_display_item_downloads( $item, $args = array() ) {
2394
		$strings = array();
2395
		$html    = '';
2396
		$args    = wp_parse_args( $args, array(
2397
			'before'    => '<ul class ="wc-item-downloads"><li>',
2398
			'after'     => '</li></ul>',
2399
			'separator' => '</li><li>',
2400
			'echo'      => true,
2401
			'show_url'  => false,
2402
		) );
2403
2404
		if ( is_object( $item ) && $item->is_type( 'line_item' ) && ( $downloads = $item->get_item_downloads() ) ) {
2405
			$i = 0;
2406
			foreach ( $downloads as $file ) {
2407
				$i ++;
2408
2409
				if ( $args['show_url'] ) {
2410
					$strings[] = '<strong class="wc-item-download-label">' . esc_html( $file['name'] ) . ':</strong> ' . esc_html( $file['download_url'] );
2411
				} else {
2412
					$prefix = sizeof( $downloads ) > 1 ? sprintf( __( 'Download %d', 'woocommerce' ), $i ) : __( 'Download', 'woocommerce' );
2413
					$strings[] = '<strong class="wc-item-download-label">' . $prefix . ':</strong> <a href="' . esc_url( $file['download_url'] ) . '" target="_blank">' . esc_html( $file['name'] ) . '</a>';
2414
				}
2415
			}
2416
		}
2417
2418 View Code Duplication
		if ( $strings ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $strings of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2419
			$html = $args['before'] . implode( $args['separator'], $strings ) . $args['after'];
2420
		}
2421
2422
		$html = apply_filters( 'woocommerce_display_item_downloads', $html, $item, $args );
2423
2424
		if ( $args['echo'] ) {
2425
			echo $html;
2426
		} else {
2427
			return $html;
2428
		}
2429
	}
2430
}
2431