Completed
Push — master ( ad3f9d...dea212 )
by Mike
08:30
created

wc-template-functions.php ➔ woocommerce_form_field()   F

Complexity

Conditions 45
Paths > 20000

Size

Total Lines 205
Code Lines 121

Duplication

Lines 23
Ratio 11.22 %
Metric Value
cc 45
dl 23
loc 205
rs 2
eloc 121
nc 57600
nop 3

How to fix   Long Method    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
1 ignored issue
show
Coding Style Compatibility introduced by
For compatibility and reusability of your code, PSR1 recommends that a file should introduce either new symbols (like classes, functions, etc.) or have side-effects (like outputting something, or including other files), but not both at the same time. The first symbol is defined on line 20 and the first side effect is on line 14.

The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.

The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.

To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.

Loading history...
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' ) );
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 === $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' );
1 ignored issue
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
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
 *
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
		$feed = add_query_arg('product_cat', $term->slug, get_post_type_archive_feed_link( 'product' ));
153
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
	} elseif ( is_tax( 'product_tag' ) ) {
157
158
		$term = get_term_by('slug', esc_attr( get_query_var('product_tag') ), 'product_tag');
159
160
		$feed = add_query_arg('product_tag', $term->slug, get_post_type_archive_feed_link( 'product' ));
161
162
		echo '<link rel="alternate" type="application/rss+xml"  title="' . sprintf(__( 'New products tagged %s', 'woocommerce' ), urlencode($term->name)) . '" href="' . esc_url( $feed ) . '" />';
163
164
	}
165
}
166
167
/**
168
 * Output generator tag to aid debugging.
169
 *
170
 * @access public
171
 */
172
function wc_generator_tag( $gen, $type ) {
173
	switch ( $type ) {
174
		case 'html':
175
			$gen .= "\n" . '<meta name="generator" content="WooCommerce ' . esc_attr( WC_VERSION ) . '">';
176
			break;
177
		case 'xhtml':
178
			$gen .= "\n" . '<meta name="generator" content="WooCommerce ' . esc_attr( WC_VERSION ) . '" />';
179
			break;
180
	}
181
	return $gen;
182
}
183
184
/**
185
 * Add body classes for WC pages.
186
 *
187
 * @param  array $classes
188
 * @return array
189
 */
190
function wc_body_class( $classes ) {
191
	$classes = (array) $classes;
192
193
	if ( is_woocommerce() ) {
194
		$classes[] = 'woocommerce';
195
		$classes[] = 'woocommerce-page';
196
	}
197
198
	elseif ( is_checkout() ) {
199
		$classes[] = 'woocommerce-checkout';
200
		$classes[] = 'woocommerce-page';
201
	}
202
203
	elseif ( is_cart() ) {
204
		$classes[] = 'woocommerce-cart';
205
		$classes[] = 'woocommerce-page';
206
	}
207
208
	elseif ( is_account_page() ) {
209
		$classes[] = 'woocommerce-account';
210
		$classes[] = 'woocommerce-page';
211
	}
212
213
	if ( is_store_notice_showing() ) {
214
		$classes[] = 'woocommerce-demo-store';
215
	}
216
217
	foreach ( WC()->query->query_vars as $key => $value ) {
218
		if ( is_wc_endpoint_url( $key ) ) {
219
			$classes[] = 'woocommerce-' . sanitize_html_class( $key );
220
		}
221
	}
222
223
	return array_unique( $classes );
224
}
225
226
/**
227
 * Display the classes for the product cat div.
228
 *
229
 * @since 2.4.0
230
 * @param string|array $class One or more classes to add to the class list.
231
 * @param object $category object Optional.
232
 */
233
function wc_product_cat_class( $class = '', $category = null ) {
234
	// Separates classes with a single space, collates classes for post DIV
235
	echo 'class="' . esc_attr( join( ' ', wc_get_product_cat_class( $class, $category ) ) ) . '"';
236
}
237
238
/**
239
 * Get classname for loops based on $woocommerce_loop global.
240
 * @since 2.6.0
241
 * @return string
242
 */
243
function wc_get_loop_class() {
244
	global $woocommerce_loop;
245
246
	$woocommerce_loop['loop']    = ! empty( $woocommerce_loop['loop'] ) ? $woocommerce_loop['loop'] + 1   : 1;
247
	$woocommerce_loop['columns'] = ! empty( $woocommerce_loop['columns'] ) ? $woocommerce_loop['columns'] : apply_filters( 'loop_shop_columns', 4 );
248
249
	if ( 0 === ( $woocommerce_loop['loop'] - 1 ) % $woocommerce_loop['columns'] || 1 === $woocommerce_loop['columns'] ) {
250
		return 'first';
251
	} elseif ( 0 === $woocommerce_loop['loop'] % $woocommerce_loop['columns'] ) {
252
		return 'last';
253
	} else {
254
		return '';
255
	}
256
}
257
258
/**
259
 * Get the classes for the product cat div.
260
 *
261
 * @since 2.4.0
262
 * @param string|array $class One or more classes to add to the class list.
263
 * @param object $category object Optional.
264
 */
265
function wc_get_product_cat_class( $class = '', $category = null ) {
266
	$classes   = is_array( $class ) ? $class : array_map( 'trim', explode( ' ', $class ) );
267
	$classes[] = 'product-category';
268
	$classes[] = 'product';
269
	$classes[] = wc_get_loop_class();
270
	$classes   = apply_filters( 'product_cat_class', $classes, $class, $category );
271
272
	return array_unique( array_filter( $classes ) );
273
}
274
275
/**
276
 * Adds extra post classes for products.
277
 *
278
 * @since 2.1.0
279
 * @param array $classes
280
 * @param string|array $class
281
 * @param int $post_id
282
 * @return array
283
 */
284
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...
285
	if ( ! $post_id || 'product' !== get_post_type( $post_id ) ) {
286
		return $classes;
287
	}
288
289
	$product = wc_get_product( $post_id );
290
291
	if ( $product ) {
292
		$classes[] = wc_get_loop_class();
293
		$classes[] = $product->stock_status;
294
295
		if ( $product->is_on_sale() ) {
296
			$classes[] = 'sale';
297
		}
298
		if ( $product->is_featured() ) {
299
			$classes[] = 'featured';
300
		}
301
		if ( $product->is_downloadable() ) {
302
			$classes[] = 'downloadable';
303
		}
304
		if ( $product->is_virtual() ) {
305
			$classes[] = 'virtual';
306
		}
307
		if ( $product->is_sold_individually() ) {
308
			$classes[] = 'sold-individually';
309
		}
310
		if ( $product->is_taxable() ) {
311
			$classes[] = 'taxable';
312
		}
313
		if ( $product->is_shipping_taxable() ) {
314
			$classes[] = 'shipping-taxable';
315
		}
316
		if ( $product->is_purchasable() ) {
317
			$classes[] = 'purchasable';
318
		}
319
		if ( $product->get_type() ) {
320
			$classes[] = "product-type-" . $product->get_type();
321
		}
322
		if ( $product->is_type( 'variable' ) ) {
323
			if ( $product->has_default_attributes() ) {
324
				$classes[] = 'has-default-attributes';
325
			}
326
			if ( $product->has_child() ) {
327
				$classes[] = 'has-children';
328
			}
329
		}
330
	}
331
332
	if ( false !== ( $key = array_search( 'hentry', $classes ) ) ) {
333
		unset( $classes[ $key ] );
334
	}
335
336
	return $classes;
