Completed
Push — master ( 63fb13...1c592b )
by Mike
22:09
created

wc-template-functions.php ➔ wc_display_item_downloads()   D

Complexity

Conditions 9
Paths 8

Size

Total Lines 37
Code Lines 25

Duplication

Lines 3
Ratio 8.11 %

Importance

Changes 0
Metric Value
cc 9
eloc 25
nc 8
nop 2
dl 3
loc 37
rs 4.909
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 wc_get_template( 'loop/no-products-found.php' ); ?>
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_tax( array( 'product_cat', 'product_tag' ) ) && 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_schema' ) ) {
729
730
	/**
731
	 * Get a products Schema.
732
	 * @return string
733
	 */
734
	function woocommerce_get_product_schema() {
735
		global $product;
736
737
		$schema = "Product";
738
739
		// Downloadable product schema handling
740
		if ( $product->is_downloadable() ) {
741
			switch ( $product->download_type ) {
742
				case 'application' :
743
					$schema = "SoftwareApplication";
744
				break;
745
				case 'music' :
746
					$schema = "MusicAlbum";
747
				break;
748
				default :
749
					$schema = "Product";
750
				break;
751
			}
752
		}
753
754
		return 'http://schema.org/' . $schema;
755
	}
756
}
757
758
if ( ! function_exists( 'woocommerce_get_product_thumbnail' ) ) {
759
760
	/**
761
	 * Get the product thumbnail, or the placeholder if not set.
762
	 *
763
	 * @subpackage	Loop
764
	 * @param string $size (default: 'shop_catalog')
765
	 * @param int $deprecated1 Deprecated since WooCommerce 2.0 (default: 0)
766
	 * @param int $deprecated2 Deprecated since WooCommerce 2.0 (default: 0)
767
	 * @return string
768
	 */
769
	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...
770
		global $post;
771
		$image_size = apply_filters( 'single_product_archive_thumbnail_size', $size );
772
773
		if ( has_post_thumbnail() ) {
774
			$props = wc_get_product_attachment_props( get_post_thumbnail_id(), $post );
775
			return get_the_post_thumbnail( $post->ID, $image_size, array(
776
				'title'	 => $props['title'],
777
				'alt'    => $props['alt'],
778
			) );
779
		} elseif ( wc_placeholder_img_src() ) {
780
			return wc_placeholder_img( $image_size );
781
		}
782
	}
