Completed
Pull Request — master (#11455)
by
unknown
09:43
created

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

Complexity

Conditions 2
Paths 2

Size

Total Lines 25
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 14
nc 2
nop 1
dl 0
loc 25
rs 8.8571
c 0
b 0
f 0
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
	// When default permalinks are enabled, redirect shop page to post type archive url
24
	if ( ! empty( $_GET['page_id'] ) && '' === get_option( 'permalink_structure' ) && $_GET['page_id'] == wc_get_page_id( 'shop' ) ) {
25
		wp_safe_redirect( get_post_type_archive_link('product') );
26
		exit;
27
	}
28
29
	// When on the checkout with an empty cart, redirect to cart page
30
	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'] ) ) {
31
		wc_add_notice( __( 'Checkout is not available whilst your cart is empty.', 'woocommerce' ), 'notice' );
32
		wp_redirect( wc_get_page_permalink( 'cart' ) );
33
		exit;
34
	}
35
36
	// Logout
37
	elseif ( isset( $wp->query_vars['customer-logout'] ) ) {
38
		wp_redirect( str_replace( '&amp;', '&', wp_logout_url( wc_get_page_permalink( 'myaccount' ) ) ) );
39
		exit;
40
	}
41
42
	// Redirect to the product page if we have a single product
43
	elseif ( is_search() && is_post_type_archive( 'product' ) && apply_filters( 'woocommerce_redirect_single_search_result', true ) && 1 === absint( $wp_query->found_posts ) ) {
44
		$product = wc_get_product( $wp_query->post );
45
46
		if ( $product && $product->is_visible() ) {
47
			wp_safe_redirect( get_permalink( $product->id ), 302 );
48
			exit;
49
		}
50
	}
51
52
	// Ensure payment gateways are loaded early
53
	elseif ( is_add_payment_method_page() ) {
54
55
		WC()->payment_gateways();
56
57
	}
58
59
	// Checkout pages handling
60
	elseif ( is_checkout() ) {
61
		// Buffer the checkout page
62
		ob_start();
63
64
		// Ensure gateways and shipping methods are loaded early
65
		WC()->payment_gateways();
66
		WC()->shipping();
67
	}
68
}
69
add_action( 'template_redirect', 'wc_template_redirect' );
70
71
/**
72
 * When loading sensitive checkout or account pages, send a HTTP header to limit rendering of pages to same origin iframes for security reasons.
73
 *
74
 * Can be disabled with: remove_action( 'template_redirect', 'wc_send_frame_options_header' );
75
 *
76
 * @since  2.3.10
77
 */
78
function wc_send_frame_options_header() {
79
	if ( is_checkout() || is_account_page() ) {
80
		send_frame_options_header();
81
	}
82
}
83
add_action( 'template_redirect', 'wc_send_frame_options_header' );
84
85
/**
86
 * No index our endpoints.
87
 * Prevent indexing pages like order-received.
88
 *
89
 * @since 2.5.3
90
 */
91
function wc_prevent_endpoint_indexing() {
92
	if ( is_wc_endpoint_url() || isset( $_GET['download_file'] ) ) {
93
		@header( 'X-Robots-Tag: noindex' );
94
	}
95
}
96
add_action( 'template_redirect', 'wc_prevent_endpoint_indexing' );
97
98
/**
99
 * Remove adjacent_posts_rel_link_wp_head - pointless for products.
100
 *
101
 * @since 2.7.0
102
 */
103
function wc_prevent_adjacent_posts_rel_link_wp_head() {
104
	if ( is_singular( 'product' ) ) {
105
		remove_action( 'wp_head', 'adjacent_posts_rel_link_wp_head', 10, 0 );
106
	}
107
}
108
add_action( 'template_redirect', 'wc_prevent_adjacent_posts_rel_link_wp_head' );
109
110
/**
111
 * When the_post is called, put product data into a global.
112
 *
113
 * @param mixed $post
114
 * @return WC_Product
115
 */
116
function wc_setup_product_data( $post ) {
117
	unset( $GLOBALS['product'] );
118
119
	if ( is_int( $post ) )
120
		$post = get_post( $post );
121
122
	if ( empty( $post->post_type ) || ! in_array( $post->post_type, array( 'product', 'product_variation' ) ) )
123
		return;
124
125
	$GLOBALS['product'] = wc_get_product( $post );
126
127
	return $GLOBALS['product'];
128
}
129
add_action( 'the_post', 'wc_setup_product_data' );
130
131
if ( ! function_exists( 'woocommerce_reset_loop' ) ) {
132
133
	/**
134
	 * Reset the loop's index and columns when we're done outputting a product loop.
135
	 * @subpackage	Loop
136
	 */
137
	function woocommerce_reset_loop() {
138
		$GLOBALS['woocommerce_loop'] = array(
139
			'loop'    => '',
140
			'columns' => '',
141
			'name'    => '',
142
		);
143
	}
144
}
145
add_filter( 'loop_end', 'woocommerce_reset_loop' );
146
147
/**
148
 * Products RSS Feed.
149
 * @deprecated 2.6
150
 * @access public
151
 */
152
function wc_products_rss_feed() {
153
	// Product RSS
154
	if ( is_post_type_archive( 'product' ) || is_singular( 'product' ) ) {
155
156
		$feed = get_post_type_archive_feed_link( 'product' );
157
158
		echo '<link rel="alternate" type="application/rss+xml"  title="' . esc_attr__( 'New products', 'woocommerce' ) . '" href="' . esc_url( $feed ) . '" />';
159
160
	} elseif ( is_tax( 'product_cat' ) ) {
161
162
		$term = get_term_by( 'slug', esc_attr( get_query_var('product_cat') ), 'product_cat' );
163
164 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...
165
			$feed = add_query_arg( 'product_cat', $term->slug, get_post_type_archive_feed_link( 'product' ) );
166
			echo '<link rel="alternate" type="application/rss+xml"  title="' . esc_attr( sprintf( __( 'New products added to %s', 'woocommerce' ), $term->name ) ) . '" href="' . esc_url( $feed ) . '" />';
167
		}
168
	} elseif ( is_tax( 'product_tag' ) ) {
169
170
		$term = get_term_by('slug', esc_attr( get_query_var('product_tag') ), 'product_tag');
171
172 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...
173
			$feed = add_query_arg('product_tag', $term->slug, get_post_type_archive_feed_link( 'product' ));
174
			echo '<link rel="alternate" type="application/rss+xml"  title="' . sprintf(__( 'New products tagged %s', 'woocommerce' ), urlencode($term->name)) . '" href="' . esc_url( $feed ) . '" />';
175
		}
176
	}
177
}
178
179
/**
180
 * Output generator tag to aid debugging.
181
 *
182
 * @access public
183
 */
184
function wc_generator_tag( $gen, $type ) {
185
	switch ( $type ) {
186
		case 'html':
187
			$gen .= "\n" . '<meta name="generator" content="WooCommerce ' . esc_attr( WC_VERSION ) . '">';
188
			break;
189
		case 'xhtml':
190
			$gen .= "\n" . '<meta name="generator" content="WooCommerce ' . esc_attr( WC_VERSION ) . '" />';
191
			break;
192
	}
193
	return $gen;
194
}
195
196
/**
197
 * Add body classes for WC pages.
198
 *
199
 * @param  array $classes
200
 * @return array
201
 */
202
function wc_body_class( $classes ) {
203
	$classes = (array) $classes;
204
205
	if ( is_woocommerce() ) {
206
		$classes[] = 'woocommerce';
207
		$classes[] = 'woocommerce-page';
208
	}
209
210
	elseif ( is_checkout() ) {
211
		$classes[] = 'woocommerce-checkout';
212
		$classes[] = 'woocommerce-page';
213
	}
214
215
	elseif ( is_cart() ) {
216
		$classes[] = 'woocommerce-cart';
217
		$classes[] = 'woocommerce-page';
218
	}
219
220
	elseif ( is_account_page() ) {
221
		$classes[] = 'woocommerce-account';
222
		$classes[] = 'woocommerce-page';
223
	}
224
225
	if ( is_store_notice_showing() ) {
226
		$classes[] = 'woocommerce-demo-store';
227
	}
228
229
	foreach ( WC()->query->query_vars as $key => $value ) {
230
		if ( is_wc_endpoint_url( $key ) ) {
231
			$classes[] = 'woocommerce-' . sanitize_html_class( $key );
232
		}
233
	}
234
235
	return array_unique( $classes );
236
}
237
238
/**
239
 * Display the classes for the product cat div.
240
 *
241
 * @since 2.4.0
242
 * @param string|array $class One or more classes to add to the class list.
243
 * @param object $category object Optional.
244
 */
