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

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

Complexity

Conditions 4
Paths 4

Size

Total Lines 22
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

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

1 Method

Rating   Name   Duplication   Size   Complexity  
A wc-template-functions.php ➔ woocommerce_get_product_thumbnail() 0 14 3
1
<?php
2
/**
3
 * WooCommerce Template
4
 *
5
 * Functions for the templating system.
6
 *
7
 * @author   WooThemes
8
 * @category Core
9
 * @package  WooCommerce/Functions
10
 * @version  2.5.0
11
 */
12
13
if ( ! defined( 'ABSPATH' ) ) {
14
	exit; // Exit if accessed directly
15
}
16
17
/**
18
 * Handle redirects before content is output - hooked into template_redirect so is_page works.
19
 */
20
function wc_template_redirect() {
21
	global $wp_query, $wp;
22
23
	// 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
		do_action( 'woocommerce_breadcrumb', $args );
1478
1479
		wc_get_template( 'global/breadcrumb.php', $args );
1480
	}
1481
}
1482
1483
if ( ! function_exists( 'woocommerce_order_review' ) ) {
1484
1485
	/**
1486
	 * Output the Order review table for the checkout.
1487
	 *
1488
	 * @subpackage	Checkout
1489
	 */
1490
	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...
1491
		wc_get_template( 'checkout/review-order.php', array( 'checkout' => WC()->checkout() ) );
1492
	}
1493
}
1494
1495
if ( ! function_exists( 'woocommerce_checkout_payment' ) ) {
1496
1497
	/**
1498
	 * Output the Payment Methods on the checkout.
1499
	 *
1500
	 * @subpackage	Checkout
1501
	 */
1502
	function woocommerce_checkout_payment() {
1503
		if ( WC()->cart->needs_payment() ) {
1504
			$available_gateways = WC()->payment_gateways()->get_available_payment_gateways();
1505
			WC()->payment_gateways()->set_current_gateway( $available_gateways );
1506
		} else {
1507
			$available_gateways = array();
1508
		}
1509
1510
		wc_get_template( 'checkout/payment.php', array(
1511
			'checkout'           => WC()->checkout(),
1512
			'available_gateways' => $available_gateways,
1513
			'order_button_text'  => apply_filters( 'woocommerce_order_button_text', __( 'Place order', 'woocommerce' ) )
1514
		) );
1515
	}
1516
}
1517
1518
if ( ! function_exists( 'woocommerce_checkout_coupon_form' ) ) {
1519
1520
	/**
1521
	 * Output the Coupon form for the checkout.
1522
	 *
1523
	 * @subpackage	Checkout
1524
	 */
1525
	function woocommerce_checkout_coupon_form() {
1526
		wc_get_template( 'checkout/form-coupon.php', array( 'checkout' => WC()->checkout() ) );
1527
	}
1528
}
1529
1530
if ( ! function_exists( 'woocommerce_products_will_display' ) ) {
1531
1532
	/**
1533
	 * Check if we will be showing products or not (and not sub-categories only).
1534
	 * @subpackage	Loop
1535
	 * @return bool
1536
	 */
1537
	function woocommerce_products_will_display() {
1538
		global $wpdb;
1539
1540
		if ( is_shop() ) {
1541
			return 'subcategories' !== get_option( 'woocommerce_shop_page_display' ) || is_search();
1542
		}
1543
1544
		if ( ! is_product_taxonomy() ) {
1545
			return false;
1546
		}
1547
1548
		if ( is_search() || is_filtered() || is_paged() ) {
1549
			return true;
1550
		}
1551
1552
		$term = get_queried_object();
1553
1554
		if ( is_product_category() ) {
1555
			switch ( get_woocommerce_term_meta( $term->term_id, 'display_type', true ) ) {
1556
				case 'subcategories' :
1557
					// Nothing - we want to continue to see if there are products/subcats
1558
				break;
1559
				case 'products' :
1560
				case 'both' :
1561
					return true;
1562
				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...
1563
				default :
1564
					// Default - no setting
1565
					if ( get_option( 'woocommerce_category_archive_display' ) != 'subcategories' ) {
1566
						return true;
1567
					}
1568
				break;
1569
			}
1570
		}
1571
1572
		// Begin subcategory logic
1573
		if ( empty( $term->term_id ) || empty( $term->taxonomy ) ) {
1574
			return true;
1575
		}
1576
1577
		$transient_name = 'wc_products_will_display_' . $term->term_id . '_' . WC_Cache_Helper::get_transient_version( 'product_query' );
1578
1579
		if ( false === ( $products_will_display = get_transient( $transient_name ) ) ) {
1580
			$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 ) );
1581
1582
			if ( $has_children ) {
1583
				// Check terms have products inside - parents first. If products are found inside, subcats will be shown instead of products so we can return false.
1584
				if ( sizeof( get_objects_in_term( $has_children, $term->taxonomy ) ) > 0 ) {
1585
					$products_will_display = false;
1586
				} else {
1587
					// If we get here, the parents were empty so we're forced to check children
1588
					foreach ( $has_children as $term_id ) {
1589
						$children = get_term_children( $term_id, $term->taxonomy );
1590
1591
						if ( sizeof( get_objects_in_term( $children, $term->taxonomy ) ) > 0 ) {
1592
							$products_will_display = false;
1593
							break;
1594
						}
1595
					}
1596
				}
1597
			} else {
1598
				$products_will_display = true;
1599
			}
1600
		}