783
}
784
785
if ( ! function_exists( 'woocommerce_result_count' ) ) {
786
787
	/**
788
	 * Output the result count text (Showing x - x of x results).
789
	 *
790
	 * @subpackage	Loop
791
	 */
792
	function woocommerce_result_count() {
793
		wc_get_template( 'loop/result-count.php' );
794
	}
795
}
796
797
if ( ! function_exists( 'woocommerce_catalog_ordering' ) ) {
798
799
	/**
800
	 * Output the product sorting options.
801
	 *
802
	 * @subpackage	Loop
803
	 */
804
	function woocommerce_catalog_ordering() {
805
		global $wp_query;
806
807
		if ( 1 === $wp_query->found_posts || ! woocommerce_products_will_display() ) {
808
			return;
809
		}
810
811
		$orderby                 = isset( $_GET['orderby'] ) ? wc_clean( $_GET['orderby'] ) : apply_filters( 'woocommerce_default_catalog_orderby', get_option( 'woocommerce_default_catalog_orderby' ) );
812
		$show_default_orderby    = 'menu_order' === apply_filters( 'woocommerce_default_catalog_orderby', get_option( 'woocommerce_default_catalog_orderby' ) );
813
		$catalog_orderby_options = apply_filters( 'woocommerce_catalog_orderby', array(
814
			'menu_order' => __( 'Default sorting', 'woocommerce' ),
815
			'popularity' => __( 'Sort by popularity', 'woocommerce' ),
816
			'rating'     => __( 'Sort by average rating', 'woocommerce' ),
817
			'date'       => __( 'Sort by newness', 'woocommerce' ),
818
			'price'      => __( 'Sort by price: low to high', 'woocommerce' ),
819
			'price-desc' => __( 'Sort by price: high to low', 'woocommerce' )
820
		) );
821
822
		if ( ! $show_default_orderby ) {
823
			unset( $catalog_orderby_options['menu_order'] );
824
		}
825
826
		if ( 'no' === get_option( 'woocommerce_enable_review_rating' ) ) {
827
			unset( $catalog_orderby_options['rating'] );
828
		}
829
830
		wc_get_template( 'loop/orderby.php', array( 'catalog_orderby_options' => $catalog_orderby_options, 'orderby' => $orderby, 'show_default_orderby' => $show_default_orderby ) );
831
	}
832
}
833
834
if ( ! function_exists( 'woocommerce_pagination' ) ) {
835
836
	/**
837
	 * Output the pagination.
838
	 *
839
	 * @subpackage	Loop
840
	 */
841
	function woocommerce_pagination() {
842
		wc_get_template( 'loop/pagination.php' );
843
	}
844
}
845
846
/** Single Product ********************************************************/
847
848
if ( ! function_exists( 'woocommerce_show_product_images' ) ) {
849
850
	/**
851
	 * Output the product image before the single product summary.
852
	 *
853
	 * @subpackage	Product
854
	 */
855
	function woocommerce_show_product_images() {
856
		wc_get_template( 'single-product/product-image.php' );
857
	}
858
}
859
if ( ! function_exists( 'woocommerce_show_product_thumbnails' ) ) {
860
861
	/**
862
	 * Output the product thumbnails.
863
	 *
864
	 * @subpackage	Product
865
	 */
866
	function woocommerce_show_product_thumbnails() {
867
		wc_get_template( 'single-product/product-thumbnails.php' );
868
	}
869
}
870
if ( ! function_exists( 'woocommerce_output_product_data_tabs' ) ) {
871
872
	/**
873
	 * Output the product tabs.
874
	 *
875
	 * @subpackage	Product/Tabs
876
	 */
877
	function woocommerce_output_product_data_tabs() {
878
		wc_get_template( 'single-product/tabs/tabs.php' );
879
	}
880
}
881
if ( ! function_exists( 'woocommerce_template_single_title' ) ) {
882
883
	/**
884
	 * Output the product title.
885
	 *
886
	 * @subpackage	Product
887
	 */
888
	function woocommerce_template_single_title() {
889
		wc_get_template( 'single-product/title.php' );
890
	}
891
}
892
if ( ! function_exists( 'woocommerce_template_single_rating' ) ) {
893
894
	/**
895
	 * Output the product rating.
896
	 *
897
	 * @subpackage	Product
898
	 */
899
	function woocommerce_template_single_rating() {
900
		wc_get_template( 'single-product/rating.php' );
901
	}
902
}
903
if ( ! function_exists( 'woocommerce_template_single_price' ) ) {
904
905
	/**
906
	 * Output the product price.
907
	 *
908
	 * @subpackage	Product
909
	 */
910
	function woocommerce_template_single_price() {
911
		wc_get_template( 'single-product/price.php' );
912
	}
913
}
914
if ( ! function_exists( 'woocommerce_template_single_excerpt' ) ) {
915
916
	/**
917
	 * Output the product short description (excerpt).
918
	 *
919
	 * @subpackage	Product
920
	 */
921
	function woocommerce_template_single_excerpt() {
922
		wc_get_template( 'single-product/short-description.php' );
923
	}
924
}
925
if ( ! function_exists( 'woocommerce_template_single_meta' ) ) {
926
927
	/**
928
	 * Output the product meta.
929
	 *
930
	 * @subpackage	Product
931
	 */
932
	function woocommerce_template_single_meta() {
933
		wc_get_template( 'single-product/meta.php' );
934
	}
935
}
936
if ( ! function_exists( 'woocommerce_template_single_sharing' ) ) {
937
938
	/**
939
	 * Output the product sharing.
940
	 *
941
	 * @subpackage	Product
942
	 */
943
	function woocommerce_template_single_sharing() {
944
		wc_get_template( 'single-product/share.php' );
945
	}
946
}
947
if ( ! function_exists( 'woocommerce_show_product_sale_flash' ) ) {
948
949
	/**
950
	 * Output the product sale flash.
951
	 *
952
	 * @subpackage	Product
953
	 */
954
	function woocommerce_show_product_sale_flash() {
955
		wc_get_template( 'single-product/sale-flash.php' );
956
	}
957
}
958
959
if ( ! function_exists( 'woocommerce_template_single_add_to_cart' ) ) {
960
961
	/**
962
	 * Trigger the single product add to cart action.
963
	 *
964
	 * @subpackage	Product
965
	 */
966
	function woocommerce_template_single_add_to_cart() {
967
		global $product;
968
		do_action( 'woocommerce_' . $product->product_type . '_add_to_cart' );
969
	}
970
}
971
if ( ! function_exists( 'woocommerce_simple_add_to_cart' ) ) {
972
973
	/**
974
	 * Output the simple product add to cart area.
975
	 *
976
	 * @subpackage	Product
977
	 */
978
	function woocommerce_simple_add_to_cart() {
979
		wc_get_template( 'single-product/add-to-cart/simple.php' );
980
	}
981
}
982
if ( ! function_exists( 'woocommerce_grouped_add_to_cart' ) ) {
983
984
	/**
985
	 * Output the grouped product add to cart area.
986
	 *
987
	 * @subpackage	Product
988
	 */
989
	function woocommerce_grouped_add_to_cart() {
990
		global $product;
991
992
		wc_get_template( 'single-product/add-to-cart/grouped.php', array(
993
			'grouped_product'    => $product,
994
			'grouped_products'   => $product->get_children(),
995
			'quantites_required' => false
996
		) );
997
	}
998
}
999
if ( ! function_exists( 'woocommerce_variable_add_to_cart' ) ) {
1000
1001
	/**
1002
	 * Output the variable product add to cart area.
1003
	 *
1004
	 * @subpackage	Product
1005
	 */
1006
	function woocommerce_variable_add_to_cart() {
1007
		global $product;
1008
1009
		// Enqueue variation scripts
1010
		wp_enqueue_script( 'wc-add-to-cart-variation' );
1011
1012
		// Get Available variations?
1013
		$get_variations = sizeof( $product->get_children() ) <= apply_filters( 'woocommerce_ajax_variation_threshold', 30, $product );
1014
1015
		// Load the template
1016
		wc_get_template( 'single-product/add-to-cart/variable.php', array(
1017
			'available_variations' => $get_variations ? $product->get_available_variations() : false,
1018
			'attributes'           => $product->get_variation_attributes(),
1019
			'selected_attributes'  => $product->get_variation_default_attributes()
1020
		) );
1021
	}
1022
}
1023
if ( ! function_exists( 'woocommerce_external_add_to_cart' ) ) {
1024
1025
	/**
1026
	 * Output the external product add to cart area.
1027
	 *
1028
	 * @subpackage	Product
1029
	 */
1030
	function woocommerce_external_add_to_cart() {
1031
		global $product;
1032
1033
		if ( ! $product->add_to_cart_url() ) {
1034
			return;
1035
		}
1036
1037
		wc_get_template( 'single-product/add-to-cart/external.php', array(
1038
			'product_url' => $product->add_to_cart_url(),
1039
			'button_text' => $product->single_add_to_cart_text()
1040
		) );
1041
	}
1042
}
1043
1044
if ( ! function_exists( 'woocommerce_quantity_input' ) ) {
1045
1046
	/**
1047
	 * Output the quantity input for add to cart forms.
1048
	 *
1049
	 * @param  array $args Args for the input
1050
	 * @param  WC_Product|null $product
1051
	 * @param  boolean $echo Whether to return or echo|string
1052
	 */
1053
	function woocommerce_quantity_input( $args = array(), $product = null, $echo = true ) {
1054
		if ( is_null( $product ) ) {
1055
			$product = $GLOBALS['product'];
1056
		}
1057
1058
		$defaults = array(
1059
			'input_name'  => 'quantity',
1060
			'input_value' => '1',
1061
			'max_value'   => apply_filters( 'woocommerce_quantity_input_max', '', $product ),
1062
			'min_value'   => apply_filters( 'woocommerce_quantity_input_min', '', $product ),
1063
			'step'        => apply_filters( 'woocommerce_quantity_input_step', '1', $product ),
1064
			'pattern'     => apply_filters( 'woocommerce_quantity_input_pattern', has_filter( 'woocommerce_stock_amount', 'intval' ) ? '[0-9]*' : '' ),
1065
			'inputmode'   => apply_filters( 'woocommerce_quantity_input_inputmode', has_filter( 'woocommerce_stock_amount', 'intval' ) ? 'numeric' : '' ),
1066
		);
1067
1068
		$args = apply_filters( 'woocommerce_quantity_input_args', wp_parse_args( $args, $defaults ), $product );
1069
1070
		// Set min and max value to empty string if not set.
1071
		$args['min_value'] = isset( $args['min_value'] ) ? $args['min_value'] : '';
1072
		$args['max_value'] = isset( $args['max_value'] ) ? $args['max_value'] : '';
1073
1074
		// Apply sanity to min/max args - min cannot be lower than 0
1075
		if ( '' !== $args['min_value'] && is_numeric( $args['min_value'] ) && $args['min_value'] < 0 ) {
1076
			$args['min_value'] = 0; // Cannot be lower than 0
1077
		}
1078
1079
		// Max cannot be lower than 0 or min
1080
		if ( '' !== $args['max_value'] && is_numeric( $args['max_value'] ) ) {
1081
			$args['max_value'] = $args['max_value'] < 0 ? 0 : $args['max_value'];
1082
			$args['max_value'] = $args['max_value'] < $args['min_value'] ? $args['min_value'] : $args['max_value'];
1083
		}
1084
1085
		ob_start();
1086
1087
		wc_get_template( 'global/quantity-input.php', $args );
1088
1089
		if ( $echo ) {
1090
			echo ob_get_clean();
1091
		} else {
1092
			return ob_get_clean();
1093
		}
1094
	}
1095
}
1096
1097
if ( ! function_exists( 'woocommerce_product_description_tab' ) ) {
1098
1099
	/**
1100
	 * Output the description tab content.
1101
	 *
1102
	 * @subpackage	Product/Tabs
1103
	 */
1104
	function woocommerce_product_description_tab() {
1105
		wc_get_template( 'single-product/tabs/description.php' );
1106
	}
1107
}
1108
if ( ! function_exists( 'woocommerce_product_additional_information_tab' ) ) {
1109
1110
	/**
1111
	 * Output the attributes tab content.
1112
	 *
1113
	 * @subpackage	Product/Tabs
1114
	 */
1115
	function woocommerce_product_additional_information_tab() {
1116
		wc_get_template( 'single-product/tabs/additional-information.php' );
1117
	}
1118
}
1119
if ( ! function_exists( 'woocommerce_product_reviews_tab' ) ) {
1120
1121
	/**
1122
	 * Output the reviews tab content.
1123
	 * @deprecated  2.4.0 Unused
1124
	 * @subpackage	Product/Tabs
1125
	 */
1126
	function woocommerce_product_reviews_tab() {
1127
		_deprecated_function( 'woocommerce_product_reviews_tab', '2.4', '' );
1128
	}
1129
}
1130
1131
if ( ! function_exists( 'woocommerce_default_product_tabs' ) ) {
1132
1133
	/**
1134
	 * Add default product tabs to product pages.
1135
	 *
1136
	 * @param array $tabs
1137
	 * @return array
1138
	 */
1139
	function woocommerce_default_product_tabs( $tabs = array() ) {
1140
		global $product, $post;
1141
1142
		// Description tab - shows product content
1143
		if ( $post->post_content ) {
1144
			$tabs['description'] = array(
1145
				'title'    => __( 'Description', 'woocommerce' ),
1146
				'priority' => 10,
1147
				'callback' => 'woocommerce_product_description_tab'
1148
			);
1149
		}
1150
1151
		// Additional information tab - shows attributes
1152
		if ( $product && ( $product->has_attributes() || $product->enable_dimensions_display() ) ) {
1153
			$tabs['additional_information'] = array(
1154
				'title'    => __( 'Additional Information', 'woocommerce' ),
1155
				'priority' => 20,
1156
				'callback' => 'woocommerce_product_additional_information_tab'
1157
			);
1158
		}
1159
1160
		// Reviews tab - shows comments
1161
		if ( comments_open() ) {
1162
			$tabs['reviews'] = array(
1163
				'title'    => sprintf( __( 'Reviews (%d)', 'woocommerce' ), $product->get_review_count() ),
1164
				'priority' => 30,
1165
				'callback' => 'comments_template'
1166
			);
1167
		}
1168
1169
		return $tabs;
1170
	}
1171
}
1172
1173
if ( ! function_exists( 'woocommerce_sort_product_tabs' ) ) {
1174
1175
	/**
1176
	 * Sort tabs by priority.
1177
	 *
1178
	 * @param array $tabs
1179
	 * @return array
1180
	 */
1181
	function woocommerce_sort_product_tabs( $tabs = array() ) {
1182
1183
		// Make sure the $tabs parameter is an array
1184
		if ( ! is_array( $tabs ) ) {
1185
			trigger_error( "Function woocommerce_sort_product_tabs() expects an array as the first parameter. Defaulting to empty array." );
1186
			$tabs = array( );
1187
		}
1188
1189
		// Re-order tabs by priority
1190
		if ( ! function_exists( '_sort_priority_callback' ) ) {
1191
			function _sort_priority_callback( $a, $b ) {
1192
				if ( $a['priority'] === $b['priority'] )
1193
					return 0;
1194
				return ( $a['priority'] < $b['priority'] ) ? -1 : 1;
1195
			}
1196
		}
1197
1198
		uasort( $tabs, '_sort_priority_callback' );
1199
1200
		return $tabs;
1201
	}
1202
}
1203
1204
if ( ! function_exists( 'woocommerce_comments' ) ) {
1205
1206
	/**
1207
	 * Output the Review comments template.
1208
	 *
1209
	 * @subpackage	Product
1210
	 * @param WP_Comment $comment
1211
	 * @param array $args
1212
	 * @param int $depth
1213
	 */
1214
	function woocommerce_comments( $comment, $args, $depth ) {
1215
		$GLOBALS['comment'] = $comment;
1216
		wc_get_template( 'single-product/review.php', array( 'comment' => $comment, 'args' => $args, 'depth' => $depth ) );
1217
	}
1218
}
1219
1220
if ( ! function_exists( 'woocommerce_review_display_gravatar' ) ) {
1221
	/**
1222
	 * Display the review authors gravatar
1223
	 *
1224
	 * @param array $comment WP_Comment.
1225
	 * @return void
1226
	 */
1227
	function woocommerce_review_display_gravatar( $comment ) {
1228
		echo get_avatar( $comment, apply_filters( 'woocommerce_review_gravatar_size', '60' ), '' );
1229
	}
1230
}
1231
1232
if ( ! function_exists( 'woocommerce_review_display_rating' ) ) {
1233
	/**
1234
	 * Display the reviewers star rating
1235
	 *
1236
	 * @return void
1237
	 */
1238
	function woocommerce_review_display_rating() {
1239
		wc_get_template( 'single-product/review-rating.php' );
1240
	}
1241
}
1242
1243
if ( ! function_exists( 'woocommerce_review_display_meta' ) ) {
1244
	/**
1245
	 * Display the review authors meta (name, verified owner, review date)
1246
	 *
1247
	 * @return void
1248
	 */
1249
	function woocommerce_review_display_meta() {
1250
		wc_get_template( 'single-product/review-meta.php' );
1251
	}
1252
}
1253
1254
if ( ! function_exists( 'woocommerce_review_display_comment_text' ) ) {
1255
1256
	/**
1257
	 * Display the review content.
1258
	 */
1259
	function woocommerce_review_display_comment_text() {
1260
		echo '<div itemprop="description" class="description">';
1261
		comment_text();
1262
		echo '</div>';
1263
	}
1264
}
1265
1266
if ( ! function_exists( 'woocommerce_output_related_products' ) ) {
1267
1268
	/**
1269
	 * Output the related products.
1270
	 *
1271
	 * @subpackage	Product
1272
	 */
1273
	function woocommerce_output_related_products() {
1274
1275
		$args = array(
1276
			'posts_per_page' 	=> 4,
1277
			'columns' 			=> 4,
1278
			'orderby' 			=> 'rand'
1279
		);
1280
1281
		woocommerce_related_products( apply_filters( 'woocommerce_output_related_products_args', $args ) );
1282
	}
1283
}
1284
1285
if ( ! function_exists( 'woocommerce_related_products' ) ) {
1286
1287
	/**
1288
	 * Output the related products.
1289
	 *
1290
	 * @param array Provided arguments
1291
	 * @param bool Columns argument for backwards compat
1292
	 * @param bool Order by argument for backwards compat
1293
	 */
1294
	function woocommerce_related_products( $args = array(), $columns = false, $orderby = false ) {
1295
		if ( ! is_array( $args ) ) {
1296
			_deprecated_argument( __FUNCTION__, '2.1', __( 'Use $args argument as an array instead. Deprecated argument will be removed in WC 2.2.', 'woocommerce' ) );
1297
1298
			$argsvalue = $args;
1299
1300
			$args = array(
1301
				'posts_per_page' => $argsvalue,
1302
				'columns'        => $columns,
1303
				'orderby'        => $orderby,
1304
			);
1305
		}
1306
1307
		$defaults = array(
1308
			'posts_per_page' => 2,
1309
			'columns'        => 2,
1310
			'orderby'        => 'rand'
1311
		);
1312
1313
		$args = wp_parse_args( $args, $defaults );
1314
1315
		wc_get_template( 'single-product/related.php', $args );
1316
	}
1317
}
1318
1319
if ( ! function_exists( 'woocommerce_upsell_display' ) ) {
1320
1321
	/**
1322
	 * Output product up sells.
1323
	 *
1324
	 * @param int $posts_per_page (default: -1)
1325
	 * @param int $columns (default: 4)
1326
	 * @param string $orderby (default: 'rand')
1327
	 */
1328
	function woocommerce_upsell_display( $posts_per_page = '-1', $columns = 4, $orderby = 'rand' ) {
1329
		$args = apply_filters( 'woocommerce_upsell_display_args', array(
1330
			'posts_per_page'	=> $posts_per_page,
1331
			'orderby'			=> apply_filters( 'woocommerce_upsells_orderby', $orderby ),
1332
			'columns'			=> $columns
1333
		) );
1334
1335
		wc_get_template( 'single-product/up-sells.php', $args );
1336
	}
1337
}
1338
1339
/** Cart ******************************************************************/
1340
1341
if ( ! function_exists( 'woocommerce_shipping_calculator' ) ) {
1342
1343
	/**
1344
	 * Output the cart shipping calculator.
1345
	 *
1346
	 * @subpackage	Cart
1347
	 */
1348
	function woocommerce_shipping_calculator() {
1349
		wc_get_template( 'cart/shipping-calculator.php' );
1350
	}
1351
}
1352
1353
if ( ! function_exists( 'woocommerce_cart_totals' ) ) {
1354
1355
	/**
1356
	 * Output the cart totals.
1357
	 *
1358
	 * @subpackage	Cart
1359
	 */
1360
	function woocommerce_cart_totals() {
1361
		if ( is_checkout() ) {
1362
			return;
1363
		}
1364
		wc_get_template( 'cart/cart-totals.php' );
1365
	}
1366
}
1367
1368
if ( ! function_exists( 'woocommerce_cross_sell_display' ) ) {
1369
1370
	/**
1371
	 * Output the cart cross-sells.
1372
	 *
1373
	 * @param  int $posts_per_page (default: 2)
1374
	 * @param  int $columns (default: 2)
1375
	 * @param  string $orderby (default: 'rand')
1376
	 */
1377
	function woocommerce_cross_sell_display( $posts_per_page = 2, $columns = 2, $orderby = 'rand' ) {
1378
		if ( is_checkout() ) {
1379
			return;
1380
		}
1381
		wc_get_template( 'cart/cross-sells.php', array(
1382
			'posts_per_page' => $posts_per_page,
1383
			'orderby'        => $orderby,
1384
			'columns'        => $columns
1385
		) );
1386
	}
1387
}
1388
1389
if ( ! function_exists( 'woocommerce_button_proceed_to_checkout' ) ) {
1390
1391
	/**
1392
	 * Output the proceed to checkout button.
1393
	 *
1394
	 * @subpackage	Cart
1395
	 */
1396
	function woocommerce_button_proceed_to_checkout() {
1397
		wc_get_template( 'cart/proceed-to-checkout-button.php' );
1398
	}
1399
}
1400
1401 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...
1402
1403
	/**
1404
	 * Output the proceed to checkout button.
1405
	 *
1406
	 * @subpackage	Cart
1407
	 */