245
function wc_product_cat_class( $class = '', $category = null ) {
246
	// Separates classes with a single space, collates classes for post DIV
247
	echo 'class="' . esc_attr( join( ' ', wc_get_product_cat_class( $class, $category ) ) ) . '"';
248
}
249
250
/**
251
 * Get classname for loops based on $woocommerce_loop global.
252
 * @since 2.6.0
253
 * @return string
254
 */
255
function wc_get_loop_class() {
256
	global $woocommerce_loop;
257
258
	$woocommerce_loop['loop']    = ! empty( $woocommerce_loop['loop'] ) ? $woocommerce_loop['loop'] + 1   : 1;
259
	$woocommerce_loop['columns'] = ! empty( $woocommerce_loop['columns'] ) ? $woocommerce_loop['columns'] : apply_filters( 'loop_shop_columns', 4 );
260
261
	if ( 0 === ( $woocommerce_loop['loop'] - 1 ) % $woocommerce_loop['columns'] || 1 === $woocommerce_loop['columns'] ) {
262
		return 'first';
263
	} elseif ( 0 === $woocommerce_loop['loop'] % $woocommerce_loop['columns'] ) {
264
		return 'last';
265
	} else {
266
		return '';
267
	}
268
}
269
270
/**
271
 * Get the classes for the product cat div.
272
 *
273
 * @since 2.4.0
274
 * @param string|array $class One or more classes to add to the class list.
275
 * @param object $category object Optional.
276
 */
277
function wc_get_product_cat_class( $class = '', $category = null ) {
278
	$classes   = is_array( $class ) ? $class : array_map( 'trim', explode( ' ', $class ) );
279
	$classes[] = 'product-category';
280
	$classes[] = 'product';
281
	$classes[] = wc_get_loop_class();
282
	$classes   = apply_filters( 'product_cat_class', $classes, $class, $category );
283
284
	return array_unique( array_filter( $classes ) );
285
}
286
287
/**
288
 * Adds extra post classes for products.
289
 *
290
 * @since 2.1.0
291
 * @param array $classes
292
 * @param string|array $class
293
 * @param int $post_id
294
 * @return array
295
 */
296
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...
297
	if ( ! $post_id || 'product' !== get_post_type( $post_id ) ) {
298
		return $classes;
299
	}
300
301
	$product = wc_get_product( $post_id );
302
303
	if ( $product ) {
304
		$classes[] = wc_get_loop_class();
305
		$classes[] = $product->stock_status;
306
307
		if ( $product->is_on_sale() ) {
308
			$classes[] = 'sale';
309
		}
310
		if ( $product->is_featured() ) {
311
			$classes[] = 'featured';
312
		}
313
		if ( $product->is_downloadable() ) {
314
			$classes[] = 'downloadable';
315
		}
316
		if ( $product->is_virtual() ) {
317
			$classes[] = 'virtual';
318
		}
319
		if ( $product->is_sold_individually() ) {
320
			$classes[] = 'sold-individually';
321
		}
322
		if ( $product->is_taxable() ) {
323
			$classes[] = 'taxable';
324
		}
325
		if ( $product->is_shipping_taxable() ) {
326
			$classes[] = 'shipping-taxable';
327
		}
328
		if ( $product->is_purchasable() ) {
329
			$classes[] = 'purchasable';
330
		}
331
		if ( $product->get_type() ) {
332
			$classes[] = "product-type-" . $product->get_type();
333
		}
334
		if ( $product->is_type( 'variable' ) ) {
335
			if ( $product->has_default_attributes() ) {
336
				$classes[] = 'has-default-attributes';
337
			}
338
			if ( $product->has_child() ) {
339
				$classes[] = 'has-children';
340
			}
341
		}
342
	}
343
344
	if ( false !== ( $key = array_search( 'hentry', $classes ) ) ) {
345
		unset( $classes[ $key ] );
346
	}
347
348
	return $classes;
349
}
350
351
/**
352
 * Outputs hidden form inputs for each query string variable.
353
 * @since 2.7.0
354
 * @param array $values Name value pairs.
355
 * @param array $exclude Keys to exclude.
356
 * @param string $current_key Current key we are outputting.
357
 */
358
function wc_query_string_form_fields( $values = null, $exclude = array(), $current_key = '', $return = false ) {
359
	if ( is_null( $values ) ) {
360
		$values = $_GET;
361
	}
362
	$html = '';
363
364
	foreach ( $values as $key => $value ) {
365
		if ( in_array( $key, $exclude, true ) ) {
366
			continue;
367
		}
368
		if ( $current_key ) {
369
			$key = $current_key . '[' . $key . ']';
370
		}
371
		if ( is_array( $value ) ) {
372
			$html .= wc_query_string_form_fields( $value, $exclude, $key, true );
373
		} else {
374
			$html .= '<input type="hidden" name="' . esc_attr( $key ) . '" value="' . esc_attr( $value ) . '" />';
375
		}
376
	}
377
378
	if ( $return ) {
379
		return $html;
380
	} else {
381
		echo $html;
382
	}
383
}
384
385
/** Template pages ********************************************************/
386
387
if ( ! function_exists( 'woocommerce_content' ) ) {
388
389
	/**
390
	 * Output WooCommerce content.
391
	 *
392
	 * This function is only used in the optional 'woocommerce.php' template.
393
	 * which people can add to their themes to add basic woocommerce support.
394
	 * without hooks or modifying core templates.
395
	 *
396
	 */
397
	function woocommerce_content() {
398
399
		if ( is_singular( 'product' ) ) {
400
401
			while ( have_posts() ) : the_post();
402
403
				wc_get_template_part( 'content', 'single-product' );
404
405
			endwhile;
406
407
		} else { ?>
408
409
			<?php if ( apply_filters( 'woocommerce_show_page_title', true ) ) : ?>
410
411
				<h1 class="page-title"><?php woocommerce_page_title(); ?></h1>
412
413
			<?php endif; ?>
414
415
			<?php do_action( 'woocommerce_archive_description' ); ?>
416
417 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...
418
419
				<?php do_action('woocommerce_before_shop_loop'); ?>
420
421
				<?php woocommerce_product_loop_start(); ?>
422
423
					<?php woocommerce_product_subcategories(); ?>
424
425
					<?php while ( have_posts() ) : the_post(); ?>
426
427
						<?php wc_get_template_part( 'content', 'product' ); ?>
428
429
					<?php endwhile; // end of the loop. ?>
430
431
				<?php woocommerce_product_loop_end(); ?>
432
433
				<?php do_action('woocommerce_after_shop_loop'); ?>
434
435
			<?php elseif ( ! woocommerce_product_subcategories( array( 'before' => woocommerce_product_loop_start( false ), 'after' => woocommerce_product_loop_end( false ) ) ) ) : ?>
436
437
				<?php do_action( 'woocommerce_no_products_found' ); ?>
438
439
			<?php endif;
440
441
		}
442
	}
443
}
444
445
/** Global ****************************************************************/
446
447
if ( ! function_exists( 'woocommerce_output_content_wrapper' ) ) {
448
449
	/**
450
	 * Output the start of the page wrapper.
451
	 *
452
	 */
453
	function woocommerce_output_content_wrapper() {
454
		wc_get_template( 'global/wrapper-start.php' );
455
	}
456
}
457
if ( ! function_exists( 'woocommerce_output_content_wrapper_end' ) ) {
458
459
	/**
460
	 * Output the end of the page wrapper.
461
	 *
462
	 */
463
	function woocommerce_output_content_wrapper_end() {
464
		wc_get_template( 'global/wrapper-end.php' );
465
	}
466
}
467
468
if ( ! function_exists( 'woocommerce_get_sidebar' ) ) {
469
470
	/**
471
	 * Get the shop sidebar template.
472
	 *
473
	 */
474
	function woocommerce_get_sidebar() {
475
		wc_get_template( 'global/sidebar.php' );
476
	}
477
}
478
479
if ( ! function_exists( 'woocommerce_demo_store' ) ) {
480
481
	/**
482
	 * Adds a demo store banner to the site if enabled.
483
	 *
484
	 */
485
	function woocommerce_demo_store() {
486
		if ( ! is_store_notice_showing() ) {
487
			return;
488
		}
489
490
		$notice = get_option( 'woocommerce_demo_store_notice' );
491
492
		if ( empty( $notice ) ) {
493
			$notice = __( 'This is a demo store for testing purposes &mdash; no orders shall be fulfilled.', 'woocommerce' );
494
		}
495
496
		echo apply_filters( 'woocommerce_demo_store', '<p class="demo_store">' . wp_kses_post( $notice ) . '</p>', $notice );
497
	}
498
}
499
500
/** Loop ******************************************************************/
501
502
if ( ! function_exists( 'woocommerce_page_title' ) ) {
503
504
	/**
505
	 * woocommerce_page_title function.
506
	 *
507
	 * @param  bool $echo
508
	 * @return string
509
	 */
510
	function woocommerce_page_title( $echo = true ) {
511
512
		if ( is_search() ) {
513
			$page_title = sprintf( __( 'Search Results: &ldquo;%s&rdquo;', 'woocommerce' ), get_search_query() );
514
515
			if ( get_query_var( 'paged' ) )
516
				$page_title .= sprintf( __( '&nbsp;&ndash; Page %s', 'woocommerce' ), get_query_var( 'paged' ) );
517
518
		} elseif ( is_tax() ) {
519
520
			$page_title = single_term_title( "", false );
521
522
		} else {
523
524
			$shop_page_id = wc_get_page_id( 'shop' );
525
			$page_title   = get_the_title( $shop_page_id );
526
527
		}
528
529
		$page_title = apply_filters( 'woocommerce_page_title', $page_title );
530
531
		if ( $echo )
532
			echo $page_title;
533
		else
534
			return $page_title;
535
	}
536
}
537
538
if ( ! function_exists( 'woocommerce_product_loop_start' ) ) {
539
540
	/**
541
	 * Output the start of a product loop. By default this is a UL.
542
	 *
543
	 * @param bool $echo
544
	 * @return string
545
	 */
546
	function woocommerce_product_loop_start( $echo = true ) {
547
		ob_start();
548
		$GLOBALS['woocommerce_loop']['loop'] = 0;
549
		wc_get_template( 'loop/loop-start.php' );
550
		if ( $echo )
551
			echo ob_get_clean();
552
		else
553
			return ob_get_clean();
554
	}
555
}
556
if ( ! function_exists( 'woocommerce_product_loop_end' ) ) {
557
558
	/**
559
	 * Output the end of a product loop. By default this is a UL.
560
	 *
561
	 * @param bool $echo
562
	 * @return string
563
	 */
564
	function woocommerce_product_loop_end( $echo = true ) {
565
		ob_start();
566
567
		wc_get_template( 'loop/loop-end.php' );
568
569
		if ( $echo )
570
			echo ob_get_clean();
571
		else
572
			return ob_get_clean();
573
	}
574
}
575
if ( ! function_exists( 'woocommerce_template_loop_product_title' ) ) {
576
577
	/**
578
	 * Show the product title in the product loop. By default this is an H3.
579
	 */
580
	function woocommerce_template_loop_product_title() {
581
		$tag = is_product_taxonomy() || is_shop() ? 'h2' : 'h3';
582
583
		echo '<' . $tag . ' class="woocommerce-loop-product__title">' . get_the_title() . '</' . $tag . '>';
584
	}
585
}
586
if ( ! function_exists( 'woocommerce_template_loop_category_title' ) ) {
587
588
	/**
589
	 * Show the subcategory title in the product loop.
590
	 */
591
	function woocommerce_template_loop_category_title( $category ) {
592
		?>
593
		<h2 class="woocommerce-loop-category__title">
594
			<?php
595
				echo $category->name;
596
597
				if ( $category->count > 0 )
598
					echo apply_filters( 'woocommerce_subcategory_count_html', ' <mark class="count">(' . $category->count . ')</mark>', $category );
599
			?>
600
		</h2>
601
		<?php
602
	}
603
}
604
/**
605
 * Insert the opening anchor tag for products in the loop.
606
 */