1601
1602
		set_transient( $transient_name, $products_will_display, DAY_IN_SECONDS * 30 );
1603
1604
		return $products_will_display;
1605
	}
1606
}
1607
1608
if ( ! function_exists( 'woocommerce_product_subcategories' ) ) {
1609
1610
	/**
1611
	 * Display product sub categories as thumbnails.
1612
	 *
1613
	 * @subpackage	Loop
1614
	 * @param array $args
1615
	 * @return null|boolean
1616
	 */
1617
	function woocommerce_product_subcategories( $args = array() ) {
1618
		global $wp_query;
1619
1620
		$defaults = array(
1621
			'before'        => '',
1622
			'after'         => '',
1623
			'force_display' => false
1624
		);
1625
1626
		$args = wp_parse_args( $args, $defaults );
1627
1628
		extract( $args );
1629
1630
		// Main query only
1631
		if ( ! is_main_query() && ! $force_display ) {
1632
			return;
1633
		}
1634
1635
		// Don't show when filtering, searching or when on page > 1 and ensure we're on a product archive
1636
		if ( is_search() || is_filtered() || is_paged() || ( ! is_product_category() && ! is_shop() ) ) {
1637
			return;
1638
		}
1639
1640
		// Check categories are enabled
1641
		if ( is_shop() && '' === get_option( 'woocommerce_shop_page_display' ) ) {
1642
			return;
1643
		}
1644
1645
		// Find the category + category parent, if applicable
1646
		$term 			= get_queried_object();
1647
		$parent_id 		= empty( $term->term_id ) ? 0 : $term->term_id;
1648
1649
		if ( is_product_category() ) {
1650
			$display_type = get_woocommerce_term_meta( $term->term_id, 'display_type', true );
1651
1652
			switch ( $display_type ) {
1653
				case 'products' :
1654
					return;
1655
				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...
1656
				case '' :
1657
					if ( '' === get_option( 'woocommerce_category_archive_display' ) ) {
1658
						return;
1659
					}
1660
				break;
1661
			}
1662
		}
1663
1664
		// 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
1665
		$product_categories = get_categories( apply_filters( 'woocommerce_product_subcategories_args', array(
1666
			'parent'       => $parent_id,
1667
			'menu_order'   => 'ASC',
1668
			'hide_empty'   => 0,
1669
			'hierarchical' => 1,
1670
			'taxonomy'     => 'product_cat',
1671
			'pad_counts'   => 1
1672
		) ) );
1673
1674
		if ( ! apply_filters( 'woocommerce_product_subcategories_hide_empty', false ) ) {
1675
			$product_categories = wp_list_filter( $product_categories, array( 'count' => 0 ), 'NOT' );
1676
		}
1677
1678
		if ( $product_categories ) {
1679
			echo $before;
1680
1681
			foreach ( $product_categories as $category ) {
1682
				wc_get_template( 'content-product_cat.php', array(
1683
					'category' => $category
1684
				) );
1685
			}
1686
1687
			// If we are hiding products disable the loop and pagination
1688
			if ( is_product_category() ) {
1689
				$display_type = get_woocommerce_term_meta( $term->term_id, 'display_type', true );
1690
1691
				switch ( $display_type ) {
1692
					case 'subcategories' :
1693
						$wp_query->post_count    = 0;
1694
						$wp_query->max_num_pages = 0;
1695
					break;
1696
					case '' :
1697
						if ( 'subcategories' === get_option( 'woocommerce_category_archive_display' ) ) {
1698
							$wp_query->post_count    = 0;
1699
							$wp_query->max_num_pages = 0;
1700
						}
1701
					break;
1702
				}
1703
			}
1704
1705
			if ( is_shop() && 'subcategories' === get_option( 'woocommerce_shop_page_display' ) ) {
1706
				$wp_query->post_count    = 0;
1707
				$wp_query->max_num_pages = 0;
1708
			}
1709
1710
			echo $after;
1711
1712
			return true;
1713
		}
1714
	}
1715
}
1716
1717
if ( ! function_exists( 'woocommerce_subcategory_thumbnail' ) ) {
1718
1719
	/**
1720
	 * Show subcategory thumbnails.
1721
	 *
1722
	 * @param mixed $category
1723
	 * @subpackage	Loop
1724
	 */
1725
	function woocommerce_subcategory_thumbnail( $category ) {
1726
		$small_thumbnail_size  	= apply_filters( 'subcategory_archive_thumbnail_size', 'shop_catalog' );
1727
		$dimensions    			= wc_get_image_size( $small_thumbnail_size );
1728
		$thumbnail_id  			= get_woocommerce_term_meta( $category->term_id, 'thumbnail_id', true  );
1729
1730
		if ( $thumbnail_id ) {
1731
			$image        = wp_get_attachment_image_src( $thumbnail_id, $small_thumbnail_size  );
1732
			$image        = $image[0];
1733
			$image_srcset = function_exists( 'wp_get_attachment_image_srcset' ) ? wp_get_attachment_image_srcset( $thumbnail_id, $small_thumbnail_size ) : false;
1734
			$image_sizes  = function_exists( 'wp_get_attachment_image_sizes' ) ? wp_get_attachment_image_sizes( $thumbnail_id, $small_thumbnail_size ) : false;
1735
		} else {
1736
			$image        = wc_placeholder_img_src();
1737
			$image_srcset = $image_sizes = false;
1738
		}
1739
1740
		if ( $image ) {
1741
			// Prevent esc_url from breaking spaces in urls for image embeds
1742
			// Ref: https://core.trac.wordpress.org/ticket/23605
1743
			$image = str_replace( ' ', '%20', $image );
1744
1745
			// Add responsive image markup if available
1746
			if ( $image_srcset && $image_sizes ) {
1747
				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 ) . '" />';
1748
			} else {
1749
				echo '<img src="' . esc_url( $image ) . '" alt="' . esc_attr( $category->name ) . '" width="' . esc_attr( $dimensions['width'] ) . '" height="' . esc_attr( $dimensions['height'] ) . '" />';
1750
			}
1751
		}
1752
	}
