wc-template-functions.php ➔ woocommerce_template_single_title()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
dl 0
loc 3
rs 10
c 0
b 0
f 0
eloc 2
nc 1
nop 0
1
<?php
2
/**
3
 * WooCommerce Template
4
 *
5
 * Functions for the templating system.
6
 *
7
 * @author   WooThemes
8
 * @category Core
9
 * @package  WooCommerce/Functions
10
 * @version  2.5.0
11
 */
12
13
if ( ! defined( 'ABSPATH' ) ) {
14
	exit; // Exit if accessed directly
15
}
16
17
/**
18
 * Handle redirects before content is output - hooked into template_redirect so is_page works.
19
 */
20
function wc_template_redirect() {
21
	global $wp_query, $wp;
22
23
	// When default permalinks are enabled, redirect shop page to post type archive url
24
	if ( ! empty( $_GET['page_id'] ) && '' === get_option( 'permalink_structure' ) && $_GET['page_id'] == wc_get_page_id( 'shop' ) ) {
25
		wp_safe_redirect( get_post_type_archive_link('product') );
26
		exit;
27
	}
28
29
	// When on the checkout with an empty cart, redirect to cart page
30
	elseif ( is_page( wc_get_page_id( 'checkout' ) ) && WC()->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' );
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 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>'  );
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
		// Apply sanity to min/max args - min cannot be lower than 0
1032
		if ( '' !== $args['min_value'] && is_numeric( $args['min_value'] ) && $args['min_value'] < 0 ) {
1033
			$args['min_value'] = 0; // Cannot be lower than 0
1034
		}
1035
1036
		// Max cannot be lower than 0 or min
1037
		if ( '' !== $args['max_value'] && is_numeric( $args['max_value'] ) ) {
1038
			$args['max_value'] = $args['max_value'] < 0 ? 0 : $args['max_value'];
1039
			$args['max_value'] = $args['max_value'] < $args['min_value'] ? $args['min_value'] : $args['max_value'];
1040
		}
1041
1042
		ob_start();
1043
1044
		wc_get_template( 'global/quantity-input.php', $args );
1045
1046
		if ( $echo ) {
1047
			echo ob_get_clean();
1048
		} else {
1049
			return ob_get_clean();
1050
		}
1051
	}
1052
}
1053
1054
if ( ! function_exists( 'woocommerce_product_description_tab' ) ) {
1055
1056
	/**
1057
	 * Output the description tab content.
1058
	 *
1059
	 * @subpackage	Product/Tabs
1060
	 */
1061
	function woocommerce_product_description_tab() {
1062
		wc_get_template( 'single-product/tabs/description.php' );
1063
	}
1064
}
1065
if ( ! function_exists( 'woocommerce_product_additional_information_tab' ) ) {
1066
1067
	/**
1068
	 * Output the attributes tab content.
1069
	 *
1070
	 * @subpackage	Product/Tabs
1071
	 */
1072
	function woocommerce_product_additional_information_tab() {
1073
		wc_get_template( 'single-product/tabs/additional-information.php' );
1074
	}
1075
}
1076
if ( ! function_exists( 'woocommerce_product_reviews_tab' ) ) {
1077
1078
	/**
1079
	 * Output the reviews tab content.
1080
	 * @deprecated  2.4.0 Unused
1081
	 * @subpackage	Product/Tabs
1082
	 */
1083
	function woocommerce_product_reviews_tab() {
1084
		_deprecated_function( 'woocommerce_product_reviews_tab', '2.4', '' );
1085
	}
1086
}
1087
1088
if ( ! function_exists( 'woocommerce_default_product_tabs' ) ) {
1089
1090
	/**
1091
	 * Add default product tabs to product pages.
1092
	 *
1093
	 * @param array $tabs
1094
	 * @return array
1095
	 */
1096
	function woocommerce_default_product_tabs( $tabs = array() ) {
1097
		global $product, $post;
1098
1099
		// Description tab - shows product content
1100
		if ( $post->post_content ) {
1101
			$tabs['description'] = array(
1102
				'title'    => __( 'Description', 'woocommerce' ),
1103
				'priority' => 10,
1104
				'callback' => 'woocommerce_product_description_tab'
1105
			);
1106
		}
1107
1108
		// Additional information tab - shows attributes
1109
		if ( $product && ( $product->has_attributes() || ( $product->enable_dimensions_display() && ( $product->has_dimensions() || $product->has_weight() ) ) ) ) {
1110
			$tabs['additional_information'] = array(
1111
				'title'    => __( 'Additional Information', 'woocommerce' ),
1112
				'priority' => 20,
1113
				'callback' => 'woocommerce_product_additional_information_tab'
1114
			);
1115
		}
1116
1117
		// Reviews tab - shows comments
1118
		if ( comments_open() ) {
1119
			$tabs['reviews'] = array(
1120
				'title'    => sprintf( __( 'Reviews (%d)', 'woocommerce' ), $product->get_review_count() ),
1121
				'priority' => 30,
1122
				'callback' => 'comments_template'
1123
			);
1124
		}
1125
1126
		return $tabs;
1127
	}
1128
}
1129
1130
if ( ! function_exists( 'woocommerce_sort_product_tabs' ) ) {
1131
1132
	/**
1133
	 * Sort tabs by priority.
1134
	 *
1135
	 * @param array $tabs
1136
	 * @return array
1137
	 */
1138
	function woocommerce_sort_product_tabs( $tabs = array() ) {
1139
1140
		// Make sure the $tabs parameter is an array
1141
		if ( ! is_array( $tabs ) ) {
1142
			trigger_error( "Function woocommerce_sort_product_tabs() expects an array as the first parameter. Defaulting to empty array." );
1143
			$tabs = array( );
1144
		}
1145
1146
		// Re-order tabs by priority
1147
		if ( ! function_exists( '_sort_priority_callback' ) ) {
1148
			function _sort_priority_callback( $a, $b ) {
1149
				if ( $a['priority'] === $b['priority'] )
1150
			        return 0;
1151
			    return ( $a['priority'] < $b['priority'] ) ? -1 : 1;
1152
			}
1153
		}
1154
1155
		uasort( $tabs, '_sort_priority_callback' );
1156
1157
		return $tabs;
1158
	}
1159
}
1160
1161
if ( ! function_exists( 'woocommerce_comments' ) ) {
1162
1163
	/**
1164
	 * Output the Review comments template.
1165
	 *
1166
	 * @subpackage	Product
1167
	 * @param WP_Comment $comment
1168
	 * @param array $args
1169
	 * @param int $depth
1170
	 */
1171
	function woocommerce_comments( $comment, $args, $depth ) {
1172
		$GLOBALS['comment'] = $comment;
1173
		wc_get_template( 'single-product/review.php', array( 'comment' => $comment, 'args' => $args, 'depth' => $depth ) );
1174
	}
1175
}
1176
1177
if ( ! function_exists( 'woocommerce_review_display_gravatar' ) ) {
1178
	/**
1179
	 * Display the review authors gravatar
1180
	 *
1181
	 * @param array $comment WP_Comment.
1182
	 * @return void
1183
	 */
1184
	function woocommerce_review_display_gravatar( $comment ) {
1185
		echo get_avatar( $comment, apply_filters( 'woocommerce_review_gravatar_size', '60' ), '' );
1186
	}
1187
}
1188
1189
if ( ! function_exists( 'woocommerce_review_display_rating' ) ) {
1190
	/**
1191
	 * Display the reviewers star rating
1192
	 *
1193
	 * @return void
1194
	 */
1195
	function woocommerce_review_display_rating() {
1196
		wc_get_template( 'single-product/review-rating.php' );
1197
	}
1198
}
1199
1200
if ( ! function_exists( 'woocommerce_review_display_meta' ) ) {
1201
	/**
1202
	 * Display the review authors meta (name, verified owner, review date)
1203
	 *
1204
	 * @return void
1205
	 */
1206
	function woocommerce_review_display_meta() {
1207
		wc_get_template( 'single-product/review-meta.php' );
1208
	}
1209
}
1210
1211
if ( ! function_exists( 'woocommerce_review_display_comment_text' ) ) {
1212
	/**
1213
	 * Display the review content
1214
	 *
1215
	 * @return void
1216
	 */
1217
	function woocommerce_review_display_comment_text() {
1218
		echo '<div itemprop="description" class="description">' . get_comment_text() . '</div>';
1219
	}
1220
}
1221
1222
if ( ! function_exists( 'woocommerce_output_related_products' ) ) {
1223
1224
	/**
1225
	 * Output the related products.
1226
	 *
1227
	 * @subpackage	Product
1228
	 */
1229
	function woocommerce_output_related_products() {
1230
1231
		$args = array(
1232
			'posts_per_page' 	=> 4,
1233
			'columns' 			=> 4,
1234
			'orderby' 			=> 'rand'
1235
		);
1236
1237
		woocommerce_related_products( apply_filters( 'woocommerce_output_related_products_args', $args ) );
1238
	}
1239
}
1240
1241
if ( ! function_exists( 'woocommerce_related_products' ) ) {
1242
1243
	/**
1244
	 * Output the related products.
1245
	 *
1246
	 * @param array Provided arguments
1247
	 * @param bool Columns argument for backwards compat
1248
	 * @param bool Order by argument for backwards compat
1249
	 */
1250
	function woocommerce_related_products( $args = array(), $columns = false, $orderby = false ) {
1251
		if ( ! is_array( $args ) ) {
1252
			_deprecated_argument( __FUNCTION__, '2.1', __( 'Use $args argument as an array instead. Deprecated argument will be removed in WC 2.2.', 'woocommerce' ) );
1253
1254
			$argsvalue = $args;
1255
1256
			$args = array(
1257
				'posts_per_page' => $argsvalue,
1258
				'columns'        => $columns,
1259
				'orderby'        => $orderby,
1260
			);
1261
		}
1262
1263
		$defaults = array(
1264
			'posts_per_page' => 2,
1265
			'columns'        => 2,
1266
			'orderby'        => 'rand'
1267
		);
1268
1269
		$args = wp_parse_args( $args, $defaults );
1270
1271
		wc_get_template( 'single-product/related.php', $args );
1272
	}
1273
}
1274
1275
if ( ! function_exists( 'woocommerce_upsell_display' ) ) {
1276
1277
	/**
1278
	 * Output product up sells.
1279
	 *
1280
	 * @param int $posts_per_page (default: -1)
1281
	 * @param int $columns (default: 4)
1282
	 * @param string $orderby (default: 'rand')
1283
	 */
1284
	function woocommerce_upsell_display( $posts_per_page = '-1', $columns = 4, $orderby = 'rand' ) {
1285
		$args = apply_filters( 'woocommerce_upsell_display_args', array(
1286
			'posts_per_page'	=> $posts_per_page,
1287
			'orderby'			=> apply_filters( 'woocommerce_upsells_orderby', $orderby ),
1288
			'columns'			=> $columns
1289
		) );
1290
1291
		wc_get_template( 'single-product/up-sells.php', $args );
1292
	}
1293
}
1294
1295
/** Cart ******************************************************************/
1296
1297
if ( ! function_exists( 'woocommerce_shipping_calculator' ) ) {
1298
1299
	/**
1300
	 * Output the cart shipping calculator.
1301
	 *
1302
	 * @subpackage	Cart
1303
	 */
1304
	function woocommerce_shipping_calculator() {
1305
		wc_get_template( 'cart/shipping-calculator.php' );
1306
	}
1307
}
1308
1309
if ( ! function_exists( 'woocommerce_cart_totals' ) ) {
1310
1311
	/**
1312
	 * Output the cart totals.
1313
	 *
1314
	 * @subpackage	Cart
1315
	 */
1316
	function woocommerce_cart_totals() {
1317
		wc_get_template( 'cart/cart-totals.php' );
1318
	}
1319
}
1320
1321
if ( ! function_exists( 'woocommerce_cross_sell_display' ) ) {
1322
1323
	/**
1324
	 * Output the cart cross-sells.
1325
	 *
1326
	 * @param  int $posts_per_page (default: 2)
1327
	 * @param  int $columns (default: 2)
1328
	 * @param  string $orderby (default: 'rand')
1329
	 */
1330
	function woocommerce_cross_sell_display( $posts_per_page = 2, $columns = 2, $orderby = 'rand' ) {
1331
		wc_get_template( 'cart/cross-sells.php', array(
1332
				'posts_per_page' => $posts_per_page,
1333
				'orderby'        => $orderby,
1334
				'columns'        => $columns
1335
			) );
1336
	}
1337
}
1338
1339
if ( ! function_exists( 'woocommerce_button_proceed_to_checkout' ) ) {
1340
1341
	/**
1342
	 * Output the proceed to checkout button.
1343
	 *
1344
	 * @subpackage	Cart
1345
	 */
1346
	function woocommerce_button_proceed_to_checkout() {
1347
		wc_get_template( 'cart/proceed-to-checkout-button.php' );
1348
	}
1349
}
1350
1351
1352
1353
/** Mini-Cart *************************************************************/
1354
1355
if ( ! function_exists( 'woocommerce_mini_cart' ) ) {
1356
1357
	/**
1358
	 * Output the Mini-cart - used by cart widget.
1359
	 *
1360
	 * @param array $args
1361
	 */
1362
	function woocommerce_mini_cart( $args = array() ) {
1363
1364
		$defaults = array(
1365
			'list_class' => ''
1366
		);
1367
1368
		$args = wp_parse_args( $args, $defaults );
1369
1370
		wc_get_template( 'cart/mini-cart.php', $args );
1371
	}
1372
}
1373
1374
/** Login *****************************************************************/
1375
1376
if ( ! function_exists( 'woocommerce_login_form' ) ) {
1377
1378
	/**
1379
	 * Output the WooCommerce Login Form.
1380
	 *
1381
	 * @subpackage	Forms
1382
	 * @param array $args
1383
	 */
1384
	function woocommerce_login_form( $args = array() ) {
1385
1386
		$defaults = array(
1387
			'message'  => '',
1388
			'redirect' => '',
1389
			'hidden'   => false
1390
		);
1391
1392
		$args = wp_parse_args( $args, $defaults  );
1393
1394
		wc_get_template( 'global/form-login.php', $args );
1395
	}
1396
}
1397
1398
if ( ! function_exists( 'woocommerce_checkout_login_form' ) ) {
1399
1400
	/**
1401
	 * Output the WooCommerce Checkout Login Form.
1402
	 *
1403
	 * @subpackage	Checkout
1404
	 */
1405
	function woocommerce_checkout_login_form() {
1406
		wc_get_template( 'checkout/form-login.php', array( 'checkout' => WC()->checkout() ) );
1407
	}
1408
}
1409
1410
if ( ! function_exists( 'woocommerce_breadcrumb' ) ) {
1411
1412
	/**
1413
	 * Output the WooCommerce Breadcrumb.
1414
	 *
1415
	 * @param array $args
1416
	 */
1417
	function woocommerce_breadcrumb( $args = array() ) {
1418
		$args = wp_parse_args( $args, apply_filters( 'woocommerce_breadcrumb_defaults', array(
1419
			'delimiter'   => '&nbsp;&#47;&nbsp;',
1420
			'wrap_before' => '<nav class="woocommerce-breadcrumb" ' . ( is_single() ? 'itemprop="breadcrumb"' : '' ) . '>',
1421
			'wrap_after'  => '</nav>',
1422
			'before'      => '',
1423
			'after'       => '',
1424
			'home'        => _x( 'Home', 'breadcrumb', 'woocommerce' )
1425
		) ) );
1426
1427
		$breadcrumbs = new WC_Breadcrumb();
1428
1429
		if ( $args['home'] ) {
1430
			$breadcrumbs->add_crumb( $args['home'], apply_filters( 'woocommerce_breadcrumb_home_url', home_url() ) );
1431
		}
1432
1433
		$args['breadcrumb'] = $breadcrumbs->generate();
1434
1435
		wc_get_template( 'global/breadcrumb.php', $args );
1436
	}
1437
}
1438
1439
if ( ! function_exists( 'woocommerce_order_review' ) ) {
1440
1441
	/**
1442
	 * Output the Order review table for the checkout.
1443
	 *
1444
	 * @subpackage	Checkout
1445
	 */
1446
	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...
1447
		wc_get_template( 'checkout/review-order.php', array( 'checkout' => WC()->checkout() ) );
1448
	}
