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

wc-template-functions.php ➔ woocommerce_get_product_thumbnail()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 14
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 10
nc 3
nop 3
dl 0
loc 14
rs 9.4285
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
 * When the_post is called, put product data into a global.
100
 *
101
 * @param mixed $post
102
 * @return WC_Product
103
 */
104
function wc_setup_product_data( $post ) {
105
	unset( $GLOBALS['product'] );
106
107
	if ( is_int( $post ) )
108
		$post = get_post( $post );
109
110
	if ( empty( $post->post_type ) || ! in_array( $post->post_type, array( 'product', 'product_variation' ) ) )
111
		return;
112
113
	$GLOBALS['product'] = wc_get_product( $post );
114
115
	return $GLOBALS['product'];
116
}
117
add_action( 'the_post', 'wc_setup_product_data' );
118
119
if ( ! function_exists( 'woocommerce_reset_loop' ) ) {
120
121
	/**
122
	 * Reset the loop's index and columns when we're done outputting a product loop.
123
	 * @subpackage	Loop
124
	 */
125
	function woocommerce_reset_loop() {
126
		$GLOBALS['woocommerce_loop'] = array(
127
			'loop'    => '',
128
			'columns' => '',
129
			'name'    => '',
130
		);
131
	}
132
}
133
add_filter( 'loop_end', 'woocommerce_reset_loop' );
134
135
/**
136
 * Products RSS Feed.
137
 * @deprecated 2.6
138
 * @access public
139
 */
140
function wc_products_rss_feed() {
141
	// Product RSS
142
	if ( is_post_type_archive( 'product' ) || is_singular( 'product' ) ) {
143
144
		$feed = get_post_type_archive_feed_link( 'product' );
145
146
		echo '<link rel="alternate" type="application/rss+xml"  title="' . esc_attr__( 'New products', 'woocommerce' ) . '" href="' . esc_url( $feed ) . '" />';
147
148
	} elseif ( is_tax( 'product_cat' ) ) {
149
150
		$term = get_term_by( 'slug', esc_attr( get_query_var('product_cat') ), 'product_cat' );
151
152 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...
153
			$feed = add_query_arg( 'product_cat', $term->slug, get_post_type_archive_feed_link( 'product' ) );
154
			echo '<link rel="alternate" type="application/rss+xml"  title="' . esc_attr( sprintf( __( 'New products added to %s', 'woocommerce' ), $term->name ) ) . '" href="' . esc_url( $feed ) . '" />';
155
		}
156
157
	} elseif ( is_tax( 'product_tag' ) ) {
158
159
		$term = get_term_by('slug', esc_attr( get_query_var('product_tag') ), 'product_tag');
160
161 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...
162
			$feed = add_query_arg('product_tag', $term->slug, get_post_type_archive_feed_link( 'product' ));
163
			echo '<link rel="alternate" type="application/rss+xml"  title="' . sprintf(__( 'New products tagged %s', 'woocommerce' ), urlencode($term->name)) . '" href="' . esc_url( $feed ) . '" />';
164
		}
165
	}
166
}
167
168
/**
169
 * Output generator tag to aid debugging.
170
 *
171
 * @access public
172
 */
173
function wc_generator_tag( $gen, $type ) {
174
	switch ( $type ) {
175
		case 'html':
176
			$gen .= "\n" . '<meta name="generator" content="WooCommerce ' . esc_attr( WC_VERSION ) . '">';
177
			break;
178
		case 'xhtml':
179
			$gen .= "\n" . '<meta name="generator" content="WooCommerce ' . esc_attr( WC_VERSION ) . '" />';
180
			break;
181
	}
182
	return $gen;
183
}
184
185
/**
186
 * Add body classes for WC pages.
187
 *
188
 * @param  array $classes
189
 * @return array
190
 */
191
function wc_body_class( $classes ) {
192
	$classes = (array) $classes;
193
194
	if ( is_woocommerce() ) {
195
		$classes[] = 'woocommerce';
196
		$classes[] = 'woocommerce-page';
197
	}
198
199
	elseif ( is_checkout() ) {
200
		$classes[] = 'woocommerce-checkout';
201
		$classes[] = 'woocommerce-page';
202
	}
203
204
	elseif ( is_cart() ) {
205
		$classes[] = 'woocommerce-cart';
206
		$classes[] = 'woocommerce-page';
207
	}
208
209
	elseif ( is_account_page() ) {
210
		$classes[] = 'woocommerce-account';
211
		$classes[] = 'woocommerce-page';
212
	}
213
214
	if ( is_store_notice_showing() ) {
215
		$classes[] = 'woocommerce-demo-store';
216
	}
217
218
	foreach ( WC()->query->query_vars as $key => $value ) {
219
		if ( is_wc_endpoint_url( $key ) ) {
220
			$classes[] = 'woocommerce-' . sanitize_html_class( $key );
221
		}
222
	}
223
224
	return array_unique( $classes );
225
}
226
227
/**
228
 * Display the classes for the product cat div.
229
 *
230
 * @since 2.4.0
231
 * @param string|array $class One or more classes to add to the class list.
232
 * @param object $category object Optional.
233
 */
234
function wc_product_cat_class( $class = '', $category = null ) {
235
	// Separates classes with a single space, collates classes for post DIV
236
	echo 'class="' . esc_attr( join( ' ', wc_get_product_cat_class( $class, $category ) ) ) . '"';
237
}
238
239
/**
240
 * Get classname for loops based on $woocommerce_loop global.
241
 * @since 2.6.0
242
 * @return string
243
 */
244
function wc_get_loop_class() {
245
	global $woocommerce_loop;
246
247
	$woocommerce_loop['loop']    = ! empty( $woocommerce_loop['loop'] ) ? $woocommerce_loop['loop'] + 1   : 1;
248
	$woocommerce_loop['columns'] = ! empty( $woocommerce_loop['columns'] ) ? $woocommerce_loop['columns'] : apply_filters( 'loop_shop_columns', 4 );
249
250
	if ( 0 === ( $woocommerce_loop['loop'] - 1 ) % $woocommerce_loop['columns'] || 1 === $woocommerce_loop['columns'] ) {
251
		return 'first';
252
	} elseif ( 0 === $woocommerce_loop['loop'] % $woocommerce_loop['columns'] ) {
253
		return 'last';
254
	} else {
255
		return '';
256
	}
257
}
258
259
/**
260
 * Get the classes for the product cat div.
261
 *
262
 * @since 2.4.0
263
 * @param string|array $class One or more classes to add to the class list.
264
 * @param object $category object Optional.
265
 */
266
function wc_get_product_cat_class( $class = '', $category = null ) {
267
	$classes   = is_array( $class ) ? $class : array_map( 'trim', explode( ' ', $class ) );
268
	$classes[] = 'product-category';
269
	$classes[] = 'product';
270
	$classes[] = wc_get_loop_class();
271
	$classes   = apply_filters( 'product_cat_class', $classes, $class, $category );
272
273
	return array_unique( array_filter( $classes ) );
274
}
275
276
/**
277
 * Adds extra post classes for products.
278
 *
279
 * @since 2.1.0
280
 * @param array $classes
281
 * @param string|array $class
282
 * @param int $post_id
283
 * @return array
284
 */
285
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...
286
	if ( ! $post_id || 'product' !== get_post_type( $post_id ) ) {
287
		return $classes;
288
	}
289
290
	$product = wc_get_product( $post_id );
291
292
	if ( $product ) {
293
		$classes[] = wc_get_loop_class();
294
		$classes[] = $product->stock_status;
295
296
		if ( $product->is_on_sale() ) {
297
			$classes[] = 'sale';
298
		}
299
		if ( $product->is_featured() ) {
300
			$classes[] = 'featured';
301
		}
302
		if ( $product->is_downloadable() ) {
303
			$classes[] = 'downloadable';
304
		}
305
		if ( $product->is_virtual() ) {
306
			$classes[] = 'virtual';
307
		}
308
		if ( $product->is_sold_individually() ) {
309
			$classes[] = 'sold-individually';
310
		}
311
		if ( $product->is_taxable() ) {
312
			$classes[] = 'taxable';
313
		}
314
		if ( $product->is_shipping_taxable() ) {
315
			$classes[] = 'shipping-taxable';
316
		}
317
		if ( $product->is_purchasable() ) {
318
			$classes[] = 'purchasable';
319
		}
320
		if ( $product->get_type() ) {
321
			$classes[] = "product-type-" . $product->get_type();
322
		}
323
		if ( $product->is_type( 'variable' ) ) {
324
			if ( $product->has_default_attributes() ) {
325
				$classes[] = 'has-default-attributes';
326
			}
327
			if ( $product->has_child() ) {
328
				$classes[] = 'has-children';
329
			}
330
		}
331
	}
332
333
	if ( false !== ( $key = array_search( 'hentry', $classes ) ) ) {
334
		unset( $classes[ $key ] );
335
	}
336
337
	return $classes;
338
}
339
340
/**
341
 * Outputs hidden form inputs for each query string variable.
342
 * @since 2.7.0
343
 * @param array $values Name value pairs.
344
 * @param array $exclude Keys to exclude.
345
 * @param string $current_key Current key we are outputting.
346
 */