337
}
338
339
/** Template pages ********************************************************/
340
341
if ( ! function_exists( 'woocommerce_content' ) ) {
342
343
	/**
344
	 * Output WooCommerce content.
345
	 *
346
	 * This function is only used in the optional 'woocommerce.php' template.
347
	 * which people can add to their themes to add basic woocommerce support.
348
	 * without hooks or modifying core templates.
349
	 *
350
	 */
351
	function woocommerce_content() {
352
353
		if ( is_singular( 'product' ) ) {
354
355
			while ( have_posts() ) : the_post();
356
357
				wc_get_template_part( 'content', 'single-product' );
358
359
			endwhile;
360
361
		} else { ?>
362
363
			<?php if ( apply_filters( 'woocommerce_show_page_title', true ) ) : ?>
364
365
				<h1 class="page-title"><?php woocommerce_page_title(); ?></h1>
366
367
			<?php endif; ?>
368
369
			<?php do_action( 'woocommerce_archive_description' ); ?>
370
371 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...
372
373
				<?php do_action('woocommerce_before_shop_loop'); ?>
374
375
				<?php woocommerce_product_loop_start(); ?>
376
377
					<?php woocommerce_product_subcategories(); ?>
378
379
					<?php while ( have_posts() ) : the_post(); ?>
380
381
						<?php wc_get_template_part( 'content', 'product' ); ?>
382
383
					<?php endwhile; // end of the loop. ?>
384
385
				<?php woocommerce_product_loop_end(); ?>
386
387
				<?php do_action('woocommerce_after_shop_loop'); ?>
388
389
			<?php elseif ( ! woocommerce_product_subcategories( array( 'before' => woocommerce_product_loop_start( false ), 'after' => woocommerce_product_loop_end( false ) ) ) ) : ?>
390
391
				<?php wc_get_template( 'loop/no-products-found.php' ); ?>
392
393
			<?php endif;
394
395
		}
396
	}
397
}
398
399
/** Global ****************************************************************/
400
401
if ( ! function_exists( 'woocommerce_output_content_wrapper' ) ) {
402
403
	/**
404
	 * Output the start of the page wrapper.
405
	 *
406
	 */
407
	function woocommerce_output_content_wrapper() {
408
		wc_get_template( 'global/wrapper-start.php' );
409
	}
410
}
411
if ( ! function_exists( 'woocommerce_output_content_wrapper_end' ) ) {
412
413
	/**
414
	 * Output the end of the page wrapper.
415
	 *
416
	 */
417
	function woocommerce_output_content_wrapper_end() {
418
		wc_get_template( 'global/wrapper-end.php' );
419
	}
420
}
421
422
if ( ! function_exists( 'woocommerce_get_sidebar' ) ) {
423
424
	/**
425
	 * Get the shop sidebar template.
426
	 *
427
	 */
428
	function woocommerce_get_sidebar() {
429
		wc_get_template( 'global/sidebar.php' );
430
	}
431
}
432
433
if ( ! function_exists( 'woocommerce_demo_store' ) ) {
434
435
	/**
436
	 * Adds a demo store banner to the site if enabled.
437
	 *
438
	 */
439
	function woocommerce_demo_store() {
440
		if ( ! is_store_notice_showing() ) {
441
			return;
442
		}
443
444
		$notice = get_option( 'woocommerce_demo_store_notice' );
445
446
		if ( empty( $notice ) ) {
447
			$notice = __( 'This is a demo store for testing purposes &mdash; no orders shall be fulfilled.', 'woocommerce' );
448
		}
449
450
		echo apply_filters( 'woocommerce_demo_store', '<p class="demo_store">' . wp_kses_post( $notice ) . '</p>'  );
451
	}
452
}
453
454
/** Loop ******************************************************************/
455
456
if ( ! function_exists( 'woocommerce_page_title' ) ) {
457
458
	/**
459
	 * woocommerce_page_title function.
460
	 *
461
	 * @param  bool $echo
462
	 * @return string
463
	 */
464
	function woocommerce_page_title( $echo = true ) {
465
466
		if ( is_search() ) {
467
			$page_title = sprintf( __( 'Search Results: &ldquo;%s&rdquo;', 'woocommerce' ), get_search_query() );
468
469
			if ( get_query_var( 'paged' ) )
470
				$page_title .= sprintf( __( '&nbsp;&ndash; Page %s', 'woocommerce' ), get_query_var( 'paged' ) );
471
472
		} elseif ( is_tax() ) {
473
474
			$page_title = single_term_title( "", false );
475
476
		} else {
477
478
			$shop_page_id = wc_get_page_id( 'shop' );
479
			$page_title   = get_the_title( $shop_page_id );
480
481
		}
482
483
		$page_title = apply_filters( 'woocommerce_page_title', $page_title );
484
485
		if ( $echo )
486
	    	echo $page_title;
487
	    else
488
	    	return $page_title;
489
	}
490
}
491
492
if ( ! function_exists( 'woocommerce_product_loop_start' ) ) {
493
494
	/**
495
	 * Output the start of a product loop. By default this is a UL.
496
	 *
497
	 * @param bool $echo
498
	 * @return string
499
	 */
500
	function woocommerce_product_loop_start( $echo = true ) {
501
		ob_start();
502
		$GLOBALS['woocommerce_loop']['loop'] = 0;
503
		wc_get_template( 'loop/loop-start.php' );
504
		if ( $echo )
505
			echo ob_get_clean();
506
		else
507
			return ob_get_clean();
508
	}
509
}
510
if ( ! function_exists( 'woocommerce_product_loop_end' ) ) {
511
512
	/**
513
	 * Output the end of a product loop. By default this is a UL.
514
	 *
515
	 * @param bool $echo
516
	 * @return string
517
	 */
518
	function woocommerce_product_loop_end( $echo = true ) {
519
		ob_start();
520
521
		wc_get_template( 'loop/loop-end.php' );
522
523
		if ( $echo )
524
			echo ob_get_clean();
525
		else
526
			return ob_get_clean();
527
	}
528
}
529
if (  ! function_exists( 'woocommerce_template_loop_product_title' ) ) {
530
531
	/**
532
	 * Show the product title in the product loop. By default this is an H3.
533
	 */
534
	function woocommerce_template_loop_product_title() {
535
		echo '<h3>' . get_the_title() . '</h3>';
536
	}
537
}
538
if (  ! function_exists( 'woocommerce_template_loop_category_title' ) ) {
539
540
	/**
541
	 * Show the subcategory title in the product loop.
542
	 */
543
	function woocommerce_template_loop_category_title( $category ) {
544
		?>
545
		<h3>
546
			<?php
547
				echo $category->name;
548
549
				if ( $category->count > 0 )
550
					echo apply_filters( 'woocommerce_subcategory_count_html', ' <mark class="count">(' . $category->count . ')</mark>', $category );
551
			?>
552
		</h3>
553
		<?php
554
	}
555
}
556
/**
557
 * Insert the opening anchor tag for products in the loop.
558
 */
559
function woocommerce_template_loop_product_link_open() {
560
	echo '<a href="' . get_the_permalink() . '" class="woocommerce-LoopProduct-link">';
561
}
562
/**
563
 * Insert the opening anchor tag for products in the loop.
564
 */
565
function woocommerce_template_loop_product_link_close() {
566
	echo '</a>';
567
}
568
/**
569
 * Insert the opening anchor tag for categories in the loop.
570
 */
571
function woocommerce_template_loop_category_link_open( $category ) {
572
	echo '<a href="' . get_term_link( $category, 'product_cat' ) . '">';
573
}
574
/**
575
 * Insert the opening anchor tag for categories in the loop.
576
 */
577
function woocommerce_template_loop_category_link_close() {
578
	echo '</a>';
579
}
580
if ( ! function_exists( 'woocommerce_taxonomy_archive_description' ) ) {
581
582
	/**
583
	 * Show an archive description on taxonomy archives.
584
	 *
585
	 * @subpackage	Archives
586
	 */
587
	function woocommerce_taxonomy_archive_description() {
588
		if ( is_tax( array( 'product_cat', 'product_tag' ) ) && 0 === absint( get_query_var( 'paged' ) ) ) {
589
			$description = wc_format_content( term_description() );
590
			if ( $description ) {
591
				echo '<div class="term-description">' . $description . '</div>';
592
			}
593
		}
594
	}
595
}
596
if ( ! function_exists( 'woocommerce_product_archive_description' ) ) {
597
598
	/**
599
	 * Show a shop page description on product archives.
600
	 *
601
	 * @subpackage	Archives
602
	 */
603
	function woocommerce_product_archive_description() {
604
		if ( is_post_type_archive( 'product' ) && 0 === absint( get_query_var( 'paged' ) ) ) {
605
			$shop_page   = get_post( wc_get_page_id( 'shop' ) );
606
			if ( $shop_page ) {
607
				$description = wc_format_content( $shop_page->post_content );
608
				if ( $description ) {
609
					echo '<div class="page-description">' . $description . '</div>';
610
				}
611
			}
612
		}
613
	}
614
}
615
616
if ( ! function_exists( 'woocommerce_template_loop_add_to_cart' ) ) {
617
618
	/**
619
	 * Get the add to cart template for the loop.
620
	 *
621
	 * @subpackage	Loop
622
	 */
623
	function woocommerce_template_loop_add_to_cart( $args = array() ) {
624
		global $product;
625
626
		if ( $product ) {
627
			$defaults = array(
628
				'quantity' => 1,
629
				'class'    => implode( ' ', array_filter( array(
630
						'button',
631
						'product_type_' . $product->product_type,
632
						$product->is_purchasable() && $product->is_in_stock() ? 'add_to_cart_button' : '',
633
						$product->supports( 'ajax_add_to_cart' ) ? 'ajax_add_to_cart' : ''
634
				) ) )
635
			);
636
637
			$args = apply_filters( 'woocommerce_loop_add_to_cart_args', wp_parse_args( $args, $defaults ), $product );
638
639
			wc_get_template( 'loop/add-to-cart.php', $args );
640
		}
641
	}
642
}
643
if ( ! function_exists( 'woocommerce_template_loop_product_thumbnail' ) ) {
644
645
	/**
646
	 * Get the product thumbnail for the loop.
647
	 *
648
	 * @subpackage	Loop
649
	 */
650
	function woocommerce_template_loop_product_thumbnail() {
651
		echo woocommerce_get_product_thumbnail();
652
	}
653
}
654
if ( ! function_exists( 'woocommerce_template_loop_price' ) ) {
655
656
	/**
657
	 * Get the product price for the loop.
658
	 *
659
	 * @subpackage	Loop
660
	 */
661
	function woocommerce_template_loop_price() {
662
		wc_get_template( 'loop/price.php' );
663
	}
664
}
665
if ( ! function_exists( 'woocommerce_template_loop_rating' ) ) {
666
667
	/**
668
	 * Display the average rating in the loop.
669
	 *
670
	 * @subpackage	Loop
671
	 */
672
	function woocommerce_template_loop_rating() {
673
		wc_get_template( 'loop/rating.php' );
674
	}
675
}
676
if ( ! function_exists( 'woocommerce_show_product_loop_sale_flash' ) ) {
677
678
	/**
679
	 * Get the sale flash for the loop.
680
	 *
681
	 * @subpackage	Loop
682
	 */
683
	function woocommerce_show_product_loop_sale_flash() {
684
		wc_get_template( 'loop/sale-flash.php' );
685
	}
686
}
687
688
if ( ! function_exists( 'woocommerce_get_product_schema' ) ) {
689
690
	/**
691
	 * Get a products Schema.
692
	 * @return string
693
	 */
694
	function woocommerce_get_product_schema() {
695
		global $product;
696
697
		$schema = "Product";
698
699
		// Downloadable product schema handling
700
		if ( $product->is_downloadable() ) {
701
			switch ( $product->download_type ) {
702
				case 'application' :
703
					$schema = "SoftwareApplication";
704
				break;
705
				case 'music' :
706
					$schema = "MusicAlbum";
707
				break;
708
				default :
709
					$schema = "Product";
710
				break;
711
			}
712
		}
713
714
		return 'http://schema.org/' . $schema;
715
	}
716
}
717
718
if ( ! function_exists( 'woocommerce_get_product_thumbnail' ) ) {
719
720
	/**
721
	 * Get the product thumbnail, or the placeholder if not set.
722
	 *
723
	 * @subpackage	Loop
724
	 * @param string $size (default: 'shop_catalog')
725
	 * @param int $deprecated1 Deprecated since WooCommerce 2.0 (default: 0)
726
	 * @param int $deprecated2 Deprecated since WooCommerce 2.0 (default: 0)
727
	 * @return string
728
	 */
729
	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...
730
		global $post;
731
732
		if ( has_post_thumbnail() ) {
733
			return get_the_post_thumbnail( $post->ID, $size );
734
		} elseif ( wc_placeholder_img_src() ) {
735
			return wc_placeholder_img( $size );
736
		}
737
	}