1408
	function woocommerce_widget_shopping_cart_button_view_cart() {
1409
		echo '<a href="' . esc_url( wc_get_cart_url() ) . '" class="button wc-forward">' . __( 'View Cart', 'woocommerce' ) . '</a>';
1410
	}
1411
}
1412
1413 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...
1414
1415
	/**
1416
	 * Output the proceed to checkout button.
1417
	 *
1418
	 * @subpackage	Cart
1419
	 */
1420
	function woocommerce_widget_shopping_cart_proceed_to_checkout() {
1421
		echo '<a href="' . esc_url( wc_get_checkout_url() ) . '" class="button checkout wc-forward">' . __( 'Checkout', 'woocommerce' ) . '</a>';
1422
	}
1423
}
1424
1425
/** Mini-Cart *************************************************************/
1426
1427
if ( ! function_exists( 'woocommerce_mini_cart' ) ) {
1428
1429
	/**
1430
	 * Output the Mini-cart - used by cart widget.
1431
	 *
1432
	 * @param array $args
1433
	 */
1434
	function woocommerce_mini_cart( $args = array() ) {
1435
1436
		$defaults = array(
1437
			'list_class' => ''
1438
		);
1439
1440
		$args = wp_parse_args( $args, $defaults );
1441
1442
		wc_get_template( 'cart/mini-cart.php', $args );
1443
	}
1444
}
1445
1446
/** Login *****************************************************************/
1447
1448
if ( ! function_exists( 'woocommerce_login_form' ) ) {
1449
1450
	/**
1451
	 * Output the WooCommerce Login Form.
1452
	 *
1453
	 * @subpackage	Forms
1454
	 * @param array $args
1455
	 */
1456
	function woocommerce_login_form( $args = array() ) {
1457
1458
		$defaults = array(
1459
			'message'  => '',
1460
			'redirect' => '',
1461
			'hidden'   => false
1462
		);
1463
1464
		$args = wp_parse_args( $args, $defaults  );
1465
1466
		wc_get_template( 'global/form-login.php', $args );
1467
	}
1468
}
1469
1470
if ( ! function_exists( 'woocommerce_checkout_login_form' ) ) {
1471
1472
	/**
1473
	 * Output the WooCommerce Checkout Login Form.
1474
	 *
1475
	 * @subpackage	Checkout
1476
	 */
1477
	function woocommerce_checkout_login_form() {
1478
		wc_get_template( 'checkout/form-login.php', array( 'checkout' => WC()->checkout() ) );
1479
	}
1480
}
1481
1482
if ( ! function_exists( 'woocommerce_breadcrumb' ) ) {
1483
1484
	/**
1485
	 * Output the WooCommerce Breadcrumb.
1486
	 *
1487
	 * @param array $args
1488
	 */
1489
	function woocommerce_breadcrumb( $args = array() ) {
1490
		$args = wp_parse_args( $args, apply_filters( 'woocommerce_breadcrumb_defaults', array(
1491
			'delimiter'   => '&nbsp;&#47;&nbsp;',
1492
			'wrap_before' => '<nav class="woocommerce-breadcrumb" ' . ( is_single() ? 'itemprop="breadcrumb"' : '' ) . '>',
1493
			'wrap_after'  => '</nav>',
1494
			'before'      => '',
1495
			'after'       => '',
1496
			'home'        => _x( 'Home', 'breadcrumb', 'woocommerce' )
1497
		) ) );
1498
1499
		$breadcrumbs = new WC_Breadcrumb();
1500
1501
		if ( ! empty( $args['home'] ) ) {
1502
			$breadcrumbs->add_crumb( $args['home'], apply_filters( 'woocommerce_breadcrumb_home_url', home_url() ) );
1503
		}
1504
1505
		$args['breadcrumb'] = $breadcrumbs->generate();
1506
1507
		wc_get_template( 'global/breadcrumb.php', $args );
1508
	}
1509
}
1510
1511
if ( ! function_exists( 'woocommerce_order_review' ) ) {
1512
1513
	/**
1514
	 * Output the Order review table for the checkout.
1515
	 *
1516
	 * @subpackage	Checkout
1517
	 */
1518
	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...
1519
		wc_get_template( 'checkout/review-order.php', array( 'checkout' => WC()->checkout() ) );
1520
	}