1449
}
1450
1451
if ( ! function_exists( 'woocommerce_checkout_payment' ) ) {
1452
1453
	/**
1454
	 * Output the Payment Methods on the checkout.
1455
	 *
1456
	 * @subpackage	Checkout
1457
	 */
1458
	function woocommerce_checkout_payment() {
1459
		if ( WC()->cart->needs_payment() ) {
1460
			$available_gateways = WC()->payment_gateways()->get_available_payment_gateways();
1461
			WC()->payment_gateways()->set_current_gateway( $available_gateways );
1462
		} else {
1463
			$available_gateways = array();
1464
		}
1465
1466
		wc_get_template( 'checkout/payment.php', array(
1467
			'checkout'           => WC()->checkout(),
1468
			'available_gateways' => $available_gateways,
1469
			'order_button_text'  => apply_filters( 'woocommerce_order_button_text', __( 'Place order', 'woocommerce' ) )
1470
		) );
1471
	}
1472
}
1473
1474
if ( ! function_exists( 'woocommerce_checkout_coupon_form' ) ) {
1475
1476
	/**
1477
	 * Output the Coupon form for the checkout.
1478
	 *
1479
	 * @subpackage	Checkout
1480
	 */
1481
	function woocommerce_checkout_coupon_form() {
1482
		wc_get_template( 'checkout/form-coupon.php', array( 'checkout' => WC()->checkout() ) );
1483
	}
1484
}
1485
1486
if ( ! function_exists( 'woocommerce_products_will_display' ) ) {
1487
1488
	/**
1489
	 * Check if we will be showing products or not (and not sub-categories only).
1490
	 * @subpackage	Loop
1491
	 * @return bool
1492
	 */
1493
	function woocommerce_products_will_display() {
1494
		global $wpdb;
1495
1496
		if ( is_shop() ) {
1497
			return 'subcategories' !== get_option( 'woocommerce_shop_page_display' ) || is_search();
1498
		}
1499
1500
		if ( ! is_product_taxonomy() ) {
1501
			return false;
1502
		}
1503
1504
		if ( is_search() || is_filtered() || is_paged() ) {
1505
			return true;
1506
		}
1507
1508
		$term = get_queried_object();
1509
1510
		if ( is_product_category() ) {
1511
			switch ( get_woocommerce_term_meta( $term->term_id, 'display_type', true ) ) {
1512
				case 'subcategories' :
1513
					// Nothing - we want to continue to see if there are products/subcats
1514
				break;
1515
				case 'products' :
1516
				case 'both' :
1517
					return true;
1518
				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...
1519
				default :
1520
					// Default - no setting
1521
					if ( get_option( 'woocommerce_category_archive_display' ) != 'subcategories' ) {
1522
						return true;
1523
					}
1524
				break;
1525
			}
1526
		}
1527
1528
		// Begin subcategory logic
1529
		if ( empty( $term->term_id ) || empty( $term->taxonomy ) ) {
1530
			return true;
1531
		}
1532
1533
		$transient_name = 'wc_products_will_display_' . $term->term_id . '_' . WC_Cache_Helper::get_transient_version( 'product_query' );
1534
1535
		if ( false === ( $products_will_display = get_transient( $transient_name ) ) ) {
1536
			$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 ) );
1537
1538
			if ( $has_children ) {
1539
				// Check terms have products inside - parents first. If products are found inside, subcats will be shown instead of products so we can return false.
1540
				if ( sizeof( get_objects_in_term( $has_children, $term->taxonomy ) ) > 0 ) {
1541
					$products_will_display = false;
1542
				} else {
1543
					// If we get here, the parents were empty so we're forced to check children
1544
					foreach ( $has_children as $term_id ) {
1545
						$children = get_term_children( $term_id, $term->taxonomy );
1546
1547
						if ( sizeof( get_objects_in_term( $children, $term->taxonomy ) ) > 0 ) {
1548
							$products_will_display = false;
1549
							break;
1550
						}
1551
					}
1552
				}
1553
			} else {
1554
				$products_will_display = true;
1555
			}
1556
		}