347
function wc_query_string_form_fields( $values = null, $exclude = array(), $current_key = '', $return = false ) {
348
	if ( is_null( $values ) ) {
349
		$values = $_GET;
350
	}
351
	$html = '';
352
353
	foreach ( $values as $key => $value ) {
354
		if ( in_array( $key, $exclude, true ) ) {
355
			continue;
356
		}
357
		if ( $current_key ) {
358
			$key = $current_key . '[' . $key . ']';
359
		}
360
		if ( is_array( $value ) ) {
361
			$html .= wc_query_string_form_fields( $value, $exclude, $key, true );
362
		} else {
363
			$html .= '<input type="hidden" name="' . esc_attr( $key ) . '" value="' . esc_attr( $value ) . '" />';
364
		}
365
	}
366
367
	if ( $return ) {
368
		return $html;
369
	} else {
370
		echo $html;
371
	}
372
}
373
374
/** Template pages ********************************************************/
375
376
if ( ! function_exists( 'woocommerce_content' ) ) {
377
378
	/**
379
	 * Output WooCommerce content.
380
	 *
381
	 * This function is only used in the optional 'woocommerce.php' template.
382
	 * which people can add to their themes to add basic woocommerce support.
383
	 * without hooks or modifying core templates.
384
	 *
385
	 */
386
	function woocommerce_content() {
387
388
		if ( is_singular( 'product' ) ) {
389
390
			while ( have_posts() ) : the_post();
391
392
				wc_get_template_part( 'content', 'single-product' );
393
394
			endwhile;
395
396
		} else { ?>
397
398
			<?php if ( apply_filters( 'woocommerce_show_page_title', true ) ) : ?>
399
400
				<h1 class="page-title"><?php woocommerce_page_title(); ?></h1>
401
402
			<?php endif; ?>
403
404
			<?php do_action( 'woocommerce_archive_description' ); ?>
405
406 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...
407
408
				<?php do_action('woocommerce_before_shop_loop'); ?>
409
410
				<?php woocommerce_product_loop_start(); ?>
411
412
					<?php woocommerce_product_subcategories(); ?>
413
414
					<?php while ( have_posts() ) : the_post(); ?>
415
416
						<?php wc_get_template_part( 'content', 'product' ); ?>
417
418
					<?php endwhile; // end of the loop. ?>
419
420
				<?php woocommerce_product_loop_end(); ?>
421
422
				<?php do_action('woocommerce_after_shop_loop'); ?>
423
424
			<?php elseif ( ! woocommerce_product_subcategories( array( 'before' => woocommerce_product_loop_start( false ), 'after' => woocommerce_product_loop_end( false ) ) ) ) : ?>
425
426
				<?php do_action( 'woocommerce_no_products_found' ); ?>
427
428
			<?php endif;
429
430
		}
431
	}
432
}
433
434
/** Global ****************************************************************/
435
436
if ( ! function_exists( 'woocommerce_output_content_wrapper' ) ) {
437
438
	/**
439
	 * Output the start of the page wrapper.
440
	 *
441
	 */
442
	function woocommerce_output_content_wrapper() {
443
		wc_get_template( 'global/wrapper-start.php' );
444
	}
445
}
446
if ( ! function_exists( 'woocommerce_output_content_wrapper_end' ) ) {
447
448
	/**
449
	 * Output the end of the page wrapper.
450
	 *
451
	 */
452
	function woocommerce_output_content_wrapper_end() {
453
		wc_get_template( 'global/wrapper-end.php' );
454
	}
455
}
456
457
if ( ! function_exists( 'woocommerce_get_sidebar' ) ) {
458
459
	/**
460
	 * Get the shop sidebar template.
461
	 *
462
	 */
463
	function woocommerce_get_sidebar() {
464
		wc_get_template( 'global/sidebar.php' );
465
	}
466
}
467
468
if ( ! function_exists( 'woocommerce_demo_store' ) ) {
469
470
	/**
471
	 * Adds a demo store banner to the site if enabled.
472
	 *
473
	 */
474
	function woocommerce_demo_store() {
475
		if ( ! is_store_notice_showing() ) {
476
			return;
477
		}
478
479
		$notice = get_option( 'woocommerce_demo_store_notice' );
480
481
		if ( empty( $notice ) ) {
482
			$notice = __( 'This is a demo store for testing purposes &mdash; no orders shall be fulfilled.', 'woocommerce' );
483
		}
484
485
		echo apply_filters( 'woocommerce_demo_store', '<p class="demo_store">' . wp_kses_post( $notice ) . '</p>', $notice );
486
	}
487
}
488
489
/** Loop ******************************************************************/
490
491
if ( ! function_exists( 'woocommerce_page_title' ) ) {
492
493
	/**
494
	 * woocommerce_page_title function.
495
	 *
496
	 * @param  bool $echo
497
	 * @return string
498
	 */
499
	function woocommerce_page_title( $echo = true ) {
500
501
		if ( is_search() ) {
502
			$page_title = sprintf( __( 'Search Results: &ldquo;%s&rdquo;', 'woocommerce' ), get_search_query() );
503
504
			if ( get_query_var( 'paged' ) )
505
				$page_title .= sprintf( __( '&nbsp;&ndash; Page %s', 'woocommerce' ), get_query_var( 'paged' ) );
506
507
		} elseif ( is_tax() ) {
508
509
			$page_title = single_term_title( "", false );
510
511
		} else {
512
513
			$shop_page_id = wc_get_page_id( 'shop' );
514
			$page_title   = get_the_title( $shop_page_id );
515
516
		}
517
518
		$page_title = apply_filters( 'woocommerce_page_title', $page_title );
519
520
		if ( $echo )
521
			echo $page_title;
522
		else
523
			return $page_title;
524
	}
525
}
526
527
if ( ! function_exists( 'woocommerce_product_loop_start' ) ) {
528
529
	/**
530
	 * Output the start of a product loop. By default this is a UL.
531
	 *
532
	 * @param bool $echo
533
	 * @return string
534
	 */
535
	function woocommerce_product_loop_start( $echo = true ) {
536
		ob_start();
537
		$GLOBALS['woocommerce_loop']['loop'] = 0;
538
		wc_get_template( 'loop/loop-start.php' );
539
		if ( $echo )
540
			echo ob_get_clean();
541
		else
542
			return ob_get_clean();
543
	}
544
}
545
if ( ! function_exists( 'woocommerce_product_loop_end' ) ) {
546
547
	/**
548
	 * Output the end of a product loop. By default this is a UL.
549
	 *
550
	 * @param bool $echo
551
	 * @return string
552
	 */
553
	function woocommerce_product_loop_end( $echo = true ) {
554
		ob_start();
555
556
		wc_get_template( 'loop/loop-end.php' );
557
558
		if ( $echo )
559
			echo ob_get_clean();
560
		else
561
			return ob_get_clean();
562
	}
563
}
564
if (  ! function_exists( 'woocommerce_template_loop_product_title' ) ) {
565
566
	/**
567
	 * Show the product title in the product loop. By default this is an H3.
568
	 */
569
	function woocommerce_template_loop_product_title() {
570
		echo '<h3>' . get_the_title() . '</h3>';
571
	}
572
}
573
if (  ! function_exists( 'woocommerce_template_loop_category_title' ) ) {
574
575
	/**
576
	 * Show the subcategory title in the product loop.
577
	 */
578
	function woocommerce_template_loop_category_title( $category ) {
579
		?>
580
		<h3>
581
			<?php
582
				echo $category->name;
583
584
				if ( $category->count > 0 )
585
					echo apply_filters( 'woocommerce_subcategory_count_html', ' <mark class="count">(' . $category->count . ')</mark>', $category );
586
			?>
587
		</h3>
588
		<?php
589
	}
590
}
591
/**
592
 * Insert the opening anchor tag for products in the loop.
593
 */
594
function woocommerce_template_loop_product_link_open() {
595
	echo '<a href="' . get_the_permalink() . '" class="woocommerce-LoopProduct-link">';
596
}
597
/**
598
 * Insert the opening anchor tag for products in the loop.
599
 */
600
function woocommerce_template_loop_product_link_close() {
601
	echo '</a>';
602
}
603
/**
604
 * Insert the opening anchor tag for categories in the loop.
605
 */
606
function woocommerce_template_loop_category_link_open( $category ) {
607
	echo '<a href="' . get_term_link( $category, 'product_cat' ) . '">';
608
}
609
/**
610
 * Insert the opening anchor tag for categories in the loop.
611
 */
612
function woocommerce_template_loop_category_link_close() {
613
	echo '</a>';
614
}
615
if ( ! function_exists( 'woocommerce_taxonomy_archive_description' ) ) {
616
617
	/**
618
	 * Show an archive description on taxonomy archives.
619
	 *
620
	 * @subpackage	Archives
621
	 */
622
	function woocommerce_taxonomy_archive_description() {
623
		if ( is_product_taxonomy() && 0 === absint( get_query_var( 'paged' ) ) ) {
624
			$description = wc_format_content( term_description() );
625
			if ( $description ) {
626
				echo '<div class="term-description">' . $description . '</div>';
627
			}
628
		}
629
	}
630
}
631
if ( ! function_exists( 'woocommerce_product_archive_description' ) ) {
632
633
	/**
634
	 * Show a shop page description on product archives.
635
	 *
636
	 * @subpackage	Archives
637
	 */
638
	function woocommerce_product_archive_description() {
639
		// Don't display the description on search results page
640
		if ( is_search() ) {
641
			return;
642
		}
643
644
		if ( is_post_type_archive( 'product' ) && 0 === absint( get_query_var( 'paged' ) ) ) {
645
			$shop_page   = get_post( wc_get_page_id( 'shop' ) );
646
			if ( $shop_page ) {
647
				$description = wc_format_content( $shop_page->post_content );
648
				if ( $description ) {
649
					echo '<div class="page-description">' . $description . '</div>';
650
				}
651
			}
652
		}
653
	}
654
}
655
656
if ( ! function_exists( 'woocommerce_template_loop_add_to_cart' ) ) {
657
658
	/**
659
	 * Get the add to cart template for the loop.
660
	 *
661
	 * @subpackage	Loop
662
	 */
663
	function woocommerce_template_loop_add_to_cart( $args = array() ) {
664
		global $product;
665
666
		if ( $product ) {
667
			$defaults = array(
668
				'quantity' => 1,
669
				'class'    => implode( ' ', array_filter( array(
670
						'button',
671
						'product_type_' . $product->product_type,
672
						$product->is_purchasable() && $product->is_in_stock() ? 'add_to_cart_button' : '',
673
						$product->supports( 'ajax_add_to_cart' ) ? 'ajax_add_to_cart' : ''
674
				) ) )
675
			);
676
677
			$args = apply_filters( 'woocommerce_loop_add_to_cart_args', wp_parse_args( $args, $defaults ), $product );
678
679
			wc_get_template( 'loop/add-to-cart.php', $args );
680
		}
681
	}
682
}
683
if ( ! function_exists( 'woocommerce_template_loop_product_thumbnail' ) ) {
684
685
	/**
686
	 * Get the product thumbnail for the loop.
687
	 *
688
	 * @subpackage	Loop
689
	 */
690
	function woocommerce_template_loop_product_thumbnail() {
691
		echo woocommerce_get_product_thumbnail();
692
	}
693
}
694
if ( ! function_exists( 'woocommerce_template_loop_price' ) ) {
695
696
	/**
697
	 * Get the product price for the loop.
698
	 *
699
	 * @subpackage	Loop
700
	 */
701
	function woocommerce_template_loop_price() {
702
		wc_get_template( 'loop/price.php' );
703
	}
704
}
705
if ( ! function_exists( 'woocommerce_template_loop_rating' ) ) {
706
707
	/**
708
	 * Display the average rating in the loop.
709
	 *
710
	 * @subpackage	Loop
711
	 */
712
	function woocommerce_template_loop_rating() {
713
		wc_get_template( 'loop/rating.php' );
714
	}
715
}
716
if ( ! function_exists( 'woocommerce_show_product_loop_sale_flash' ) ) {
717
718
	/**
719
	 * Get the sale flash for the loop.
720
	 *
721
	 * @subpackage	Loop
722
	 */
723
	function woocommerce_show_product_loop_sale_flash() {
724
		wc_get_template( 'loop/sale-flash.php' );
725
	}
726
}
727
728
if ( ! function_exists( 'woocommerce_get_product_thumbnail' ) ) {
729
730
	/**
731
	 * Get the product thumbnail, or the placeholder if not set.
732
	 *
733
	 * @subpackage	Loop
734
	 * @param string $size (default: 'shop_catalog')
735
	 * @param int $deprecated1 Deprecated since WooCommerce 2.0 (default: 0)
736
	 * @param int $deprecated2 Deprecated since WooCommerce 2.0 (default: 0)
737
	 * @return string
738
	 */
739
	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...
740
		global $post;
741
		$image_size = apply_filters( 'single_product_archive_thumbnail_size', $size );
742
743
		if ( has_post_thumbnail() ) {
744
			$props = wc_get_product_attachment_props( get_post_thumbnail_id(), $post );
745
			return get_the_post_thumbnail( $post->ID, $image_size, array(
746
				'title'	 => $props['title'],
747
				'alt'    => $props['alt'],
748
			) );
749
		} elseif ( wc_placeholder_img_src() ) {
750
			return wc_placeholder_img( $image_size );
751
		}
752
	}