1521
}
1522
1523
if ( ! function_exists( 'woocommerce_checkout_payment' ) ) {
1524
1525
	/**
1526
	 * Output the Payment Methods on the checkout.
1527
	 *
1528
	 * @subpackage	Checkout
1529
	 */
1530
	function woocommerce_checkout_payment() {
1531
		if ( WC()->cart->needs_payment() ) {
1532
			$available_gateways = WC()->payment_gateways()->get_available_payment_gateways();
1533
			WC()->payment_gateways()->set_current_gateway( $available_gateways );
1534
		} else {
1535
			$available_gateways = array();
1536
		}
1537
1538
		wc_get_template( 'checkout/payment.php', array(
1539
			'checkout'           => WC()->checkout(),
1540
			'available_gateways' => $available_gateways,
1541
			'order_button_text'  => apply_filters( 'woocommerce_order_button_text', __( 'Place order', 'woocommerce' ) )
1542
		) );
1543
	}
1544
}
1545
1546
if ( ! function_exists( 'woocommerce_checkout_coupon_form' ) ) {
1547
1548
	/**
1549
	 * Output the Coupon form for the checkout.
1550
	 *
1551
	 * @subpackage	Checkout
1552
	 */
1553
	function woocommerce_checkout_coupon_form() {
1554
		wc_get_template( 'checkout/form-coupon.php', array( 'checkout' => WC()->checkout() ) );
1555
	}
1556
}
1557
1558
if ( ! function_exists( 'woocommerce_products_will_display' ) ) {
1559
1560
	/**
1561
	 * Check if we will be showing products or not (and not sub-categories only).
1562
	 * @subpackage	Loop
1563
	 * @return bool
1564
	 */
1565
	function woocommerce_products_will_display() {
1566
		global $wpdb;
1567
1568
		if ( is_shop() ) {
1569
			return 'subcategories' !== get_option( 'woocommerce_shop_page_display' ) || is_search();
1570
		}
1571
1572
		if ( ! is_product_taxonomy() ) {
1573
			return false;
1574
		}
1575
1576
		if ( is_search() || is_filtered() || is_paged() ) {
1577
			return true;
1578
		}
1579
1580
		$term = get_queried_object();
1581
1582
		if ( is_product_category() ) {
1583
			switch ( get_woocommerce_term_meta( $term->term_id, 'display_type', true ) ) {
1584
				case 'subcategories' :
1585
					// Nothing - we want to continue to see if there are products/subcats
1586
				break;
1587
				case 'products' :
1588
				case 'both' :
1589
					return true;
1590
				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...
1591
				default :
1592
					// Default - no setting
1593
					if ( get_option( 'woocommerce_category_archive_display' ) != 'subcategories' ) {
1594
						return true;
1595
					}
1596
				break;
1597
			}
1598
		}
1599
1600
		// Begin subcategory logic
1601
		if ( empty( $term->term_id ) || empty( $term->taxonomy ) ) {
1602
			return true;
1603
		}
1604
1605
		$transient_name = 'wc_products_will_display_' . $term->term_id . '_' . WC_Cache_Helper::get_transient_version( 'product_query' );
1606
1607
		if ( false === ( $products_will_display = get_transient( $transient_name ) ) ) {
1608
			$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 ) );
1609
1610
			if ( $has_children ) {
1611
				// Check terms have products inside - parents first. If products are found inside, subcats will be shown instead of products so we can return false.
1612
				if ( sizeof( get_objects_in_term( $has_children, $term->taxonomy ) ) > 0 ) {
1613
					$products_will_display = false;
1614
				} else {
1615
					// If we get here, the parents were empty so we're forced to check children
1616
					foreach ( $has_children as $term_id ) {
1617
						$children = get_term_children( $term_id, $term->taxonomy );
1618
1619
						if ( sizeof( get_objects_in_term( $children, $term->taxonomy ) ) > 0 ) {
1620
							$products_will_display = false;
1621
							break;
1622
						}
1623
					}
1624
				}
1625
			} else {
1626
				$products_will_display = true;
1627
			}
1628
		}