1557
1558
		set_transient( $transient_name, $products_will_display, DAY_IN_SECONDS * 30 );
1559
1560
		return $products_will_display;
1561
	}
1562
}
1563
1564
if ( ! function_exists( 'woocommerce_product_subcategories' ) ) {
1565
1566
	/**
1567
	 * Display product sub categories as thumbnails.
1568
	 *
1569
	 * @subpackage	Loop
1570
	 * @param array $args
1571
	 * @return null|boolean
1572
	 */
1573
	function woocommerce_product_subcategories( $args = array() ) {
1574
		global $wp_query;
1575
1576
		$defaults = array(
1577
			'before'        => '',
1578
			'after'         => '',
1579
			'force_display' => false
1580
		);
1581
1582
		$args = wp_parse_args( $args, $defaults );
1583
1584
		extract( $args );
1585
1586
		// Main query only
1587
		if ( ! is_main_query() && ! $force_display ) {
1588
			return;
1589
		}
1590
1591
		// Don't show when filtering, searching or when on page > 1 and ensure we're on a product archive
1592
		if ( is_search() || is_filtered() || is_paged() || ( ! is_product_category() && ! is_shop() ) ) {
1593
			return;
1594
		}
1595
1596
		// Check categories are enabled
1597
		if ( is_shop() && '' === get_option( 'woocommerce_shop_page_display' ) ) {
1598
			return;
1599
		}
1600
1601
		// Find the category + category parent, if applicable
1602
		$term 			= get_queried_object();
1603
		$parent_id 		= empty( $term->term_id ) ? 0 : $term->term_id;
1604
1605
		if ( is_product_category() ) {
1606
			$display_type = get_woocommerce_term_meta( $term->term_id, 'display_type', true );
1607
1608
			switch ( $display_type ) {
1609
				case 'products' :
1610
					return;
1611
				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...
1612
				case '' :
1613
					if ( '' === get_option( 'woocommerce_category_archive_display' ) ) {
1614
						return;
1615
					}
1616
				break;
1617
			}
1618
		}
1619
1620
		// 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
1621
		$product_categories = get_categories( apply_filters( 'woocommerce_product_subcategories_args', array(
1622
			'parent'       => $parent_id,
1623
			'menu_order'   => 'ASC',
1624
			'hide_empty'   => 0,
1625
			'hierarchical' => 1,
1626
			'taxonomy'     => 'product_cat',
1627
			'pad_counts'   => 1
1628
		) ) );
1629
1630
		if ( ! apply_filters( 'woocommerce_product_subcategories_hide_empty', false ) ) {
1631
			$product_categories = wp_list_filter( $product_categories, array( 'count' => 0 ), 'NOT' );
1632
		}
1633
1634
		if ( $product_categories ) {
1635
			echo $before;
1636
1637
			foreach ( $product_categories as $category ) {
1638
				wc_get_template( 'content-product_cat.php', array(
1639
					'category' => $category
1640
				) );
1641
			}
1642
1643
			// If we are hiding products disable the loop and pagination
1644
			if ( is_product_category() ) {
1645
				$display_type = get_woocommerce_term_meta( $term->term_id, 'display_type', true );
1646
1647
				switch ( $display_type ) {
1648
					case 'subcategories' :
1649
						$wp_query->post_count    = 0;
1650
						$wp_query->max_num_pages = 0;
1651
					break;
1652
					case '' :
1653
						if ( 'subcategories' === get_option( 'woocommerce_category_archive_display' ) ) {
1654
							$wp_query->post_count    = 0;
1655
							$wp_query->max_num_pages = 0;
1656
						}
1657
					break;
1658
				}
1659
			}
1660
1661
			if ( is_shop() && 'subcategories' === get_option( 'woocommerce_shop_page_display' ) ) {
1662
				$wp_query->post_count    = 0;
1663
				$wp_query->max_num_pages = 0;
1664
			}
1665
1666
			echo $after;
1667
1668
			return true;
1669
		}
1670
	}
1671
}
1672
1673
if ( ! function_exists( 'woocommerce_subcategory_thumbnail' ) ) {
1674
1675
	/**
1676
	 * Show subcategory thumbnails.
1677
	 *
1678
	 * @param mixed $category
1679
	 * @subpackage	Loop
1680
	 */
1681
	function woocommerce_subcategory_thumbnail( $category ) {
1682
		$small_thumbnail_size  	= apply_filters( 'subcategory_archive_thumbnail_size', 'shop_catalog' );
1683
		$dimensions    			= wc_get_image_size( $small_thumbnail_size );
1684
		$thumbnail_id  			= get_woocommerce_term_meta( $category->term_id, 'thumbnail_id', true  );
1685
1686
		if ( $thumbnail_id ) {
1687
			$image = wp_get_attachment_image_src( $thumbnail_id, $small_thumbnail_size  );
1688
			$image = $image[0];
1689
		} else {
1690
			$image = wc_placeholder_img_src();
1691
		}
1692
1693
		if ( $image ) {
1694
			// Prevent esc_url from breaking spaces in urls for image embeds
1695
			// Ref: https://core.trac.wordpress.org/ticket/23605
1696
			$image = str_replace( ' ', '%20', $image );
1697
1698
			echo '<img src="' . esc_url( $image ) . '" alt="' . esc_attr( $category->name ) . '" width="' . esc_attr( $dimensions['width'] ) . '" height="' . esc_attr( $dimensions['height'] ) . '" />';
1699
		}
1700
	}
1701
}
1702
1703
if ( ! function_exists( 'woocommerce_order_details_table' ) ) {
1704
1705
	/**
1706
	 * Displays order details in a table.
1707
	 *
1708
	 * @param mixed $order_id
1709
	 * @subpackage	Orders
1710
	 */
1711
	function woocommerce_order_details_table( $order_id ) {
1712
		if ( ! $order_id ) return;
1713
1714
		wc_get_template( 'order/order-details.php', array(
1715
			'order_id' => $order_id
1716
		) );
1717
	}
1718
}
1719
1720
1721
if ( ! function_exists( 'woocommerce_order_again_button' ) ) {
1722
1723
	/**
1724
	 * Display an 'order again' button on the view order page.
1725
	 *
1726
	 * @param object $order
1727
	 * @subpackage	Orders
1728
	 */
1729
	function woocommerce_order_again_button( $order ) {
1730
		if ( ! $order || ! $order->has_status( 'completed' ) || ! is_user_logged_in() ) {
1731
			return;
1732
		}
1733
1734
		wc_get_template( 'order/order-again.php', array(
1735
			'order' => $order
1736
		) );
1737
	}
1738
}
1739
1740
/** Forms ****************************************************************/
1741
1742
if ( ! function_exists( 'woocommerce_form_field' ) ) {
1743
1744
	/**
1745
	 * Outputs a checkout/address form field.
1746
	 *
1747
	 * @subpackage	Forms
1748
	 * @param string $key
1749
	 * @param mixed $args
1750
	 * @param string $value (default: null)
1751
	 * @todo This function needs to be broken up in smaller pieces
1752
	 */
1753
	function woocommerce_form_field( $key, $args, $value = null ) {
1754
		$defaults = array(
1755
			'type'              => 'text',
1756
			'label'             => '',
1757
			'description'       => '',
1758
			'placeholder'       => '',
1759
			'maxlength'         => false,
1760
			'required'          => false,
1761
			'autocomplete'      => false,
1762
			'id'                => $key,
1763
			'class'             => array(),
1764
			'label_class'       => array(),
1765
			'input_class'       => array(),
1766
			'return'            => false,
1767
			'options'           => array(),
1768
			'custom_attributes' => array(),
1769
			'validate'          => array(),
1770
			'default'           => '',
1771
		);
1772
1773
		$args = wp_parse_args( $args, $defaults );
1774
		$args = apply_filters( 'woocommerce_form_field_args', $args, $key, $value );
1775
1776
		if ( $args['required'] ) {
1777
			$args['class'][] = 'validate-required';
1778
			$required = ' <abbr class="required" title="' . esc_attr__( 'required', 'woocommerce'  ) . '">*</abbr>';
1779
		} else {
1780
			$required = '';
1781
		}
1782
1783
		$args['maxlength'] = ( $args['maxlength'] ) ? 'maxlength="' . absint( $args['maxlength'] ) . '"' : '';
1784
1785
		$args['autocomplete'] = ( $args['autocomplete'] ) ? 'autocomplete="' . esc_attr( $args['autocomplete'] ) . '"' : '';
1786
1787
		if ( is_string( $args['label_class'] ) ) {
1788
			$args['label_class'] = array( $args['label_class'] );
1789
		}
1790
1791
		if ( is_null( $value ) ) {
1792
			$value = $args['default'];
1793
		}
1794
1795
		// Custom attribute handling
1796
		$custom_attributes = array();
1797
1798 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...
1799
			foreach ( $args['custom_attributes'] as $attribute => $attribute_value ) {
1800
				$custom_attributes[] = esc_attr( $attribute ) . '="' . esc_attr( $attribute_value ) . '"';
1801
			}
1802
		}
1803
1804
		if ( ! empty( $args['validate'] ) ) {
1805
			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...
1806
				$args['class'][] = 'validate-' . $validate;
1807
			}
1808
		}