753
}
754
755
if ( ! function_exists( 'woocommerce_result_count' ) ) {
756
757
	/**
758
	 * Output the result count text (Showing x - x of x results).
759
	 *
760
	 * @subpackage	Loop
761
	 */
762
	function woocommerce_result_count() {
763
		wc_get_template( 'loop/result-count.php' );
764
	}
765
}
766
767
if ( ! function_exists( 'woocommerce_catalog_ordering' ) ) {
768
769
	/**
770
	 * Output the product sorting options.
771
	 *
772
	 * @subpackage	Loop
773
	 */
774
	function woocommerce_catalog_ordering() {
775
		global $wp_query;
776
777
		if ( 1 === $wp_query->found_posts || ! woocommerce_products_will_display() ) {
778
			return;
779
		}
780
781
		$orderby                 = isset( $_GET['orderby'] ) ? wc_clean( $_GET['orderby'] ) : apply_filters( 'woocommerce_default_catalog_orderby', get_option( 'woocommerce_default_catalog_orderby' ) );
782
		$show_default_orderby    = 'menu_order' === apply_filters( 'woocommerce_default_catalog_orderby', get_option( 'woocommerce_default_catalog_orderby' ) );
783
		$catalog_orderby_options = apply_filters( 'woocommerce_catalog_orderby', array(
784
			'menu_order' => __( 'Default sorting', 'woocommerce' ),
785
			'popularity' => __( 'Sort by popularity', 'woocommerce' ),
786
			'rating'     => __( 'Sort by average rating', 'woocommerce' ),
787
			'date'       => __( 'Sort by newness', 'woocommerce' ),
788
			'price'      => __( 'Sort by price: low to high', 'woocommerce' ),
789
			'price-desc' => __( 'Sort by price: high to low', 'woocommerce' )
790
		) );
791
792
		if ( ! $show_default_orderby ) {
793
			unset( $catalog_orderby_options['menu_order'] );
794
		}
795
796
		if ( 'no' === get_option( 'woocommerce_enable_review_rating' ) ) {
797
			unset( $catalog_orderby_options['rating'] );
798
		}
799
800
		wc_get_template( 'loop/orderby.php', array( 'catalog_orderby_options' => $catalog_orderby_options, 'orderby' => $orderby, 'show_default_orderby' => $show_default_orderby ) );
801
	}
802
}
803
804
if ( ! function_exists( 'woocommerce_pagination' ) ) {
805
806
	/**
807
	 * Output the pagination.
808
	 *
809
	 * @subpackage	Loop
810
	 */
811
	function woocommerce_pagination() {
812
		wc_get_template( 'loop/pagination.php' );
813
	}
814
}
815
816
/** Single Product ********************************************************/
817
818
if ( ! function_exists( 'woocommerce_show_product_images' ) ) {
819
820
	/**
821
	 * Output the product image before the single product summary.
822
	 *
823
	 * @subpackage	Product
824
	 */
825
	function woocommerce_show_product_images() {
826
		wc_get_template( 'single-product/product-image.php' );
827
	}
828
}
829
if ( ! function_exists( 'woocommerce_show_product_thumbnails' ) ) {
830
831
	/**
832
	 * Output the product thumbnails.
833
	 *
834
	 * @subpackage	Product
835
	 */
836
	function woocommerce_show_product_thumbnails() {
837
		wc_get_template( 'single-product/product-thumbnails.php' );
838
	}
839
}
840
if ( ! function_exists( 'woocommerce_output_product_data_tabs' ) ) {
841
842
	/**
843
	 * Output the product tabs.
844
	 *
845
	 * @subpackage	Product/Tabs
846
	 */
847
	function woocommerce_output_product_data_tabs() {
848
		wc_get_template( 'single-product/tabs/tabs.php' );
849
	}
850
}
851
if ( ! function_exists( 'woocommerce_template_single_title' ) ) {
852
853
	/**
854
	 * Output the product title.
855
	 *
856
	 * @subpackage	Product
857
	 */
858
	function woocommerce_template_single_title() {
859
		wc_get_template( 'single-product/title.php' );
860
	}
861
}
862
if ( ! function_exists( 'woocommerce_template_single_rating' ) ) {
863
864
	/**
865
	 * Output the product rating.
866
	 *
867
	 * @subpackage	Product
868
	 */
869
	function woocommerce_template_single_rating() {
870
		wc_get_template( 'single-product/rating.php' );
871
	}
872
}
873
if ( ! function_exists( 'woocommerce_template_single_price' ) ) {
874
875
	/**
876
	 * Output the product price.
877
	 *
878
	 * @subpackage	Product
879
	 */
880
	function woocommerce_template_single_price() {
881
		wc_get_template( 'single-product/price.php' );
882
	}
883
}
884
if ( ! function_exists( 'woocommerce_template_single_excerpt' ) ) {
885
886
	/**
887
	 * Output the product short description (excerpt).
888
	 *
889
	 * @subpackage	Product
890
	 */
891
	function woocommerce_template_single_excerpt() {
892
		wc_get_template( 'single-product/short-description.php' );
893
	}
894
}
895
if ( ! function_exists( 'woocommerce_template_single_meta' ) ) {
896
897
	/**
898
	 * Output the product meta.
899
	 *
900
	 * @subpackage	Product
901
	 */
902
	function woocommerce_template_single_meta() {
903
		wc_get_template( 'single-product/meta.php' );
904
	}
905
}
906
if ( ! function_exists( 'woocommerce_template_single_sharing' ) ) {
907
908
	/**
909
	 * Output the product sharing.
910
	 *
911
	 * @subpackage	Product
912
	 */
913
	function woocommerce_template_single_sharing() {
914
		wc_get_template( 'single-product/share.php' );
915
	}
916
}
917
if ( ! function_exists( 'woocommerce_show_product_sale_flash' ) ) {
918
919
	/**
920
	 * Output the product sale flash.
921
	 *
922
	 * @subpackage	Product
923
	 */
924
	function woocommerce_show_product_sale_flash() {
925
		wc_get_template( 'single-product/sale-flash.php' );
926
	}
927
}
928
929
if ( ! function_exists( 'woocommerce_template_single_add_to_cart' ) ) {
930
931
	/**
932
	 * Trigger the single product add to cart action.
933
	 *
934
	 * @subpackage	Product
935
	 */
936
	function woocommerce_template_single_add_to_cart() {
937
		global $product;
938
		do_action( 'woocommerce_' . $product->product_type . '_add_to_cart' );
939
	}
940
}
941
if ( ! function_exists( 'woocommerce_simple_add_to_cart' ) ) {
942
943
	/**
944
	 * Output the simple product add to cart area.
945
	 *
946
	 * @subpackage	Product
947
	 */
948
	function woocommerce_simple_add_to_cart() {
949
		wc_get_template( 'single-product/add-to-cart/simple.php' );
950
	}
951
}
952
if ( ! function_exists( 'woocommerce_grouped_add_to_cart' ) ) {
953
954
	/**
955
	 * Output the grouped product add to cart area.
956
	 *
957
	 * @subpackage	Product
958
	 */
959
	function woocommerce_grouped_add_to_cart() {
960
		global $product;
961
962
		wc_get_template( 'single-product/add-to-cart/grouped.php', array(
963
			'grouped_product'    => $product,
964
			'grouped_products'   => $product->get_children(),
965
			'quantites_required' => false
966
		) );
967
	}
968
}
969
if ( ! function_exists( 'woocommerce_variable_add_to_cart' ) ) {
970
971
	/**
972
	 * Output the variable product add to cart area.
973
	 *
974
	 * @subpackage	Product
975
	 */
976
	function woocommerce_variable_add_to_cart() {
977
		global $product;
978
979
		// Enqueue variation scripts
980
		wp_enqueue_script( 'wc-add-to-cart-variation' );
981
982
		// Get Available variations?
983
		$get_variations = sizeof( $product->get_children() ) <= apply_filters( 'woocommerce_ajax_variation_threshold', 30, $product );
984
985
		// Load the template
986
		wc_get_template( 'single-product/add-to-cart/variable.php', array(
987
			'available_variations' => $get_variations ? $product->get_available_variations() : false,
988
			'attributes'           => $product->get_variation_attributes(),
989
			'selected_attributes'  => $product->get_variation_default_attributes()
990
		) );
991
	}
992
}
993
if ( ! function_exists( 'woocommerce_external_add_to_cart' ) ) {
994
995
	/**
996
	 * Output the external product add to cart area.
997
	 *
998
	 * @subpackage	Product
999
	 */
1000
	function woocommerce_external_add_to_cart() {
1001
		global $product;
1002
1003
		if ( ! $product->add_to_cart_url() ) {
1004
			return;
1005
		}
1006
1007
		wc_get_template( 'single-product/add-to-cart/external.php', array(
1008
			'product_url' => $product->add_to_cart_url(),
1009
			'button_text' => $product->single_add_to_cart_text()
1010
		) );
1011
	}
1012
}
1013
1014
if ( ! function_exists( 'woocommerce_quantity_input' ) ) {
1015
1016
	/**
1017
	 * Output the quantity input for add to cart forms.
1018
	 *
1019
	 * @param  array $args Args for the input
1020
	 * @param  WC_Product|null $product
1021
	 * @param  boolean $echo Whether to return or echo|string
1022
	 */
1023
	function woocommerce_quantity_input( $args = array(), $product = null, $echo = true ) {
1024
		if ( is_null( $product ) ) {
1025
			$product = $GLOBALS['product'];
1026
		}
1027
1028
		$defaults = array(
1029
			'input_name'  => 'quantity',
1030
			'input_value' => '1',
1031
			'max_value'   => apply_filters( 'woocommerce_quantity_input_max', '', $product ),
1032
			'min_value'   => apply_filters( 'woocommerce_quantity_input_min', '', $product ),
1033
			'step'        => apply_filters( 'woocommerce_quantity_input_step', '1', $product ),
1034
			'pattern'     => apply_filters( 'woocommerce_quantity_input_pattern', has_filter( 'woocommerce_stock_amount', 'intval' ) ? '[0-9]*' : '' ),
1035
			'inputmode'   => apply_filters( 'woocommerce_quantity_input_inputmode', has_filter( 'woocommerce_stock_amount', 'intval' ) ? 'numeric' : '' ),
1036
		);
1037
1038
		$args = apply_filters( 'woocommerce_quantity_input_args', wp_parse_args( $args, $defaults ), $product );
1039
1040
		// Set min and max value to empty string if not set.
1041
		$args['min_value'] = isset( $args['min_value'] ) ? $args['min_value'] : '';
1042
		$args['max_value'] = isset( $args['max_value'] ) ? $args['max_value'] : '';
1043
1044
		// Apply sanity to min/max args - min cannot be lower than 0
1045
		if ( '' !== $args['min_value'] && is_numeric( $args['min_value'] ) && $args['min_value'] < 0 ) {
1046
			$args['min_value'] = 0; // Cannot be lower than 0
1047
		}
1048
1049
		// Max cannot be lower than 0 or min
1050
		if ( '' !== $args['max_value'] && is_numeric( $args['max_value'] ) ) {
1051
			$args['max_value'] = $args['max_value'] < 0 ? 0 : $args['max_value'];
1052
			$args['max_value'] = $args['max_value'] < $args['min_value'] ? $args['min_value'] : $args['max_value'];
1053
		}
1054
1055
		ob_start();
1056
1057
		wc_get_template( 'global/quantity-input.php', $args );
1058
1059
		if ( $echo ) {
1060
			echo ob_get_clean();
1061
		} else {
1062
			return ob_get_clean();
1063
		}
1064
	}
1065
}
1066
1067
if ( ! function_exists( 'woocommerce_product_description_tab' ) ) {
1068
1069
	/**
1070
	 * Output the description tab content.
1071
	 *
1072
	 * @subpackage	Product/Tabs
1073
	 */
1074
	function woocommerce_product_description_tab() {
1075
		wc_get_template( 'single-product/tabs/description.php' );
1076
	}
1077
}
1078
if ( ! function_exists( 'woocommerce_product_additional_information_tab' ) ) {
1079
1080
	/**
1081
	 * Output the attributes tab content.
1082
	 *
1083
	 * @subpackage	Product/Tabs
1084
	 */
1085
	function woocommerce_product_additional_information_tab() {
1086
		wc_get_template( 'single-product/tabs/additional-information.php' );
1087
	}
1088
}
1089
if ( ! function_exists( 'woocommerce_product_reviews_tab' ) ) {
1090
1091
	/**
1092
	 * Output the reviews tab content.
1093
	 * @deprecated  2.4.0 Unused
1094
	 * @subpackage	Product/Tabs
1095
	 */
1096
	function woocommerce_product_reviews_tab() {
1097
		_deprecated_function( 'woocommerce_product_reviews_tab', '2.4', '' );
1098
	}
1099
}
1100
1101
if ( ! function_exists( 'woocommerce_default_product_tabs' ) ) {
1102
1103
	/**
1104
	 * Add default product tabs to product pages.
1105
	 *
1106
	 * @param array $tabs
1107
	 * @return array
1108
	 */
1109
	function woocommerce_default_product_tabs( $tabs = array() ) {
1110
		global $product, $post;
1111
1112
		// Description tab - shows product content
1113
		if ( $post->post_content ) {
1114
			$tabs['description'] = array(
1115
				'title'    => __( 'Description', 'woocommerce' ),
1116
				'priority' => 10,
1117
				'callback' => 'woocommerce_product_description_tab'
1118
			);
1119
		}
1120
1121
		// Additional information tab - shows attributes
1122
		if ( $product && ( $product->has_attributes() || $product->enable_dimensions_display() ) ) {
1123
			$tabs['additional_information'] = array(
1124
				'title'    => __( 'Additional Information', 'woocommerce' ),
1125
				'priority' => 20,
1126
				'callback' => 'woocommerce_product_additional_information_tab'
1127
			);
1128
		}
1129
1130
		// Reviews tab - shows comments
1131
		if ( comments_open() ) {
1132
			$tabs['reviews'] = array(
1133
				'title'    => sprintf( __( 'Reviews (%d)', 'woocommerce' ), $product->get_review_count() ),
1134
				'priority' => 30,
1135
				'callback' => 'comments_template'
1136
			);
1137
		}
1138
1139
		return $tabs;
1140
	}
1141
}
1142
1143
if ( ! function_exists( 'woocommerce_sort_product_tabs' ) ) {
1144
1145
	/**
1146
	 * Sort tabs by priority.
1147
	 *
1148
	 * @param array $tabs
1149
	 * @return array
1150
	 */
1151
	function woocommerce_sort_product_tabs( $tabs = array() ) {
1152
1153
		// Make sure the $tabs parameter is an array
1154
		if ( ! is_array( $tabs ) ) {
1155
			trigger_error( "Function woocommerce_sort_product_tabs() expects an array as the first parameter. Defaulting to empty array." );
1156
			$tabs = array( );
1157
		}
1158
1159
		// Re-order tabs by priority
1160
		if ( ! function_exists( '_sort_priority_callback' ) ) {
1161
			function _sort_priority_callback( $a, $b ) {
1162
				if ( $a['priority'] === $b['priority'] )
1163
					return 0;
1164
				return ( $a['priority'] < $b['priority'] ) ? -1 : 1;
1165
			}
1166
		}
1167
1168
		uasort( $tabs, '_sort_priority_callback' );
1169
1170
		return $tabs;
1171
	}
1172
}
1173
1174
if ( ! function_exists( 'woocommerce_comments' ) ) {
1175
1176
	/**
1177
	 * Output the Review comments template.
1178
	 *
1179
	 * @subpackage	Product
1180
	 * @param WP_Comment $comment
1181
	 * @param array $args
1182
	 * @param int $depth
1183
	 */
1184
	function woocommerce_comments( $comment, $args, $depth ) {
1185
		$GLOBALS['comment'] = $comment;
1186
		wc_get_template( 'single-product/review.php', array( 'comment' => $comment, 'args' => $args, 'depth' => $depth ) );
1187
	}
1188
}
1189
1190
if ( ! function_exists( 'woocommerce_review_display_gravatar' ) ) {
1191
	/**
1192
	 * Display the review authors gravatar
1193
	 *
1194
	 * @param array $comment WP_Comment.
1195
	 * @return void
1196
	 */
1197
	function woocommerce_review_display_gravatar( $comment ) {
1198
		echo get_avatar( $comment, apply_filters( 'woocommerce_review_gravatar_size', '60' ), '' );
1199
	}
1200
}
1201
1202
if ( ! function_exists( 'woocommerce_review_display_rating' ) ) {
1203
	/**
1204
	 * Display the reviewers star rating
1205
	 *
1206
	 * @return void
1207
	 */
1208
	function woocommerce_review_display_rating() {
1209
		wc_get_template( 'single-product/review-rating.php' );
1210
	}
1211
}
1212
1213
if ( ! function_exists( 'woocommerce_review_display_meta' ) ) {
1214
	/**
1215
	 * Display the review authors meta (name, verified owner, review date)
1216
	 *
1217
	 * @return void
1218
	 */
1219
	function woocommerce_review_display_meta() {
1220
		wc_get_template( 'single-product/review-meta.php' );
1221
	}
1222
}
1223
1224
if ( ! function_exists( 'woocommerce_review_display_comment_text' ) ) {
1225
1226
	/**
1227
	 * Display the review content.
1228
	 */
1229
	function woocommerce_review_display_comment_text() {
1230
		echo '<div class="description">';
1231
		comment_text();
1232
		echo '</div>';
1233
	}
1234
}
1235
1236
if ( ! function_exists( 'woocommerce_output_related_products' ) ) {
1237
1238
	/**
1239
	 * Output the related products.
1240
	 *
1241
	 * @subpackage	Product
1242
	 */
1243
	function woocommerce_output_related_products() {
1244
1245
		$args = array(
1246
			'posts_per_page' 	=> 4,
1247
			'columns' 			=> 4,
1248
			'orderby' 			=> 'rand'
1249
		);
1250
1251
		woocommerce_related_products( apply_filters( 'woocommerce_output_related_products_args', $args ) );
1252
	}
1253
}
1254
1255
if ( ! function_exists( 'woocommerce_related_products' ) ) {
1256
1257
	/**
1258
	 * Output the related products.
1259
	 *
1260
	 * @param array Provided arguments
1261
	 * @param bool Columns argument for backwards compat
1262
	 * @param bool Order by argument for backwards compat
1263
	 */
1264
	function woocommerce_related_products( $args = array(), $columns = false, $orderby = false ) {
1265
		if ( ! is_array( $args ) ) {
1266
			_deprecated_argument( __FUNCTION__, '2.1', __( 'Use $args argument as an array instead. Deprecated argument will be removed in WC 2.2.', 'woocommerce' ) );
1267
1268
			$argsvalue = $args;
1269
1270
			$args = array(
1271
				'posts_per_page' => $argsvalue,
1272
				'columns'        => $columns,
1273
				'orderby'        => $orderby,
1274
			);
1275
		}
1276
1277
		$defaults = array(
1278
			'posts_per_page' => 2,
1279
			'columns'        => 2,
1280
			'orderby'        => 'rand'
1281
		);
1282
1283
		$args = wp_parse_args( $args, $defaults );
1284
1285
		wc_get_template( 'single-product/related.php', $args );
1286
	}
1287
}
1288
1289
if ( ! function_exists( 'woocommerce_upsell_display' ) ) {
1290
1291
	/**
1292
	 * Output product up sells.
1293
	 *
1294
	 * @param int $posts_per_page (default: -1)
1295
	 * @param int $columns (default: 4)
1296
	 * @param string $orderby (default: 'rand')
1297
	 */
1298
	function woocommerce_upsell_display( $posts_per_page = '-1', $columns = 4, $orderby = 'rand' ) {
1299
		$args = apply_filters( 'woocommerce_upsell_display_args', array(
1300
			'posts_per_page'	=> $posts_per_page,
1301
			'orderby'			=> apply_filters( 'woocommerce_upsells_orderby', $orderby ),
1302
			'columns'			=> $columns
1303
		) );
1304
1305
		wc_get_template( 'single-product/up-sells.php', $args );
1306
	}
1307
}
1308
1309
/** Cart ******************************************************************/
1310
1311
if ( ! function_exists( 'woocommerce_shipping_calculator' ) ) {
1312
1313
	/**
1314
	 * Output the cart shipping calculator.
1315
	 *
1316
	 * @subpackage	Cart
1317
	 */
1318
	function woocommerce_shipping_calculator() {
1319
		wc_get_template( 'cart/shipping-calculator.php' );
1320
	}
1321
}
1322
1323
if ( ! function_exists( 'woocommerce_cart_totals' ) ) {
1324
1325
	/**
1326
	 * Output the cart totals.
1327
	 *
1328
	 * @subpackage	Cart
1329
	 */
1330
	function woocommerce_cart_totals() {
1331
		if ( is_checkout() ) {
1332
			return;
1333
		}
1334
		wc_get_template( 'cart/cart-totals.php' );
1335
	}
1336
}
1337
1338
if ( ! function_exists( 'woocommerce_cross_sell_display' ) ) {
1339
1340
	/**
1341
	 * Output the cart cross-sells.
1342
	 *
1343
	 * @param  int $posts_per_page (default: 2)
1344
	 * @param  int $columns (default: 2)
1345
	 * @param  string $orderby (default: 'rand')
1346
	 */
1347
	function woocommerce_cross_sell_display( $posts_per_page = 2, $columns = 2, $orderby = 'rand' ) {
1348
		if ( is_checkout() ) {
1349
			return;
1350
		}
1351
		wc_get_template( 'cart/cross-sells.php', array(
1352
			'posts_per_page' => $posts_per_page,
1353
			'orderby'        => $orderby,
1354
			'columns'        => $columns
1355
		) );
1356
	}
1357
}
1358
1359
if ( ! function_exists( 'woocommerce_button_proceed_to_checkout' ) ) {
1360
1361
	/**
1362
	 * Output the proceed to checkout button.
1363
	 *
1364
	 * @subpackage	Cart
1365
	 */
1366
	function woocommerce_button_proceed_to_checkout() {
1367
		wc_get_template( 'cart/proceed-to-checkout-button.php' );
1368
	}
1369
}
1370
1371 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...
1372
1373
	/**
1374
	 * Output the proceed to checkout button.
1375
	 *
1376
	 * @subpackage	Cart
1377
	 */