1629
1630
		set_transient( $transient_name, $products_will_display, DAY_IN_SECONDS * 30 );
1631
1632
		return $products_will_display;
1633
	}
1634
}
1635
1636
if ( ! function_exists( 'woocommerce_product_subcategories' ) ) {
1637
1638
	/**
1639
	 * Display product sub categories as thumbnails.
1640
	 *
1641
	 * @subpackage	Loop
1642
	 * @param array $args
1643
	 * @return null|boolean
1644
	 */
1645
	function woocommerce_product_subcategories( $args = array() ) {
1646
		global $wp_query;
1647
1648
		$defaults = array(
1649
			'before'        => '',
1650
			'after'         => '',
1651
			'force_display' => false
1652
		);
1653
1654
		$args = wp_parse_args( $args, $defaults );
1655
1656
		extract( $args );
1657
1658
		// Main query only
1659
		if ( ! is_main_query() && ! $force_display ) {
1660
			return;
1661
		}
1662
1663
		// Don't show when filtering, searching or when on page > 1 and ensure we're on a product archive
1664
		if ( is_search() || is_filtered() || is_paged() || ( ! is_product_category() && ! is_shop() ) ) {
1665
			return;
1666
		}
1667
1668
		// Check categories are enabled
1669
		if ( is_shop() && '' === get_option( 'woocommerce_shop_page_display' ) ) {
1670
			return;
1671
		}
1672
1673
		// Find the category + category parent, if applicable
1674
		$term 			= get_queried_object();
1675
		$parent_id 		= empty( $term->term_id ) ? 0 : $term->term_id;
1676
1677
		if ( is_product_category() ) {
1678
			$display_type = get_woocommerce_term_meta( $term->term_id, 'display_type', true );
1679
1680
			switch ( $display_type ) {
1681
				case 'products' :
1682
					return;
1683
				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...
1684
				case '' :
1685
					if ( '' === get_option( 'woocommerce_category_archive_display' ) ) {
1686
						return;
1687
					}
1688
				break;
1689
			}
1690
		}
1691
1692
		// 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
1693
		$product_categories = get_categories( apply_filters( 'woocommerce_product_subcategories_args', array(
1694
			'parent'       => $parent_id,
1695
			'menu_order'   => 'ASC',
1696
			'hide_empty'   => 0,
1697
			'hierarchical' => 1,
1698
			'taxonomy'     => 'product_cat',
1699
			'pad_counts'   => 1
1700
		) ) );
1701
1702
		if ( ! apply_filters( 'woocommerce_product_subcategories_hide_empty', false ) ) {
1703
			$product_categories = wp_list_filter( $product_categories, array( 'count' => 0 ), 'NOT' );
1704
		}
1705
1706
		if ( $product_categories ) {
1707
			echo $before;
1708
1709
			foreach ( $product_categories as $category ) {
1710
				wc_get_template( 'content-product_cat.php', array(
1711
					'category' => $category
1712
				) );
1713
			}
1714
1715
			// If we are hiding products disable the loop and pagination
1716
			if ( is_product_category() ) {
1717
				$display_type = get_woocommerce_term_meta( $term->term_id, 'display_type', true );
1718
1719
				switch ( $display_type ) {
1720
					case 'subcategories' :
1721
						$wp_query->post_count    = 0;
1722
						$wp_query->max_num_pages = 0;
1723
					break;
1724
					case '' :
1725
						if ( 'subcategories' === get_option( 'woocommerce_category_archive_display' ) ) {
1726
							$wp_query->post_count    = 0;
1727
							$wp_query->max_num_pages = 0;
1728
						}
1729
					break;
1730
				}
1731
			}
1732
1733
			if ( is_shop() && 'subcategories' === get_option( 'woocommerce_shop_page_display' ) ) {
1734
				$wp_query->post_count    = 0;
1735
				$wp_query->max_num_pages = 0;
1736
			}
1737
1738
			echo $after;
1739
1740
			return true;
1741
		}
1742
	}
1743
}
1744
1745
if ( ! function_exists( 'woocommerce_subcategory_thumbnail' ) ) {
1746
1747
	/**
1748
	 * Show subcategory thumbnails.
1749
	 *
1750
	 * @param mixed $category
1751
	 * @subpackage	Loop
1752
	 */
1753
	function woocommerce_subcategory_thumbnail( $category ) {
1754
		$small_thumbnail_size  	= apply_filters( 'subcategory_archive_thumbnail_size', 'shop_catalog' );
1755
		$dimensions    			= wc_get_image_size( $small_thumbnail_size );
1756
		$thumbnail_id  			= get_woocommerce_term_meta( $category->term_id, 'thumbnail_id', true  );
1757
1758
		if ( $thumbnail_id ) {
1759
			$image        = wp_get_attachment_image_src( $thumbnail_id, $small_thumbnail_size  );
1760
			$image        = $image[0];
1761
			$image_srcset = function_exists( 'wp_get_attachment_image_srcset' ) ? wp_get_attachment_image_srcset( $thumbnail_id, $small_thumbnail_size ) : false;
1762
			$image_sizes  = function_exists( 'wp_get_attachment_image_sizes' ) ? wp_get_attachment_image_sizes( $thumbnail_id, $small_thumbnail_size ) : false;
1763
		} else {
1764
			$image        = wc_placeholder_img_src();
1765
			$image_srcset = $image_sizes = false;
1766
		}
1767
1768
		if ( $image ) {
1769
			// Prevent esc_url from breaking spaces in urls for image embeds
1770
			// Ref: https://core.trac.wordpress.org/ticket/23605
1771
			$image = str_replace( ' ', '%20', $image );
1772
1773
			// Add responsive image markup if available
1774
			if ( $image_srcset && $image_sizes ) {
1775
				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 ) . '" />';
1776
			} else {
1777
				echo '<img src="' . esc_url( $image ) . '" alt="' . esc_attr( $category->name ) . '" width="' . esc_attr( $dimensions['width'] ) . '" height="' . esc_attr( $dimensions['height'] ) . '" />';
1778
			}
1779
		}
1780
	}