1809
1810
		$field = '';
1811
		$label_id = $args['id'];
1812
		$field_container = '<p class="form-row %1$s" id="%2$s">%3$s</p>';
1813
1814
		switch ( $args['type'] ) {
1815
			case 'country' :
1816
1817
				$countries = 'shipping_country' === $key ? WC()->countries->get_shipping_countries() : WC()->countries->get_allowed_countries();
1818
1819
				if ( 1 === sizeof( $countries ) ) {
1820
1821
					$field .= '<strong>' . current( array_values( $countries ) ) . '</strong>';
1822
1823
					$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" />';
1824
1825
				} else {
1826
1827
					$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 ) . '>'
1828
							. '<option value="">'.__( 'Select a country&hellip;', 'woocommerce' ) .'</option>';
1829
1830 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...
1831
						$field .= '<option value="' . esc_attr( $ckey ) . '" '. selected( $value, $ckey, false ) . '>'. __( $cvalue, 'woocommerce' ) .'</option>';
1832
					}
1833
1834
					$field .= '</select>';
1835
1836
					$field .= '<noscript><input type="submit" name="woocommerce_checkout_update_totals" value="' . esc_attr__( 'Update country', 'woocommerce' ) . '" /></noscript>';
1837
1838
				}
1839
1840
				break;