1378
	function woocommerce_widget_shopping_cart_button_view_cart() {
1379
		echo '<a href="' . esc_url( wc_get_cart_url() ) . '" class="button wc-forward">' . __( 'View Cart', 'woocommerce' ) . '</a>';
1380
	}
1381
}
1382
1383 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...
1384
1385
	/**
1386
	 * Output the proceed to checkout button.
1387
	 *
1388
	 * @subpackage	Cart
1389
	 */
1390
	function woocommerce_widget_shopping_cart_proceed_to_checkout() {
1391
		echo '<a href="' . esc_url( wc_get_checkout_url() ) . '" class="button checkout wc-forward">' . __( 'Checkout', 'woocommerce' ) . '</a>';
1392
	}
1393
}
1394
1395
/** Mini-Cart *************************************************************/
1396
1397
if ( ! function_exists( 'woocommerce_mini_cart' ) ) {
1398
1399
	/**
1400
	 * Output the Mini-cart - used by cart widget.
1401
	 *
1402
	 * @param array $args
1403
	 */
1404
	function woocommerce_mini_cart( $args = array() ) {
1405
1406
		$defaults = array(
1407
			'list_class' => ''
1408
		);
1409
1410
		$args = wp_parse_args( $args, $defaults );
1411
1412
		wc_get_template( 'cart/mini-cart.php', $args );
1413
	}
1414
}
1415
1416
/** Login *****************************************************************/
1417
1418
if ( ! function_exists( 'woocommerce_login_form' ) ) {
1419
1420
	/**
1421
	 * Output the WooCommerce Login Form.
1422
	 *
1423
	 * @subpackage	Forms
1424
	 * @param array $args
1425
	 */
1426
	function woocommerce_login_form( $args = array() ) {
1427
1428
		$defaults = array(
1429
			'message'  => '',
1430
			'redirect' => '',
1431
			'hidden'   => false
1432
		);
1433
1434
		$args = wp_parse_args( $args, $defaults  );
1435
1436
		wc_get_template( 'global/form-login.php', $args );
1437
	}
1438
}
1439
1440
if ( ! function_exists( 'woocommerce_checkout_login_form' ) ) {
1441
1442
	/**
1443
	 * Output the WooCommerce Checkout Login Form.
1444
	 *
1445
	 * @subpackage	Checkout
1446
	 */
1447
	function woocommerce_checkout_login_form() {
1448
		wc_get_template( 'checkout/form-login.php', array( 'checkout' => WC()->checkout() ) );
1449
	}
1450
}
1451
1452
if ( ! function_exists( 'woocommerce_breadcrumb' ) ) {
1453
1454
	/**
1455
	 * Output the WooCommerce Breadcrumb.
1456
	 *
1457
	 * @param array $args
1458
	 */
1459
	function woocommerce_breadcrumb( $args = array() ) {
1460
		$args = wp_parse_args( $args, apply_filters( 'woocommerce_breadcrumb_defaults', array(
1461
			'delimiter'   => '&nbsp;&#47;&nbsp;',
1462
			'wrap_before' => '<nav class="woocommerce-breadcrumb">',
1463
			'wrap_after'  => '</nav>',
1464
			'before'      => '',
1465
			'after'       => '',
1466
			'home'        => _x( 'Home', 'breadcrumb', 'woocommerce' )
1467
		) ) );
1468
1469
		$breadcrumbs = new WC_Breadcrumb();
1470
1471
		if ( ! empty( $args['home'] ) ) {
1472
			$breadcrumbs->add_crumb( $args['home'], apply_filters( 'woocommerce_breadcrumb_home_url', home_url() ) );
1473
		}
1474
1475
		$args['breadcrumb'] = $breadcrumbs->generate();
1476
1477
		/**
1478
		 * @hooked WC_Structured_Data::generate_breadcrumb_data() - 10
1479
		 */
1480
		do_action( 'woocommerce_breadcrumb', $args );
1481
1482
		wc_get_template( 'global/breadcrumb.php', $args );
1483
	}
1484
}
1485
1486
if ( ! function_exists( 'woocommerce_order_review' ) ) {
1487
1488
	/**
1489
	 * Output the Order review table for the checkout.
1490
	 *
1491
	 * @subpackage	Checkout
1492
	 */
1493
	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...
1494
		wc_get_template( 'checkout/review-order.php', array( 'checkout' => WC()->checkout() ) );
1495
	}