738
}
739
740
if ( ! function_exists( 'woocommerce_result_count' ) ) {
741
742
	/**
743
	 * Output the result count text (Showing x - x of x results).
744
	 *
745
	 * @subpackage	Loop
746
	 */
747
	function woocommerce_result_count() {
748
		wc_get_template( 'loop/result-count.php' );
749
	}
750
}
751
752
if ( ! function_exists( 'woocommerce_catalog_ordering' ) ) {
753
754
	/**
755
	 * Output the product sorting options.
756
	 *
757
	 * @subpackage	Loop
758
	 */
759
	function woocommerce_catalog_ordering() {
760
		global $wp_query;
761
762
		if ( 1 === $wp_query->found_posts || ! woocommerce_products_will_display() ) {
763
			return;
764
		}
765
766
		$orderby                 = isset( $_GET['orderby'] ) ? wc_clean( $_GET['orderby'] ) : apply_filters( 'woocommerce_default_catalog_orderby', get_option( 'woocommerce_default_catalog_orderby' ) );
767
		$show_default_orderby    = 'menu_order' === apply_filters( 'woocommerce_default_catalog_orderby', get_option( 'woocommerce_default_catalog_orderby' ) );
768
		$catalog_orderby_options = apply_filters( 'woocommerce_catalog_orderby', array(
769
			'menu_order' => __( 'Default sorting', 'woocommerce' ),
770
			'popularity' => __( 'Sort by popularity', 'woocommerce' ),
771
			'rating'     => __( 'Sort by average rating', 'woocommerce' ),
772
			'date'       => __( 'Sort by newness', 'woocommerce' ),
773
			'price'      => __( 'Sort by price: low to high', 'woocommerce' ),
774
			'price-desc' => __( 'Sort by price: high to low', 'woocommerce' )
775
		) );
776
777
		if ( ! $show_default_orderby ) {
778
			unset( $catalog_orderby_options['menu_order'] );
779
		}
780
781
		if ( 'no' === get_option( 'woocommerce_enable_review_rating' ) ) {
782
			unset( $catalog_orderby_options['rating'] );
783
		}
784
785
		wc_get_template( 'loop/orderby.php', array( 'catalog_orderby_options' => $catalog_orderby_options, 'orderby' => $orderby, 'show_default_orderby' => $show_default_orderby ) );
786
	}
787
}
788
789
if ( ! function_exists( 'woocommerce_pagination' ) ) {
790
791
	/**
792
	 * Output the pagination.
793
	 *
794
	 * @subpackage	Loop
795
	 */
796
	function woocommerce_pagination() {
797
		wc_get_template( 'loop/pagination.php' );
798
	}
799
}
800
801
/** Single Product ********************************************************/
802
803
if ( ! function_exists( 'woocommerce_show_product_images' ) ) {
804
805
	/**
806
	 * Output the product image before the single product summary.
807
	 *
808
	 * @subpackage	Product
809
	 */
810
	function woocommerce_show_product_images() {
811
		wc_get_template( 'single-product/product-image.php' );
812
	}
813
}
814
if ( ! function_exists( 'woocommerce_show_product_thumbnails' ) ) {
815
816
	/**
817
	 * Output the product thumbnails.
818
	 *
819
	 * @subpackage	Product
820
	 */
821
	function woocommerce_show_product_thumbnails() {
822
		wc_get_template( 'single-product/product-thumbnails.php' );
823
	}
824
}
825
if ( ! function_exists( 'woocommerce_output_product_data_tabs' ) ) {
826
827
	/**
828
	 * Output the product tabs.
829
	 *
830
	 * @subpackage	Product/Tabs
831
	 */
832
	function woocommerce_output_product_data_tabs() {
833
		wc_get_template( 'single-product/tabs/tabs.php' );
834
	}
835
}
836
if ( ! function_exists( 'woocommerce_template_single_title' ) ) {
837
838
	/**
839
	 * Output the product title.
840
	 *
841
	 * @subpackage	Product
842
	 */
843
	function woocommerce_template_single_title() {
844
		wc_get_template( 'single-product/title.php' );
845
	}
846
}
847
if ( ! function_exists( 'woocommerce_template_single_rating' ) ) {
848
849
	/**
850
	 * Output the product rating.
851
	 *
852
	 * @subpackage	Product
853
	 */
854
	function woocommerce_template_single_rating() {
855
		wc_get_template( 'single-product/rating.php' );
856
	}
857
}
858
if ( ! function_exists( 'woocommerce_template_single_price' ) ) {
859
860
	/**
861
	 * Output the product price.
862
	 *
863
	 * @subpackage	Product
864
	 */
865
	function woocommerce_template_single_price() {
866
		wc_get_template( 'single-product/price.php' );
867
	}
868
}
869
if ( ! function_exists( 'woocommerce_template_single_excerpt' ) ) {
870
871
	/**
872
	 * Output the product short description (excerpt).
873
	 *
874
	 * @subpackage	Product
875
	 */
876
	function woocommerce_template_single_excerpt() {
877
		wc_get_template( 'single-product/short-description.php' );
878
	}
879
}
880
if ( ! function_exists( 'woocommerce_template_single_meta' ) ) {
881
882
	/**
883
	 * Output the product meta.
884
	 *
885
	 * @subpackage	Product
886
	 */
887
	function woocommerce_template_single_meta() {
888
		wc_get_template( 'single-product/meta.php' );
889
	}
890
}
891
if ( ! function_exists( 'woocommerce_template_single_sharing' ) ) {
892
893
	/**
894
	 * Output the product sharing.
895
	 *
896
	 * @subpackage	Product
897
	 */
898
	function woocommerce_template_single_sharing() {
899
		wc_get_template( 'single-product/share.php' );
900
	}
901
}
902
if ( ! function_exists( 'woocommerce_show_product_sale_flash' ) ) {
903
904
	/**
905
	 * Output the product sale flash.
906
	 *
907
	 * @subpackage	Product
908
	 */
909
	function woocommerce_show_product_sale_flash() {
910
		wc_get_template( 'single-product/sale-flash.php' );
911
	}
912
}
913
914
if ( ! function_exists( 'woocommerce_template_single_add_to_cart' ) ) {
915
916
	/**
917
	 * Trigger the single product add to cart action.
918
	 *
919
	 * @subpackage	Product
920
	 */
921
	function woocommerce_template_single_add_to_cart() {
922
		global $product;
923
		do_action( 'woocommerce_' . $product->product_type . '_add_to_cart' );
924
	}
925
}
926
if ( ! function_exists( 'woocommerce_simple_add_to_cart' ) ) {
927
928
	/**
929
	 * Output the simple product add to cart area.
930
	 *
931
	 * @subpackage	Product
932
	 */
933
	function woocommerce_simple_add_to_cart() {
934
		wc_get_template( 'single-product/add-to-cart/simple.php' );
935
	}
936
}
937
if ( ! function_exists( 'woocommerce_grouped_add_to_cart' ) ) {
938
939
	/**
940
	 * Output the grouped product add to cart area.
941
	 *
942
	 * @subpackage	Product
943
	 */
944
	function woocommerce_grouped_add_to_cart() {
945
		global $product;
946
947
		wc_get_template( 'single-product/add-to-cart/grouped.php', array(
948
			'grouped_product'    => $product,
949
			'grouped_products'   => $product->get_children(),
950
			'quantites_required' => false
951
		) );
952
	}
953
}
954
if ( ! function_exists( 'woocommerce_variable_add_to_cart' ) ) {
955
956
	/**
957
	 * Output the variable product add to cart area.
958
	 *
959
	 * @subpackage	Product
960
	 */
961
	function woocommerce_variable_add_to_cart() {
962
		global $product;
963
964
		// Enqueue variation scripts
965
		wp_enqueue_script( 'wc-add-to-cart-variation' );
966
967
		// Get Available variations?
968
		$get_variations = sizeof( $product->get_children() ) <= apply_filters( 'woocommerce_ajax_variation_threshold', 30, $product );
969
970
		// Load the template
971
		wc_get_template( 'single-product/add-to-cart/variable.php', array(
972
			'available_variations' => $get_variations ? $product->get_available_variations() : false,
973
			'attributes'           => $product->get_variation_attributes(),
974
			'selected_attributes'  => $product->get_variation_default_attributes()
975
		) );
976
	}
977
}
978
if ( ! function_exists( 'woocommerce_external_add_to_cart' ) ) {
979
980
	/**
981
	 * Output the external product add to cart area.
982
	 *
983
	 * @subpackage	Product
984
	 */
985
	function woocommerce_external_add_to_cart() {
986
		global $product;
987
988
		if ( ! $product->add_to_cart_url() ) {
989
			return;
990
		}
991
992
		wc_get_template( 'single-product/add-to-cart/external.php', array(
993
			'product_url' => $product->add_to_cart_url(),
994
			'button_text' => $product->single_add_to_cart_text()
995
		) );
996
	}
997
}
998
999
if ( ! function_exists( 'woocommerce_quantity_input' ) ) {
1000
1001
	/**
1002
	 * Output the quantity input for add to cart forms.
1003
	 *
1004
	 * @param  array $args Args for the input
1005
	 * @param  WC_Product|null $product
1006
	 * @param  boolean $echo Whether to return or echo|string
1007
	 */
1008
	function woocommerce_quantity_input( $args = array(), $product = null, $echo = true ) {
1009
		if ( is_null( $product ) ) {
1010
			$product = $GLOBALS['product'];
1011
		}
1012
1013
		$defaults = array(
1014
			'input_name'  => 'quantity',
1015
			'input_value' => '1',
1016
			'max_value'   => apply_filters( 'woocommerce_quantity_input_max', '', $product ),
1017
			'min_value'   => apply_filters( 'woocommerce_quantity_input_min', '', $product ),
1018
			'step'        => apply_filters( 'woocommerce_quantity_input_step', '1', $product ),
1019
			'pattern'     => apply_filters( 'woocommerce_quantity_input_pattern', has_filter( 'woocommerce_stock_amount', 'intval' ) ? '[0-9]*' : '' ),
1020
			'inputmode'   => apply_filters( 'woocommerce_quantity_input_inputmode', has_filter( 'woocommerce_stock_amount', 'intval' ) ? 'numeric' : '' ),
1021
		);
1022
1023
		$args = apply_filters( 'woocommerce_quantity_input_args', wp_parse_args( $args, $defaults ), $product );
1024
1025
		// Apply sanity to min/max args - min cannot be lower than 0
1026
		if ( '' !== $args['min_value'] && is_numeric( $args['min_value'] ) && $args['min_value'] < 0 ) {
1027
			$args['min_value'] = 0; // Cannot be lower than 0
1028
		}
1029
1030
		// Max cannot be lower than 0 or min
1031
		if ( '' !== $args['max_value'] && is_numeric( $args['max_value'] ) ) {
1032
			$args['max_value'] = $args['max_value'] < 0 ? 0 : $args['max_value'];
1033
			$args['max_value'] = $args['max_value'] < $args['min_value'] ? $args['min_value'] : $args['max_value'];
1034
		}
1035
1036
		ob_start();
1037
1038
		wc_get_template( 'global/quantity-input.php', $args );
1039
1040
		if ( $echo ) {
1041
			echo ob_get_clean();
1042
		} else {
1043
			return ob_get_clean();
1044
		}
1045
	}
1046
}
1047
1048
if ( ! function_exists( 'woocommerce_product_description_tab' ) ) {
1049
1050
	/**
1051
	 * Output the description tab content.
1052
	 *
1053
	 * @subpackage	Product/Tabs
1054
	 */
1055
	function woocommerce_product_description_tab() {
1056
		wc_get_template( 'single-product/tabs/description.php' );
1057
	}
1058
}
1059
if ( ! function_exists( 'woocommerce_product_additional_information_tab' ) ) {
1060
1061
	/**
1062
	 * Output the attributes tab content.
1063
	 *
1064
	 * @subpackage	Product/Tabs
1065
	 */
1066
	function woocommerce_product_additional_information_tab() {
1067
		wc_get_template( 'single-product/tabs/additional-information.php' );
1068
	}
1069
}
1070
if ( ! function_exists( 'woocommerce_product_reviews_tab' ) ) {
1071
1072
	/**
1073
	 * Output the reviews tab content.
1074
	 * @deprecated  2.4.0 Unused
1075
	 * @subpackage	Product/Tabs
1076
	 */
1077
	function woocommerce_product_reviews_tab() {
1078
		_deprecated_function( 'woocommerce_product_reviews_tab', '2.4', '' );
1079
	}
1080
}
1081
1082
if ( ! function_exists( 'woocommerce_default_product_tabs' ) ) {
1083
1084
	/**
1085
	 * Add default product tabs to product pages.
1086
	 *
1087
	 * @param array $tabs
1088
	 * @return array
1089
	 */
1090
	function woocommerce_default_product_tabs( $tabs = array() ) {
1091
		global $product, $post;
1092
1093
		// Description tab - shows product content
1094
		if ( $post->post_content ) {
1095
			$tabs['description'] = array(
1096
				'title'    => __( 'Description', 'woocommerce' ),
1097
				'priority' => 10,
1098
				'callback' => 'woocommerce_product_description_tab'
1099
			);
1100
		}
1101
1102
		// Additional information tab - shows attributes
1103
		if ( $product && ( $product->has_attributes() || ( $product->enable_dimensions_display() && ( $product->has_dimensions() || $product->has_weight() ) ) ) ) {
1104
			$tabs['additional_information'] = array(
1105
				'title'    => __( 'Additional Information', 'woocommerce' ),
1106
				'priority' => 20,
1107
				'callback' => 'woocommerce_product_additional_information_tab'
1108
			);
1109
		}
1110
1111
		// Reviews tab - shows comments
1112
		if ( comments_open() ) {
1113
			$tabs['reviews'] = array(
1114
				'title'    => sprintf( __( 'Reviews (%d)', 'woocommerce' ), $product->get_review_count() ),
1115
				'priority' => 30,
1116
				'callback' => 'comments_template'
1117
			);
1118
		}
1119
1120
		return $tabs;
1121
	}
1122
}
1123
1124
if ( ! function_exists( 'woocommerce_sort_product_tabs' ) ) {
1125
1126
	/**
1127
	 * Sort tabs by priority.
1128
	 *
1129
	 * @param array $tabs
1130
	 * @return array
1131
	 */
1132
	function woocommerce_sort_product_tabs( $tabs = array() ) {
1133
1134
		// Make sure the $tabs parameter is an array
1135
		if ( ! is_array( $tabs ) ) {
1136
			trigger_error( "Function woocommerce_sort_product_tabs() expects an array as the first parameter. Defaulting to empty array." );
1137
			$tabs = array( );
1138
		}
1139
1140
		// Re-order tabs by priority
1141
		if ( ! function_exists( '_sort_priority_callback' ) ) {
1142
			function _sort_priority_callback( $a, $b ) {
1143
				if ( $a['priority'] === $b['priority'] )
1144
			        return 0;
1145
			    return ( $a['priority'] < $b['priority'] ) ? -1 : 1;
1146
			}
1147
		}
1148
1149
		uasort( $tabs, '_sort_priority_callback' );
1150
1151
		return $tabs;
1152
	}
1153
}
1154
1155
if ( ! function_exists( 'woocommerce_comments' ) ) {
1156
1157
	/**
1158
	 * Output the Review comments template.
1159
	 *
1160
	 * @subpackage	Product
1161
	 * @param WP_Comment $comment
1162
	 * @param array $args
1163
	 * @param int $depth
1164
	 */
1165
	function woocommerce_comments( $comment, $args, $depth ) {
1166
		$GLOBALS['comment'] = $comment;
1167
		wc_get_template( 'single-product/review.php', array( 'comment' => $comment, 'args' => $args, 'depth' => $depth ) );
1168
	}
1169
}
1170
1171
if ( ! function_exists( 'woocommerce_review_display_gravatar' ) ) {
1172
	/**
1173
	 * Display the review authors gravatar
1174
	 *
1175
	 * @param array $comment WP_Comment.
1176
	 * @return void
1177
	 */
1178
	function woocommerce_review_display_gravatar( $comment ) {
1179
		echo get_avatar( $comment, apply_filters( 'woocommerce_review_gravatar_size', '60' ), '' );
1180
	}
1181
}
1182
1183
if ( ! function_exists( 'woocommerce_review_display_rating' ) ) {
1184
	/**
1185
	 * Display the reviewers star rating
1186
	 *
1187
	 * @return void
1188
	 */
1189
	function woocommerce_review_display_rating() {
1190
		wc_get_template( 'single-product/review-rating.php' );
1191
	}
1192
}
1193
1194
if ( ! function_exists( 'woocommerce_review_display_meta' ) ) {
1195
	/**
1196
	 * Display the review authors meta (name, verified owner, review date)
1197
	 *
1198
	 * @return void
1199
	 */
1200
	function woocommerce_review_display_meta() {
1201
		wc_get_template( 'single-product/review-meta.php' );
1202
	}
1203
}
1204
1205
if ( ! function_exists( 'woocommerce_review_display_comment_text' ) ) {
1206
	/**
1207
	 * Display the review content
1208
	 *
1209
	 * @return void
1210
	 */
1211
	function woocommerce_review_display_comment_text() {
1212
		echo '<div itemprop="description" class="description">' . comment_text() . '</div>';
1213
	}
1214
}
1215
1216
if ( ! function_exists( 'woocommerce_output_related_products' ) ) {
1217
1218
	/**
1219
	 * Output the related products.
1220
	 *
1221
	 * @subpackage	Product
1222
	 */
1223
	function woocommerce_output_related_products() {
1224
1225
		$args = array(
1226
			'posts_per_page' 	=> 4,
1227
			'columns' 			=> 4,
1228
			'orderby' 			=> 'rand'
1229
		);
1230
1231
		woocommerce_related_products( apply_filters( 'woocommerce_output_related_products_args', $args ) );
1232
	}
1233
}
1234
1235
if ( ! function_exists( 'woocommerce_related_products' ) ) {
1236
1237
	/**
1238
	 * Output the related products.
1239
	 *
1240
	 * @param array Provided arguments
1241
	 * @param bool Columns argument for backwards compat
1242
	 * @param bool Order by argument for backwards compat
1243
	 */
1244
	function woocommerce_related_products( $args = array(), $columns = false, $orderby = false ) {
1245
		if ( ! is_array( $args ) ) {
1246
			_deprecated_argument( __FUNCTION__, '2.1', __( 'Use $args argument as an array instead. Deprecated argument will be removed in WC 2.2.', 'woocommerce' ) );
1247
1248
			$argsvalue = $args;
1249
1250
			$args = array(
1251
				'posts_per_page' => $argsvalue,
1252
				'columns'        => $columns,
1253
				'orderby'        => $orderby,
1254
			);
1255
		}
1256
1257
		$defaults = array(
1258
			'posts_per_page' => 2,
1259
			'columns'        => 2,
1260
			'orderby'        => 'rand'
1261
		);
1262
1263
		$args = wp_parse_args( $args, $defaults );
1264
1265
		wc_get_template( 'single-product/related.php', $args );
1266
	}
1267
}
1268
1269
if ( ! function_exists( 'woocommerce_upsell_display' ) ) {
1270
1271
	/**
1272
	 * Output product up sells.
1273
	 *
1274
	 * @param int $posts_per_page (default: -1)
1275
	 * @param int $columns (default: 4)
1276
	 * @param string $orderby (default: 'rand')
1277
	 */
1278
	function woocommerce_upsell_display( $posts_per_page = '-1', $columns = 4, $orderby = 'rand' ) {
1279
		$args = apply_filters( 'woocommerce_upsell_display_args', array(
1280
			'posts_per_page'	=> $posts_per_page,
1281
			'orderby'			=> apply_filters( 'woocommerce_upsells_orderby', $orderby ),
1282
			'columns'			=> $columns
1283
		) );
1284
1285
		wc_get_template( 'single-product/up-sells.php', $args );
1286
	}
1287
}
1288
1289
/** Cart ******************************************************************/
1290
1291
if ( ! function_exists( 'woocommerce_shipping_calculator' ) ) {
1292
1293
	/**
1294
	 * Output the cart shipping calculator.
1295
	 *
1296
	 * @subpackage	Cart
1297
	 */
1298
	function woocommerce_shipping_calculator() {
1299
		wc_get_template( 'cart/shipping-calculator.php' );
1300
	}
1301
}
1302
1303
if ( ! function_exists( 'woocommerce_cart_totals' ) ) {
1304
1305
	/**
1306
	 * Output the cart totals.
1307
	 *
1308
	 * @subpackage	Cart
1309
	 */
1310
	function woocommerce_cart_totals() {
1311
		wc_get_template( 'cart/cart-totals.php' );
1312
	}
1313
}
1314
1315
if ( ! function_exists( 'woocommerce_cross_sell_display' ) ) {
1316
1317
	/**
1318
	 * Output the cart cross-sells.
1319
	 *
1320
	 * @param  int $posts_per_page (default: 2)
1321
	 * @param  int $columns (default: 2)
1322
	 * @param  string $orderby (default: 'rand')
1323
	 */
1324
	function woocommerce_cross_sell_display( $posts_per_page = 2, $columns = 2, $orderby = 'rand' ) {
1325
		wc_get_template( 'cart/cross-sells.php', array(
1326
				'posts_per_page' => $posts_per_page,
1327
				'orderby'        => $orderby,
1328
				'columns'        => $columns
1329
			) );
1330
	}
1331
}
1332
1333
if ( ! function_exists( 'woocommerce_button_proceed_to_checkout' ) ) {
1334
1335
	/**
1336
	 * Output the proceed to checkout button.
1337
	 *
1338
	 * @subpackage	Cart
1339
	 */
1340
	function woocommerce_button_proceed_to_checkout() {
1341
		wc_get_template( 'cart/proceed-to-checkout-button.php' );
1342
	}
1343
}
1344
1345
1346
1347
/** Mini-Cart *************************************************************/
1348
1349
if ( ! function_exists( 'woocommerce_mini_cart' ) ) {
1350
1351
	/**
1352
	 * Output the Mini-cart - used by cart widget.
1353
	 *
1354
	 * @param array $args
1355
	 */
1356
	function woocommerce_mini_cart( $args = array() ) {
1357
1358
		$defaults = array(
1359
			'list_class' => ''
1360
		);
1361
1362
		$args = wp_parse_args( $args, $defaults );
1363
1364
		wc_get_template( 'cart/mini-cart.php', $args );
1365
	}
1366
}
1367
1368
/** Login *****************************************************************/
1369
1370
if ( ! function_exists( 'woocommerce_login_form' ) ) {
1371
1372
	/**
1373
	 * Output the WooCommerce Login Form.
1374
	 *
1375
	 * @subpackage	Forms
1376
	 * @param array $args
1377
	 */
1378
	function woocommerce_login_form( $args = array() ) {
1379
1380
		$defaults = array(
1381
			'message'  => '',
1382
			'redirect' => '',
1383
			'hidden'   => false
1384
		);
1385
1386
		$args = wp_parse_args( $args, $defaults  );
1387
1388
		wc_get_template( 'global/form-login.php', $args );
1389
	}
1390
}
1391
1392
if ( ! function_exists( 'woocommerce_checkout_login_form' ) ) {
1393
1394
	/**
1395
	 * Output the WooCommerce Checkout Login Form.
1396
	 *
1397
	 * @subpackage	Checkout
1398
	 */
1399
	function woocommerce_checkout_login_form() {
1400
		wc_get_template( 'checkout/form-login.php', array( 'checkout' => WC()->checkout() ) );
1401
	}
1402
}
1403
1404
if ( ! function_exists( 'woocommerce_breadcrumb' ) ) {
1405
1406
	/**
1407
	 * Output the WooCommerce Breadcrumb.
1408
	 *
1409
	 * @param array $args
1410
	 */
1411
	function woocommerce_breadcrumb( $args = array() ) {
1412
		$args = wp_parse_args( $args, apply_filters( 'woocommerce_breadcrumb_defaults', array(
1413
			'delimiter'   => '&nbsp;&#47;&nbsp;',
1414
			'wrap_before' => '<nav class="woocommerce-breadcrumb" ' . ( is_single() ? 'itemprop="breadcrumb"' : '' ) . '>',
1415
			'wrap_after'  => '</nav>',
1416
			'before'      => '',
1417
			'after'       => '',
1418
			'home'        => _x( 'Home', 'breadcrumb', 'woocommerce' )
1419
		) ) );
1420
1421
		$breadcrumbs = new WC_Breadcrumb();
1422
1423
		if ( $args['home'] ) {
1424
			$breadcrumbs->add_crumb( $args['home'], apply_filters( 'woocommerce_breadcrumb_home_url', home_url() ) );
1425
		}
1426
1427
		$args['breadcrumb'] = $breadcrumbs->generate();
1428
1429
		wc_get_template( 'global/breadcrumb.php', $args );
1430
	}
1431
}
1432
1433
if ( ! function_exists( 'woocommerce_order_review' ) ) {
1434
1435
	/**
1436
	 * Output the Order review table for the checkout.
1437
	 *
1438
	 * @subpackage	Checkout
1439
	 */
1440
	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...
1441
		wc_get_template( 'checkout/review-order.php', array( 'checkout' => WC()->checkout() ) );
1442
	}