1753
}
1754
1755
if ( ! function_exists( 'woocommerce_order_details_table' ) ) {
1756
1757
	/**
1758
	 * Displays order details in a table.
1759
	 *
1760
	 * @param mixed $order_id
1761
	 * @subpackage	Orders
1762
	 */
1763
	function woocommerce_order_details_table( $order_id ) {
1764
		if ( ! $order_id ) return;
1765
1766
		wc_get_template( 'order/order-details.php', array(
1767
			'order_id' => $order_id
1768
		) );
1769
	}
1770
}
1771
1772
1773
if ( ! function_exists( 'woocommerce_order_again_button' ) ) {
1774
1775
	/**
1776
	 * Display an 'order again' button on the view order page.
1777
	 *
1778
	 * @param object $order
1779
	 * @subpackage	Orders
1780
	 */
1781
	function woocommerce_order_again_button( $order ) {
1782
		if ( ! $order || ! $order->has_status( 'completed' ) || ! is_user_logged_in() ) {
1783
			return;
1784
		}
1785
1786
		wc_get_template( 'order/order-again.php', array(
1787
			'order' => $order
1788
		) );
1789
	}
1790
}
1791
1792
/** Forms ****************************************************************/
1793
1794
if ( ! function_exists( 'woocommerce_form_field' ) ) {
1795
1796
	/**
1797
	 * Outputs a checkout/address form field.
1798
	 *
1799
	 * @subpackage	Forms
1800
	 * @param string $key
1801
	 * @param mixed $args
1802
	 * @param string $value (default: null)
1803
	 * @todo This function needs to be broken up in smaller pieces
1804
	 */
1805
	function woocommerce_form_field( $key, $args, $value = null ) {
1806
		$defaults = array(
1807
			'type'              => 'text',
1808
			'label'             => '',
1809
			'description'       => '',
1810
			'placeholder'       => '',
1811
			'maxlength'         => false,
1812
			'required'          => false,
1813
			'autocomplete'      => false,
1814
			'id'                => $key,
1815
			'class'             => array(),
1816
			'label_class'       => array(),
1817
			'input_class'       => array(),
1818
			'return'            => false,
1819
			'options'           => array(),
1820
			'custom_attributes' => array(),
1821
			'validate'          => array(),
1822
			'default'           => '',
1823
		);
1824
1825
		$args = wp_parse_args( $args, $defaults );
1826
		$args = apply_filters( 'woocommerce_form_field_args', $args, $key, $value );
1827
1828
		if ( $args['required'] ) {
1829
			$args['class'][] = 'validate-required';
1830
			$required = ' <abbr class="required" title="' . esc_attr__( 'required', 'woocommerce'  ) . '">*</abbr>';
1831
		} else {
1832
			$required = '';
1833
		}
1834
1835
		$args['maxlength'] = ( $args['maxlength'] ) ? 'maxlength="' . absint( $args['maxlength'] ) . '"' : '';
1836
1837
		$args['autocomplete'] = ( $args['autocomplete'] ) ? 'autocomplete="' . esc_attr( $args['autocomplete'] ) . '"' : '';
1838
1839
		if ( is_string( $args['label_class'] ) ) {
1840
			$args['label_class'] = array( $args['label_class'] );
1841
		}
1842
1843
		if ( is_null( $value ) ) {
1844
			$value = $args['default'];
1845
		}
1846
1847
		// Custom attribute handling
1848
		$custom_attributes = array();
1849
1850 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...
1851
			foreach ( $args['custom_attributes'] as $attribute => $attribute_value ) {
1852
				$custom_attributes[] = esc_attr( $attribute ) . '="' . esc_attr( $attribute_value ) . '"';
1853
			}
1854
		}
1855
1856
		if ( ! empty( $args['validate'] ) ) {
1857
			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...
1858
				$args['class'][] = 'validate-' . $validate;
1859
			}
1860
		}