1496
}
1497
1498
if ( ! function_exists( 'woocommerce_checkout_payment' ) ) {
1499
1500
	/**
1501
	 * Output the Payment Methods on the checkout.
1502
	 *
1503
	 * @subpackage	Checkout
1504
	 */
1505
	function woocommerce_checkout_payment() {
1506
		if ( WC()->cart->needs_payment() ) {
1507
			$available_gateways = WC()->payment_gateways()->get_available_payment_gateways();
1508
			WC()->payment_gateways()->set_current_gateway( $available_gateways );
1509
		} else {
1510
			$available_gateways = array();
1511
		}
1512
1513
		wc_get_template( 'checkout/payment.php', array(
1514
			'checkout'           => WC()->checkout(),
1515
			'available_gateways' => $available_gateways,
1516
			'order_button_text'  => apply_filters( 'woocommerce_order_button_text', __( 'Place order', 'woocommerce' ) )
1517
		) );
1518
	}
1519
}
1520
1521
if ( ! function_exists( 'woocommerce_checkout_coupon_form' ) ) {
1522
1523
	/**
1524
	 * Output the Coupon form for the checkout.
1525
	 *
1526
	 * @subpackage	Checkout
1527
	 */
1528
	function woocommerce_checkout_coupon_form() {
1529
		wc_get_template( 'checkout/form-coupon.php', array( 'checkout' => WC()->checkout() ) );
1530
	}
1531
}
1532
1533
if ( ! function_exists( 'woocommerce_products_will_display' ) ) {
1534
1535
	/**
1536
	 * Check if we will be showing products or not (and not sub-categories only).
1537
	 * @subpackage	Loop
1538
	 * @return bool
1539
	 */
1540
	function woocommerce_products_will_display() {
1541
		global $wpdb;
1542
1543
		if ( is_shop() ) {
1544
			return 'subcategories' !== get_option( 'woocommerce_shop_page_display' ) || is_search();
1545
		}
1546
1547
		if ( ! is_product_taxonomy() ) {
1548
			return false;
1549
		}
1550
1551
		if ( is_search() || is_filtered() || is_paged() ) {
1552
			return true;
1553
		}
1554
1555
		$term = get_queried_object();
1556
1557
		if ( is_product_category() ) {
1558
			switch ( get_woocommerce_term_meta( $term->term_id, 'display_type', true ) ) {
1559
				case 'subcategories' :
1560
					// Nothing - we want to continue to see if there are products/subcats
1561
				break;
1562
				case 'products' :
1563
				case 'both' :
1564
					return true;
1565
				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...
1566
				default :
1567
					// Default - no setting
1568
					if ( get_option( 'woocommerce_category_archive_display' ) != 'subcategories' ) {
1569
						return true;
1570
					}
1571
				break;
1572
			}
1573
		}
1574
1575
		// Begin subcategory logic
1576
		if ( empty( $term->term_id ) || empty( $term->taxonomy ) ) {
1577
			return true;
1578
		}
1579
1580
		$transient_name = 'wc_products_will_display_' . $term->term_id . '_' . WC_Cache_Helper::get_transient_version( 'product_query' );
1581
1582
		if ( false === ( $products_will_display = get_transient( $transient_name ) ) ) {
1583
			$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 ) );
1584
1585
			if ( $has_children ) {
1586
				// Check terms have products inside - parents first. If products are found inside, subcats will be shown instead of products so we can return false.
1587
				if ( sizeof( get_objects_in_term( $has_children, $term->taxonomy ) ) > 0 ) {
1588
					$products_will_display = false;
1589
				} else {
1590
					// If we get here, the parents were empty so we're forced to check children
1591
					foreach ( $has_children as $term_id ) {
1592
						$children = get_term_children( $term_id, $term->taxonomy );
1593
1594
						if ( sizeof( get_objects_in_term( $children, $term->taxonomy ) ) > 0 ) {
1595
							$products_will_display = false;
1596
							break;
1597
						}
1598
					}
1599
				}
1600
			} else {
1601
				$products_will_display = true;
1602
			}
1603
		}