1781
}
1782
1783
if ( ! function_exists( 'woocommerce_order_details_table' ) ) {
1784
1785
	/**
1786
	 * Displays order details in a table.
1787
	 *
1788
	 * @param mixed $order_id
1789
	 * @subpackage	Orders
1790
	 */
1791
	function woocommerce_order_details_table( $order_id ) {
1792
		if ( ! $order_id ) return;
1793
1794
		wc_get_template( 'order/order-details.php', array(
1795
			'order_id' => $order_id
1796
		) );
1797
	}
1798
}
1799
1800
1801
if ( ! function_exists( 'woocommerce_order_again_button' ) ) {
1802
1803
	/**
1804
	 * Display an 'order again' button on the view order page.
1805
	 *
1806
	 * @param object $order
1807
	 * @subpackage	Orders
1808
	 */
1809
	function woocommerce_order_again_button( $order ) {
1810
		if ( ! $order || ! $order->has_status( 'completed' ) || ! is_user_logged_in() ) {
1811
			return;
1812
		}
1813
1814
		wc_get_template( 'order/order-again.php', array(
1815
			'order' => $order
1816
		) );
1817
	}
1818
}
1819
1820
/** Forms ****************************************************************/
1821
1822
if ( ! function_exists( 'woocommerce_form_field' ) ) {
1823
1824
	/**
1825
	 * Outputs a checkout/address form field.
1826
	 *
1827
	 * @subpackage	Forms
1828
	 * @param string $key
1829
	 * @param mixed $args
1830
	 * @param string $value (default: null)
1831
	 * @todo This function needs to be broken up in smaller pieces
1832
	 */
1833
	function woocommerce_form_field( $key, $args, $value = null ) {
1834
		$defaults = array(
1835
			'type'              => 'text',
1836
			'label'             => '',
1837
			'description'       => '',
1838
			'placeholder'       => '',
1839
			'maxlength'         => false,
1840
			'required'          => false,
1841
			'autocomplete'      => false,
1842
			'id'                => $key,
1843
			'class'             => array(),
1844
			'label_class'       => array(),
1845
			'input_class'       => array(),
1846
			'return'            => false,
1847
			'options'           => array(),
1848
			'custom_attributes' => array(),
1849
			'validate'          => array(),
1850
			'default'           => '',
1851
		);
1852
1853
		$args = wp_parse_args( $args, $defaults );
1854
		$args = apply_filters( 'woocommerce_form_field_args', $args, $key, $value );
1855
1856
		if ( $args['required'] ) {
1857
			$args['class'][] = 'validate-required';
1858
			$required = ' <abbr class="required" title="' . esc_attr__( 'required', 'woocommerce'  ) . '">*</abbr>';
1859
		} else {
1860
			$required = '';
1861
		}
1862
1863
		$args['maxlength'] = ( $args['maxlength'] ) ? 'maxlength="' . absint( $args['maxlength'] ) . '"' : '';
1864
1865
		$args['autocomplete'] = ( $args['autocomplete'] ) ? 'autocomplete="' . esc_attr( $args['autocomplete'] ) . '"' : '';
1866
1867
		if ( is_string( $args['label_class'] ) ) {
1868
			$args['label_class'] = array( $args['label_class'] );
1869
		}
1870
1871
		if ( is_null( $value ) ) {
1872
			$value = $args['default'];
1873
		}
1874
1875
		// Custom attribute handling
1876
		$custom_attributes = array();
1877
1878 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...
1879
			foreach ( $args['custom_attributes'] as $attribute => $attribute_value ) {
1880
				$custom_attributes[] = esc_attr( $attribute ) . '="' . esc_attr( $attribute_value ) . '"';
1881
			}
1882
		}
1883
1884
		if ( ! empty( $args['validate'] ) ) {
1885
			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...
1886
				$args['class'][] = 'validate-' . $validate;
1887
			}
1888
		}
1889
1890
		$field = '';
1891
		$label_id = $args['id'];
1892
		$field_container = '<p class="form-row %1$s" id="%2$s">%3$s</p>';
1893
1894
		switch ( $args['type'] ) {
1895
			case 'country' :
1896
1897
				$countries = 'shipping_country' === $key ? WC()->countries->get_shipping_countries() : WC()->countries->get_allowed_countries();
1898
1899
				if ( 1 === sizeof( $countries ) ) {
1900
1901
					$field .= '<strong>' . current( array_values( $countries ) ) . '</strong>';
1902
1903
					$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" />';
1904
1905
				} else {
1906
1907
					$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 ) . '>'
1908
							. '<option value="">'.__( 'Select a country&hellip;', 'woocommerce' ) .'</option>';
1909
1910 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...
1911
						$field .= '<option value="' . esc_attr( $ckey ) . '" '. selected( $value, $ckey, false ) . '>'. __( $cvalue, 'woocommerce' ) .'</option>';
1912
					}
1913
1914
					$field .= '</select>';
1915
1916
					$field .= '<noscript><input type="submit" name="woocommerce_checkout_update_totals" value="' . esc_attr__( 'Update country', 'woocommerce' ) . '" /></noscript>';
1917
1918
				}
1919
1920
				break;
1921
			case 'state' :
1922
1923
				/* Get Country */
1924
				$country_key = 'billing_state' === $key ? 'billing_country' : 'shipping_country';
1925
				$current_cc  = WC()->checkout->get_value( $country_key );
1926
				$states      = WC()->countries->get_states( $current_cc );
1927
1928
				if ( is_array( $states ) && empty( $states ) ) {
1929
1930
					$field_container = '<p class="form-row %1$s" id="%2$s" style="display: none">%3$s</p>';
1931
1932
					$field .= '<input type="hidden" class="hidden" name="' . esc_attr( $key )  . '" id="' . esc_attr( $args['id'] ) . '" value="" ' . implode( ' ', $custom_attributes ) . ' placeholder="' . esc_attr( $args['placeholder'] ) . '" />';
1933
1934
				} elseif ( is_array( $states ) ) {
1935
1936
					$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'] . '>
1937
						<option value="">'.__( 'Select a state&hellip;', 'woocommerce' ) .'</option>';
1938
1939 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...
1940
						$field .= '<option value="' . esc_attr( $ckey ) . '" '.selected( $value, $ckey, false ) .'>'.__( $cvalue, 'woocommerce' ) .'</option>';
1941
					}
1942
1943
					$field .= '</select>';
1944
1945
				} else {
1946
1947
					$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 ) . ' />';
1948
1949
				}
1950
1951
				break;
1952
			case 'textarea' :
1953
1954
				$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>';
1955
1956
				break;
1957 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...
1958
1959
				$field = '<label class="checkbox ' . implode( ' ', $args['label_class'] ) .'" ' . implode( ' ', $custom_attributes ) . '>
1960
						<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 ) .' /> '
1961
						 . $args['label'] . $required . '</label>';
1962
1963
				break;
1964
			case 'password' :
1965
			case 'text' :
1966
			case 'email' :
1967
			case 'tel' :
1968 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...
1969
1970
				$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 ) . ' />';
1971
1972
				break;
1973
			case 'select' :
1974
1975
				$options = $field = '';
1976
1977
				if ( ! empty( $args['options'] ) ) {
1978
					foreach ( $args['options'] as $option_key => $option_text ) {
1979
						if ( '' === $option_key ) {
1980
							// If we have a blank option, select2 needs a placeholder
1981
							if ( empty( $args['placeholder'] ) ) {
1982
								$args['placeholder'] = $option_text ? $option_text : __( 'Choose an option', 'woocommerce' );
1983
							}
1984
							$custom_attributes[] = 'data-allow_clear="true"';
1985
						}
1986
						$options .= '<option value="' . esc_attr( $option_key ) . '" '. selected( $value, $option_key, false ) . '>' . esc_attr( $option_text ) .'</option>';
1987
					}
1988
1989
					$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'] . '>
1990
							' . $options . '
1991
						</select>';
1992
				}
1993
1994
				break;
1995
			case 'radio' :
1996
1997
				$label_id = current( array_keys( $args['options'] ) );
1998
1999
				if ( ! empty( $args['options'] ) ) {
2000
					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...
2001
						$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 ) . ' />';
2002
						$field .= '<label for="' . esc_attr( $args['id'] ) . '_' . esc_attr( $option_key ) . '" class="radio ' . implode( ' ', $args['label_class'] ) .'">' . $option_text . '</label>';
2003
					}
2004
				}
2005
2006
				break;
2007
		}