1841
			case 'state' :
1842
1843
				/* Get Country */
1844
				$country_key = 'billing_state' === $key ? 'billing_country' : 'shipping_country';
1845
				$current_cc  = WC()->checkout->get_value( $country_key );
1846
				$states      = WC()->countries->get_states( $current_cc );
1847
1848
				if ( is_array( $states ) && empty( $states ) ) {
1849
1850
					$field_container = '<p class="form-row %1$s" id="%2$s" style="display: none">%3$s</p>';
1851
1852
					$field .= '<input type="hidden" class="hidden" name="' . esc_attr( $key )  . '" id="' . esc_attr( $args['id'] ) . '" value="" ' . implode( ' ', $custom_attributes ) . ' placeholder="' . esc_attr( $args['placeholder'] ) . '" />';
1853
1854
				} elseif ( is_array( $states ) ) {
1855
1856
					$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'] . '>
1857
						<option value="">'.__( 'Select a state&hellip;', 'woocommerce' ) .'</option>';
1858
1859 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...
1860
						$field .= '<option value="' . esc_attr( $ckey ) . '" '.selected( $value, $ckey, false ) .'>'.__( $cvalue, 'woocommerce' ) .'</option>';
1861
					}
1862
1863
					$field .= '</select>';
1864
1865
				} else {
1866
1867
					$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 ) . ' />';