1443
}
1444
1445
if ( ! function_exists( 'woocommerce_checkout_payment' ) ) {
1446
1447
	/**
1448
	 * Output the Payment Methods on the checkout.
1449
	 *
1450
	 * @subpackage	Checkout
1451
	 */
1452
	function woocommerce_checkout_payment() {
1453
		if ( WC()->cart->needs_payment() ) {
1454
			$available_gateways = WC()->payment_gateways()->get_available_payment_gateways();
1455
			WC()->payment_gateways()->set_current_gateway( $available_gateways );
1456
		} else {
1457
			$available_gateways = array();
0 ignored issues
show
Unused Code introduced by
$available_gateways is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1458
		}
1459
1460
		wc_get_template( 'checkout/payment.php', array(
1461
			'checkout'           => WC()->checkout(),
1462
			'available_gateways' => WC()->payment_gateways()->get_available_payment_gateways(),
1463
			'order_button_text'  => apply_filters( 'woocommerce_order_button_text', __( 'Place order', 'woocommerce' ) )
1464
		) );
1465
	}
1466
}
1467
1468
if ( ! function_exists( 'woocommerce_checkout_coupon_form' ) ) {
1469
1470
	/**
1471
	 * Output the Coupon form for the checkout.
1472
	 *
1473
	 * @subpackage	Checkout
1474
	 */
1475
	function woocommerce_checkout_coupon_form() {
1476
		wc_get_template( 'checkout/form-coupon.php', array( 'checkout' => WC()->checkout() ) );
1477
	}
1478
}
1479
1480
if ( ! function_exists( 'woocommerce_products_will_display' ) ) {
1481
1482
	/**
1483
	 * Check if we will be showing products or not (and not sub-categories only).
1484
	 * @subpackage	Loop
1485
	 * @return bool
1486
	 */
1487
	function woocommerce_products_will_display() {
1488
		global $wpdb;
1489
1490
		if ( is_shop() ) {
1491
			return 'subcategories' !== get_option( 'woocommerce_shop_page_display' ) || is_search();
1492
		}
1493
1494
		if ( ! is_product_taxonomy() ) {
1495
			return false;
1496
		}
1497
1498
		if ( is_search() || is_filtered() || is_paged() ) {
1499
			return true;
1500
		}
1501
1502
		$term = get_queried_object();
1503
1504
		if ( is_product_category() ) {
1505
			switch ( get_woocommerce_term_meta( $term->term_id, 'display_type', true ) ) {
1506
				case 'subcategories' :
1507
					// Nothing - we want to continue to see if there are products/subcats
1508
				break;
1509
				case 'products' :
1510
				case 'both' :
1511
					return true;
1512
				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...
1513
				default :
1514
					// Default - no setting
1515
					if ( get_option( 'woocommerce_category_archive_display' ) != 'subcategories' ) {
1516
						return true;
1517
					}
1518
				break;
1519
			}
1520
		}
1521
1522
		// Begin subcategory logic
1523
		if ( empty( $term->term_id ) || empty( $term->taxonomy ) ) {
1524
			return true;
1525
		}
1526
1527
		$transient_name = 'wc_products_will_display_' . $term->term_id . '_' . WC_Cache_Helper::get_transient_version( 'product_query' );
1528
1529
		if ( false === ( $products_will_display = get_transient( $transient_name ) ) ) {
1530
			$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 ) );
1531
1532
			if ( $has_children ) {
1533
				// Check terms have products inside - parents first. If products are found inside, subcats will be shown instead of products so we can return false.
1534
				if ( sizeof( get_objects_in_term( $has_children, $term->taxonomy ) ) > 0 ) {
1535
					$products_will_display = false;
1536
				} else {
1537
					// If we get here, the parents were empty so we're forced to check children
1538
					foreach ( $has_children as $term_id ) {
1539
						$children = get_term_children( $term_id, $term->taxonomy );
1540
1541
						if ( sizeof( get_objects_in_term( $children, $term->taxonomy ) ) > 0 ) {
1542
							$products_will_display = false;
1543
							break;
1544
						}
1545
					}
1546
				}
1547
			} else {
1548
				$products_will_display = true;
1549
			}
1550
		}