2008
2009
		if ( ! empty( $field ) ) {
2010
			$field_html = '';
2011
2012
			if ( $args['label'] && 'checkbox' != $args['type'] ) {
2013
				$field_html .= '<label for="' . esc_attr( $label_id ) . '" class="' . esc_attr( implode( ' ', $args['label_class'] ) ) .'">' . $args['label'] . $required . '</label>';
2014
			}
2015
2016
			$field_html .= $field;
2017
2018
			if ( $args['description'] ) {
2019
				$field_html .= '<span class="description">' . esc_html( $args['description'] ) . '</span>';
2020
			}
2021
2022
			$container_class = 'form-row ' . esc_attr( implode( ' ', $args['class'] ) );
2023
			$container_id = esc_attr( $args['id'] ) . '_field';
2024
2025
			$after = ! empty( $args['clear'] ) ? '<div class="clear"></div>' : '';
2026
2027
			$field = sprintf( $field_container, $container_class, $container_id, $field_html ) . $after;
2028
		}
2029
2030
		$field = apply_filters( 'woocommerce_form_field_' . $args['type'], $field, $key, $args, $value );
2031
2032
		if ( $args['return'] ) {
2033
			return $field;
2034
		} else {
2035
			echo $field;
2036
		}
2037
	}
2038
}
2039
2040
if ( ! function_exists( 'get_product_search_form' ) ) {
2041
2042
	/**
2043
	 * Display product search form.
2044
	 *
2045
	 * Will first attempt to locate the product-searchform.php file in either the child or.
2046
	 * the parent, then load it. If it doesn't exist, then the default search form.
2047
	 * will be displayed.
2048
	 *
2049
	 * The default searchform uses html5.
2050
	 *
2051
	 * @subpackage	Forms
2052
	 * @param bool $echo (default: true)
2053
	 * @return string
2054
	 */
2055
	function get_product_search_form( $echo = true  ) {
2056
		global $product_search_form_index;
2057
2058
		ob_start();
2059
2060
		if ( empty( $product_search_form_index ) ) {
2061
			$product_search_form_index = 0;
2062
		}
2063
2064
		do_action( 'pre_get_product_search_form'  );
2065
2066
		wc_get_template( 'product-searchform.php', array(
2067
			'index' => $product_search_form_index++,
2068
		) );
2069
2070
		$form = apply_filters( 'get_product_search_form', ob_get_clean() );
2071
2072
		if ( $echo ) {
2073
			echo $form;
2074
		} else {
2075
			return $form;
2076
		}
2077
	}
2078
}
2079
2080
if ( ! function_exists( 'woocommerce_output_auth_header' ) ) {
2081
2082
	/**
2083
	 * Output the Auth header.
2084
	 */
2085
	function woocommerce_output_auth_header() {
2086
		wc_get_template( 'auth/header.php' );
2087
	}
2088
}
2089
2090
if ( ! function_exists( 'woocommerce_output_auth_footer' ) ) {
2091
2092
	/**
2093
	 * Output the Auth footer.
2094
	 */
2095
	function woocommerce_output_auth_footer() {
2096
		wc_get_template( 'auth/footer.php' );
2097
	}
2098
}
2099
2100
if ( ! function_exists( 'woocommerce_single_variation' ) ) {
2101
2102
	/**
2103
	 * Output placeholders for the single variation.
2104
	 */
2105
	function woocommerce_single_variation() {
2106
		echo '<div class="woocommerce-variation single_variation"></div>';
2107
	}
2108
}
2109
2110
if ( ! function_exists( 'woocommerce_single_variation_add_to_cart_button' ) ) {
2111
2112
	/**
2113
	 * Output the add to cart button for variations.
2114
	 */
2115
	function woocommerce_single_variation_add_to_cart_button() {
2116
		wc_get_template( 'single-product/add-to-cart/variation-add-to-cart-button.php' );
2117
	}
2118
}
2119
2120
if ( ! function_exists( 'wc_dropdown_variation_attribute_options' ) ) {
2121
2122
	/**
2123
	 * Output a list of variation attributes for use in the cart forms.
2124
	 *
2125
	 * @param array $args
2126
	 * @since 2.4.0
2127
	 */
2128
	function wc_dropdown_variation_attribute_options( $args = array() ) {
2129
		$args = wp_parse_args( apply_filters( 'woocommerce_dropdown_variation_attribute_options_args', $args ), array(
2130
			'options'          => false,
2131
			'attribute'        => false,
2132
			'product'          => false,
2133
			'selected' 	       => false,
2134
			'name'             => '',
2135
			'id'               => '',
2136
			'class'            => '',
2137
			'show_option_none' => __( 'Choose an option', 'woocommerce' )
2138
		) );
2139
2140
		$options   = $args['options'];
2141
		$product   = $args['product'];
2142
		$attribute = $args['attribute'];
2143
		$name      = $args['name'] ? $args['name'] : 'attribute_' . sanitize_title( $attribute );
2144
		$id        = $args['id'] ? $args['id'] : sanitize_title( $attribute );
2145
		$class     = $args['class'];
2146
2147
		if ( empty( $options ) && ! empty( $product ) && ! empty( $attribute ) ) {
2148
			$attributes = $product->get_variation_attributes();
2149
			$options    = $attributes[ $attribute ];
2150
		}
2151
2152
		$html = '<select id="' . esc_attr( $id ) . '" class="' . esc_attr( $class ) . '" name="' . esc_attr( $name ) . '" data-attribute_name="attribute_' . esc_attr( sanitize_title( $attribute ) ) . '">';
2153
2154
		if ( $args['show_option_none'] ) {
2155
			$html .= '<option value="">' . esc_html( $args['show_option_none'] ) . '</option>';
2156
		}
2157
2158
		if ( ! empty( $options ) ) {
2159
			if ( $product && taxonomy_exists( $attribute ) ) {
2160
				// Get terms if this is a taxonomy - ordered. We need the names too.
2161
				$terms = wc_get_product_terms( $product->id, $attribute, array( 'fields' => 'all' ) );
2162
2163 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...
2164
					if ( in_array( $term->slug, $options ) ) {
2165
						$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>';
2166
					}
2167
				}
2168
			} else {
2169
				foreach ( $options as $option ) {
2170
					// This handles < 2.4.0 bw compatibility where text attributes were not sanitized.
2171
					$selected = sanitize_title( $args['selected'] ) === $args['selected'] ? selected( $args['selected'], sanitize_title( $option ), false ) : selected( $args['selected'], $option, false );
2172
					$html .= '<option value="' . esc_attr( $option ) . '" ' . $selected . '>' . esc_html( apply_filters( 'woocommerce_variation_option_name', $option ) ) . '</option>';
2173
				}
2174
			}
2175
		}
2176
2177
		$html .= '</select>';
2178
2179
		echo apply_filters( 'woocommerce_dropdown_variation_attribute_options_html', $html, $args );
2180
	}