1868
1869
				}
1870
1871
				break;
1872
			case 'textarea' :
1873
1874
				$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>';
1875
1876
				break;
1877 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...
1878
1879
				$field = '<label class="checkbox ' . implode( ' ', $args['label_class'] ) .'" ' . implode( ' ', $custom_attributes ) . '>
1880
						<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 ) .' /> '
1881
						 . $args['label'] . $required . '</label>';
1882
1883
				break;
1884
			case 'password' :
1885
			case 'text' :
1886
			case 'email' :
1887
			case 'tel' :
1888 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...
1889
1890
				$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 ) . ' />';
1891
1892
				break;
1893
			case 'select' :
1894
1895
				$options = $field = '';
1896
1897
				if ( ! empty( $args['options'] ) ) {
1898
					foreach ( $args['options'] as $option_key => $option_text ) {
1899
						if ( '' === $option_key ) {
1900
							// If we have a blank option, select2 needs a placeholder
1901
							if ( empty( $args['placeholder'] ) ) {
1902
								$args['placeholder'] = $option_text ? $option_text : __( 'Choose an option', 'woocommerce' );
1903
							}
1904
							$custom_attributes[] = 'data-allow_clear="true"';
1905
						}
1906
						$options .= '<option value="' . esc_attr( $option_key ) . '" '. selected( $value, $option_key, false ) . '>' . esc_attr( $option_text ) .'</option>';
1907
					}
1908
1909
					$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'] . '>
1910
							' . $options . '
1911
						</select>';
1912
				}
1913
1914
				break;
1915
			case 'radio' :
1916
1917
				$label_id = current( array_keys( $args['options'] ) );