607
function woocommerce_template_loop_product_link_open() {
608
	echo '<a href="' . get_the_permalink() . '" class="woocommerce-LoopProduct-link">';
609
}
610
/**
611
 * Insert the opening anchor tag for products in the loop.
612
 */
613
function woocommerce_template_loop_product_link_close() {
614
	echo '</a>';
615
}
616
/**
617
 * Insert the opening anchor tag for categories in the loop.
618
 */
619
function woocommerce_template_loop_category_link_open( $category ) {
620
	echo '<a href="' . get_term_link( $category, 'product_cat' ) . '">';
621
}
622
/**
623
 * Insert the opening anchor tag for categories in the loop.
624
 */
625
function woocommerce_template_loop_category_link_close() {
626
	echo '</a>';
627
}
628
if ( ! function_exists( 'woocommerce_taxonomy_archive_description' ) ) {
629
630
	/**
631
	 * Show an archive description on taxonomy archives.
632
	 *
633
	 * @subpackage	Archives
634
	 */
635
	function woocommerce_taxonomy_archive_description() {
636
		if ( is_product_taxonomy() && 0 === absint( get_query_var( 'paged' ) ) ) {
637
			$description = wc_format_content( term_description() );
638
			if ( $description ) {
639
				echo '<div class="term-description">' . $description . '</div>';
640
			}
641
		}
642
	}
643
}
644
if ( ! function_exists( 'woocommerce_product_archive_description' ) ) {
645
646
	/**
647
	 * Show a shop page description on product archives.
648
	 *
649
	 * @subpackage	Archives
650
	 */
651
	function woocommerce_product_archive_description() {
652
		// Don't display the description on search results page
653
		if ( is_search() ) {
654
			return;
655
		}
656
657
		if ( is_post_type_archive( 'product' ) && 0 === absint( get_query_var( 'paged' ) ) ) {
658
			$shop_page   = get_post( wc_get_page_id( 'shop' ) );
659
			if ( $shop_page ) {
660
				$description = wc_format_content( $shop_page->post_content );
661
				if ( $description ) {
662
					echo '<div class="page-description">' . $description . '</div>';
663
				}
664
			}
665
		}
666
	}
667
}
668
669
if ( ! function_exists( 'woocommerce_template_loop_add_to_cart' ) ) {
670
671
	/**
672
	 * Get the add to cart template for the loop.
673
	 *
674
	 * @subpackage	Loop
675
	 */
676
	function woocommerce_template_loop_add_to_cart( $args = array() ) {
677
		global $product;
678
679
		if ( $product ) {
680
			$defaults = array(
681
				'quantity' => 1,
682
				'class'    => implode( ' ', array_filter( array(
683
						'button',
684
						'product_type_' . $product->product_type,
685
						$product->is_purchasable() && $product->is_in_stock() ? 'add_to_cart_button' : '',
686
						$product->supports( 'ajax_add_to_cart' ) ? 'ajax_add_to_cart' : '',
687
				) ) ),
688
			);
689
690
			$args = apply_filters( 'woocommerce_loop_add_to_cart_args', wp_parse_args( $args, $defaults ), $product );
691
692
			wc_get_template( 'loop/add-to-cart.php', $args );
693
		}
694
	}
695
}
696
if ( ! function_exists( 'woocommerce_template_loop_product_thumbnail' ) ) {
697
698
	/**
699
	 * Get the product thumbnail for the loop.
700
	 *
701
	 * @subpackage	Loop
702
	 */
703
	function woocommerce_template_loop_product_thumbnail() {
704
		echo woocommerce_get_product_thumbnail();
705
	}
706
}
707
if ( ! function_exists( 'woocommerce_template_loop_price' ) ) {
708
709
	/**
710
	 * Get the product price for the loop.
711
	 *
712
	 * @subpackage	Loop
713
	 */
714
	function woocommerce_template_loop_price() {
715
		wc_get_template( 'loop/price.php' );
716
	}
717
}
718
if ( ! function_exists( 'woocommerce_template_loop_rating' ) ) {
719
720
	/**
721
	 * Display the average rating in the loop.
722
	 *
723
	 * @subpackage	Loop
724
	 */
725
	function woocommerce_template_loop_rating() {
726
		wc_get_template( 'loop/rating.php' );
727
	}
728
}
729
if ( ! function_exists( 'woocommerce_show_product_loop_sale_flash' ) ) {
730
731
	/**
732
	 * Get the sale flash for the loop.
733
	 *
734
	 * @subpackage	Loop
735
	 */
736
	function woocommerce_show_product_loop_sale_flash() {
737
		wc_get_template( 'loop/sale-flash.php' );
738
	}
739
}
740
741
if ( ! function_exists( 'woocommerce_get_product_thumbnail' ) ) {
742
743
	/**
744
	 * Get the product thumbnail, or the placeholder if not set.
745
	 *
746
	 * @subpackage	Loop
747
	 * @param string $size (default: 'shop_catalog')
748
	 * @param int $deprecated1 Deprecated since WooCommerce 2.0 (default: 0)
749
	 * @param int $deprecated2 Deprecated since WooCommerce 2.0 (default: 0)
750
	 * @return string
751
	 */
752
	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...
753
		global $post;
754
		$image_size = apply_filters( 'single_product_archive_thumbnail_size', $size );
755
756
		if ( has_post_thumbnail() ) {
757
			$props = wc_get_product_attachment_props( get_post_thumbnail_id(), $post );
758
			return get_the_post_thumbnail( $post->ID, $image_size, array(
759
				'title'	 => $props['title'],
760
				'alt'    => $props['alt'],
761
			) );
762
		} elseif ( wc_placeholder_img_src() ) {
763
			return wc_placeholder_img( $image_size );
764
		}
765
	}