1861
1862
		$field = '';
1863
		$label_id = $args['id'];
1864
		$field_container = '<p class="form-row %1$s" id="%2$s">%3$s</p>';
1865
1866
		switch ( $args['type'] ) {
1867
			case 'country' :
1868
1869
				$countries = 'shipping_country' === $key ? WC()->countries->get_shipping_countries() : WC()->countries->get_allowed_countries();
1870
1871
				if ( 1 === sizeof( $countries ) ) {
1872
1873
					$field .= '<strong>' . current( array_values( $countries ) ) . '</strong>';
1874
1875
					$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" />';
1876
1877
				} else {
1878
1879
					$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 ) . '>'
1880
							. '<option value="">'.__( 'Select a country&hellip;', 'woocommerce' ) .'</option>';
1881
1882 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...
1883
						$field .= '<option value="' . esc_attr( $ckey ) . '" '. selected( $value, $ckey, false ) . '>'. __( $cvalue, 'woocommerce' ) .'</option>';
1884
					}
1885
1886
					$field .= '</select>';
1887
1888
					$field .= '<noscript><input type="submit" name="woocommerce_checkout_update_totals" value="' . esc_attr__( 'Update country', 'woocommerce' ) . '" /></noscript>';
1889
1890
				}
1891
1892
				break;
1893
			case 'state' :
1894
1895
				/* Get Country */
1896
				$country_key = 'billing_state' === $key ? 'billing_country' : 'shipping_country';
1897
				$current_cc  = WC()->checkout->get_value( $country_key );
1898
				$states      = WC()->countries->get_states( $current_cc );
1899
1900
				if ( is_array( $states ) && empty( $states ) ) {
1901
1902
					$field_container = '<p class="form-row %1$s" id="%2$s" style="display: none">%3$s</p>';
1903
1904
					$field .= '<input type="hidden" class="hidden" name="' . esc_attr( $key )  . '" id="' . esc_attr( $args['id'] ) . '" value="" ' . implode( ' ', $custom_attributes ) . ' placeholder="' . esc_attr( $args['placeholder'] ) . '" />';
1905
1906
				} elseif ( is_array( $states ) ) {
1907
1908
					$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'] . '>
1909
						<option value="">'.__( 'Select a state&hellip;', 'woocommerce' ) .'</option>';
1910
1911 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...
1912
						$field .= '<option value="' . esc_attr( $ckey ) . '" '.selected( $value, $ckey, false ) .'>'.__( $cvalue, 'woocommerce' ) .'</option>';
1913
					}
1914
1915
					$field .= '</select>';
1916
1917
				} else {
1918
1919
					$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 ) . ' />';
1920
1921
				}
1922
1923
				break;
1924
			case 'textarea' :
1925
1926
				$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>';
1927
1928
				break;
1929 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...
1930
1931
				$field = '<label class="checkbox ' . implode( ' ', $args['label_class'] ) .'" ' . implode( ' ', $custom_attributes ) . '>
1932
						<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 ) .' /> '
1933
						 . $args['label'] . $required . '</label>';
1934
1935
				break;
1936
			case 'password' :