1604
1605
		set_transient( $transient_name, $products_will_display, DAY_IN_SECONDS * 30 );
1606
1607
		return $products_will_display;
1608
	}
1609
}
1610
1611
if ( ! function_exists( 'woocommerce_product_subcategories' ) ) {
1612
1613
	/**
1614
	 * Display product sub categories as thumbnails.
1615
	 *
1616
	 * @subpackage	Loop
1617
	 * @param array $args
1618
	 * @return null|boolean
1619
	 */
1620
	function woocommerce_product_subcategories( $args = array() ) {
1621
		global $wp_query;
1622
1623
		$defaults = array(
1624
			'before'        => '',
1625
			'after'         => '',
1626
			'force_display' => false
1627
		);
1628
1629
		$args = wp_parse_args( $args, $defaults );
1630
1631
		extract( $args );
1632
1633
		// Main query only
1634
		if ( ! is_main_query() && ! $force_display ) {
1635
			return;
1636
		}
1637
1638
		// Don't show when filtering, searching or when on page > 1 and ensure we're on a product archive
1639
		if ( is_search() || is_filtered() || is_paged() || ( ! is_product_category() && ! is_shop() ) ) {
1640
			return;
1641
		}
1642
1643
		// Check categories are enabled
1644
		if ( is_shop() && '' === get_option( 'woocommerce_shop_page_display' ) ) {
1645
			return;
1646
		}
1647
1648
		// Find the category + category parent, if applicable
1649
		$term 			= get_queried_object();
1650
		$parent_id 		= empty( $term->term_id ) ? 0 : $term->term_id;
1651
1652
		if ( is_product_category() ) {
1653
			$display_type = get_woocommerce_term_meta( $term->term_id, 'display_type', true );
1654
1655
			switch ( $display_type ) {
1656
				case 'products' :
1657
					return;
1658
				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...
1659
				case '' :
1660
					if ( '' === get_option( 'woocommerce_category_archive_display' ) ) {
1661
						return;
1662
					}
1663
				break;
1664
			}
1665
		}
1666
1667
		// 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
1668
		$product_categories = get_categories( apply_filters( 'woocommerce_product_subcategories_args', array(
1669
			'parent'       => $parent_id,
1670
			'menu_order'   => 'ASC',
1671
			'hide_empty'   => 0,
1672
			'hierarchical' => 1,
1673
			'taxonomy'     => 'product_cat',
1674
			'pad_counts'   => 1
1675
		) ) );
1676
1677
		if ( ! apply_filters( 'woocommerce_product_subcategories_hide_empty', false ) ) {
1678
			$product_categories = wp_list_filter( $product_categories, array( 'count' => 0 ), 'NOT' );
1679
		}
1680
1681
		if ( $product_categories ) {
1682
			echo $before;
1683
1684
			foreach ( $product_categories as $category ) {
1685
				wc_get_template( 'content-product_cat.php', array(
1686
					'category' => $category
1687
				) );
1688
			}
1689
1690
			// If we are hiding products disable the loop and pagination
1691
			if ( is_product_category() ) {
1692
				$display_type = get_woocommerce_term_meta( $term->term_id, 'display_type', true );
1693
1694
				switch ( $display_type ) {
1695
					case 'subcategories' :
1696
						$wp_query->post_count    = 0;
1697
						$wp_query->max_num_pages = 0;
1698
					break;
1699
					case '' :
1700
						if ( 'subcategories' === get_option( 'woocommerce_category_archive_display' ) ) {
1701
							$wp_query->post_count    = 0;
1702
							$wp_query->max_num_pages = 0;
1703
						}
1704
					break;
1705
				}
1706
			}
1707
1708
			if ( is_shop() && 'subcategories' === get_option( 'woocommerce_shop_page_display' ) ) {
1709
				$wp_query->post_count    = 0;
1710
				$wp_query->max_num_pages = 0;
1711
			}
1712
1713
			echo $after;
1714
1715
			return true;
1716
		}
1717
	}
1718
}
1719
1720
if ( ! function_exists( 'woocommerce_subcategory_thumbnail' ) ) {
1721
1722
	/**
1723
	 * Show subcategory thumbnails.
1724
	 *
1725
	 * @param mixed $category
1726
	 * @subpackage	Loop
1727
	 */
1728
	function woocommerce_subcategory_thumbnail( $category ) {
1729
		$small_thumbnail_size  	= apply_filters( 'subcategory_archive_thumbnail_size', 'shop_catalog' );
1730
		$dimensions    			= wc_get_image_size( $small_thumbnail_size );
1731
		$thumbnail_id  			= get_woocommerce_term_meta( $category->term_id, 'thumbnail_id', true  );
1732
1733
		if ( $thumbnail_id ) {
1734
			$image        = wp_get_attachment_image_src( $thumbnail_id, $small_thumbnail_size  );
1735
			$image        = $image[0];
1736
			$image_srcset = function_exists( 'wp_get_attachment_image_srcset' ) ? wp_get_attachment_image_srcset( $thumbnail_id, $small_thumbnail_size ) : false;
1737
			$image_sizes  = function_exists( 'wp_get_attachment_image_sizes' ) ? wp_get_attachment_image_sizes( $thumbnail_id, $small_thumbnail_size ) : false;
1738
		} else {
1739
			$image        = wc_placeholder_img_src();
1740
			$image_srcset = $image_sizes = false;
1741
		}
1742
1743
		if ( $image ) {
1744
			// Prevent esc_url from breaking spaces in urls for image embeds
1745
			// Ref: https://core.trac.wordpress.org/ticket/23605
1746
			$image = str_replace( ' ', '%20', $image );
1747
1748
			// Add responsive image markup if available
1749
			if ( $image_srcset && $image_sizes ) {
1750
				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 ) . '" />';
1751
			} else {
1752
				echo '<img src="' . esc_url( $image ) . '" alt="' . esc_attr( $category->name ) . '" width="' . esc_attr( $dimensions['width'] ) . '" height="' . esc_attr( $dimensions['height'] ) . '" />';
1753
			}
1754
		}
1755
	}
1756
}
1757
1758
if ( ! function_exists( 'woocommerce_order_details_table' ) ) {
1759
1760
	/**
1761
	 * Displays order details in a table.
1762
	 *
1763
	 * @param mixed $order_id
1764
	 * @subpackage	Orders
1765
	 */
1766
	function woocommerce_order_details_table( $order_id ) {
1767
		if ( ! $order_id ) return;
1768
1769
		wc_get_template( 'order/order-details.php', array(
1770
			'order_id' => $order_id
1771
		) );
1772
	}
1773
}
1774
1775
1776
if ( ! function_exists( 'woocommerce_order_again_button' ) ) {
1777
1778
	/**
1779
	 * Display an 'order again' button on the view order page.
1780
	 *
1781
	 * @param object $order
1782
	 * @subpackage	Orders
1783
	 */
1784
	function woocommerce_order_again_button( $order ) {
1785
		if ( ! $order || ! $order->has_status( 'completed' ) || ! is_user_logged_in() ) {
1786
			return;
1787
		}
1788
1789
		wc_get_template( 'order/order-again.php', array(
1790
			'order' => $order
1791
		) );
1792
	}
1793
}
1794
1795
/** Forms ****************************************************************/
1796
1797
if ( ! function_exists( 'woocommerce_form_field' ) ) {
1798
1799
	/**
1800
	 * Outputs a checkout/address form field.
1801
	 *
1802
	 * @subpackage	Forms
1803
	 * @param string $key
1804
	 * @param mixed $args
1805
	 * @param string $value (default: null)
1806
	 * @todo This function needs to be broken up in smaller pieces
1807
	 */
1808
	function woocommerce_form_field( $key, $args, $value = null ) {
1809
		$defaults = array(
1810
			'type'              => 'text',
1811
			'label'             => '',
1812
			'description'       => '',
1813
			'placeholder'       => '',
1814
			'maxlength'         => false,
1815
			'required'          => false,
1816
			'autocomplete'      => false,
1817
			'id'                => $key,
1818
			'class'             => array(),
1819
			'label_class'       => array(),
1820
			'input_class'       => array(),
1821
			'return'            => false,
1822
			'options'           => array(),
1823
			'custom_attributes' => array(),
1824
			'validate'          => array(),
1825
			'default'           => '',
1826
		);
1827
1828
		$args = wp_parse_args( $args, $defaults );
1829
		$args = apply_filters( 'woocommerce_form_field_args', $args, $key, $value );
1830
1831
		if ( $args['required'] ) {
1832
			$args['class'][] = 'validate-required';
1833
			$required = ' <abbr class="required" title="' . esc_attr__( 'required', 'woocommerce'  ) . '">*</abbr>';
1834
		} else {
1835
			$required = '';
1836
		}
1837
1838
		$args['maxlength'] = ( $args['maxlength'] ) ? 'maxlength="' . absint( $args['maxlength'] ) . '"' : '';
1839
1840
		$args['autocomplete'] = ( $args['autocomplete'] ) ? 'autocomplete="' . esc_attr( $args['autocomplete'] ) . '"' : '';
1841
1842
		if ( is_string( $args['label_class'] ) ) {
1843
			$args['label_class'] = array( $args['label_class'] );
1844
		}
1845
1846
		if ( is_null( $value ) ) {
1847
			$value = $args['default'];
1848
		}
1849
1850
		// Custom attribute handling
1851
		$custom_attributes = array();
1852
1853 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...
1854
			foreach ( $args['custom_attributes'] as $attribute => $attribute_value ) {
1855
				$custom_attributes[] = esc_attr( $attribute ) . '="' . esc_attr( $attribute_value ) . '"';
1856
			}
1857
		}
1858
1859
		if ( ! empty( $args['validate'] ) ) {
1860
			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...
1861
				$args['class'][] = 'validate-' . $validate;
1862
			}
1863
		}
1864
1865
		$field = '';
1866
		$label_id = $args['id'];