766
}
767
768
if ( ! function_exists( 'woocommerce_result_count' ) ) {
769
770
	/**
771
	 * Output the result count text (Showing x - x of x results).
772
	 *
773
	 * @subpackage	Loop
774
	 */
775
	function woocommerce_result_count() {
776
		wc_get_template( 'loop/result-count.php' );
777
	}
778
}
779
780
if ( ! function_exists( 'woocommerce_catalog_ordering' ) ) {
781
782
	/**
783
	 * Output the product sorting options.
784
	 *
785
	 * @subpackage	Loop
786
	 */
787
	function woocommerce_catalog_ordering() {
788
		global $wp_query;
789
790
		if ( 1 === $wp_query->found_posts || ! woocommerce_products_will_display() ) {
791
			return;
792
		}
793
794
		$orderby                 = isset( $_GET['orderby'] ) ? wc_clean( $_GET['orderby'] ) : apply_filters( 'woocommerce_default_catalog_orderby', get_option( 'woocommerce_default_catalog_orderby' ) );
795
		$show_default_orderby    = 'menu_order' === apply_filters( 'woocommerce_default_catalog_orderby', get_option( 'woocommerce_default_catalog_orderby' ) );
796
		$catalog_orderby_options = apply_filters( 'woocommerce_catalog_orderby', array(
797
			'menu_order' => __( 'Default sorting', 'woocommerce' ),
798
			'popularity' => __( 'Sort by popularity', 'woocommerce' ),
799
			'rating'     => __( 'Sort by average rating', 'woocommerce' ),
800
			'date'       => __( 'Sort by newness', 'woocommerce' ),
801
			'price'      => __( 'Sort by price: low to high', 'woocommerce' ),
802
			'price-desc' => __( 'Sort by price: high to low', 'woocommerce' ),
803
		) );
804
805
		if ( ! $show_default_orderby ) {
806
			unset( $catalog_orderby_options['menu_order'] );
807
		}
808
809
		if ( 'no' === get_option( 'woocommerce_enable_review_rating' ) ) {
810
			unset( $catalog_orderby_options['rating'] );
811
		}
812
813
		wc_get_template( 'loop/orderby.php', array( 'catalog_orderby_options' => $catalog_orderby_options, 'orderby' => $orderby, 'show_default_orderby' => $show_default_orderby ) );
814
	}
815
}
816
817
if ( ! function_exists( 'woocommerce_pagination' ) ) {
818
819
	/**
820
	 * Output the pagination.
821
	 *
822
	 * @subpackage	Loop
823
	 */
824
	function woocommerce_pagination() {
825
		wc_get_template( 'loop/pagination.php' );
826
	}
827
}
828
829
/** Single Product ********************************************************/
830
831
if ( ! function_exists( 'woocommerce_show_product_images' ) ) {
832
833
	/**
834
	 * Output the product image before the single product summary.
835
	 *
836
	 * @subpackage	Product
837
	 */
838
	function woocommerce_show_product_images() {
839
		wc_get_template( 'single-product/product-image.php' );
840
	}
841
}
842
if ( ! function_exists( 'woocommerce_show_product_thumbnails' ) ) {
843
844
	/**
845
	 * Output the product thumbnails.
846
	 *
847
	 * @subpackage	Product
848
	 */
849
	function woocommerce_show_product_thumbnails() {
850
		wc_get_template( 'single-product/product-thumbnails.php' );
851
	}
852
}
853
if ( ! function_exists( 'woocommerce_output_product_data_tabs' ) ) {
854
855
	/**
856
	 * Output the product tabs.
857
	 *
858
	 * @subpackage	Product/Tabs
859
	 */
860
	function woocommerce_output_product_data_tabs() {
861
		wc_get_template( 'single-product/tabs/tabs.php' );
862
	}
863
}
864
if ( ! function_exists( 'woocommerce_template_single_title' ) ) {
865
866
	/**
867
	 * Output the product title.
868
	 *
869
	 * @subpackage	Product
870
	 */
871
	function woocommerce_template_single_title() {
872
		wc_get_template( 'single-product/title.php' );
873
	}
874
}
875
if ( ! function_exists( 'woocommerce_template_single_rating' ) ) {
876
877
	/**
878
	 * Output the product rating.
879
	 *
880
	 * @subpackage	Product
881
	 */
882
	function woocommerce_template_single_rating() {
883
		wc_get_template( 'single-product/rating.php' );
884
	}
885
}
886
if ( ! function_exists( 'woocommerce_template_single_price' ) ) {
887
888
	/**
889
	 * Output the product price.
890
	 *
891
	 * @subpackage	Product
892
	 */
893
	function woocommerce_template_single_price() {
894
		wc_get_template( 'single-product/price.php' );
895
	}
896
}
897
if ( ! function_exists( 'woocommerce_template_single_excerpt' ) ) {
898
899
	/**
900
	 * Output the product short description (excerpt).
901
	 *
902
	 * @subpackage	Product
903
	 */
904
	function woocommerce_template_single_excerpt() {
905
		wc_get_template( 'single-product/short-description.php' );
906
	}
907
}
908
if ( ! function_exists( 'woocommerce_template_single_meta' ) ) {
909
910
	/**
911
	 * Output the product meta.
912
	 *
913
	 * @subpackage	Product
914
	 */
915
	function woocommerce_template_single_meta() {
916
		wc_get_template( 'single-product/meta.php' );
917
	}
918
}
919
if ( ! function_exists( 'woocommerce_template_single_sharing' ) ) {
920
921
	/**
922
	 * Output the product sharing.
923
	 *
924
	 * @subpackage	Product
925
	 */
926
	function woocommerce_template_single_sharing() {
927
		wc_get_template( 'single-product/share.php' );
928
	}
929
}
930
if ( ! function_exists( 'woocommerce_show_product_sale_flash' ) ) {
931
932
	/**
933
	 * Output the product sale flash.
934
	 *
935
	 * @subpackage	Product
936
	 */
937
	function woocommerce_show_product_sale_flash() {
938
		wc_get_template( 'single-product/sale-flash.php' );
939
	}
940
}
941
942
if ( ! function_exists( 'woocommerce_template_single_add_to_cart' ) ) {
943
944
	/**
945
	 * Trigger the single product add to cart action.
946
	 *
947
	 * @subpackage	Product
948
	 */
949
	function woocommerce_template_single_add_to_cart() {
950
		global $product;
951
		do_action( 'woocommerce_' . $product->product_type . '_add_to_cart' );
952
	}
953
}
954
if ( ! function_exists( 'woocommerce_simple_add_to_cart' ) ) {
955
956
	/**
957
	 * Output the simple product add to cart area.
958
	 *
959
	 * @subpackage	Product
960
	 */
961
	function woocommerce_simple_add_to_cart() {
962
		wc_get_template( 'single-product/add-to-cart/simple.php' );
963
	}
964
}
965
if ( ! function_exists( 'woocommerce_grouped_add_to_cart' ) ) {
966
967
	/**
968
	 * Output the grouped product add to cart area.
969
	 *
970
	 * @subpackage	Product
971
	 */
972
	function woocommerce_grouped_add_to_cart() {
973
		global $product;
974
975
		wc_get_template( 'single-product/add-to-cart/grouped.php', array(
976
			'grouped_product'    => $product,
977
			'grouped_products'   => $product->get_children(),
978
			'quantites_required' => false,
979
		) );
980
	}
981
}
982
if ( ! function_exists( 'woocommerce_variable_add_to_cart' ) ) {
983
984
	/**
985
	 * Output the variable product add to cart area.
986
	 *
987
	 * @subpackage	Product
988
	 */
989
	function woocommerce_variable_add_to_cart() {
990
		global $product;
991
992
		// Enqueue variation scripts
993
		wp_enqueue_script( 'wc-add-to-cart-variation' );
994
995
		// Get Available variations?
996
		$get_variations = sizeof( $product->get_children() ) <= apply_filters( 'woocommerce_ajax_variation_threshold', 30, $product );
997
998
		// Load the template
999
		wc_get_template( 'single-product/add-to-cart/variable.php', array(
1000
			'available_variations' => $get_variations ? $product->get_available_variations() : false,
1001
			'attributes'           => $product->get_variation_attributes(),
1002
			'selected_attributes'  => $product->get_variation_default_attributes(),
1003
		) );
1004
	}
1005
}
1006
if ( ! function_exists( 'woocommerce_external_add_to_cart' ) ) {
1007
1008
	/**
1009
	 * Output the external product add to cart area.
1010
	 *
1011
	 * @subpackage	Product
1012
	 */
1013
	function woocommerce_external_add_to_cart() {
1014
		global $product;
1015
1016
		if ( ! $product->add_to_cart_url() ) {
1017
			return;
1018
		}
1019
1020
		wc_get_template( 'single-product/add-to-cart/external.php', array(
1021
			'product_url' => $product->add_to_cart_url(),
1022
			'button_text' => $product->single_add_to_cart_text(),
1023
		) );
1024
	}
1025
}
1026
1027
if ( ! function_exists( 'woocommerce_quantity_input' ) ) {
1028
1029
	/**
1030
	 * Output the quantity input for add to cart forms.
1031
	 *
1032
	 * @param  array $args Args for the input
1033
	 * @param  WC_Product|null $product
1034
	 * @param  boolean $echo Whether to return or echo|string
1035
	 */
1036
	function woocommerce_quantity_input( $args = array(), $product = null, $echo = true ) {
1037
		if ( is_null( $product ) ) {
1038
			$product = $GLOBALS['product'];
1039
		}
1040
1041
		$defaults = array(
1042
			'input_name'  => 'quantity',
1043
			'input_value' => '1',
1044
			'max_value'   => apply_filters( 'woocommerce_quantity_input_max', '', $product ),
1045
			'min_value'   => apply_filters( 'woocommerce_quantity_input_min', '', $product ),
1046
			'step'        => apply_filters( 'woocommerce_quantity_input_step', '1', $product ),
1047
			'pattern'     => apply_filters( 'woocommerce_quantity_input_pattern', has_filter( 'woocommerce_stock_amount', 'intval' ) ? '[0-9]*' : '' ),
1048
			'inputmode'   => apply_filters( 'woocommerce_quantity_input_inputmode', has_filter( 'woocommerce_stock_amount', 'intval' ) ? 'numeric' : '' ),
1049
		);
1050
1051
		$args = apply_filters( 'woocommerce_quantity_input_args', wp_parse_args( $args, $defaults ), $product );
1052
1053
		// Set min and max value to empty string if not set.
1054
		$args['min_value'] = isset( $args['min_value'] ) ? $args['min_value'] : '';
1055
		$args['max_value'] = isset( $args['max_value'] ) ? $args['max_value'] : '';
1056
1057
		// Apply sanity to min/max args - min cannot be lower than 0
1058
		if ( '' !== $args['min_value'] && is_numeric( $args['min_value'] ) && $args['min_value'] < 0 ) {
1059
			$args['min_value'] = 0; // Cannot be lower than 0
1060
		}
1061
1062
		// Max cannot be lower than 0 or min
1063
		if ( '' !== $args['max_value'] && is_numeric( $args['max_value'] ) ) {
1064
			$args['max_value'] = $args['max_value'] < 0 ? 0 : $args['max_value'];
1065
			$args['max_value'] = $args['max_value'] < $args['min_value'] ? $args['min_value'] : $args['max_value'];
1066
		}
1067
1068
		ob_start();
1069
1070
		wc_get_template( 'global/quantity-input.php', $args );
1071
1072
		if ( $echo ) {
1073
			echo ob_get_clean();
1074
		} else {
1075
			return ob_get_clean();
1076
		}
1077
	}
1078
}
1079
1080
if ( ! function_exists( 'woocommerce_product_description_tab' ) ) {
1081
1082
	/**
1083
	 * Output the description tab content.
1084
	 *
1085
	 * @subpackage	Product/Tabs
1086
	 */
1087
	function woocommerce_product_description_tab() {
1088
		wc_get_template( 'single-product/tabs/description.php' );
1089
	}
1090
}
1091
if ( ! function_exists( 'woocommerce_product_additional_information_tab' ) ) {
1092
1093
	/**
1094
	 * Output the attributes tab content.
1095
	 *
1096
	 * @subpackage	Product/Tabs
1097
	 */
1098
	function woocommerce_product_additional_information_tab() {
1099
		wc_get_template( 'single-product/tabs/additional-information.php' );
1100
	}
1101
}
1102
if ( ! function_exists( 'woocommerce_product_reviews_tab' ) ) {
1103
1104
	/**
1105
	 * Output the reviews tab content.
1106
	 * @deprecated  2.4.0 Unused
1107
	 * @subpackage	Product/Tabs
1108
	 */
1109
	function woocommerce_product_reviews_tab() {
1110
		_deprecated_function( 'woocommerce_product_reviews_tab', '2.4', '' );
1111
	}
1112
}
1113
1114
if ( ! function_exists( 'woocommerce_default_product_tabs' ) ) {
1115
1116
	/**
1117
	 * Add default product tabs to product pages.
1118
	 *
1119
	 * @param array $tabs
1120
	 * @return array
1121
	 */
1122
	function woocommerce_default_product_tabs( $tabs = array() ) {
1123
		global $product, $post;
1124
1125
		// Description tab - shows product content
1126
		if ( $post->post_content ) {
1127
			$tabs['description'] = array(
1128
				'title'    => __( 'Description', 'woocommerce' ),
1129
				'priority' => 10,
1130
				'callback' => 'woocommerce_product_description_tab',
1131
			);
1132
		}
1133
1134
		// Additional information tab - shows attributes
1135
		if ( $product && ( $product->has_attributes() || $product->enable_dimensions_display() ) ) {
1136
			$tabs['additional_information'] = array(
1137
				'title'    => __( 'Additional Information', 'woocommerce' ),
1138
				'priority' => 20,
1139
				'callback' => 'woocommerce_product_additional_information_tab',
1140
			);
1141
		}
1142
1143
		// Reviews tab - shows comments
1144
		if ( comments_open() ) {
1145
			$tabs['reviews'] = array(
1146
				'title'    => sprintf( __( 'Reviews (%d)', 'woocommerce' ), $product->get_review_count() ),
1147
				'priority' => 30,
1148
				'callback' => 'comments_template',
1149
			);
1150
		}
1151
1152
		return $tabs;
1153
	}
1154
}
1155
1156
if ( ! function_exists( 'woocommerce_sort_product_tabs' ) ) {
1157
1158
	/**
1159
	 * Sort tabs by priority.
1160
	 *
1161
	 * @param array $tabs
1162
	 * @return array
1163
	 */
1164
	function woocommerce_sort_product_tabs( $tabs = array() ) {
1165
1166
		// Make sure the $tabs parameter is an array
1167
		if ( ! is_array( $tabs ) ) {
1168
			trigger_error( "Function woocommerce_sort_product_tabs() expects an array as the first parameter. Defaulting to empty array." );
1169
			$tabs = array();
1170
		}
1171
1172
		// Re-order tabs by priority
1173
		if ( ! function_exists( '_sort_priority_callback' ) ) {
1174
			function _sort_priority_callback( $a, $b ) {
1175
				if ( $a['priority'] === $b['priority'] )
1176
					return 0;
1177
				return ( $a['priority'] < $b['priority'] ) ? -1 : 1;
1178
			}
1179
		}
1180
1181
		uasort( $tabs, '_sort_priority_callback' );
1182
1183
		return $tabs;
1184
	}
1185
}
1186
1187
if ( ! function_exists( 'woocommerce_comments' ) ) {
1188
1189
	/**
1190
	 * Output the Review comments template.
1191
	 *
1192
	 * @subpackage	Product
1193
	 * @param WP_Comment $comment
1194
	 * @param array $args
1195
	 * @param int $depth
1196
	 */
1197
	function woocommerce_comments( $comment, $args, $depth ) {
1198
		$GLOBALS['comment'] = $comment;
1199
		wc_get_template( 'single-product/review.php', array( 'comment' => $comment, 'args' => $args, 'depth' => $depth ) );
1200
	}
1201
}
1202
1203
if ( ! function_exists( 'woocommerce_review_display_gravatar' ) ) {
1204
	/**
1205
	 * Display the review authors gravatar
1206
	 *
1207
	 * @param array $comment WP_Comment.
1208
	 * @return void
1209
	 */
1210
	function woocommerce_review_display_gravatar( $comment ) {
1211
		echo get_avatar( $comment, apply_filters( 'woocommerce_review_gravatar_size', '60' ), '' );
1212
	}
1213
}
1214
1215
if ( ! function_exists( 'woocommerce_review_display_rating' ) ) {
1216
	/**
1217
	 * Display the reviewers star rating
1218
	 *
1219
	 * @return void
1220
	 */
1221
	function woocommerce_review_display_rating() {
1222
		wc_get_template( 'single-product/review-rating.php' );
1223
	}
1224
}
1225
1226
if ( ! function_exists( 'woocommerce_review_display_meta' ) ) {
1227
	/**
1228
	 * Display the review authors meta (name, verified owner, review date)
1229
	 *
1230
	 * @return void
1231
	 */
1232
	function woocommerce_review_display_meta() {
1233
		wc_get_template( 'single-product/review-meta.php' );
1234
	}
1235
}
1236
1237
if ( ! function_exists( 'woocommerce_review_display_comment_text' ) ) {
1238
1239
	/**
1240
	 * Display the review content.
1241
	 */
1242
	function woocommerce_review_display_comment_text() {
1243
		echo '<div class="description">';
1244
		comment_text();
1245
		echo '</div>';
1246
	}
1247
}
1248
1249
if ( ! function_exists( 'woocommerce_output_related_products' ) ) {
1250
1251
	/**
1252
	 * Output the related products.
1253
	 *
1254
	 * @subpackage	Product
1255
	 */
1256
	function woocommerce_output_related_products() {
1257
1258
		$args = array(
1259
			'posts_per_page' 	=> 4,
1260
			'columns' 			=> 4,
1261
			'orderby' 			=> 'rand',
1262
		);
1263
1264
		woocommerce_related_products( apply_filters( 'woocommerce_output_related_products_args', $args ) );
1265
	}
1266
}
1267
1268
if ( ! function_exists( 'woocommerce_related_products' ) ) {
1269
1270
	/**
1271
	 * Output the related products.
1272
	 *
1273
	 * @param array Provided arguments
1274
	 * @param bool Columns argument for backwards compat
1275
	 * @param bool Order by argument for backwards compat
1276
	 */
1277
	function woocommerce_related_products( $args = array(), $columns = false, $orderby = false ) {
1278
		if ( ! is_array( $args ) ) {
1279
			_deprecated_argument( __FUNCTION__, '2.1', __( 'Use $args argument as an array instead. Deprecated argument will be removed in WC 2.2.', 'woocommerce' ) );
1280
1281
			$argsvalue = $args;
1282
1283
			$args = array(
1284
				'posts_per_page' => $argsvalue,
1285
				'columns'        => $columns,
1286
				'orderby'        => $orderby,
1287
			);
1288
		}
1289
1290
		$defaults = array(
1291
			'posts_per_page' => 2,
1292
			'columns'        => 2,
1293
			'orderby'        => 'rand',
1294
		);
1295
1296
		$args = wp_parse_args( $args, $defaults );
1297
1298
		wc_get_template( 'single-product/related.php', $args );
1299
	}
1300
}
1301
1302
if ( ! function_exists( 'woocommerce_upsell_display' ) ) {
1303
1304
	/**
1305
	 * Output product up sells.
1306
	 *
1307
	 * @param int $posts_per_page (default: -1)
1308
	 * @param int $columns (default: 4)
1309
	 * @param string $orderby (default: 'rand')
1310
	 */
1311
	function woocommerce_upsell_display( $posts_per_page = '-1', $columns = 4, $orderby = 'rand' ) {
1312
		$args = apply_filters( 'woocommerce_upsell_display_args', array(
1313
			'posts_per_page'	=> $posts_per_page,
1314
			'orderby'			=> apply_filters( 'woocommerce_upsells_orderby', $orderby ),
1315
			'columns'			=> $columns,
1316
		) );
1317
1318
		wc_get_template( 'single-product/up-sells.php', $args );
1319
	}
1320
}
1321
1322
/** Cart ******************************************************************/
1323
1324
if ( ! function_exists( 'woocommerce_shipping_calculator' ) ) {
1325
1326
	/**
1327
	 * Output the cart shipping calculator.
1328
	 *
1329
	 * @subpackage	Cart
1330
	 */
1331
	function woocommerce_shipping_calculator() {
1332
		wc_get_template( 'cart/shipping-calculator.php' );
1333
	}
1334
}
1335
1336
if ( ! function_exists( 'woocommerce_cart_totals' ) ) {
1337
1338
	/**
1339
	 * Output the cart totals.
1340
	 *
1341
	 * @subpackage	Cart
1342
	 */
1343
	function woocommerce_cart_totals() {
1344
		if ( is_checkout() ) {
1345
			return;
1346
		}
1347
		wc_get_template( 'cart/cart-totals.php' );
1348
	}
1349
}
1350
1351
if ( ! function_exists( 'woocommerce_cross_sell_display' ) ) {
1352
1353
	/**
1354
	 * Output the cart cross-sells.
1355
	 *
1356
	 * @param  int $posts_per_page (default: 2)
1357
	 * @param  int $columns (default: 2)
1358
	 * @param  string $orderby (default: 'rand')
1359
	 */
1360
	function woocommerce_cross_sell_display( $posts_per_page = 2, $columns = 2, $orderby = 'rand' ) {
1361
		if ( is_checkout() ) {
1362
			return;
1363
		}
1364
		wc_get_template( 'cart/cross-sells.php', array(
1365
			'posts_per_page' => $posts_per_page,
1366
			'orderby'        => $orderby,
1367
			'columns'        => $columns,
1368
		) );
1369
	}
1370
}
1371
1372
if ( ! function_exists( 'woocommerce_button_proceed_to_checkout' ) ) {
1373
1374
	/**
1375
	 * Output the proceed to checkout button.
1376
	 *
1377
	 * @subpackage	Cart
1378
	 */
1379
	function woocommerce_button_proceed_to_checkout() {
1380
		wc_get_template( 'cart/proceed-to-checkout-button.php' );
1381
	}
1382
}
1383
1384 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...
1385
1386
	/**
1387
	 * Output the proceed to checkout button.
1388
	 *
1389
	 * @subpackage	Cart
1390
	 */