1551
1552
		set_transient( $transient_name, $products_will_display, DAY_IN_SECONDS * 30 );
1553
1554
		return $products_will_display;
1555
	}
1556
}
1557
1558
if ( ! function_exists( 'woocommerce_product_subcategories' ) ) {
1559
1560
	/**
1561
	 * Display product sub categories as thumbnails.
1562
	 *
1563
	 * @subpackage	Loop
1564
	 * @param array $args
1565
	 * @return null|boolean
1566
	 */
1567
	function woocommerce_product_subcategories( $args = array() ) {
1568
		global $wp_query;
1569
1570
		$defaults = array(
1571
			'before'        => '',
1572
			'after'         => '',
1573
			'force_display' => false
1574
		);
1575
1576
		$args = wp_parse_args( $args, $defaults );
1577
1578
		extract( $args );
1579
1580
		// Main query only
1581
		if ( ! is_main_query() && ! $force_display ) {
1582
			return;
1583
		}
1584
1585
		// Don't show when filtering, searching or when on page > 1 and ensure we're on a product archive
1586
		if ( is_search() || is_filtered() || is_paged() || ( ! is_product_category() && ! is_shop() ) ) {
1587
			return;
1588
		}
1589
1590
		// Check categories are enabled
1591
		if ( is_shop() && '' === get_option( 'woocommerce_shop_page_display' ) ) {
1592
			return;
1593
		}
1594
1595
		// Find the category + category parent, if applicable
1596
		$term 			= get_queried_object();
1597
		$parent_id 		= empty( $term->term_id ) ? 0 : $term->term_id;
1598
1599
		if ( is_product_category() ) {
1600
			$display_type = get_woocommerce_term_meta( $term->term_id, 'display_type', true );
1601
1602
			switch ( $display_type ) {
1603
				case 'products' :
1604
					return;
1605
				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...
1606
				case '' :
1607
					if ( '' === get_option( 'woocommerce_category_archive_display' ) ) {
1608
						return;
1609
					}
1610
				break;
1611
			}
1612
		}
1613
1614
		// NOTE: using child_of instead of parent - this is not ideal but due to a WP bug ( http://core.trac.wordpress.org/ticket/15626 ) pad_counts won't work
1615
		$product_categories = get_categories( apply_filters( 'woocommerce_product_subcategories_args', array(
1616
			'parent'       => $parent_id,
1617
			'menu_order'   => 'ASC',
1618
			'hide_empty'   => 0,
1619
			'hierarchical' => 1,
1620
			'taxonomy'     => 'product_cat',
1621
			'pad_counts'   => 1
1622
		) ) );
1623
1624
		if ( ! apply_filters( 'woocommerce_product_subcategories_hide_empty', false ) ) {
1625
			$product_categories = wp_list_filter( $product_categories, array( 'count' => 0 ), 'NOT' );
1626
		}
1627
1628
		if ( $product_categories ) {
1629
			echo $before;
1630
1631
			foreach ( $product_categories as $category ) {
1632
				wc_get_template( 'content-product_cat.php', array(
1633
					'category' => $category
1634
				) );
1635
			}
1636
1637
			// If we are hiding products disable the loop and pagination
1638
			if ( is_product_category() ) {
1639
				$display_type = get_woocommerce_term_meta( $term->term_id, 'display_type', true );
1640
1641
				switch ( $display_type ) {
1642
					case 'subcategories' :
1643
						$wp_query->post_count    = 0;
1644
						$wp_query->max_num_pages = 0;
1645
					break;
1646
					case '' :
1647
						if ( 'subcategories' === get_option( 'woocommerce_category_archive_display' ) ) {
1648
							$wp_query->post_count    = 0;
1649
							$wp_query->max_num_pages = 0;
1650
						}
1651
					break;
1652
				}
1653
			}
1654
1655
			if ( is_shop() && 'subcategories' === get_option( 'woocommerce_shop_page_display' ) ) {
1656
				$wp_query->post_count    = 0;
1657
				$wp_query->max_num_pages = 0;
1658
			}
1659
1660
			echo $after;
1661
1662
			return true;
1663
		}
1664
	}
1665
}
1666
1667
if ( ! function_exists( 'woocommerce_subcategory_thumbnail' ) ) {
1668
1669
	/**
1670
	 * Show subcategory thumbnails.
1671
	 *
1672
	 * @param mixed $category
1673
	 * @subpackage	Loop
1674
	 */
1675
	function woocommerce_subcategory_thumbnail( $category ) {
1676
		$small_thumbnail_size  	= apply_filters( 'single_product_small_thumbnail_size', 'shop_catalog' );
1677
		$dimensions    			= wc_get_image_size( $small_thumbnail_size );
1678
		$thumbnail_id  			= get_woocommerce_term_meta( $category->term_id, 'thumbnail_id', true  );
1679
1680
		if ( $thumbnail_id ) {
1681
			$image = wp_get_attachment_image_src( $thumbnail_id, $small_thumbnail_size  );
1682
			$image = $image[0];
1683
		} else {
1684
			$image = wc_placeholder_img_src();
1685
		}
1686
1687
		if ( $image ) {
1688
			// Prevent esc_url from breaking spaces in urls for image embeds
1689
			// Ref: http://core.trac.wordpress.org/ticket/23605
1690
			$image = str_replace( ' ', '%20', $image );
1691
1692
			echo '<img src="' . esc_url( $image ) . '" alt="' . esc_attr( $category->name ) . '" width="' . esc_attr( $dimensions['width'] ) . '" height="' . esc_attr( $dimensions['height'] ) . '" />';
1693
		}
1694
	}
1695
}
1696
1697
if ( ! function_exists( 'woocommerce_order_details_table' ) ) {
1698
1699
	/**
1700
	 * Displays order details in a table.
1701
	 *
1702
	 * @param mixed $order_id
1703
	 * @subpackage	Orders
1704
	 */
1705
	function woocommerce_order_details_table( $order_id ) {
1706
		if ( ! $order_id ) return;
1707
1708
		wc_get_template( 'order/order-details.php', array(
1709
			'order_id' => $order_id
1710
		) );
1711
	}
1712
}
1713
1714
1715
if ( ! function_exists( 'woocommerce_order_again_button' ) ) {
1716
1717
	/**
1718
	 * Display an 'order again' button on the view order page.
1719
	 *
1720
	 * @param object $order
1721
	 * @subpackage	Orders
1722
	 */
1723
	function woocommerce_order_again_button( $order ) {
1724
		if ( ! $order || ! $order->has_status( 'completed' ) || ! is_user_logged_in() ) {
1725
			return;
1726
		}
1727
1728
		wc_get_template( 'order/order-again.php', array(
1729
			'order' => $order
1730
		) );
1731
	}
1732
}
1733
1734
/** Forms ****************************************************************/
1735
1736
if ( ! function_exists( 'woocommerce_form_field' ) ) {
1737
1738
	/**
1739
	 * Outputs a checkout/address form field.
1740
	 *
1741
	 * @subpackage	Forms
1742
	 * @param string $key
1743
	 * @param mixed $args
1744
	 * @param string $value (default: null)
1745
	 * @todo This function needs to be broken up in smaller pieces
1746
	 */
1747
	function woocommerce_form_field( $key, $args, $value = null ) {
1748
		$defaults = array(
1749
			'type'              => 'text',
1750
			'label'             => '',
1751
			'description'       => '',
1752
			'placeholder'       => '',
1753
			'maxlength'         => false,
1754
			'required'          => false,
1755
			'autocomplete'      => false,
1756
			'id'                => $key,
1757
			'class'             => array(),
1758
			'label_class'       => array(),
1759
			'input_class'       => array(),
1760
			'return'            => false,
1761
			'options'           => array(),
1762
			'custom_attributes' => array(),
1763
			'validate'          => array(),
1764
			'default'           => '',
1765
		);
1766
1767
		$args = wp_parse_args( $args, $defaults );
1768
		$args = apply_filters( 'woocommerce_form_field_args', $args, $key, $value );
1769
1770
		if ( $args['required'] ) {
1771
			$args['class'][] = 'validate-required';
1772
			$required = ' <abbr class="required" title="' . esc_attr__( 'required', 'woocommerce'  ) . '">*</abbr>';
1773
		} else {
1774
			$required = '';
1775
		}
1776
1777
		$args['maxlength'] = ( $args['maxlength'] ) ? 'maxlength="' . absint( $args['maxlength'] ) . '"' : '';
1778
1779
		$args['autocomplete'] = ( $args['autocomplete'] ) ? 'autocomplete="' . esc_attr( $args['autocomplete'] ) . '"' : '';
1780
1781
		if ( is_string( $args['label_class'] ) ) {
1782
			$args['label_class'] = array( $args['label_class'] );
1783
		}
1784
1785
		if ( is_null( $value ) ) {
1786
			$value = $args['default'];
1787
		}
1788
1789
		// Custom attribute handling
1790
		$custom_attributes = array();
1791
1792 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...
1793
			foreach ( $args['custom_attributes'] as $attribute => $attribute_value ) {
1794
				$custom_attributes[] = esc_attr( $attribute ) . '="' . esc_attr( $attribute_value ) . '"';
1795
			}
1796
		}
1797
1798
		if ( ! empty( $args['validate'] ) ) {
1799
			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...
1800
				$args['class'][] = 'validate-' . $validate;
1801
			}
1802
		}