1867
		$field_container = '<p class="form-row %1$s" id="%2$s">%3$s</p>';
1868
1869
		switch ( $args['type'] ) {
1870
			case 'country' :
1871
1872
				$countries = 'shipping_country' === $key ? WC()->countries->get_shipping_countries() : WC()->countries->get_allowed_countries();
1873
1874
				if ( 1 === sizeof( $countries ) ) {
1875
1876
					$field .= '<strong>' . current( array_values( $countries ) ) . '</strong>';
1877
1878
					$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" />';
1879
1880
				} else {
1881
1882
					$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 ) . '>'
1883
							. '<option value="">'.__( 'Select a country&hellip;', 'woocommerce' ) .'</option>';
1884
1885 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...
1886
						$field .= '<option value="' . esc_attr( $ckey ) . '" '. selected( $value, $ckey, false ) . '>'. __( $cvalue, 'woocommerce' ) .'</option>';
1887
					}
1888
1889
					$field .= '</select>';
1890
1891
					$field .= '<noscript><input type="submit" name="woocommerce_checkout_update_totals" value="' . esc_attr__( 'Update country', 'woocommerce' ) . '" /></noscript>';
1892
1893
				}
1894
1895
				break;
1896
			case 'state' :
1897
1898
				/* Get Country */
1899
				$country_key = 'billing_state' === $key ? 'billing_country' : 'shipping_country';
1900
				$current_cc  = WC()->checkout->get_value( $country_key );
1901
				$states      = WC()->countries->get_states( $current_cc );
1902
1903
				if ( is_array( $states ) && empty( $states ) ) {
1904
1905
					$field_container = '<p class="form-row %1$s" id="%2$s" style="display: none">%3$s</p>';
1906
1907
					$field .= '<input type="hidden" class="hidden" name="' . esc_attr( $key )  . '" id="' . esc_attr( $args['id'] ) . '" value="" ' . implode( ' ', $custom_attributes ) . ' placeholder="' . esc_attr( $args['placeholder'] ) . '" />';
1908
1909
				} elseif ( is_array( $states ) ) {
1910
1911
					$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'] . '>
1912
						<option value="">'.__( 'Select a state&hellip;', 'woocommerce' ) .'</option>';
1913
1914 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...
1915
						$field .= '<option value="' . esc_attr( $ckey ) . '" '.selected( $value, $ckey, false ) .'>'.__( $cvalue, 'woocommerce' ) .'</option>';
1916
					}
1917
1918
					$field .= '</select>';
1919
1920
				} else {
1921
1922
					$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 ) . ' />';
1923
1924
				}
1925
1926
				break;
1927
			case 'textarea' :
1928
1929
				$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>';
1930
1931
				break;
1932 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...
1933
1934
				$field = '<label class="checkbox ' . implode( ' ', $args['label_class'] ) .'" ' . implode( ' ', $custom_attributes ) . '>
1935
						<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 ) .' /> '
1936
						 . $args['label'] . $required . '</label>';
1937
1938
				break;
1939
			case 'password' :
1940
			case 'text' :
1941
			case 'email' :
1942
			case 'tel' :
1943 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...
1944
1945
				$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 ) . ' />';
1946
1947
				break;
1948
			case 'select' :
1949
1950
				$options = $field = '';
1951
1952
				if ( ! empty( $args['options'] ) ) {
1953
					foreach ( $args['options'] as $option_key => $option_text ) {
1954
						if ( '' === $option_key ) {
1955
							// If we have a blank option, select2 needs a placeholder
1956
							if ( empty( $args['placeholder'] ) ) {
1957
								$args['placeholder'] = $option_text ? $option_text : __( 'Choose an option', 'woocommerce' );
1958
							}
1959
							$custom_attributes[] = 'data-allow_clear="true"';
1960
						}
1961
						$options .= '<option value="' . esc_attr( $option_key ) . '" '. selected( $value, $option_key, false ) . '>' . esc_attr( $option_text ) .'</option>';
1962
					}
1963
1964
					$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'] . '>
1965
							' . $options . '
1966
						</select>';
1967
				}
1968
1969
				break;
1970
			case 'radio' :
1971
1972
				$label_id = current( array_keys( $args['options'] ) );
1973
1974
				if ( ! empty( $args['options'] ) ) {
1975
					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...
1976
						$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 ) . ' />';
1977
						$field .= '<label for="' . esc_attr( $args['id'] ) . '_' . esc_attr( $option_key ) . '" class="radio ' . implode( ' ', $args['label_class'] ) .'">' . $option_text . '</label>';
1978
					}
1979
				}
1980
1981
				break;
1982
		}
1983
1984
		if ( ! empty( $field ) ) {
1985
			$field_html = '';
1986
1987
			if ( $args['label'] && 'checkbox' != $args['type'] ) {
1988
				$field_html .= '<label for="' . esc_attr( $label_id ) . '" class="' . esc_attr( implode( ' ', $args['label_class'] ) ) .'">' . $args['label'] . $required . '</label>';
1989
			}
1990
1991
			$field_html .= $field;
1992
1993
			if ( $args['description'] ) {
1994
				$field_html .= '<span class="description">' . esc_html( $args['description'] ) . '</span>';
1995
			}
1996
1997
			$container_class = 'form-row ' . esc_attr( implode( ' ', $args['class'] ) );
1998
			$container_id = esc_attr( $args['id'] ) . '_field';
1999
2000
			$after = ! empty( $args['clear'] ) ? '<div class="clear"></div>' : '';
2001
2002
			$field = sprintf( $field_container, $container_class, $container_id, $field_html ) . $after;
2003
		}
2004
2005
		$field = apply_filters( 'woocommerce_form_field_' . $args['type'], $field, $key, $args, $value );
2006
2007
		if ( $args['return'] ) {
2008
			return $field;
2009
		} else {
2010
			echo $field;
2011
		}
2012
	}
2013
}
2014
2015
if ( ! function_exists( 'get_product_search_form' ) ) {
2016
2017
	/**
2018
	 * Display product search form.
2019
	 *
2020
	 * Will first attempt to locate the product-searchform.php file in either the child or.
2021
	 * the parent, then load it. If it doesn't exist, then the default search form.
2022
	 * will be displayed.
2023
	 *
2024
	 * The default searchform uses html5.
2025
	 *
2026
	 * @subpackage	Forms
2027
	 * @param bool $echo (default: true)
2028
	 * @return string
2029
	 */
2030
	function get_product_search_form( $echo = true  ) {
2031
		global $product_search_form_index;
2032
2033
		ob_start();
2034
2035
		if ( empty( $product_search_form_index ) ) {
2036
			$product_search_form_index = 0;
2037
		}
2038
2039
		do_action( 'pre_get_product_search_form'  );
2040
2041
		wc_get_template( 'product-searchform.php', array(
2042
			'index' => $product_search_form_index++,
2043
		) );
2044
2045
		$form = apply_filters( 'get_product_search_form', ob_get_clean() );
2046
2047
		if ( $echo ) {
2048
			echo $form;
2049
		} else {
2050
			return $form;
2051
		}
2052
	}
2053
}
2054
2055
if ( ! function_exists( 'woocommerce_output_auth_header' ) ) {
2056
2057
	/**
2058
	 * Output the Auth header.
2059
	 */
2060
	function woocommerce_output_auth_header() {
2061
		wc_get_template( 'auth/header.php' );
2062
	}
2063
}
2064
2065
if ( ! function_exists( 'woocommerce_output_auth_footer' ) ) {
2066
2067
	/**
2068
	 * Output the Auth footer.
2069
	 */
2070
	function woocommerce_output_auth_footer() {
2071
		wc_get_template( 'auth/footer.php' );
2072
	}
2073
}
2074
2075
if ( ! function_exists( 'woocommerce_single_variation' ) ) {
2076
2077
	/**
2078
	 * Output placeholders for the single variation.
2079
	 */
2080
	function woocommerce_single_variation() {
2081
		echo '<div class="woocommerce-variation single_variation"></div>';
2082
	}
2083
}
2084
2085
if ( ! function_exists( 'woocommerce_single_variation_add_to_cart_button' ) ) {
2086
2087
	/**
2088
	 * Output the add to cart button for variations.
2089
	 */
2090
	function woocommerce_single_variation_add_to_cart_button() {
2091
		wc_get_template( 'single-product/add-to-cart/variation-add-to-cart-button.php' );
2092
	}
2093
}
2094
2095
if ( ! function_exists( 'wc_dropdown_variation_attribute_options' ) ) {
2096
2097
	/**
2098
	 * Output a list of variation attributes for use in the cart forms.
2099
	 *
2100
	 * @param array $args
2101
	 * @since 2.4.0
2102
	 */
2103
	function wc_dropdown_variation_attribute_options( $args = array() ) {
2104
		$args = wp_parse_args( apply_filters( 'woocommerce_dropdown_variation_attribute_options_args', $args ), array(
2105
			'options'          => false,
2106
			'attribute'        => false,
2107
			'product'          => false,
2108
			'selected' 	       => false,
2109
			'name'             => '',
2110
			'id'               => '',
2111
			'class'            => '',
2112
			'show_option_none' => __( 'Choose an option', 'woocommerce' )
2113
		) );
2114
2115
		$options   = $args['options'];
2116
		$product   = $args['product'];
2117
		$attribute = $args['attribute'];
2118
		$name      = $args['name'] ? $args['name'] : 'attribute_' . sanitize_title( $attribute );
2119
		$id        = $args['id'] ? $args['id'] : sanitize_title( $attribute );
2120
		$class     = $args['class'];
2121
2122
		if ( empty( $options ) && ! empty( $product ) && ! empty( $attribute ) ) {
2123
			$attributes = $product->get_variation_attributes();
2124
			$options    = $attributes[ $attribute ];
2125
		}
2126
2127
		$html = '<select id="' . esc_attr( $id ) . '" class="' . esc_attr( $class ) . '" name="' . esc_attr( $name ) . '" data-attribute_name="attribute_' . esc_attr( sanitize_title( $attribute ) ) . '">';
2128
2129
		if ( $args['show_option_none'] ) {
2130
			$html .= '<option value="">' . esc_html( $args['show_option_none'] ) . '</option>';
2131
		}
2132
2133
		if ( ! empty( $options ) ) {
2134
			if ( $product && taxonomy_exists( $attribute ) ) {
2135
				// Get terms if this is a taxonomy - ordered. We need the names too.
2136
				$terms = wc_get_product_terms( $product->id, $attribute, array( 'fields' => 'all' ) );
2137
2138 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...
2139
					if ( in_array( $term->slug, $options ) ) {
2140
						$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>';
2141
					}
2142
				}
2143
			} else {
2144
				foreach ( $options as $option ) {
2145
					// This handles < 2.4.0 bw compatibility where text attributes were not sanitized.
2146
					$selected = sanitize_title( $args['selected'] ) === $args['selected'] ? selected( $args['selected'], sanitize_title( $option ), false ) : selected( $args['selected'], $option, false );
2147
					$html .= '<option value="' . esc_attr( $option ) . '" ' . $selected . '>' . esc_html( apply_filters( 'woocommerce_variation_option_name', $option ) ) . '</option>';
2148
				}
2149
			}
2150
		}
2151
2152
		$html .= '</select>';
2153
2154
		echo apply_filters( 'woocommerce_dropdown_variation_attribute_options_html', $html, $args );
2155
	}