1391
	function woocommerce_widget_shopping_cart_button_view_cart() {
1392
		echo '<a href="' . esc_url( wc_get_cart_url() ) . '" class="button wc-forward">' . __( 'View Cart', 'woocommerce' ) . '</a>';
1393
	}
1394
}
1395
1396 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...
1397
1398
	/**
1399
	 * Output the proceed to checkout button.
1400
	 *
1401
	 * @subpackage	Cart
1402
	 */
1403
	function woocommerce_widget_shopping_cart_proceed_to_checkout() {
1404
		echo '<a href="' . esc_url( wc_get_checkout_url() ) . '" class="button checkout wc-forward">' . __( 'Checkout', 'woocommerce' ) . '</a>';
1405
	}
1406
}
1407
1408
/** Mini-Cart *************************************************************/
1409
1410
if ( ! function_exists( 'woocommerce_mini_cart' ) ) {
1411
1412
	/**
1413
	 * Output the Mini-cart - used by cart widget.
1414
	 *
1415
	 * @param array $args
1416
	 */
1417
	function woocommerce_mini_cart( $args = array() ) {
1418
1419
		$defaults = array(
1420
			'list_class' => '',
1421
		);
1422
1423
		$args = wp_parse_args( $args, $defaults );
1424
1425
		wc_get_template( 'cart/mini-cart.php', $args );
1426
	}
1427
}
1428
1429
/** Login *****************************************************************/
1430
1431
if ( ! function_exists( 'woocommerce_login_form' ) ) {
1432
1433
	/**
1434
	 * Output the WooCommerce Login Form.
1435
	 *
1436
	 * @subpackage	Forms
1437
	 * @param array $args
1438
	 */
1439
	function woocommerce_login_form( $args = array() ) {
1440
1441
		$defaults = array(
1442
			'message'  => '',
1443
			'redirect' => '',
1444
			'hidden'   => false,
1445
		);
1446
1447
		$args = wp_parse_args( $args, $defaults  );
1448
1449
		wc_get_template( 'global/form-login.php', $args );
1450
	}
1451
}
1452
1453
if ( ! function_exists( 'woocommerce_checkout_login_form' ) ) {
1454
1455
	/**
1456
	 * Output the WooCommerce Checkout Login Form.
1457
	 *
1458
	 * @subpackage	Checkout
1459
	 */
1460
	function woocommerce_checkout_login_form() {
1461
		wc_get_template( 'checkout/form-login.php', array( 'checkout' => WC()->checkout() ) );
1462
	}
1463
}
1464
1465
if ( ! function_exists( 'woocommerce_breadcrumb' ) ) {
1466
1467
	/**
1468
	 * Output the WooCommerce Breadcrumb.
1469
	 *
1470
	 * @param array $args
1471
	 */
1472
	function woocommerce_breadcrumb( $args = array() ) {
1473
		$args = wp_parse_args( $args, apply_filters( 'woocommerce_breadcrumb_defaults', array(
1474
			'delimiter'   => '&nbsp;&#47;&nbsp;',
1475
			'wrap_before' => '<nav class="woocommerce-breadcrumb">',
1476
			'wrap_after'  => '</nav>',
1477
			'before'      => '',
1478
			'after'       => '',
1479
			'home'        => _x( 'Home', 'breadcrumb', 'woocommerce' ),
1480
		) ) );
1481
1482
		$breadcrumbs = new WC_Breadcrumb();
1483
1484
		if ( ! empty( $args['home'] ) ) {
1485
			$breadcrumbs->add_crumb( $args['home'], apply_filters( 'woocommerce_breadcrumb_home_url', home_url() ) );
1486
		}
1487
1488
		$args['breadcrumb'] = $breadcrumbs->generate();
1489
1490
		/**
1491
		 * @hooked WC_Structured_Data::generate_breadcrumblist_data() - 10
1492
		 */
1493
		do_action( 'woocommerce_breadcrumb', $breadcrumbs, $args );
1494
1495
		wc_get_template( 'global/breadcrumb.php', $args );
1496
	}
1497
}
1498
1499
if ( ! function_exists( 'woocommerce_order_review' ) ) {
1500
1501
	/**
1502
	 * Output the Order review table for the checkout.
1503
	 *
1504
	 * @subpackage	Checkout
1505
	 */
1506
	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...
1507
		wc_get_template( 'checkout/review-order.php', array( 'checkout' => WC()->checkout() ) );
1508
	}