1918
1919
				if ( ! empty( $args['options'] ) ) {
1920
					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...
1921
						$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 ) . ' />';
1922
						$field .= '<label for="' . esc_attr( $args['id'] ) . '_' . esc_attr( $option_key ) . '" class="radio ' . implode( ' ', $args['label_class'] ) .'">' . $option_text . '</label>';
1923
					}
1924
				}
1925
1926
				break;
1927
		}
1928
1929
		if ( ! empty( $field ) ) {
1930
			$field_html = '';
1931
1932
			if ( $args['label'] && 'checkbox' != $args['type'] ) {
1933
				$field_html .= '<label for="' . esc_attr( $label_id ) . '" class="' . esc_attr( implode( ' ', $args['label_class'] ) ) .'">' . $args['label'] . $required . '</label>';
1934
			}
1935
1936
			$field_html .= $field;
1937
1938
			if ( $args['description'] ) {
1939
				$field_html .= '<span class="description">' . esc_html( $args['description'] ) . '</span>';
1940
			}
1941
1942
			$container_class = 'form-row ' . esc_attr( implode( ' ', $args['class'] ) );
1943
			$container_id = esc_attr( $args['id'] ) . '_field';
1944
1945
			$after = ! empty( $args['clear'] ) ? '<div class="clear"></div>' : '';
1946
1947
			$field = sprintf( $field_container, $container_class, $container_id, $field_html ) . $after;
1948
		}
1949
1950
		$field = apply_filters( 'woocommerce_form_field_' . $args['type'], $field, $key, $args, $value );
1951
1952
		if ( $args['return'] ) {
1953
			return $field;
1954
		} else {
1955
			echo $field;
1956
		}
1957
	}
1958
}
1959
1960
if ( ! function_exists( 'get_product_search_form' ) ) {
1961
1962
	/**
1963
	 * Display product search form.
1964
	 *
1965
	 * Will first attempt to locate the product-searchform.php file in either the child or.
1966
	 * the parent, then load it. If it doesn't exist, then the default search form.
1967
	 * will be displayed.
1968
	 *
1969
	 * The default searchform uses html5.
1970
	 *
1971
	 * @subpackage	Forms
1972
	 * @param bool $echo (default: true)
1973
	 * @return string
1974
	 */
1975
	function get_product_search_form( $echo = true  ) {
1976
		ob_start();
1977
1978
		do_action( 'pre_get_product_search_form'  );
1979
1980
		wc_get_template( 'product-searchform.php' );
1981
1982
		$form = apply_filters( 'get_product_search_form', ob_get_clean() );
1983
1984
		if ( $echo ) {
1985
			echo $form;
1986
		} else {
1987
			return $form;
1988
		}
1989
	}
1990
}
1991
1992
if ( ! function_exists( 'woocommerce_output_auth_header' ) ) {
1993
1994
	/**
1995
	 * Output the Auth header.
1996
	 */
1997
	function woocommerce_output_auth_header() {
1998
		wc_get_template( 'auth/header.php' );
1999
	}
2000
}
2001
2002
if ( ! function_exists( 'woocommerce_output_auth_footer' ) ) {
2003
2004
	/**
2005
	 * Output the Auth footer.
2006
	 */
2007
	function woocommerce_output_auth_footer() {
2008
		wc_get_template( 'auth/footer.php' );
2009
	}
2010
}
2011
2012
if ( ! function_exists( 'woocommerce_single_variation' ) ) {
2013
2014
	/**
2015
	 * Output placeholders for the single variation.
2016
	 */
2017
	function woocommerce_single_variation() {
2018
		echo '<div class="woocommerce-variation single_variation"></div>';
2019
	}
2020
}
2021
2022
if ( ! function_exists( 'woocommerce_single_variation_add_to_cart_button' ) ) {
2023
2024
	/**
2025
	 * Output the add to cart button for variations.
2026
	 */
2027
	function woocommerce_single_variation_add_to_cart_button() {
2028
		wc_get_template( 'single-product/add-to-cart/variation-add-to-cart-button.php' );
2029
	}
2030
}
2031
2032
if ( ! function_exists( 'wc_dropdown_variation_attribute_options' ) ) {
2033
2034
	/**
2035
	 * Output a list of variation attributes for use in the cart forms.
2036
	 *
2037
	 * @param array $args
2038
	 * @since 2.4.0
2039
	 */
2040
	function wc_dropdown_variation_attribute_options( $args = array() ) {
2041
		$args = wp_parse_args( apply_filters( 'woocommerce_dropdown_variation_attribute_options_args', $args ), array(
2042
			'options'          => false,
2043
			'attribute'        => false,
2044
			'product'          => false,
2045
			'selected' 	       => false,
2046
			'name'             => '',
2047
			'id'               => '',
2048
			'class'            => '',
2049
			'show_option_none' => __( 'Choose an option', 'woocommerce' )
2050
		) );
2051
2052
		$options   = $args['options'];
2053
		$product   = $args['product'];
2054
		$attribute = $args['attribute'];
2055
		$name      = $args['name'] ? $args['name'] : 'attribute_' . sanitize_title( $attribute );
2056
		$id        = $args['id'] ? $args['id'] : sanitize_title( $attribute );
2057
		$class     = $args['class'];
2058
2059
		if ( empty( $options ) && ! empty( $product ) && ! empty( $attribute ) ) {
2060
			$attributes = $product->get_variation_attributes();
2061
			$options    = $attributes[ $attribute ];
2062
		}
2063
2064
		$html = '<select id="' . esc_attr( $id ) . '" class="' . esc_attr( $class ) . '" name="' . esc_attr( $name ) . '" data-attribute_name="attribute_' . esc_attr( sanitize_title( $attribute ) ) . '">';
2065
2066
		if ( $args['show_option_none'] ) {
2067
			$html .= '<option value="">' . esc_html( $args['show_option_none'] ) . '</option>';
2068
		}
2069
2070
		if ( ! empty( $options ) ) {
2071
			if ( $product && taxonomy_exists( $attribute ) ) {
2072
				// Get terms if this is a taxonomy - ordered. We need the names too.
2073
				$terms = wc_get_product_terms( $product->id, $attribute, array( 'fields' => 'all' ) );
2074
2075 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...
2076
					if ( in_array( $term->slug, $options ) ) {
2077
						$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>';
2078
					}
2079
				}
2080
			} else {
2081
				foreach ( $options as $option ) {
2082
					// This handles < 2.4.0 bw compatibility where text attributes were not sanitized.
2083
					$selected = sanitize_title( $args['selected'] ) === $args['selected'] ? selected( $args['selected'], sanitize_title( $option ), false ) : selected( $args['selected'], $option, false );
2084
					$html .= '<option value="' . esc_attr( $option ) . '" ' . $selected . '>' . esc_html( apply_filters( 'woocommerce_variation_option_name', $option ) ) . '</option>';
2085
				}
2086
			}
2087
		}
2088
2089
		$html .= '</select>';
2090
2091
		echo apply_filters( 'woocommerce_dropdown_variation_attribute_options_html', $html, $args );
2092
	}
