Completed
Push — master ( fc6097...930cc3 )
by Mike
08:01
created

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

Complexity

Conditions 14
Paths 160

Size

Total Lines 42
Code Lines 25

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 14
eloc 25
c 1
b 0
f 0
nc 160
nop 3
dl 0
loc 42
rs 4.7877

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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