1509
}
1510
1511
if ( ! function_exists( 'woocommerce_checkout_payment' ) ) {
1512
1513
	/**
1514
	 * Output the Payment Methods on the checkout.
1515
	 *
1516
	 * @subpackage	Checkout
1517
	 */
1518
	function woocommerce_checkout_payment() {
1519
		if ( WC()->cart->needs_payment() ) {
1520
			$available_gateways = WC()->payment_gateways()->get_available_payment_gateways();
1521
			WC()->payment_gateways()->set_current_gateway( $available_gateways );
1522
		} else {
1523
			$available_gateways = array();
1524
		}
1525
1526
		wc_get_template( 'checkout/payment.php', array(
1527
			'checkout'           => WC()->checkout(),
1528
			'available_gateways' => $available_gateways,
1529
			'order_button_text'  => apply_filters( 'woocommerce_order_button_text', __( 'Place order', 'woocommerce' ) ),
1530
		) );
1531
	}
1532
}
1533
1534
if ( ! function_exists( 'woocommerce_checkout_coupon_form' ) ) {
1535
1536
	/**
1537
	 * Output the Coupon form for the checkout.
1538
	 *
1539
	 * @subpackage	Checkout
1540
	 */
1541
	function woocommerce_checkout_coupon_form() {
1542
		wc_get_template( 'checkout/form-coupon.php', array( 'checkout' => WC()->checkout() ) );
1543
	}
1544
}
1545
1546
if ( ! function_exists( 'woocommerce_products_will_display' ) ) {
1547
1548
	/**
1549
	 * Check if we will be showing products or not (and not sub-categories only).
1550
	 * @subpackage	Loop
1551
	 * @return bool
1552
	 */
1553
	function woocommerce_products_will_display() {
1554
		global $wpdb;
1555
1556
		if ( is_shop() ) {
1557
			return 'subcategories' !== get_option( 'woocommerce_shop_page_display' ) || is_search();
1558
		}
1559
1560
		if ( ! is_product_taxonomy() ) {
1561
			return false;
1562
		}
1563
1564
		if ( is_search() || is_filtered() || is_paged() ) {
1565
			return true;
1566
		}
1567
1568
		$term = get_queried_object();
1569
1570
		if ( is_product_category() ) {
1571
			switch ( get_woocommerce_term_meta( $term->term_id, 'display_type', true ) ) {
1572
				case 'subcategories' :
1573
					// Nothing - we want to continue to see if there are products/subcats
1574
				break;
1575
				case 'products' :
1576
				case 'both' :
1577
					return true;
1578
				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...
1579
				default :
1580
					// Default - no setting
1581
					if ( get_option( 'woocommerce_category_archive_display' ) != 'subcategories' ) {
1582
						return true;
1583
					}
1584
				break;
1585
			}
1586
		}
1587
1588
		// Begin subcategory logic
1589
		if ( empty( $term->term_id ) || empty( $term->taxonomy ) ) {
1590
			return true;
1591
		}
1592
1593
		$transient_name = 'wc_products_will_display_' . $term->term_id . '_' . WC_Cache_Helper::get_transient_version( 'product_query' );
1594
1595
		if ( false === ( $products_will_display = get_transient( $transient_name ) ) ) {
1596
			$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 ) );
1597
1598
			if ( $has_children ) {
1599
				// Check terms have products inside - parents first. If products are found inside, subcats will be shown instead of products so we can return false.
1600
				if ( sizeof( get_objects_in_term( $has_children, $term->taxonomy ) ) > 0 ) {
1601
					$products_will_display = false;
1602
				} else {
1603
					// If we get here, the parents were empty so we're forced to check children
1604
					foreach ( $has_children as $term_id ) {
1605
						$children = get_term_children( $term_id, $term->taxonomy );
1606
1607
						if ( sizeof( get_objects_in_term( $children, $term->taxonomy ) ) > 0 ) {
1608
							$products_will_display = false;
1609
							break;
1610
						}
1611
					}
1612
				}
1613
			} else {
1614
				$products_will_display = true;
1615
			}
1616
		}