1937
			case 'text' :
1938
			case 'email' :
1939
			case 'tel' :
1940 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...
1941
1942
				$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 ) . ' />';
1943
1944
				break;
1945
			case 'select' :
1946
1947
				$options = $field = '';
1948
1949
				if ( ! empty( $args['options'] ) ) {
1950
					foreach ( $args['options'] as $option_key => $option_text ) {
1951
						if ( '' === $option_key ) {
1952
							// If we have a blank option, select2 needs a placeholder
1953
							if ( empty( $args['placeholder'] ) ) {
1954
								$args['placeholder'] = $option_text ? $option_text : __( 'Choose an option', 'woocommerce' );
1955
							}
1956
							$custom_attributes[] = 'data-allow_clear="true"';
1957
						}
1958
						$options .= '<option value="' . esc_attr( $option_key ) . '" '. selected( $value, $option_key, false ) . '>' . esc_attr( $option_text ) .'</option>';
1959
					}
1960
1961
					$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'] . '>
1962
							' . $options . '
1963
						</select>';
1964
				}
1965
1966
				break;
1967
			case 'radio' :
1968
1969
				$label_id = current( array_keys( $args['options'] ) );
1970
1971
				if ( ! empty( $args['options'] ) ) {
1972
					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...
1973
						$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 ) . ' />';
1974
						$field .= '<label for="' . esc_attr( $args['id'] ) . '_' . esc_attr( $option_key ) . '" class="radio ' . implode( ' ', $args['label_class'] ) .'">' . $option_text . '</label>';
1975
					}
1976
				}
1977
1978
				break;
1979
		}
1980
1981
		if ( ! empty( $field ) ) {
1982
			$field_html = '';
1983
1984
			if ( $args['label'] && 'checkbox' != $args['type'] ) {
1985
				$field_html .= '<label for="' . esc_attr( $label_id ) . '" class="' . esc_attr( implode( ' ', $args['label_class'] ) ) .'">' . $args['label'] . $required . '</label>';
1986
			}
1987
1988
			$field_html .= $field;
1989
1990
			if ( $args['description'] ) {
1991
				$field_html .= '<span class="description">' . esc_html( $args['description'] ) . '</span>';
1992
			}
1993
1994
			$container_class = 'form-row ' . esc_attr( implode( ' ', $args['class'] ) );
1995
			$container_id = esc_attr( $args['id'] ) . '_field';
1996
1997
			$after = ! empty( $args['clear'] ) ? '<div class="clear"></div>' : '';
1998
1999
			$field = sprintf( $field_container, $container_class, $container_id, $field_html ) . $after;
2000
		}
2001
2002
		$field = apply_filters( 'woocommerce_form_field_' . $args['type'], $field, $key, $args, $value );
2003
2004
		if ( $args['return'] ) {
2005
			return $field;
2006
		} else {
2007
			echo $field;
2008
		}
2009
	}