2093
}
2094
2095
if ( ! function_exists( 'woocommerce_account_content' ) ) {
2096
2097
	/**
2098
	 * My Account content output.
2099
	 */
2100
	function woocommerce_account_content() {
2101
		global $wp;
2102
2103 View Code Duplication
		foreach ( $wp->query_vars as $key => $value ) {
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...
2104
			// Ignore pagename param.
2105
			if ( 'pagename' === $key ) {
2106
				continue;
2107
			}
2108
2109
			if ( has_action( 'woocommerce_account_' . $key . '_endpoint' ) ) {
2110
				do_action( 'woocommerce_account_' . $key . '_endpoint', $value );
2111
				return;
2112
			}
2113
		}
2114
2115
		// No endpoint found? Default to dashboard.
2116
		wc_get_template( 'myaccount/dashboard.php', array(
2117
			'current_user' => get_user_by( 'id', get_current_user_id() ),
2118
		) );
2119
	}
2120
}
2121
2122
if ( ! function_exists( 'woocommerce_account_navigation' ) ) {
2123
2124
	/**
2125
	 * My Account navigation template.
2126
	 */
2127
	function woocommerce_account_navigation() {
2128
		wc_get_template( 'myaccount/navigation.php' );
2129
	}
2130
}
2131
2132
if ( ! function_exists( 'woocommerce_account_orders' ) ) {
2133
2134
	/**
2135
	 * My Account > Orders template.
2136
	 *
2137
	 * @param int $current_page Current page number.
2138
	 */
2139
	function woocommerce_account_orders( $current_page ) {
2140
		$current_page    = empty( $current_page ) ? 1 : absint( $current_page );
2141
		$customer_orders = wc_get_orders( apply_filters( 'woocommerce_my_account_my_orders_query', array( 'customer' => get_current_user_id(), 'page' => $current_page, 'paginate' => true ) ) );
2142
2143
		wc_get_template(
2144
			'myaccount/orders.php',
2145
			array(
2146
				'current_page' => absint( $current_page ),
2147
				'customer_orders' => $customer_orders,
2148
				'has_orders' => 0 < $customer_orders->total,
2149
			)
2150
		);
2151
	}
2152
}
2153
2154
if ( ! function_exists( 'woocommerce_account_view_order' ) ) {
2155
2156
	/**
2157
	 * My Account > View order template.
2158
	 *
2159
	 * @param int $order_id Order ID.
2160
	 */
2161
	function woocommerce_account_view_order( $order_id ) {
2162
		WC_Shortcode_My_Account::view_order( absint( $order_id ) );
2163
	}
2164
}
2165
2166
if ( ! function_exists( 'woocommerce_account_downloads' ) ) {
2167
2168
	/**
2169
	 * My Account > Downloads template.
2170
	 */
2171
	function woocommerce_account_downloads() {
2172
		wc_get_template( 'myaccount/downloads.php' );
2173
	}
2174
}
2175
2176
if ( ! function_exists( 'woocommerce_account_edit_address' ) ) {
2177
2178
	/**
2179
	 * My Account > Edit address template.
2180
	 *
2181
	 * @param string $type Address type.
2182
	 */
2183
	function woocommerce_account_edit_address( $type ) {
2184
		$type = wc_edit_address_i18n( sanitize_title( $type ), true );
2185
2186
		WC_Shortcode_My_Account::edit_address( $type );
2187
	}
2188
}
2189
2190
if ( ! function_exists( 'woocommerce_account_payment_methods' ) ) {
2191
2192
	/**
2193
	 * My Account > Downloads template.
2194
	 */
2195
	function woocommerce_account_payment_methods() {
2196
		wc_get_template( 'myaccount/payment-methods.php' );
2197
	}
2198
}
2199
2200
if ( ! function_exists( 'woocommerce_account_add_payment_method' ) ) {
2201
2202
	/**
2203
	 * My Account > Add payment method template.
2204
	 */
2205
	function woocommerce_account_add_payment_method() {
2206
		WC_Shortcode_My_Account::add_payment_method();
2207
	}
2208
}
2209
2210
if ( ! function_exists( 'woocommerce_account_edit_account' ) ) {
2211
2212
	/**
2213
	 * My Account > Edit account template.
2214
	 */
2215
	function woocommerce_account_edit_account() {
2216
		WC_Shortcode_My_Account::edit_account();
2217
	}
2218
}
2219