2181
}
2182
2183
if ( ! function_exists( 'woocommerce_account_content' ) ) {
2184
2185
	/**
2186
	 * My Account content output.
2187
	 */
2188
	function woocommerce_account_content() {
2189
		global $wp;
2190
2191
		foreach ( $wp->query_vars as $key => $value ) {
2192
			// Ignore pagename param.
2193
			if ( 'pagename' === $key ) {
2194
				continue;
2195
			}
2196
2197
			if ( has_action( 'woocommerce_account_' . $key . '_endpoint' ) ) {
2198
				do_action( 'woocommerce_account_' . $key . '_endpoint', $value );
2199
				return;
2200
			}
2201
		}
2202
2203
		// No endpoint found? Default to dashboard.
2204
		wc_get_template( 'myaccount/dashboard.php', array(
2205
			'current_user' => get_user_by( 'id', get_current_user_id() ),
2206
		) );
2207
	}
2208
}
2209
2210
if ( ! function_exists( 'woocommerce_account_navigation' ) ) {
2211
2212
	/**
2213
	 * My Account navigation template.
2214
	 */
2215
	function woocommerce_account_navigation() {
2216
		wc_get_template( 'myaccount/navigation.php' );
2217
	}
2218
}
2219
2220
if ( ! function_exists( 'woocommerce_account_orders' ) ) {
2221
2222
	/**
2223
	 * My Account > Orders template.
2224
	 *
2225
	 * @param int $current_page Current page number.
2226
	 */
2227
	function woocommerce_account_orders( $current_page ) {
2228
		$current_page    = empty( $current_page ) ? 1 : absint( $current_page );
2229
		$customer_orders = wc_get_orders( apply_filters( 'woocommerce_my_account_my_orders_query', array( 'customer' => get_current_user_id(), 'page' => $current_page, 'paginate' => true ) ) );
2230
2231
		wc_get_template(
2232
			'myaccount/orders.php',
2233
			array(
2234
				'current_page' => absint( $current_page ),
2235
				'customer_orders' => $customer_orders,
2236
				'has_orders' => 0 < $customer_orders->total,
2237
			)
2238
		);
2239
	}
2240
}
2241
2242
if ( ! function_exists( 'woocommerce_account_view_order' ) ) {
2243
2244
	/**
2245
	 * My Account > View order template.
2246
	 *
2247
	 * @param int $order_id Order ID.
2248
	 */
2249
	function woocommerce_account_view_order( $order_id ) {
2250
		WC_Shortcode_My_Account::view_order( absint( $order_id ) );
2251
	}
2252
}
2253
2254
if ( ! function_exists( 'woocommerce_account_downloads' ) ) {
2255
2256
	/**
2257
	 * My Account > Downloads template.
2258
	 */
2259
	function woocommerce_account_downloads() {
2260
		wc_get_template( 'myaccount/downloads.php' );
2261
	}
2262
}
2263
2264
if ( ! function_exists( 'woocommerce_account_edit_address' ) ) {
2265
2266
	/**
2267
	 * My Account > Edit address template.
2268
	 *
2269
	 * @param string $type Address type.
2270
	 */
2271
	function woocommerce_account_edit_address( $type ) {
2272
		$type = wc_edit_address_i18n( sanitize_title( $type ), true );
2273
2274
		WC_Shortcode_My_Account::edit_address( $type );
2275
	}
2276
}
2277
2278
if ( ! function_exists( 'woocommerce_account_payment_methods' ) ) {
2279
2280
	/**
2281
	 * My Account > Downloads template.
2282
	 */
2283
	function woocommerce_account_payment_methods() {
2284
		wc_get_template( 'myaccount/payment-methods.php' );
2285
	}
2286
}
2287
2288
if ( ! function_exists( 'woocommerce_account_add_payment_method' ) ) {
2289
2290
	/**
2291
	 * My Account > Add payment method template.
2292
	 */
2293
	function woocommerce_account_add_payment_method() {
2294
		WC_Shortcode_My_Account::add_payment_method();
2295
	}
2296
}
2297
2298
if ( ! function_exists( 'woocommerce_account_edit_account' ) ) {
2299
2300
	/**
2301
	 * My Account > Edit account template.
2302
	 */
2303
	function woocommerce_account_edit_account() {
2304
		WC_Shortcode_My_Account::edit_account();
2305
	}
2306
}
2307
2308
2309
if ( ! function_exists( 'wc_get_email_order_items' ) ) {
2310
	/**
2311
	 * Get HTML for the order items to be shown in emails.
2312
	 * @param WC_Order $order
2313
	 * @param array $args
2314
	 * @since 2.7.0
2315
	 */
2316
	function wc_get_email_order_items( $order, $args = array() ) {
2317
		ob_start();
2318
2319
		$defaults = array(
2320
			'show_sku'   => false,
2321
			'show_image' => false,
2322
			'image_size' => array( 32, 32 ),
2323
			'plain_text' => false
2324
		);
2325
2326
		$args     = wp_parse_args( $args, $defaults );
2327
		$template = $args['plain_text'] ? 'emails/plain/email-order-items.php' : 'emails/email-order-items.php';
2328
2329
		wc_get_template( $template, array(
2330
			'order'               => $order,
2331
			'items'               => $order->get_items(),
2332
			'show_download_links' => $order->is_download_permitted(),
2333
			'show_sku'            => $args['show_sku'],
2334
			'show_purchase_note'  => $order->is_paid(),
2335
			'show_image'          => $args['show_image'],
2336
			'image_size'          => $args['image_size'],
2337
		) );
2338
2339
		return apply_filters( 'woocommerce_email_order_items_table', ob_get_clean(), $order );
2340
	}
2341
}
2342
2343
if ( ! function_exists( 'wc_display_item_meta' ) ) {
2344
	/**
2345
	 * Display item meta data.
2346
	 * @since  2.7.0
2347
	 * @param  WC_Item $item
2348
	 * @param  array   $args
2349
	 * @return string|void
2350
	 */
2351
	function wc_display_item_meta( $item, $args = array() ) {
2352
		$strings = array();
2353
		$html    = '';
2354
		$args    = wp_parse_args( $args, array(
2355
			'before'    => '<ul class="wc-item-meta"><li>',
2356
			'after'     => '</li></ul>',
2357
			'separator' => '</li><li>',
2358
			'echo'      => true,
2359
			'autop'     => false,
2360
		) );
2361
2362
		foreach ( $item->get_formatted_meta_data() as $meta_id => $meta ) {
2363
			if ( '_' === substr( $meta->key, 0, 1 ) ) {
2364
				continue;
2365
			}
2366
			$value = $args['autop'] ? wp_kses_post( wpautop( make_clickable( $meta->display_value ) ) ) : wp_kses_post( make_clickable( $meta->display_value ) );
2367
			$strings[] = '<strong class="wc-item-meta-label">' . wp_kses_post( $meta->display_key ) . ':</strong> ' . $value;
2368
		}
2369
2370 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...
2371
			$html = $args['before'] . implode( $args['separator'], $strings ) . $args['after'];
2372
		}
2373
2374
		$html = apply_filters( 'woocommerce_display_item_meta', $html, $item, $args );
2375
2376
		if ( $args['echo'] ) {
2377
			echo $html;
2378
		} else {
2379
			return $html;
2380
		}
2381
	}
2382
}
2383
2384
if ( ! function_exists( 'wc_display_item_downloads' ) ) {
2385
	/**
2386
	 * Display item download links.
2387
	 * @since  2.7.0
2388
	 * @param  WC_Item $item
2389
	 * @param  array   $args
2390
	 * @return string|void
2391
	 */
2392
	function wc_display_item_downloads( $item, $args = array() ) {
2393
		$strings = array();
2394
		$html    = '';
2395
		$args    = wp_parse_args( $args, array(
2396
			'before'    => '<ul class ="wc-item-downloads"><li>',
2397
			'after'     => '</li></ul>',
2398
			'separator' => '</li><li>',
2399
			'echo'      => true,
2400
			'show_url'  => false,
2401
		) );
2402
2403
		if ( is_object( $item ) && $item->is_type( 'line_item' ) && ( $downloads = $item->get_item_downloads() ) ) {
2404
			$i = 0;
2405
			foreach ( $downloads as $file ) {
2406
				$i ++;
2407
2408
				if ( $args['show_url'] ) {
2409
					$strings[] = '<strong class="wc-item-download-label">' .  esc_html( $file['name'] ) . ':</strong> ' . esc_html( $file['download_url'] );
2410
				} else {
2411
					$prefix = sizeof( $downloads ) > 1 ? sprintf( __( 'Download %d', 'woocommerce' ), $i ) : __( 'Download', 'woocommerce' );
2412
					$strings[] = '<strong class="wc-item-download-label">' . $prefix . ':</strong> <a href="' . esc_url( $file['download_url'] ) . '" target="_blank">' . esc_html( $file['name'] ) . '</a>';
2413
				}
2414
			}
2415
		}
2416
2417 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...
2418
			$html = $args['before'] . implode( $args['separator'], $strings ) . $args['after'];
2419
		}
2420
2421
		$html = apply_filters( 'woocommerce_display_item_downloads', $html, $item, $args );
2422
2423
		if ( $args['echo'] ) {
2424
			echo $html;
2425
		} else {
2426
			return $html;
2427
		}
2428
	}
2429
}
2430