1803
1804
		$field = '';
1805
		$label_id = $args['id'];
1806
		$field_container = '<p class="form-row %1$s" id="%2$s">%3$s</p>';
1807
1808
		switch ( $args['type'] ) {
1809
			case 'country' :
1810
1811
				$countries = 'shipping_country' === $key ? WC()->countries->get_shipping_countries() : WC()->countries->get_allowed_countries();
1812
1813
				if ( 1 === sizeof( $countries ) ) {
1814
1815
					$field .= '<strong>' . current( array_values( $countries ) ) . '</strong>';
1816
1817
					$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" />';
1818
1819
				} else {
1820
1821
					$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 ) . '>'
1822
							. '<option value="">'.__( 'Select a country&hellip;', 'woocommerce' ) .'</option>';
1823
1824 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...
1825
						$field .= '<option value="' . esc_attr( $ckey ) . '" '. selected( $value, $ckey, false ) . '>'. __( $cvalue, 'woocommerce' ) .'</option>';
1826
					}
1827
1828
					$field .= '</select>';
1829
1830
					$field .= '<noscript><input type="submit" name="woocommerce_checkout_update_totals" value="' . esc_attr__( 'Update country', 'woocommerce' ) . '" /></noscript>';
1831
1832
				}
1833
1834
				break;