2010
}
2011
2012
if ( ! function_exists( 'get_product_search_form' ) ) {
2013
2014
	/**
2015
	 * Display product search form.
2016
	 *
2017
	 * Will first attempt to locate the product-searchform.php file in either the child or.
2018
	 * the parent, then load it. If it doesn't exist, then the default search form.
2019
	 * will be displayed.
2020
	 *
2021
	 * The default searchform uses html5.
2022
	 *
2023
	 * @subpackage	Forms
2024
	 * @param bool $echo (default: true)
2025
	 * @return string
2026
	 */
2027
	function get_product_search_form( $echo = true  ) {
2028
		global $product_search_form_index;
2029
2030
		ob_start();
2031
2032
		if ( empty( $product_search_form_index ) ) {
2033
			$product_search_form_index = 0;
2034
		}
2035
2036
		do_action( 'pre_get_product_search_form'  );
2037
2038
		wc_get_template( 'product-searchform.php', array(
2039
			'index' => $product_search_form_index++,
2040
		) );
2041
2042
		$form = apply_filters( 'get_product_search_form', ob_get_clean() );
2043
2044
		if ( $echo ) {
2045
			echo $form;
2046
		} else {
2047
			return $form;
2048
		}
2049
	}
2050
}
2051
2052
if ( ! function_exists( 'woocommerce_output_auth_header' ) ) {
2053
2054
	/**
2055
	 * Output the Auth header.
2056
	 */
2057
	function woocommerce_output_auth_header() {
2058
		wc_get_template( 'auth/header.php' );
2059
	}
2060
}
2061
2062
if ( ! function_exists( 'woocommerce_output_auth_footer' ) ) {
2063
2064
	/**
2065
	 * Output the Auth footer.
2066
	 */
2067
	function woocommerce_output_auth_footer() {
2068
		wc_get_template( 'auth/footer.php' );
2069
	}
2070
}
2071
2072
if ( ! function_exists( 'woocommerce_single_variation' ) ) {
2073
2074
	/**
2075
	 * Output placeholders for the single variation.
2076
	 */
2077
	function woocommerce_single_variation() {
2078
		echo '<div class="woocommerce-variation single_variation"></div>';
2079
	}
2080
}
2081
2082
if ( ! function_exists( 'woocommerce_single_variation_add_to_cart_button' ) ) {
2083
2084
	/**
2085
	 * Output the add to cart button for variations.
2086
	 */
2087
	function woocommerce_single_variation_add_to_cart_button() {
2088
		wc_get_template( 'single-product/add-to-cart/variation-add-to-cart-button.php' );
2089
	}
2090
}
2091
2092
if ( ! function_exists( 'wc_dropdown_variation_attribute_options' ) ) {
2093
2094
	/**
2095
	 * Output a list of variation attributes for use in the cart forms.
2096
	 *
2097
	 * @param array $args
2098
	 * @since 2.4.0
2099
	 */
2100
	function wc_dropdown_variation_attribute_options( $args = array() ) {
2101
		$args = wp_parse_args( apply_filters( 'woocommerce_dropdown_variation_attribute_options_args', $args ), array(
2102
			'options'          => false,
2103
			'attribute'        => false,
2104
			'product'          => false,
2105
			'selected' 	       => false,
2106
			'name'             => '',
2107
			'id'               => '',
2108
			'class'            => '',
2109
			'show_option_none' => __( 'Choose an option', 'woocommerce' )
2110
		) );
2111
2112
		$options   = $args['options'];
2113
		$product   = $args['product'];
2114
		$attribute = $args['attribute'];
2115
		$name      = $args['name'] ? $args['name'] : 'attribute_' . sanitize_title( $attribute );
2116
		$id        = $args['id'] ? $args['id'] : sanitize_title( $attribute );
2117
		$class     = $args['class'];
2118
2119
		if ( empty( $options ) && ! empty( $product ) && ! empty( $attribute ) ) {
2120
			$attributes = $product->get_variation_attributes();
2121
			$options    = $attributes[ $attribute ];
2122
		}
2123
2124
		$html = '<select id="' . esc_attr( $id ) . '" class="' . esc_attr( $class ) . '" name="' . esc_attr( $name ) . '" data-attribute_name="attribute_' . esc_attr( sanitize_title( $attribute ) ) . '">';
2125
2126
		if ( $args['show_option_none'] ) {
2127
			$html .= '<option value="">' . esc_html( $args['show_option_none'] ) . '</option>';
2128
		}
2129
2130
		if ( ! empty( $options ) ) {
2131
			if ( $product && taxonomy_exists( $attribute ) ) {
2132
				// Get terms if this is a taxonomy - ordered. We need the names too.
2133
				$terms = wc_get_product_terms( $product->id, $attribute, array( 'fields' => 'all' ) );
2134
2135 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...
2136
					if ( in_array( $term->slug, $options ) ) {
2137
						$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>';
2138
					}
2139
				}
2140
			} else {
2141
				foreach ( $options as $option ) {
2142
					// This handles < 2.4.0 bw compatibility where text attributes were not sanitized.
2143
					$selected = sanitize_title( $args['selected'] ) === $args['selected'] ? selected( $args['selected'], sanitize_title( $option ), false ) : selected( $args['selected'], $option, false );
2144
					$html .= '<option value="' . esc_attr( $option ) . '" ' . $selected . '>' . esc_html( apply_filters( 'woocommerce_variation_option_name', $option ) ) . '</option>';
2145
				}
2146
			}
2147
		}
2148
2149
		$html .= '</select>';
2150
2151
		echo apply_filters( 'woocommerce_dropdown_variation_attribute_options_html', $html, $args );
2152
	}