1617
1618
		set_transient( $transient_name, $products_will_display, DAY_IN_SECONDS * 30 );
1619
1620
		return $products_will_display;
1621
	}
1622
}
1623
1624
if ( ! function_exists( 'woocommerce_product_subcategories' ) ) {
1625
1626
	/**
1627
	 * Display product sub categories as thumbnails.
1628
	 *
1629
	 * @subpackage	Loop
1630
	 * @param array $args
1631
	 * @return null|boolean
1632
	 */
1633
	function woocommerce_product_subcategories( $args = array() ) {
1634
		global $wp_query;
1635
1636
		$defaults = array(
1637
			'before'        => '',
1638
			'after'         => '',
1639
			'force_display' => false,
1640
		);
1641
1642
		$args = wp_parse_args( $args, $defaults );
1643
1644
		extract( $args );
1645
1646
		// Main query only
1647
		if ( ! is_main_query() && ! $force_display ) {
1648
			return;
1649
		}
1650
1651
		// Don't show when filtering, searching or when on page > 1 and ensure we're on a product archive
1652
		if ( is_search() || is_filtered() || is_paged() || ( ! is_product_category() && ! is_shop() ) ) {
1653
			return;
1654
		}
1655
1656
		// Check categories are enabled
1657
		if ( is_shop() && '' === get_option( 'woocommerce_shop_page_display' ) ) {
1658
			return;
1659
		}
1660
1661
		// Find the category + category parent, if applicable
1662
		$term 			= get_queried_object();
1663
		$parent_id 		= empty( $term->term_id ) ? 0 : $term->term_id;
1664
1665
		if ( is_product_category() ) {
1666
			$display_type = get_woocommerce_term_meta( $term->term_id, 'display_type', true );
1667
1668
			switch ( $display_type ) {
1669
				case 'products' :
1670
					return;
1671
				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...
1672
				case '' :
1673
					if ( '' === get_option( 'woocommerce_category_archive_display' ) ) {
1674
						return;
1675
					}
1676
				break;
1677
			}
1678
		}
1679
1680
		// 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
1681
		$product_categories = get_categories( apply_filters( 'woocommerce_product_subcategories_args', array(
1682
			'parent'       => $parent_id,
1683
			'menu_order'   => 'ASC',
1684
			'hide_empty'   => 0,
1685
			'hierarchical' => 1,
1686
			'taxonomy'     => 'product_cat',
1687
			'pad_counts'   => 1,
1688
		) ) );
1689
1690
		if ( ! apply_filters( 'woocommerce_product_subcategories_hide_empty', false ) ) {
1691
			$product_categories = wp_list_filter( $product_categories, array( 'count' => 0 ), 'NOT' );
1692
		}
1693
1694
		if ( $product_categories ) {
1695
			echo $before;
1696
1697
			foreach ( $product_categories as $category ) {
1698
				wc_get_template( 'content-product_cat.php', array(
1699
					'category' => $category,
1700
				) );
1701
			}
1702
1703
			// If we are hiding products disable the loop and pagination
1704
			if ( is_product_category() ) {
1705
				$display_type = get_woocommerce_term_meta( $term->term_id, 'display_type', true );
1706
1707
				switch ( $display_type ) {
1708
					case 'subcategories' :
1709
						$wp_query->post_count    = 0;
1710
						$wp_query->max_num_pages = 0;
1711
					break;
1712
					case '' :
1713
						if ( 'subcategories' === get_option( 'woocommerce_category_archive_display' ) ) {
1714
							$wp_query->post_count    = 0;
1715
							$wp_query->max_num_pages = 0;
1716
						}
1717
					break;
1718
				}
1719
			}
1720
1721
			if ( is_shop() && 'subcategories' === get_option( 'woocommerce_shop_page_display' ) ) {
1722
				$wp_query->post_count    = 0;
1723
				$wp_query->max_num_pages = 0;
1724
			}
1725
1726
			echo $after;
1727
1728
			return true;
1729
		}
1730
	}
1731
}
1732
1733
if ( ! function_exists( 'woocommerce_subcategory_thumbnail' ) ) {
1734
1735
	/**
1736
	 * Show subcategory thumbnails.
1737
	 *
1738
	 * @param mixed $category
1739
	 * @subpackage	Loop
1740
	 */
1741
	function woocommerce_subcategory_thumbnail( $category ) {
1742
		$small_thumbnail_size  	= apply_filters( 'subcategory_archive_thumbnail_size', 'shop_catalog' );
1743
		$dimensions    			= wc_get_image_size( $small_thumbnail_size );
1744
		$thumbnail_id  			= get_woocommerce_term_meta( $category->term_id, 'thumbnail_id', true  );
1745
1746
		if ( $thumbnail_id ) {
1747
			$image        = wp_get_attachment_image_src( $thumbnail_id, $small_thumbnail_size  );
1748
			$image        = $image[0];
1749
			$image_srcset = function_exists( 'wp_get_attachment_image_srcset' ) ? wp_get_attachment_image_srcset( $thumbnail_id, $small_thumbnail_size ) : false;
1750
			$image_sizes  = function_exists( 'wp_get_attachment_image_sizes' ) ? wp_get_attachment_image_sizes( $thumbnail_id, $small_thumbnail_size ) : false;
1751
		} else {
1752
			$image        = wc_placeholder_img_src();
1753
			$image_srcset = $image_sizes = false;
1754
		}
1755
1756
		if ( $image ) {
1757
			// Prevent esc_url from breaking spaces in urls for image embeds
1758
			// Ref: https://core.trac.wordpress.org/ticket/23605
1759
			$image = str_replace( ' ', '%20', $image );
1760
1761
			// Add responsive image markup if available
1762
			if ( $image_srcset && $image_sizes ) {
1763
				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 ) . '" />';
1764
			} else {
1765
				echo '<img src="' . esc_url( $image ) . '" alt="' . esc_attr( $category->name ) . '" width="' . esc_attr( $dimensions['width'] ) . '" height="' . esc_attr( $dimensions['height'] ) . '" />';
1766
			}
1767
		}
1768
	}