1835
			case 'state' :
1836
1837
				/* Get Country */
1838
				$country_key = 'billing_state' === $key ? 'billing_country' : 'shipping_country';
1839
				$current_cc  = WC()->checkout->get_value( $country_key );
1840
				$states      = WC()->countries->get_states( $current_cc );
1841
1842
				if ( is_array( $states ) && empty( $states ) ) {
1843
1844
					$field_container = '<p class="form-row %1$s" id="%2$s" style="display: none">%3$s</p>';
1845
1846
					$field .= '<input type="hidden" class="hidden" name="' . esc_attr( $key )  . '" id="' . esc_attr( $args['id'] ) . '" value="" ' . implode( ' ', $custom_attributes ) . ' placeholder="' . esc_attr( $args['placeholder'] ) . '" />';
1847
1848
				} elseif ( is_array( $states ) ) {
1849
1850
					$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'] . '>
1851
						<option value="">'.__( 'Select a state&hellip;', 'woocommerce' ) .'</option>';
1852
1853 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...
1854
						$field .= '<option value="' . esc_attr( $ckey ) . '" '.selected( $value, $ckey, false ) .'>'.__( $cvalue, 'woocommerce' ) .'</option>';
1855
					}
1856
1857
					$field .= '</select>';
1858
1859
				} else {
1860
1861
					$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 ) . ' />';
1862
1863
				}
1864
1865
				break;
1866
			case 'textarea' :
1867
1868
				$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>';
1869
1870
				break;
1871 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...
1872
1873
				$field = '<label class="checkbox ' . implode( ' ', $args['label_class'] ) .'" ' . implode( ' ', $custom_attributes ) . '>
1874
						<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 ) .' /> '
1875
						 . $args['label'] . $required . '</label>';
1876
1877
				break;
1878
			case 'password' :
1879
			case 'text' :
1880
			case 'email' :
1881
			case 'tel' :
1882 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...
1883
1884
				$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 ) . ' />';
1885
1886
				break;
1887
			case 'select' :
1888
1889
				$options = $field = '';
1890
1891
				if ( ! empty( $args['options'] ) ) {
1892
					foreach ( $args['options'] as $option_key => $option_text ) {
1893
						if ( '' === $option_key ) {
1894
							// If we have a blank option, select2 needs a placeholder
1895
							if ( empty( $args['placeholder'] ) ) {
1896
								$args['placeholder'] = $option_text ? $option_text : __( 'Choose an option', 'woocommerce' );
1897
							}
1898
							$custom_attributes[] = 'data-allow_clear="true"';
1899
						}
1900
						$options .= '<option value="' . esc_attr( $option_key ) . '" '. selected( $value, $option_key, false ) . '>' . esc_attr( $option_text ) .'</option>';
1901
					}
1902
1903
					$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'] . '>
1904
							' . $options . '
1905
						</select>';
1906
				}
1907
1908
				break;
1909
			case 'radio' :
1910
1911
				$label_id = current( array_keys( $args['options'] ) );
1912
1913
				if ( ! empty( $args['options'] ) ) {
1914
					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...
1915
						$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 ) . ' />';
1916
						$field .= '<label for="' . esc_attr( $args['id'] ) . '_' . esc_attr( $option_key ) . '" class="radio ' . implode( ' ', $args['label_class'] ) .'">' . $option_text . '</label>';
1917
					}
1918
				}
1919
1920
				break;
1921
		}