2156
}
2157
2158
if ( ! function_exists( 'woocommerce_account_content' ) ) {
2159
2160
	/**
2161
	 * My Account content output.
2162
	 */
2163
	function woocommerce_account_content() {
2164
		global $wp;
2165
2166
		foreach ( $wp->query_vars as $key => $value ) {
2167
			// Ignore pagename param.
2168
			if ( 'pagename' === $key ) {
2169
				continue;
2170
			}
2171
2172
			if ( has_action( 'woocommerce_account_' . $key . '_endpoint' ) ) {
2173
				do_action( 'woocommerce_account_' . $key . '_endpoint', $value );
2174
				return;
2175
			}
2176
		}
2177
2178
		// No endpoint found? Default to dashboard.
2179
		wc_get_template( 'myaccount/dashboard.php', array(
2180
			'current_user' => get_user_by( 'id', get_current_user_id() ),
2181
		) );
2182
	}
2183
}
2184
2185
if ( ! function_exists( 'woocommerce_account_navigation' ) ) {
2186
2187
	/**
2188
	 * My Account navigation template.
2189
	 */
2190
	function woocommerce_account_navigation() {
2191
		wc_get_template( 'myaccount/navigation.php' );
2192
	}
2193
}
2194
2195
if ( ! function_exists( 'woocommerce_account_orders' ) ) {
2196
2197
	/**
2198
	 * My Account > Orders template.
2199
	 *
2200
	 * @param int $current_page Current page number.
2201
	 */
2202
	function woocommerce_account_orders( $current_page ) {
2203
		$current_page    = empty( $current_page ) ? 1 : absint( $current_page );
2204
		$customer_orders = wc_get_orders( apply_filters( 'woocommerce_my_account_my_orders_query', array( 'customer' => get_current_user_id(), 'page' => $current_page, 'paginate' => true ) ) );
2205
2206
		wc_get_template(
2207
			'myaccount/orders.php',
2208
			array(
2209
				'current_page' => absint( $current_page ),
2210
				'customer_orders' => $customer_orders,
2211
				'has_orders' => 0 < $customer_orders->total,
2212
			)
2213
		);
2214
	}
2215
}
2216
2217
if ( ! function_exists( 'woocommerce_account_view_order' ) ) {
2218
2219
	/**
2220
	 * My Account > View order template.
2221
	 *
2222
	 * @param int $order_id Order ID.
2223
	 */
2224
	function woocommerce_account_view_order( $order_id ) {
2225
		WC_Shortcode_My_Account::view_order( absint( $order_id ) );
2226
	}
2227
}
2228
2229
if ( ! function_exists( 'woocommerce_account_downloads' ) ) {
2230
2231
	/**
2232
	 * My Account > Downloads template.
2233
	 */
2234
	function woocommerce_account_downloads() {
2235
		wc_get_template( 'myaccount/downloads.php' );
2236
	}
2237
}
2238
2239
if ( ! function_exists( 'woocommerce_account_edit_address' ) ) {
2240
2241
	/**
2242
	 * My Account > Edit address template.
2243
	 *
2244
	 * @param string $type Address type.
2245
	 */
2246
	function woocommerce_account_edit_address( $type ) {
2247
		$type = wc_edit_address_i18n( sanitize_title( $type ), true );
2248
2249
		WC_Shortcode_My_Account::edit_address( $type );
2250
	}
2251
}
2252
2253
if ( ! function_exists( 'woocommerce_account_payment_methods' ) ) {
2254
2255
	/**
2256
	 * My Account > Downloads template.
2257
	 */
2258
	function woocommerce_account_payment_methods() {
2259
		wc_get_template( 'myaccount/payment-methods.php' );
2260
	}
2261
}
2262
2263
if ( ! function_exists( 'woocommerce_account_add_payment_method' ) ) {
2264
2265
	/**
2266
	 * My Account > Add payment method template.
2267
	 */
2268
	function woocommerce_account_add_payment_method() {
2269
		WC_Shortcode_My_Account::add_payment_method();
2270
	}
2271
}
2272
2273
if ( ! function_exists( 'woocommerce_account_edit_account' ) ) {
2274
2275
	/**
2276
	 * My Account > Edit account template.
2277
	 */
2278
	function woocommerce_account_edit_account() {
2279
		WC_Shortcode_My_Account::edit_account();
2280
	}
2281
}
2282
2283
if ( ! function_exists( 'wc_no_products_found' ) ) {
2284
2285
	/**
2286
	 * Show no products found message.
2287
	 */
2288
	function wc_no_products_found() {
2289
		wc_get_template( 'loop/no-products-found.php' );
2290
	}
2291
}
2292
2293
2294
if ( ! function_exists( 'wc_get_email_order_items' ) ) {
2295
	/**
2296
	 * Get HTML for the order items to be shown in emails.
2297
	 * @param WC_Order $order
2298
	 * @param array $args
2299
	 * @since 2.7.0
2300
	 */
2301
	function wc_get_email_order_items( $order, $args = array() ) {
2302
		ob_start();
2303
2304
		$defaults = array(
2305
			'show_sku'      => false,
2306
			'show_image'    => false,
2307
			'image_size'    => array( 32, 32 ),
2308
			'plain_text'    => false,
2309
			'sent_to_admin' => false,
2310
		);
2311
2312
		$args     = wp_parse_args( $args, $defaults );
2313
		$template = $args['plain_text'] ? 'emails/plain/email-order-items.php' : 'emails/email-order-items.php';
2314
2315
		wc_get_template( $template, array(
2316
			'order'               => $order,
2317
			'items'               => $order->get_items(),
2318
			'show_download_links' => $order->is_download_permitted(),
2319
			'show_sku'            => $args['show_sku'],
2320
			'show_purchase_note'  => $order->is_paid(),
2321
			'show_image'          => $args['show_image'],
2322
			'image_size'          => $args['image_size'],
2323
			'plain_text'          => $args['plain_text'],
2324
			'sent_to_admin'       => $args['sent_to_admin'],
2325
		) );
2326
2327
		return apply_filters( 'woocommerce_email_order_items_table', ob_get_clean(), $order );
2328
	}
2329
}
2330
2331
if ( ! function_exists( 'wc_display_item_meta' ) ) {
2332
	/**
2333
	 * Display item meta data.
2334
	 * @since  2.7.0
2335
	 * @param  WC_Item $item
2336
	 * @param  array   $args
2337
	 * @return string|void
2338
	 */
2339
	function wc_display_item_meta( $item, $args = array() ) {
2340
		$strings = array();
2341
		$html    = '';
2342
		$args    = wp_parse_args( $args, array(
2343
			'before'    => '<ul class="wc-item-meta"><li>',
2344
			'after'     => '</li></ul>',
2345
			'separator' => '</li><li>',
2346
			'echo'      => true,
2347
			'autop'     => false,
2348
		) );
2349
2350
		foreach ( $item->get_formatted_meta_data() as $meta_id => $meta ) {
2351
			if ( '_' === substr( $meta->key, 0, 1 ) ) {
2352
				continue;
2353
			}
2354
			$value = $args['autop'] ? wp_kses_post( wpautop( make_clickable( $meta->display_value ) ) ) : wp_kses_post( make_clickable( $meta->display_value ) );
2355
			$strings[] = '<strong class="wc-item-meta-label">' . wp_kses_post( $meta->display_key ) . ':</strong> ' . $value;
2356
		}
2357
2358 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...
2359
			$html = $args['before'] . implode( $args['separator'], $strings ) . $args['after'];
2360
		}
2361
2362
		$html = apply_filters( 'woocommerce_display_item_meta', $html, $item, $args );
2363
2364
		if ( $args['echo'] ) {
2365
			echo $html;
2366
		} else {
2367
			return $html;
2368
		}
2369
	}
2370
}
2371
2372
if ( ! function_exists( 'wc_display_item_downloads' ) ) {
2373
	/**
2374
	 * Display item download links.
2375
	 * @since  2.7.0
2376
	 * @param  WC_Item $item
2377
	 * @param  array   $args
2378
	 * @return string|void
2379
	 */
2380
	function wc_display_item_downloads( $item, $args = array() ) {
2381
		$strings = array();
2382
		$html    = '';
2383
		$args    = wp_parse_args( $args, array(
2384
			'before'    => '<ul class ="wc-item-downloads"><li>',
2385
			'after'     => '</li></ul>',
2386
			'separator' => '</li><li>',
2387
			'echo'      => true,
2388
			'show_url'  => false,
2389
		) );
2390
2391
		if ( is_object( $item ) && $item->is_type( 'line_item' ) && ( $downloads = $item->get_item_downloads() ) ) {
2392
			$i = 0;
2393
			foreach ( $downloads as $file ) {
2394
				$i ++;
2395
2396
				if ( $args['show_url'] ) {
2397
					$strings[] = '<strong class="wc-item-download-label">' .  esc_html( $file['name'] ) . ':</strong> ' . esc_html( $file['download_url'] );
2398
				} else {
2399
					$prefix = sizeof( $downloads ) > 1 ? sprintf( __( 'Download %d', 'woocommerce' ), $i ) : __( 'Download', 'woocommerce' );
2400
					$strings[] = '<strong class="wc-item-download-label">' . $prefix . ':</strong> <a href="' . esc_url( $file['download_url'] ) . '" target="_blank">' . esc_html( $file['name'] ) . '</a>';
2401
				}
2402
			}
2403
		}
2404
2405 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...
2406
			$html = $args['before'] . implode( $args['separator'], $strings ) . $args['after'];
2407
		}
2408
2409
		$html = apply_filters( 'woocommerce_display_item_downloads', $html, $item, $args );
2410
2411
		if ( $args['echo'] ) {
2412
			echo $html;
2413
		} else {
2414
			return $html;
2415
		}
2416
	}
2417
}
2418