2153
}
2154
2155
if ( ! function_exists( 'woocommerce_account_content' ) ) {
2156
2157
	/**
2158
	 * My Account content output.
2159
	 */
2160
	function woocommerce_account_content() {
2161
		global $wp;
2162
2163
		foreach ( $wp->query_vars as $key => $value ) {
2164
			// Ignore pagename param.
2165
			if ( 'pagename' === $key ) {
2166
				continue;
2167
			}
2168
2169
			if ( has_action( 'woocommerce_account_' . $key . '_endpoint' ) ) {
2170
				do_action( 'woocommerce_account_' . $key . '_endpoint', $value );
2171
				return;
2172
			}
2173
		}
2174
2175
		// No endpoint found? Default to dashboard.
2176
		wc_get_template( 'myaccount/dashboard.php', array(
2177
			'current_user' => get_user_by( 'id', get_current_user_id() ),
2178
		) );
2179
	}
2180
}
2181
2182
if ( ! function_exists( 'woocommerce_account_navigation' ) ) {
2183
2184
	/**
2185
	 * My Account navigation template.
2186
	 */
2187
	function woocommerce_account_navigation() {
2188
		wc_get_template( 'myaccount/navigation.php' );
2189
	}
2190
}
2191
2192
if ( ! function_exists( 'woocommerce_account_orders' ) ) {
2193
2194
	/**
2195
	 * My Account > Orders template.
2196
	 *
2197
	 * @param int $current_page Current page number.
2198
	 */
2199
	function woocommerce_account_orders( $current_page ) {
2200
		$current_page    = empty( $current_page ) ? 1 : absint( $current_page );
2201
		$customer_orders = wc_get_orders( apply_filters( 'woocommerce_my_account_my_orders_query', array( 'customer' => get_current_user_id(), 'page' => $current_page, 'paginate' => true ) ) );
2202
2203
		wc_get_template(
2204
			'myaccount/orders.php',
2205
			array(
2206
				'current_page' => absint( $current_page ),
2207
				'customer_orders' => $customer_orders,
2208
				'has_orders' => 0 < $customer_orders->total,
2209
			)
2210
		);
2211
	}
2212
}
2213
2214
if ( ! function_exists( 'woocommerce_account_view_order' ) ) {
2215
2216
	/**
2217
	 * My Account > View order template.
2218
	 *
2219
	 * @param int $order_id Order ID.
2220
	 */
2221
	function woocommerce_account_view_order( $order_id ) {
2222
		WC_Shortcode_My_Account::view_order( absint( $order_id ) );
2223
	}
2224
}
2225
2226
if ( ! function_exists( 'woocommerce_account_downloads' ) ) {
2227
2228
	/**
2229
	 * My Account > Downloads template.
2230
	 */
2231
	function woocommerce_account_downloads() {
2232
		wc_get_template( 'myaccount/downloads.php' );
2233
	}
2234
}
2235
2236
if ( ! function_exists( 'woocommerce_account_edit_address' ) ) {
2237
2238
	/**
2239
	 * My Account > Edit address template.
2240
	 *
2241
	 * @param string $type Address type.
2242
	 */
2243
	function woocommerce_account_edit_address( $type ) {
2244
		$type = wc_edit_address_i18n( sanitize_title( $type ), true );
2245
2246
		WC_Shortcode_My_Account::edit_address( $type );
2247
	}
2248
}
2249
2250
if ( ! function_exists( 'woocommerce_account_payment_methods' ) ) {
2251
2252
	/**
2253
	 * My Account > Downloads template.
2254
	 */
2255
	function woocommerce_account_payment_methods() {
2256
		wc_get_template( 'myaccount/payment-methods.php' );
2257
	}
2258
}
2259
2260
if ( ! function_exists( 'woocommerce_account_add_payment_method' ) ) {
2261
2262
	/**
2263
	 * My Account > Add payment method template.
2264
	 */
2265
	function woocommerce_account_add_payment_method() {
2266
		WC_Shortcode_My_Account::add_payment_method();
2267
	}
2268
}
2269
2270
if ( ! function_exists( 'woocommerce_account_edit_account' ) ) {
2271
2272
	/**
2273
	 * My Account > Edit account template.
2274
	 */
2275
	function woocommerce_account_edit_account() {
2276
		WC_Shortcode_My_Account::edit_account();
2277
	}
2278
}
2279
2280
if ( ! function_exists( 'wc_no_products_found' ) ) {
2281
2282
	/**
2283
	 * Show no products found message.
2284
	 */
2285
	function wc_no_products_found() {
2286
		wc_get_template( 'loop/no-products-found.php' );
2287
	}
2288
}
2289
2290
2291
if ( ! function_exists( 'wc_get_email_order_items' ) ) {
2292
	/**
2293
	 * Get HTML for the order items to be shown in emails.
2294
	 * @param WC_Order $order
2295
	 * @param array $args
2296
	 * @since 2.7.0
2297
	 */
2298
	function wc_get_email_order_items( $order, $args = array() ) {
2299
		ob_start();
2300
2301
		$defaults = array(
2302
			'show_sku'      => false,
2303
			'show_image'    => false,
2304
			'image_size'    => array( 32, 32 ),
2305
			'plain_text'    => false,
2306
			'sent_to_admin' => false,
2307
		);
2308
2309
		$args     = wp_parse_args( $args, $defaults );
2310
		$template = $args['plain_text'] ? 'emails/plain/email-order-items.php' : 'emails/email-order-items.php';
2311
2312
		wc_get_template( $template, array(
2313
			'order'               => $order,
2314
			'items'               => $order->get_items(),
2315
			'show_download_links' => $order->is_download_permitted(),
2316
			'show_sku'            => $args['show_sku'],
2317
			'show_purchase_note'  => $order->is_paid(),
2318
			'show_image'          => $args['show_image'],
2319
			'image_size'          => $args['image_size'],
2320
			'plain_text'          => $args['plain_text'],
2321
			'sent_to_admin'       => $args['sent_to_admin'],
2322
		) );
2323
2324
		return apply_filters( 'woocommerce_email_order_items_table', ob_get_clean(), $order );
2325
	}
2326
}
2327
2328
if ( ! function_exists( 'wc_display_item_meta' ) ) {
2329
	/**
2330
	 * Display item meta data.
2331
	 * @since  2.7.0
2332
	 * @param  WC_Item $item
2333
	 * @param  array   $args
2334
	 * @return string|void
2335
	 */
2336
	function wc_display_item_meta( $item, $args = array() ) {
2337
		$strings = array();
2338
		$html    = '';
2339
		$args    = wp_parse_args( $args, array(
2340
			'before'    => '<ul class="wc-item-meta"><li>',
2341
			'after'     => '</li></ul>',
2342
			'separator' => '</li><li>',
2343
			'echo'      => true,
2344
			'autop'     => false,
2345
		) );
2346
2347
		foreach ( $item->get_formatted_meta_data() as $meta_id => $meta ) {
2348
			if ( '_' === substr( $meta->key, 0, 1 ) ) {
2349
				continue;
2350
			}
2351
			$value = $args['autop'] ? wp_kses_post( wpautop( make_clickable( $meta->display_value ) ) ) : wp_kses_post( make_clickable( $meta->display_value ) );
2352
			$strings[] = '<strong class="wc-item-meta-label">' . wp_kses_post( $meta->display_key ) . ':</strong> ' . $value;
2353
		}
2354
2355 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...
2356
			$html = $args['before'] . implode( $args['separator'], $strings ) . $args['after'];
2357
		}
2358
2359
		$html = apply_filters( 'woocommerce_display_item_meta', $html, $item, $args );
2360
2361
		if ( $args['echo'] ) {
2362
			echo $html;
2363
		} else {
2364
			return $html;
2365
		}
2366
	}