1922
1923
		if ( ! empty( $field ) ) {
1924
			$field_html = '';
1925
1926
			if ( $args['label'] && 'checkbox' != $args['type'] ) {
1927
				$field_html .= '<label for="' . esc_attr( $label_id ) . '" class="' . esc_attr( implode( ' ', $args['label_class'] ) ) .'">' . $args['label'] . $required . '</label>';
1928
			}
1929
1930
			$field_html .= $field;
1931
1932
			if ( $args['description'] ) {
1933
				$field_html .= '<span class="description">' . esc_html( $args['description'] ) . '</span>';
1934
			}
1935
1936
			$container_class = 'form-row ' . esc_attr( implode( ' ', $args['class'] ) );
1937
			$container_id = esc_attr( $args['id'] ) . '_field';
1938
1939
			$after = ! empty( $args['clear'] ) ? '<div class="clear"></div>' : '';
1940
1941
			$field = sprintf( $field_container, $container_class, $container_id, $field_html ) . $after;
1942
		}
1943
1944
		$field = apply_filters( 'woocommerce_form_field_' . $args['type'], $field, $key, $args, $value );
1945
1946
		if ( $args['return'] ) {
1947
			return $field;
1948
		} else {
1949
			echo $field;
1950
		}
1951
	}
1952
}
1953
1954
if ( ! function_exists( 'get_product_search_form' ) ) {
1955
1956
	/**
1957
	 * Display product search form.
1958
	 *
1959
	 * Will first attempt to locate the product-searchform.php file in either the child or.
1960
	 * the parent, then load it. If it doesn't exist, then the default search form.
1961
	 * will be displayed.
1962
	 *
1963
	 * The default searchform uses html5.
1964
	 *
1965
	 * @subpackage	Forms
1966
	 * @param bool $echo (default: true)
1967
	 * @return string
1968
	 */
1969
	function get_product_search_form( $echo = true  ) {
1970
		ob_start();
1971
1972
		do_action( 'pre_get_product_search_form'  );
1973
1974
		wc_get_template( 'product-searchform.php' );
1975
1976
		$form = apply_filters( 'get_product_search_form', ob_get_clean() );
1977
1978
		if ( $echo ) {
1979
			echo $form;
1980
		} else {
1981
			return $form;
1982
		}
1983
	}
1984
}
1985
1986
if ( ! function_exists( 'woocommerce_output_auth_header' ) ) {
1987
1988
	/**
1989
	 * Output the Auth header.
1990
	 */
1991
	function woocommerce_output_auth_header() {
1992
		wc_get_template( 'auth/header.php' );
1993
	}
1994
}
1995
1996
if ( ! function_exists( 'woocommerce_output_auth_footer' ) ) {
1997
1998
	/**
1999
	 * Output the Auth footer.
2000
	 */
2001
	function woocommerce_output_auth_footer() {
2002
		wc_get_template( 'auth/footer.php' );
2003
	}
2004
}
2005
2006
if ( ! function_exists( 'woocommerce_single_variation' ) ) {
2007
2008
	/**
2009
	 * Output placeholders for the single variation.
2010
	 */
2011
	function woocommerce_single_variation() {
2012
		echo '<div class="woocommerce-variation single_variation"></div>';
2013
	}
2014
}
2015
2016
if ( ! function_exists( 'woocommerce_single_variation_add_to_cart_button' ) ) {
2017
2018
	/**
2019
	 * Output the add to cart button for variations.
2020
	 */
2021
	function woocommerce_single_variation_add_to_cart_button() {
2022
		wc_get_template( 'single-product/add-to-cart/variation-add-to-cart-button.php' );
2023
	}
2024
}
2025
2026
if ( ! function_exists( 'wc_dropdown_variation_attribute_options' ) ) {
2027
2028
	/**
2029
	 * Output a list of variation attributes for use in the cart forms.
2030
	 *
2031
	 * @param array $args
2032
	 * @since 2.4.0
2033
	 */
2034
	function wc_dropdown_variation_attribute_options( $args = array() ) {
2035
		$args = wp_parse_args( apply_filters( 'woocommerce_dropdown_variation_attribute_options_args', $args ), array(
2036
			'options'          => false,
2037
			'attribute'        => false,
2038
			'product'          => false,
2039
			'selected' 	       => false,
2040
			'name'             => '',
2041
			'id'               => '',
2042
			'class'            => '',
2043
			'show_option_none' => __( 'Choose an option', 'woocommerce' )
2044
		) );
2045
2046
		$options   = $args['options'];
2047
		$product   = $args['product'];
2048
		$attribute = $args['attribute'];
2049
		$name      = $args['name'] ? $args['name'] : 'attribute_' . sanitize_title( $attribute );
2050
		$id        = $args['id'] ? $args['id'] : sanitize_title( $attribute );
2051
		$class     = $args['class'];
2052
2053
		if ( empty( $options ) && ! empty( $product ) && ! empty( $attribute ) ) {
2054
			$attributes = $product->get_variation_attributes();
2055
			$options    = $attributes[ $attribute ];
2056
		}
2057
2058
		$html = '<select id="' . esc_attr( $id ) . '" class="' . esc_attr( $class ) . '" name="' . esc_attr( $name ) . '" data-attribute_name="attribute_' . esc_attr( sanitize_title( $attribute ) ) . '">';
2059
2060
		if ( $args['show_option_none'] ) {
2061
			$html .= '<option value="">' . esc_html( $args['show_option_none'] ) . '</option>';
2062
		}
2063
2064
		if ( ! empty( $options ) ) {
2065
			if ( $product && taxonomy_exists( $attribute ) ) {
2066
				// Get terms if this is a taxonomy - ordered. We need the names too.
2067
				$terms = wc_get_product_terms( $product->id, $attribute, array( 'fields' => 'all' ) );
2068
2069
				foreach ( $terms as $term ) {
2070
					if ( in_array( $term->slug, $options ) ) {
2071
						$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>';
2072
					}
2073
				}
2074
			} else {
2075
				foreach ( $options as $option ) {
2076
					// This handles < 2.4.0 bw compatibility where text attributes were not sanitized.
2077
					$selected = sanitize_title( $args['selected'] ) === $args['selected'] ? selected( $args['selected'], sanitize_title( $option ), false ) : selected( $args['selected'], $option, false );
2078
					$html .= '<option value="' . esc_attr( $option ) . '" ' . $selected . '>' . esc_html( apply_filters( 'woocommerce_variation_option_name', $option ) ) . '</option>';
2079
				}
2080
			}
2081
		}
2082
2083
		$html .= '</select>';
2084
2085
		echo apply_filters( 'woocommerce_dropdown_variation_attribute_options_html', $html, $args );
2086
	}
2087
}
2088
2089
if ( ! function_exists( 'woocommerce_account_orders' ) ) {
2090
2091
	/**
2092
	 * My Account > Orders template.
2093
	 *
2094
	 * @param int $current_page Current page number.
2095
	 */
2096
	function woocommerce_account_orders( $current_page ) {
2097
		$current_page    = empty( $current_page ) ? 1 : absint( $current_page );
2098
		$customer_orders = wc_get_orders( apply_filters( 'woocommerce_my_account_my_orders_query', array( 'customer' => get_current_user_id(), 'page' => $current_page, 'paginate' => true ) ) );
2099
2100
		wc_get_template(
2101
			'myaccount/orders.php',
2102
			array(
2103
				'current_page' => absint( $current_page ),
2104
				'customer_orders' => $customer_orders,
2105
				'has_orders' => 0 < $customer_orders->total,
2106
			)
2107
		);
2108
	}
2109
}
2110
2111
if ( ! function_exists( 'woocommerce_account_view_order' ) ) {
2112
2113
	/**
2114
	 * My Account > View order template.
2115
	 *
2116
	 * @param int $order_id Order ID.
2117
	 */
2118
	function woocommerce_account_view_order( $order_id ) {
2119
		WC_Shortcode_My_Account::view_order( absint( $order_id ) );
2120
	}
2121
}
2122
2123
if ( ! function_exists( 'woocommerce_account_downloads' ) ) {
2124
2125
	/**
2126
	 * My Account > Downloads template.
2127
	 */
2128
	function woocommerce_account_downloads() {
2129
		wc_get_template( 'myaccount/downloads.php' );
2130
	}
2131
}
2132
2133
if ( ! function_exists( 'woocommerce_account_edit_address' ) ) {
2134
2135
	/**
2136
	 * My Account > Edit address template.
2137
	 *
2138
	 * @param string $type Address type.
2139
	 */
2140
	function woocommerce_account_edit_address( $type ) {
2141
		$type = wc_edit_address_i18n( sanitize_title( $type ), true );
2142
2143
		WC_Shortcode_My_Account::edit_address( $type );
2144
	}
2145
}
2146
2147
if ( ! function_exists( 'woocommerce_account_payment_methods' ) ) {
2148
2149
	/**
2150
	 * My Account > Downloads template.
2151
	 */
2152
	function woocommerce_account_payment_methods() {
2153
		wc_get_template( 'myaccount/payment-methods.php' );
2154
	}
2155
}
2156
2157
if ( ! function_exists( 'woocommerce_account_add_payment_method' ) ) {
2158
2159
	/**
2160
	 * My Account > Add payment method template.
2161
	 */
2162
	function woocommerce_account_add_payment_method() {
2163
		WC_Shortcode_My_Account::add_payment_method();
2164
	}
2165
}
2166
2167
if ( ! function_exists( 'woocommerce_account_edit_account' ) ) {
2168
2169
	/**
2170
	 * My Account > Edit account template.
2171
	 */
2172
	function woocommerce_account_edit_account() {
2173
		WC_Shortcode_My_Account::edit_account();
2174
	}
2175
}
2176