1769
}
1770
1771
if ( ! function_exists( 'woocommerce_order_details_table' ) ) {
1772
1773
	/**
1774
	 * Displays order details in a table.
1775
	 *
1776
	 * @param mixed $order_id
1777
	 * @subpackage	Orders
1778
	 */
1779
	function woocommerce_order_details_table( $order_id ) {
1780
		if ( ! $order_id ) return;
1781
1782
		wc_get_template( 'order/order-details.php', array(
1783
			'order_id' => $order_id,
1784
		) );
1785
	}
1786
}
1787
1788
1789
if ( ! function_exists( 'woocommerce_order_again_button' ) ) {
1790
1791
	/**
1792
	 * Display an 'order again' button on the view order page.
1793
	 *
1794
	 * @param object $order
1795
	 * @subpackage	Orders
1796
	 */
1797
	function woocommerce_order_again_button( $order ) {
1798
		if ( ! $order || ! $order->has_status( 'completed' ) || ! is_user_logged_in() ) {
1799
			return;
1800
		}
1801
1802
		wc_get_template( 'order/order-again.php', array(
1803
			'order' => $order,
1804
		) );
1805
	}
1806
}
1807
1808
/** Forms ****************************************************************/
1809
1810
if ( ! function_exists( 'woocommerce_form_field' ) ) {
1811
1812
	/**
1813
	 * Outputs a checkout/address form field.
1814
	 *
1815
	 * @subpackage	Forms
1816
	 * @param string $key
1817
	 * @param mixed $args
1818
	 * @param string $value (default: null)
1819
	 * @todo This function needs to be broken up in smaller pieces
1820
	 */
1821
	function woocommerce_form_field( $key, $args, $value = null ) {
1822
		$defaults = array(
1823
			'type'              => 'text',
1824
			'label'             => '',
1825
			'description'       => '',
1826
			'placeholder'       => '',
1827
			'maxlength'         => false,
1828
			'required'          => false,
1829
			'autocomplete'      => false,
1830
			'id'                => $key,
1831
			'class'             => array(),
1832
			'label_class'       => array(),
1833
			'input_class'       => array(),
1834
			'return'            => false,
1835
			'options'           => array(),
1836
			'custom_attributes' => array(),
1837
			'validate'          => array(),
1838
			'default'           => '',
1839
		);
1840
1841
		$args = wp_parse_args( $args, $defaults );
1842
		$args = apply_filters( 'woocommerce_form_field_args', $args, $key, $value );
1843
1844
		if ( $args['required'] ) {
1845
			$args['class'][] = 'validate-required';
1846
			$required = ' <abbr class="required" title="' . esc_attr__( 'required', 'woocommerce'  ) . '">*</abbr>';
1847
		} else {
1848
			$required = '';
1849
		}
1850
1851
		$args['maxlength'] = ( $args['maxlength'] ) ? 'maxlength="' . absint( $args['maxlength'] ) . '"' : '';
1852
1853
		$args['autocomplete'] = ( $args['autocomplete'] ) ? 'autocomplete="' . esc_attr( $args['autocomplete'] ) . '"' : '';
1854
1855
		if ( is_string( $args['label_class'] ) ) {
1856
			$args['label_class'] = array( $args['label_class'] );
1857
		}
1858
1859
		if ( is_null( $value ) ) {
1860
			$value = $args['default'];
1861
		}
1862
1863
		// Custom attribute handling
1864
		$custom_attributes = array();
1865
1866 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...
1867
			foreach ( $args['custom_attributes'] as $attribute => $attribute_value ) {
1868
				$custom_attributes[] = esc_attr( $attribute ) . '="' . esc_attr( $attribute_value ) . '"';
1869
			}
1870
		}
1871
1872
		if ( ! empty( $args['validate'] ) ) {
1873
			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...
1874
				$args['class'][] = 'validate-' . $validate;
1875
			}
1876
		}
1877
1878
		$field = '';
1879
		$label_id = $args['id'];
1880
		$field_container = '<p class="form-row %1$s" id="%2$s">%3$s</p>';
1881
1882
		switch ( $args['type'] ) {
1883
			case 'country' :
1884
1885
				$countries = 'shipping_country' === $key ? WC()->countries->get_shipping_countries() : WC()->countries->get_allowed_countries();
1886
1887
				if ( 1 === sizeof( $countries ) ) {
1888
1889
					$field .= '<strong>' . current( array_values( $countries ) ) . '</strong>';
1890
1891
					$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" />';
1892
1893
				} else {
1894
1895
					$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 ) . '>'
1896
							. '<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, 'woocommerce' ) .'</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, 'woocommerce' ) .'</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