2367
}
2368
2369
if ( ! function_exists( 'wc_display_item_downloads' ) ) {
2370
	/**
2371
	 * Display item download links.
2372
	 * @since  2.7.0
2373
	 * @param  WC_Item $item
2374
	 * @param  array   $args
2375
	 * @return string|void
2376
	 */
2377
	function wc_display_item_downloads( $item, $args = array() ) {
2378
		$strings = array();
2379
		$html    = '';
2380
		$args    = wp_parse_args( $args, array(
2381
			'before'    => '<ul class ="wc-item-downloads"><li>',
2382
			'after'     => '</li></ul>',
2383
			'separator' => '</li><li>',
2384
			'echo'      => true,
2385
			'show_url'  => false,
2386
		) );
2387
2388
		if ( is_object( $item ) && $item->is_type( 'line_item' ) && ( $downloads = $item->get_item_downloads() ) ) {
2389
			$i = 0;
2390
			foreach ( $downloads as $file ) {
2391
				$i ++;
2392
2393
				if ( $args['show_url'] ) {
2394
					$strings[] = '<strong class="wc-item-download-label">' .  esc_html( $file['name'] ) . ':</strong> ' . esc_html( $file['download_url'] );
2395
				} else {
2396
					$prefix = sizeof( $downloads ) > 1 ? sprintf( __( 'Download %d', 'woocommerce' ), $i ) : __( 'Download', 'woocommerce' );
2397
					$strings[] = '<strong class="wc-item-download-label">' . $prefix . ':</strong> <a href="' . esc_url( $file['download_url'] ) . '" target="_blank">' . esc_html( $file['name'] ) . '</a>';
2398
				}
2399
			}
2400
		}
2401
2402 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...
2403
			$html = $args['before'] . implode( $args['separator'], $strings ) . $args['after'];
2404
		}
2405
2406
		$html = apply_filters( 'woocommerce_display_item_downloads', $html, $item, $args );
2407
2408
		if ( $args['echo'] ) {
2409
			echo $html;
2410
		} else {
2411
			return $html;
2412
		}
2413
	}
2414
}
2415