/includes/wc-template-functions.php

  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. * Handle redirects before content is output - hooked into template_redirect so is_page works. 
  18. */ 
  19. function wc_template_redirect() { 
  20. global $wp_query, $wp; 
  21.  
  22. if ( ! empty( $_GET['page_id'] ) && '' === get_option( 'permalink_structure' ) && wc_get_page_id( 'shop' ) == $_GET['page_id'] ) { 
  23.  
  24. // When default permalinks are enabled, redirect shop page to post type archive url 
  25. wp_safe_redirect( get_post_type_archive_link( 'product' ) ); 
  26. exit; 
  27.  
  28. } elseif ( is_page( wc_get_page_id( 'checkout' ) ) && wc_get_page_id( 'checkout' ) !== wc_get_page_id( 'cart' ) && WC()->cart->is_empty() && empty( $wp->query_vars['order-pay'] ) && ! isset( $wp->query_vars['order-received'] ) ) { 
  29.  
  30. // When on the checkout with an empty cart, redirect to cart page 
  31. wc_add_notice( __( 'Checkout is not available whilst your cart is empty.', 'woocommerce' ), 'notice' ); 
  32. wp_redirect( wc_get_page_permalink( 'cart' ) ); 
  33. exit; 
  34.  
  35. } elseif ( isset( $wp->query_vars['customer-logout'] ) ) { 
  36.  
  37. // Logout 
  38. wp_redirect( str_replace( '&', '&', wp_logout_url( wc_get_page_permalink( 'myaccount' ) ) ) ); 
  39. exit; 
  40.  
  41. } elseif ( is_search() && is_post_type_archive( 'product' ) && apply_filters( 'woocommerce_redirect_single_search_result', true ) && 1 === absint( $wp_query->found_posts ) ) { 
  42.  
  43. // Redirect to the product page if we have a single product 
  44. $product = wc_get_product( $wp_query->post ); 
  45.  
  46. if ( $product && $product->is_visible() ) { 
  47. wp_safe_redirect( get_permalink( $product->get_id() ), 302 ); 
  48. exit; 
  49. } elseif ( is_add_payment_method_page() ) { 
  50.  
  51. // Ensure payment gateways are loaded early 
  52. WC()->payment_gateways(); 
  53.  
  54. } elseif ( is_checkout() ) { 
  55.  
  56. // Checkout pages handling 
  57. // Buffer the checkout page 
  58. ob_start(); 
  59.  
  60. // Ensure gateways and shipping methods are loaded early 
  61. WC()->payment_gateways(); 
  62. WC()->shipping(); 
  63.  
  64. add_action( 'template_redirect', 'wc_template_redirect' ); 
  65.  
  66. /** 
  67. * When loading sensitive checkout or account pages, send a HTTP header to limit rendering of pages to same origin iframes for security reasons. 
  68. * 
  69. * Can be disabled with: remove_action( 'template_redirect', 'wc_send_frame_options_header' ); 
  70. * 
  71. * @since 2.3.10 
  72. */ 
  73. function wc_send_frame_options_header() { 
  74. if ( is_checkout() || is_account_page() ) { 
  75. send_frame_options_header(); 
  76. add_action( 'template_redirect', 'wc_send_frame_options_header' ); 
  77.  
  78. /** 
  79. * No index our endpoints. 
  80. * Prevent indexing pages like order-received. 
  81. * 
  82. * @since 2.5.3 
  83. */ 
  84. function wc_prevent_endpoint_indexing() { 
  85. if ( is_wc_endpoint_url() || isset( $_GET['download_file'] ) ) { 
  86. @header( 'X-Robots-Tag: noindex' ); 
  87. add_action( 'template_redirect', 'wc_prevent_endpoint_indexing' ); 
  88.  
  89. /** 
  90. * Remove adjacent_posts_rel_link_wp_head - pointless for products. 
  91. * 
  92. * @since 3.0.0 
  93. */ 
  94. function wc_prevent_adjacent_posts_rel_link_wp_head() { 
  95. if ( is_singular( 'product' ) ) { 
  96. remove_action( 'wp_head', 'adjacent_posts_rel_link_wp_head', 10, 0 ); 
  97. add_action( 'template_redirect', 'wc_prevent_adjacent_posts_rel_link_wp_head' ); 
  98.  
  99. /** 
  100. * When the_post is called, put product data into a global. 
  101. * 
  102. * @param mixed $post 
  103. * @return WC_Product 
  104. */ 
  105. function wc_setup_product_data( $post ) { 
  106. unset( $GLOBALS['product'] ); 
  107.  
  108. if ( is_int( $post ) ) 
  109. $post = get_post( $post ); 
  110.  
  111. if ( empty( $post->post_type ) || ! in_array( $post->post_type, array( 'product', 'product_variation' ) ) ) 
  112. return; 
  113.  
  114. $GLOBALS['product'] = wc_get_product( $post ); 
  115.  
  116. return $GLOBALS['product']; 
  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. add_filter( 'loop_end', 'woocommerce_reset_loop' ); 
  132.  
  133. /** 
  134. * Products RSS Feed. 
  135. * @deprecated 2.6 
  136. * @access public 
  137. */ 
  138. function wc_products_rss_feed() { 
  139. // Product RSS 
  140. if ( is_post_type_archive( 'product' ) || is_singular( 'product' ) ) { 
  141.  
  142. $feed = get_post_type_archive_feed_link( 'product' ); 
  143.  
  144. echo '<link rel="alternate" type="application/rss+xml" title="' . esc_attr__( 'New products', 'woocommerce' ) . '" href="' . esc_url( $feed ) . '" />'; 
  145.  
  146. } elseif ( is_tax( 'product_cat' ) ) { 
  147.  
  148. $term = get_term_by( 'slug', esc_attr( get_query_var( 'product_cat' ) ), 'product_cat' ); 
  149.  
  150. if ( $term ) { 
  151. $feed = add_query_arg( 'product_cat', $term->slug, get_post_type_archive_feed_link( 'product' ) ); 
  152. echo '<link rel="alternate" type="application/rss+xml" title="' . sprintf( esc_attr__( 'New products added to %s', 'woocommerce' ), $term->name ) . '" href="' . esc_url( $feed ) . '" />'; 
  153. } elseif ( is_tax( 'product_tag' ) ) { 
  154.  
  155. $term = get_term_by( 'slug', esc_attr( get_query_var( 'product_tag' ) ), 'product_tag' ); 
  156.  
  157. if ( $term ) { 
  158. $feed = add_query_arg( 'product_tag', $term->slug, get_post_type_archive_feed_link( 'product' ) ); 
  159. echo '<link rel="alternate" type="application/rss+xml" title="' . sprintf( esc_attr__( 'New products tagged %s', 'woocommerce' ), urlencode( $term->name ) ) . '" href="' . esc_url( $feed ) . '" />'; 
  160.  
  161. /** 
  162. * Output generator tag to aid debugging. 
  163. * 
  164. * @access public 
  165. */ 
  166. function wc_generator_tag( $gen, $type ) { 
  167. switch ( $type ) { 
  168. case 'html': 
  169. $gen .= "\n" . '<meta name="generator" content="WooCommerce ' . esc_attr( WC_VERSION ) . '">'; 
  170. break; 
  171. case 'xhtml': 
  172. $gen .= "\n" . '<meta name="generator" content="WooCommerce ' . esc_attr( WC_VERSION ) . '" />'; 
  173. break; 
  174. return $gen; 
  175.  
  176. /** 
  177. * Add body classes for WC pages. 
  178. * 
  179. * @param array $classes 
  180. * @return array 
  181. */ 
  182. function wc_body_class( $classes ) { 
  183. $classes = (array) $classes; 
  184.  
  185. if ( is_woocommerce() ) { 
  186.  
  187. $classes[] = 'woocommerce'; 
  188. $classes[] = 'woocommerce-page'; 
  189.  
  190. } elseif ( is_checkout() ) { 
  191.  
  192. $classes[] = 'woocommerce-checkout'; 
  193. $classes[] = 'woocommerce-page'; 
  194.  
  195. } elseif ( is_cart() ) { 
  196.  
  197. $classes[] = 'woocommerce-cart'; 
  198. $classes[] = 'woocommerce-page'; 
  199.  
  200. } elseif ( is_account_page() ) { 
  201.  
  202. $classes[] = 'woocommerce-account'; 
  203. $classes[] = 'woocommerce-page'; 
  204.  
  205.  
  206. if ( is_store_notice_showing() ) { 
  207. $classes[] = 'woocommerce-demo-store'; 
  208.  
  209. foreach ( WC()->query->query_vars as $key => $value ) { 
  210. if ( is_wc_endpoint_url( $key ) ) { 
  211. $classes[] = 'woocommerce-' . sanitize_html_class( $key ); 
  212.  
  213. return array_unique( $classes ); 
  214.  
  215. /** 
  216. * Display the classes for the product cat div. 
  217. * 
  218. * @since 2.4.0 
  219. * @param string|array $class One or more classes to add to the class list. 
  220. * @param object $category object Optional. 
  221. */ 
  222. function wc_product_cat_class( $class = '', $category = null ) { 
  223. // Separates classes with a single space, collates classes for post DIV 
  224. echo 'class="' . esc_attr( join( ' ', wc_get_product_cat_class( $class, $category ) ) ) . '"'; 
  225.  
  226. /** 
  227. * Get classname for loops based on $woocommerce_loop global. 
  228. * @since 2.6.0 
  229. * @return string 
  230. */ 
  231. function wc_get_loop_class() { 
  232. global $woocommerce_loop; 
  233.  
  234. $woocommerce_loop['loop'] = ! empty( $woocommerce_loop['loop'] ) ? $woocommerce_loop['loop'] + 1 : 1; 
  235. $woocommerce_loop['columns'] = max( 1, ! empty( $woocommerce_loop['columns'] ) ? $woocommerce_loop['columns'] : apply_filters( 'loop_shop_columns', 4 ) ); 
  236.  
  237. if ( 0 === ( $woocommerce_loop['loop'] - 1 ) % $woocommerce_loop['columns'] || 1 === $woocommerce_loop['columns'] ) { 
  238. return 'first'; 
  239. } elseif ( 0 === $woocommerce_loop['loop'] % $woocommerce_loop['columns'] ) { 
  240. return 'last'; 
  241. } else { 
  242. return ''; 
  243.  
  244. /** 
  245. * Get the classes for the product cat div. 
  246. * 
  247. * @since 2.4.0 
  248. * @param string|array $class One or more classes to add to the class list. 
  249. * @param object $category object Optional. 
  250. */ 
  251. function wc_get_product_cat_class( $class = '', $category = null ) { 
  252. $classes = is_array( $class ) ? $class : array_map( 'trim', explode( ' ', $class ) ); 
  253. $classes[] = 'product-category'; 
  254. $classes[] = 'product'; 
  255. $classes[] = wc_get_loop_class(); 
  256. $classes = apply_filters( 'product_cat_class', $classes, $class, $category ); 
  257.  
  258. return array_unique( array_filter( $classes ) ); 
  259.  
  260. /** 
  261. * Adds extra post classes for products. 
  262. * 
  263. * @since 2.1.0 
  264. * @param array $classes 
  265. * @param string|array $class 
  266. * @param int $post_id 
  267. * @return array 
  268. */ 
  269. function wc_product_post_class( $classes, $class = '', $post_id = '' ) { 
  270. if ( ! $post_id || ! in_array( get_post_type( $post_id ), array( 'product', 'product_variation' ) ) ) { 
  271. return $classes; 
  272.  
  273. $product = wc_get_product( $post_id ); 
  274.  
  275. if ( $product ) { 
  276. $classes[] = 'product'; 
  277. $classes[] = wc_get_loop_class(); 
  278. $classes[] = $product->get_stock_status(); 
  279.  
  280. if ( $product->is_on_sale() ) { 
  281. $classes[] = 'sale'; 
  282. if ( $product->is_featured() ) { 
  283. $classes[] = 'featured'; 
  284. if ( $product->is_downloadable() ) { 
  285. $classes[] = 'downloadable'; 
  286. if ( $product->is_virtual() ) { 
  287. $classes[] = 'virtual'; 
  288. if ( $product->is_sold_individually() ) { 
  289. $classes[] = 'sold-individually'; 
  290. if ( $product->is_taxable() ) { 
  291. $classes[] = 'taxable'; 
  292. if ( $product->is_shipping_taxable() ) { 
  293. $classes[] = 'shipping-taxable'; 
  294. if ( $product->is_purchasable() ) { 
  295. $classes[] = 'purchasable'; 
  296. if ( $product->get_type() ) { 
  297. $classes[] = "product-type-" . $product->get_type(); 
  298. if ( $product->is_type( 'variable' ) ) { 
  299. if ( ! $product->get_default_attributes() ) { 
  300. $classes[] = 'has-default-attributes'; 
  301. if ( $product->has_child() ) { 
  302. $classes[] = 'has-children'; 
  303.  
  304. if ( false !== ( $key = array_search( 'hentry', $classes ) ) ) { 
  305. unset( $classes[ $key ] ); 
  306.  
  307. return $classes; 
  308.  
  309. /** 
  310. * Outputs hidden form inputs for each query string variable. 
  311. * @since 3.0.0 
  312. * @param array $values Name value pairs. 
  313. * @param array $exclude Keys to exclude. 
  314. * @param string $current_key Current key we are outputting. 
  315. */ 
  316. function wc_query_string_form_fields( $values = null, $exclude = array(), $current_key = '', $return = false ) { 
  317. if ( is_null( $values ) ) { 
  318. $values = $_GET; 
  319. $html = ''; 
  320.  
  321. foreach ( $values as $key => $value ) { 
  322. if ( in_array( $key, $exclude, true ) ) { 
  323. continue; 
  324. if ( $current_key ) { 
  325. $key = $current_key . '[' . $key . ']'; 
  326. if ( is_array( $value ) ) { 
  327. $html .= wc_query_string_form_fields( $value, $exclude, $key, true ); 
  328. } else { 
  329. $html .= '<input type="hidden" name="' . esc_attr( $key ) . '" value="' . esc_attr( $value ) . '" />'; 
  330.  
  331. if ( $return ) { 
  332. return $html; 
  333. } else { 
  334. echo $html; 
  335.  
  336. /** Template pages ********************************************************/ 
  337.  
  338. if ( ! function_exists( 'woocommerce_content' ) ) { 
  339.  
  340. /** 
  341. * Output WooCommerce content. 
  342. * 
  343. * This function is only used in the optional 'woocommerce.php' template. 
  344. * which people can add to their themes to add basic woocommerce support. 
  345. * without hooks or modifying core templates. 
  346. * 
  347. */ 
  348. function woocommerce_content() { 
  349.  
  350. if ( is_singular( 'product' ) ) { 
  351.  
  352. while ( have_posts() ) : the_post(); 
  353.  
  354. wc_get_template_part( 'content', 'single-product' ); 
  355.  
  356. endwhile; 
  357.  
  358. } else { ?> 
  359.  
  360. <?php if ( apply_filters( 'woocommerce_show_page_title', true ) ) : ?> 
  361.  
  362. <h1 class="page-title"><?php woocommerce_page_title(); ?></h1> 
  363.  
  364. <?php endif; ?> 
  365.  
  366. <?php do_action( 'woocommerce_archive_description' ); ?> 
  367.  
  368. <?php if ( have_posts() ) : ?> 
  369.  
  370. <?php do_action( 'woocommerce_before_shop_loop' ); ?> 
  371.  
  372. <?php woocommerce_product_loop_start(); ?> 
  373.  
  374. <?php woocommerce_product_subcategories(); ?> 
  375.  
  376. <?php while ( have_posts() ) : the_post(); ?> 
  377.  
  378. <?php wc_get_template_part( 'content', 'product' ); ?> 
  379.  
  380. <?php endwhile; // end of the loop. ?> 
  381.  
  382. <?php woocommerce_product_loop_end(); ?> 
  383.  
  384. <?php do_action( 'woocommerce_after_shop_loop' ); ?> 
  385.  
  386. <?php elseif ( ! woocommerce_product_subcategories( array( 'before' => woocommerce_product_loop_start( false ), 'after' => woocommerce_product_loop_end( false ) ) ) ) : ?> 
  387.  
  388. <?php do_action( 'woocommerce_no_products_found' ); ?> 
  389.  
  390. <?php endif; 
  391.  
  392.  
  393. /** Global ****************************************************************/ 
  394.  
  395. if ( ! function_exists( 'woocommerce_output_content_wrapper' ) ) { 
  396.  
  397. /** 
  398. * Output the start of the page wrapper. 
  399. * 
  400. */ 
  401. function woocommerce_output_content_wrapper() { 
  402. wc_get_template( 'global/wrapper-start.php' ); 
  403. if ( ! function_exists( 'woocommerce_output_content_wrapper_end' ) ) { 
  404.  
  405. /** 
  406. * Output the end of the page wrapper. 
  407. * 
  408. */ 
  409. function woocommerce_output_content_wrapper_end() { 
  410. wc_get_template( 'global/wrapper-end.php' ); 
  411.  
  412. if ( ! function_exists( 'woocommerce_get_sidebar' ) ) { 
  413.  
  414. /** 
  415. * Get the shop sidebar template. 
  416. * 
  417. */ 
  418. function woocommerce_get_sidebar() { 
  419. wc_get_template( 'global/sidebar.php' ); 
  420.  
  421. if ( ! function_exists( 'woocommerce_demo_store' ) ) { 
  422.  
  423. /** 
  424. * Adds a demo store banner to the site if enabled. 
  425. * 
  426. */ 
  427. function woocommerce_demo_store() { 
  428. if ( ! is_store_notice_showing() ) { 
  429. return; 
  430.  
  431. $notice = get_option( 'woocommerce_demo_store_notice' ); 
  432.  
  433. if ( empty( $notice ) ) { 
  434. $notice = __( 'This is a demo store for testing purposes — no orders shall be fulfilled.', 'woocommerce' ); 
  435.  
  436. echo apply_filters( 'woocommerce_demo_store', '<p class="woocommerce-store-notice demo_store">' . wp_kses_post( $notice ) . ' <a href="#" class="woocommerce-store-notice__dismiss-link">' . esc_html__( 'Dismiss', 'woocommerce' ) . '</a></p>', $notice ); 
  437.  
  438. /** Loop ******************************************************************/ 
  439.  
  440. if ( ! function_exists( 'woocommerce_page_title' ) ) { 
  441.  
  442. /** 
  443. * woocommerce_page_title function. 
  444. * 
  445. * @param bool $echo 
  446. * @return string 
  447. */ 
  448. function woocommerce_page_title( $echo = true ) { 
  449.  
  450. if ( is_search() ) { 
  451. $page_title = sprintf( __( 'Search results: “%s”', 'woocommerce' ), get_search_query() ); 
  452.  
  453. if ( get_query_var( 'paged' ) ) 
  454. $page_title .= sprintf( __( ' – Page %s', 'woocommerce' ), get_query_var( 'paged' ) ); 
  455.  
  456. } elseif ( is_tax() ) { 
  457.  
  458. $page_title = single_term_title( "", false ); 
  459.  
  460. } else { 
  461.  
  462. $shop_page_id = wc_get_page_id( 'shop' ); 
  463. $page_title = get_the_title( $shop_page_id ); 
  464.  
  465.  
  466. $page_title = apply_filters( 'woocommerce_page_title', $page_title ); 
  467.  
  468. if ( $echo ) 
  469. echo $page_title; 
  470. else 
  471. return $page_title; 
  472.  
  473. if ( ! function_exists( 'woocommerce_product_loop_start' ) ) { 
  474.  
  475. /** 
  476. * Output the start of a product loop. By default this is a UL. 
  477. * 
  478. * @param bool $echo 
  479. * @return string 
  480. */ 
  481. function woocommerce_product_loop_start( $echo = true ) { 
  482. ob_start(); 
  483. $GLOBALS['woocommerce_loop']['loop'] = 0; 
  484. wc_get_template( 'loop/loop-start.php' ); 
  485. if ( $echo ) 
  486. echo ob_get_clean(); 
  487. else 
  488. return ob_get_clean(); 
  489. if ( ! function_exists( 'woocommerce_product_loop_end' ) ) { 
  490.  
  491. /** 
  492. * Output the end of a product loop. By default this is a UL. 
  493. * 
  494. * @param bool $echo 
  495. * @return string 
  496. */ 
  497. function woocommerce_product_loop_end( $echo = true ) { 
  498. ob_start(); 
  499.  
  500. wc_get_template( 'loop/loop-end.php' ); 
  501.  
  502. if ( $echo ) 
  503. echo ob_get_clean(); 
  504. else 
  505. return ob_get_clean(); 
  506. if ( ! function_exists( 'woocommerce_template_loop_product_title' ) ) { 
  507.  
  508. /** 
  509. * Show the product title in the product loop. By default this is an H2. 
  510. */ 
  511. function woocommerce_template_loop_product_title() { 
  512. echo '<h2 class="woocommerce-loop-product__title">' . get_the_title() . '</h2>'; 
  513. if ( ! function_exists( 'woocommerce_template_loop_category_title' ) ) { 
  514.  
  515. /** 
  516. * Show the subcategory title in the product loop. 
  517. */ 
  518. function woocommerce_template_loop_category_title( $category ) { 
  519. ?> 
  520. <h2 class="woocommerce-loop-category__title"> 
  521. <?php 
  522. echo $category->name; 
  523.  
  524. if ( $category->count > 0 ) 
  525. echo apply_filters( 'woocommerce_subcategory_count_html', ' <mark class="count">(' . $category->count . ')</mark>', $category ); 
  526. ?> 
  527. </h2> 
  528. <?php 
  529. /** 
  530. * Insert the opening anchor tag for products in the loop. 
  531. */ 
  532. function woocommerce_template_loop_product_link_open() { 
  533. echo '<a href="' . get_the_permalink() . '" class="woocommerce-LoopProduct-link">'; 
  534. /** 
  535. * Insert the opening anchor tag for products in the loop. 
  536. */ 
  537. function woocommerce_template_loop_product_link_close() { 
  538. echo '</a>'; 
  539. /** 
  540. * Insert the opening anchor tag for categories in the loop. 
  541. */ 
  542. function woocommerce_template_loop_category_link_open( $category ) { 
  543. echo '<a href="' . get_term_link( $category, 'product_cat' ) . '">'; 
  544. /** 
  545. * Insert the closing anchor tag for categories in the loop. 
  546. */ 
  547. function woocommerce_template_loop_category_link_close() { 
  548. echo '</a>'; 
  549. if ( ! function_exists( 'woocommerce_taxonomy_archive_description' ) ) { 
  550.  
  551. /** 
  552. * Show an archive description on taxonomy archives. 
  553. * 
  554. * @subpackage Archives 
  555. */ 
  556. function woocommerce_taxonomy_archive_description() { 
  557. if ( is_product_taxonomy() && 0 === absint( get_query_var( 'paged' ) ) ) { 
  558. $description = wc_format_content( term_description() ); 
  559. if ( $description ) { 
  560. echo '<div class="term-description">' . $description . '</div>'; 
  561. if ( ! function_exists( 'woocommerce_product_archive_description' ) ) { 
  562.  
  563. /** 
  564. * Show a shop page description on product archives. 
  565. * 
  566. * @subpackage Archives 
  567. */ 
  568. function woocommerce_product_archive_description() { 
  569. // Don't display the description on search results page 
  570. if ( is_search() ) { 
  571. return; 
  572.  
  573. if ( is_post_type_archive( 'product' ) && 0 === absint( get_query_var( 'paged' ) ) ) { 
  574. $shop_page = get_post( wc_get_page_id( 'shop' ) ); 
  575. if ( $shop_page ) { 
  576. $description = wc_format_content( $shop_page->post_content ); 
  577. if ( $description ) { 
  578. echo '<div class="page-description">' . $description . '</div>'; 
  579.  
  580. if ( ! function_exists( 'woocommerce_template_loop_add_to_cart' ) ) { 
  581.  
  582. /** 
  583. * Get the add to cart template for the loop. 
  584. * 
  585. * @subpackage Loop 
  586. */ 
  587. function woocommerce_template_loop_add_to_cart( $args = array() ) { 
  588. global $product; 
  589.  
  590. if ( $product ) { 
  591. $defaults = array( 
  592. 'quantity' => 1,  
  593. 'class' => implode( ' ', array_filter( array( 
  594. 'button',  
  595. 'product_type_' . $product->get_type(),  
  596. $product->is_purchasable() && $product->is_in_stock() ? 'add_to_cart_button' : '',  
  597. $product->supports( 'ajax_add_to_cart' ) ? 'ajax_add_to_cart' : '',  
  598. ) ) ),  
  599. ); 
  600.  
  601. $args = apply_filters( 'woocommerce_loop_add_to_cart_args', wp_parse_args( $args, $defaults ), $product ); 
  602.  
  603. wc_get_template( 'loop/add-to-cart.php', $args ); 
  604. if ( ! function_exists( 'woocommerce_template_loop_product_thumbnail' ) ) { 
  605.  
  606. /** 
  607. * Get the product thumbnail for the loop. 
  608. * 
  609. * @subpackage Loop 
  610. */ 
  611. function woocommerce_template_loop_product_thumbnail() { 
  612. echo woocommerce_get_product_thumbnail(); 
  613. if ( ! function_exists( 'woocommerce_template_loop_price' ) ) { 
  614.  
  615. /** 
  616. * Get the product price for the loop. 
  617. * 
  618. * @subpackage Loop 
  619. */ 
  620. function woocommerce_template_loop_price() { 
  621. wc_get_template( 'loop/price.php' ); 
  622. if ( ! function_exists( 'woocommerce_template_loop_rating' ) ) { 
  623.  
  624. /** 
  625. * Display the average rating in the loop. 
  626. * 
  627. * @subpackage Loop 
  628. */ 
  629. function woocommerce_template_loop_rating() { 
  630. wc_get_template( 'loop/rating.php' ); 
  631. if ( ! function_exists( 'woocommerce_show_product_loop_sale_flash' ) ) { 
  632.  
  633. /** 
  634. * Get the sale flash for the loop. 
  635. * 
  636. * @subpackage Loop 
  637. */ 
  638. function woocommerce_show_product_loop_sale_flash() { 
  639. wc_get_template( 'loop/sale-flash.php' ); 
  640.  
  641. if ( ! function_exists( 'woocommerce_get_product_thumbnail' ) ) { 
  642.  
  643. /** 
  644. * Get the product thumbnail, or the placeholder if not set. 
  645. * 
  646. * @subpackage Loop 
  647. * @param string $size (default: 'shop_catalog') 
  648. * @param int $deprecated1 Deprecated since WooCommerce 2.0 (default: 0) 
  649. * @param int $deprecated2 Deprecated since WooCommerce 2.0 (default: 0) 
  650. * @return string 
  651. */ 
  652. function woocommerce_get_product_thumbnail( $size = 'shop_catalog', $deprecated1 = 0, $deprecated2 = 0 ) { 
  653. global $post; 
  654. $image_size = apply_filters( 'single_product_archive_thumbnail_size', $size ); 
  655.  
  656. if ( has_post_thumbnail() ) { 
  657. $props = wc_get_product_attachment_props( get_post_thumbnail_id(), $post ); 
  658. return get_the_post_thumbnail( $post->ID, $image_size, array( 
  659. 'title' => $props['title'],  
  660. 'alt' => $props['alt'],  
  661. ) ); 
  662. } elseif ( wc_placeholder_img_src() ) { 
  663. return wc_placeholder_img( $image_size ); 
  664.  
  665. if ( ! function_exists( 'woocommerce_result_count' ) ) { 
  666.  
  667. /** 
  668. * Output the result count text (Showing x - x of x results). 
  669. * 
  670. * @subpackage Loop 
  671. */ 
  672. function woocommerce_result_count() { 
  673. wc_get_template( 'loop/result-count.php' ); 
  674.  
  675. if ( ! function_exists( 'woocommerce_catalog_ordering' ) ) { 
  676.  
  677. /** 
  678. * Output the product sorting options. 
  679. * 
  680. * @subpackage Loop 
  681. */ 
  682. function woocommerce_catalog_ordering() { 
  683. global $wp_query; 
  684.  
  685. if ( 1 === (int) $wp_query->found_posts || ! woocommerce_products_will_display() ) { 
  686. return; 
  687.  
  688. $orderby = isset( $_GET['orderby'] ) ? wc_clean( $_GET['orderby'] ) : apply_filters( 'woocommerce_default_catalog_orderby', get_option( 'woocommerce_default_catalog_orderby' ) ); 
  689. $show_default_orderby = 'menu_order' === apply_filters( 'woocommerce_default_catalog_orderby', get_option( 'woocommerce_default_catalog_orderby' ) ); 
  690. $catalog_orderby_options = apply_filters( 'woocommerce_catalog_orderby', array( 
  691. 'menu_order' => __( 'Default sorting', 'woocommerce' ),  
  692. 'popularity' => __( 'Sort by popularity', 'woocommerce' ),  
  693. 'rating' => __( 'Sort by average rating', 'woocommerce' ),  
  694. 'date' => __( 'Sort by newness', 'woocommerce' ),  
  695. 'price' => __( 'Sort by price: low to high', 'woocommerce' ),  
  696. 'price-desc' => __( 'Sort by price: high to low', 'woocommerce' ),  
  697. ) ); 
  698.  
  699. if ( ! $show_default_orderby ) { 
  700. unset( $catalog_orderby_options['menu_order'] ); 
  701.  
  702. if ( 'no' === get_option( 'woocommerce_enable_review_rating' ) ) { 
  703. unset( $catalog_orderby_options['rating'] ); 
  704.  
  705. wc_get_template( 'loop/orderby.php', array( 'catalog_orderby_options' => $catalog_orderby_options, 'orderby' => $orderby, 'show_default_orderby' => $show_default_orderby ) ); 
  706.  
  707. if ( ! function_exists( 'woocommerce_pagination' ) ) { 
  708.  
  709. /** 
  710. * Output the pagination. 
  711. * 
  712. * @subpackage Loop 
  713. */ 
  714. function woocommerce_pagination() { 
  715. wc_get_template( 'loop/pagination.php' ); 
  716.  
  717. /** Single Product ********************************************************/ 
  718.  
  719. if ( ! function_exists( 'woocommerce_show_product_images' ) ) { 
  720.  
  721. /** 
  722. * Output the product image before the single product summary. 
  723. * 
  724. * @subpackage Product 
  725. */ 
  726. function woocommerce_show_product_images() { 
  727. wc_get_template( 'single-product/product-image.php' ); 
  728. if ( ! function_exists( 'woocommerce_show_product_thumbnails' ) ) { 
  729.  
  730. /** 
  731. * Output the product thumbnails. 
  732. * 
  733. * @subpackage Product 
  734. */ 
  735. function woocommerce_show_product_thumbnails() { 
  736. wc_get_template( 'single-product/product-thumbnails.php' ); 
  737. if ( ! function_exists( 'woocommerce_output_product_data_tabs' ) ) { 
  738.  
  739. /** 
  740. * Output the product tabs. 
  741. * 
  742. * @subpackage Product/Tabs 
  743. */ 
  744. function woocommerce_output_product_data_tabs() { 
  745. wc_get_template( 'single-product/tabs/tabs.php' ); 
  746. if ( ! function_exists( 'woocommerce_template_single_title' ) ) { 
  747.  
  748. /** 
  749. * Output the product title. 
  750. * 
  751. * @subpackage Product 
  752. */ 
  753. function woocommerce_template_single_title() { 
  754. wc_get_template( 'single-product/title.php' ); 
  755. if ( ! function_exists( 'woocommerce_template_single_rating' ) ) { 
  756.  
  757. /** 
  758. * Output the product rating. 
  759. * 
  760. * @subpackage Product 
  761. */ 
  762. function woocommerce_template_single_rating() { 
  763. wc_get_template( 'single-product/rating.php' ); 
  764. if ( ! function_exists( 'woocommerce_template_single_price' ) ) { 
  765.  
  766. /** 
  767. * Output the product price. 
  768. * 
  769. * @subpackage Product 
  770. */ 
  771. function woocommerce_template_single_price() { 
  772. wc_get_template( 'single-product/price.php' ); 
  773. if ( ! function_exists( 'woocommerce_template_single_excerpt' ) ) { 
  774.  
  775. /** 
  776. * Output the product short description (excerpt). 
  777. * 
  778. * @subpackage Product 
  779. */ 
  780. function woocommerce_template_single_excerpt() { 
  781. wc_get_template( 'single-product/short-description.php' ); 
  782. if ( ! function_exists( 'woocommerce_template_single_meta' ) ) { 
  783.  
  784. /** 
  785. * Output the product meta. 
  786. * 
  787. * @subpackage Product 
  788. */ 
  789. function woocommerce_template_single_meta() { 
  790. wc_get_template( 'single-product/meta.php' ); 
  791. if ( ! function_exists( 'woocommerce_template_single_sharing' ) ) { 
  792.  
  793. /** 
  794. * Output the product sharing. 
  795. * 
  796. * @subpackage Product 
  797. */ 
  798. function woocommerce_template_single_sharing() { 
  799. wc_get_template( 'single-product/share.php' ); 
  800. if ( ! function_exists( 'woocommerce_show_product_sale_flash' ) ) { 
  801.  
  802. /** 
  803. * Output the product sale flash. 
  804. * 
  805. * @subpackage Product 
  806. */ 
  807. function woocommerce_show_product_sale_flash() { 
  808. wc_get_template( 'single-product/sale-flash.php' ); 
  809.  
  810. if ( ! function_exists( 'woocommerce_template_single_add_to_cart' ) ) { 
  811.  
  812. /** 
  813. * Trigger the single product add to cart action. 
  814. * 
  815. * @subpackage Product 
  816. */ 
  817. function woocommerce_template_single_add_to_cart() { 
  818. global $product; 
  819. do_action( 'woocommerce_' . $product->get_type() . '_add_to_cart' ); 
  820. if ( ! function_exists( 'woocommerce_simple_add_to_cart' ) ) { 
  821.  
  822. /** 
  823. * Output the simple product add to cart area. 
  824. * 
  825. * @subpackage Product 
  826. */ 
  827. function woocommerce_simple_add_to_cart() { 
  828. wc_get_template( 'single-product/add-to-cart/simple.php' ); 
  829. if ( ! function_exists( 'woocommerce_grouped_add_to_cart' ) ) { 
  830.  
  831. /** 
  832. * Output the grouped product add to cart area. 
  833. * 
  834. * @subpackage Product 
  835. */ 
  836. function woocommerce_grouped_add_to_cart() { 
  837. global $product; 
  838.  
  839. wc_get_template( 'single-product/add-to-cart/grouped.php', array( 
  840. 'grouped_product' => $product,  
  841. 'grouped_products' => array_map( 'wc_get_product', $product->get_children() ),  
  842. 'quantites_required' => false,  
  843. ) ); 
  844. if ( ! function_exists( 'woocommerce_variable_add_to_cart' ) ) { 
  845.  
  846. /** 
  847. * Output the variable product add to cart area. 
  848. * 
  849. * @subpackage Product 
  850. */ 
  851. function woocommerce_variable_add_to_cart() { 
  852. global $product; 
  853.  
  854. // Enqueue variation scripts 
  855. wp_enqueue_script( 'wc-add-to-cart-variation' ); 
  856.  
  857. // Get Available variations? 
  858. $get_variations = sizeof( $product->get_children() ) <= apply_filters( 'woocommerce_ajax_variation_threshold', 30, $product ); 
  859.  
  860. // Load the template 
  861. wc_get_template( 'single-product/add-to-cart/variable.php', array( 
  862. 'available_variations' => $get_variations ? $product->get_available_variations() : false,  
  863. 'attributes' => $product->get_variation_attributes(),  
  864. 'selected_attributes' => $product->get_default_attributes(),  
  865. ) ); 
  866. if ( ! function_exists( 'woocommerce_external_add_to_cart' ) ) { 
  867.  
  868. /** 
  869. * Output the external product add to cart area. 
  870. * 
  871. * @subpackage Product 
  872. */ 
  873. function woocommerce_external_add_to_cart() { 
  874. global $product; 
  875.  
  876. if ( ! $product->add_to_cart_url() ) { 
  877. return; 
  878.  
  879. wc_get_template( 'single-product/add-to-cart/external.php', array( 
  880. 'product_url' => $product->add_to_cart_url(),  
  881. 'button_text' => $product->single_add_to_cart_text(),  
  882. ) ); 
  883.  
  884. if ( ! function_exists( 'woocommerce_quantity_input' ) ) { 
  885.  
  886. /** 
  887. * Output the quantity input for add to cart forms. 
  888. * 
  889. * @param array $args Args for the input 
  890. * @param WC_Product|null $product 
  891. * @param boolean $echo Whether to return or echo|string 
  892. */ 
  893. function woocommerce_quantity_input( $args = array(), $product = null, $echo = true ) { 
  894. if ( is_null( $product ) ) { 
  895. $product = $GLOBALS['product']; 
  896.  
  897. $defaults = array( 
  898. 'input_name' => 'quantity',  
  899. 'input_value' => '1',  
  900. 'max_value' => apply_filters( 'woocommerce_quantity_input_max', -1, $product ),  
  901. 'min_value' => apply_filters( 'woocommerce_quantity_input_min', 0, $product ),  
  902. 'step' => apply_filters( 'woocommerce_quantity_input_step', 1, $product ),  
  903. 'pattern' => apply_filters( 'woocommerce_quantity_input_pattern', has_filter( 'woocommerce_stock_amount', 'intval' ) ? '[0-9]*' : '' ),  
  904. 'inputmode' => apply_filters( 'woocommerce_quantity_input_inputmode', has_filter( 'woocommerce_stock_amount', 'intval' ) ? 'numeric' : '' ),  
  905. ); 
  906.  
  907. $args = apply_filters( 'woocommerce_quantity_input_args', wp_parse_args( $args, $defaults ), $product ); 
  908.  
  909. // Apply sanity to min/max args - min cannot be lower than 0. 
  910. $args['min_value'] = max( $args['min_value'], 0 ); 
  911. $args['max_value'] = 0 < $args['max_value'] ? $args['max_value'] : ''; 
  912.  
  913. // Max cannot be lower than min if defined. 
  914. if ( '' !== $args['max_value'] && $args['max_value'] < $args['min_value'] ) { 
  915. $args['max_value'] = $args['min_value']; 
  916.  
  917. ob_start(); 
  918.  
  919. wc_get_template( 'global/quantity-input.php', $args ); 
  920.  
  921. if ( $echo ) { 
  922. echo ob_get_clean(); 
  923. } else { 
  924. return ob_get_clean(); 
  925.  
  926. if ( ! function_exists( 'woocommerce_product_description_tab' ) ) { 
  927.  
  928. /** 
  929. * Output the description tab content. 
  930. * 
  931. * @subpackage Product/Tabs 
  932. */ 
  933. function woocommerce_product_description_tab() { 
  934. wc_get_template( 'single-product/tabs/description.php' ); 
  935. if ( ! function_exists( 'woocommerce_product_additional_information_tab' ) ) { 
  936.  
  937. /** 
  938. * Output the attributes tab content. 
  939. * 
  940. * @subpackage Product/Tabs 
  941. */ 
  942. function woocommerce_product_additional_information_tab() { 
  943. wc_get_template( 'single-product/tabs/additional-information.php' ); 
  944. if ( ! function_exists( 'woocommerce_product_reviews_tab' ) ) { 
  945.  
  946. /** 
  947. * Output the reviews tab content. 
  948. * @deprecated 2.4.0 Unused 
  949. * @subpackage Product/Tabs 
  950. */ 
  951. function woocommerce_product_reviews_tab() { 
  952. wc_deprecated_function( 'woocommerce_product_reviews_tab', '2.4' ); 
  953.  
  954. if ( ! function_exists( 'woocommerce_default_product_tabs' ) ) { 
  955.  
  956. /** 
  957. * Add default product tabs to product pages. 
  958. * 
  959. * @param array $tabs 
  960. * @return array 
  961. */ 
  962. function woocommerce_default_product_tabs( $tabs = array() ) { 
  963. global $product, $post; 
  964.  
  965. // Description tab - shows product content 
  966. if ( $post->post_content ) { 
  967. $tabs['description'] = array( 
  968. 'title' => __( 'Description', 'woocommerce' ),  
  969. 'priority' => 10,  
  970. 'callback' => 'woocommerce_product_description_tab',  
  971. ); 
  972.  
  973. // Additional information tab - shows attributes 
  974. if ( $product && ( $product->has_attributes() || apply_filters( 'wc_product_enable_dimensions_display', $product->has_weight() || $product->has_dimensions() ) ) ) { 
  975. $tabs['additional_information'] = array( 
  976. 'title' => __( 'Additional information', 'woocommerce' ),  
  977. 'priority' => 20,  
  978. 'callback' => 'woocommerce_product_additional_information_tab',  
  979. ); 
  980.  
  981. // Reviews tab - shows comments 
  982. if ( comments_open() ) { 
  983. $tabs['reviews'] = array( 
  984. 'title' => sprintf( __( 'Reviews (%d)', 'woocommerce' ), $product->get_review_count() ),  
  985. 'priority' => 30,  
  986. 'callback' => 'comments_template',  
  987. ); 
  988.  
  989. return $tabs; 
  990.  
  991. if ( ! function_exists( 'woocommerce_sort_product_tabs' ) ) { 
  992.  
  993. /** 
  994. * Sort tabs by priority. 
  995. * 
  996. * @param array $tabs 
  997. * @return array 
  998. */ 
  999. function woocommerce_sort_product_tabs( $tabs = array() ) { 
  1000.  
  1001. // Make sure the $tabs parameter is an array 
  1002. if ( ! is_array( $tabs ) ) { 
  1003. trigger_error( "Function woocommerce_sort_product_tabs() expects an array as the first parameter. Defaulting to empty array." ); 
  1004. $tabs = array(); 
  1005.  
  1006. // Re-order tabs by priority 
  1007. if ( ! function_exists( '_sort_priority_callback' ) ) { 
  1008. function _sort_priority_callback( $a, $b ) { 
  1009. if ( $a['priority'] === $b['priority'] ) 
  1010. return 0; 
  1011. return ( $a['priority'] < $b['priority'] ) ? -1 : 1; 
  1012.  
  1013. uasort( $tabs, '_sort_priority_callback' ); 
  1014.  
  1015. return $tabs; 
  1016.  
  1017. if ( ! function_exists( 'woocommerce_comments' ) ) { 
  1018.  
  1019. /** 
  1020. * Output the Review comments template. 
  1021. * 
  1022. * @subpackage Product 
  1023. * @param WP_Comment $comment 
  1024. * @param array $args 
  1025. * @param int $depth 
  1026. */ 
  1027. function woocommerce_comments( $comment, $args, $depth ) { 
  1028. $GLOBALS['comment'] = $comment; 
  1029. wc_get_template( 'single-product/review.php', array( 'comment' => $comment, 'args' => $args, 'depth' => $depth ) ); 
  1030.  
  1031. if ( ! function_exists( 'woocommerce_review_display_gravatar' ) ) { 
  1032. /** 
  1033. * Display the review authors gravatar 
  1034. * 
  1035. * @param array $comment WP_Comment. 
  1036. * @return void 
  1037. */ 
  1038. function woocommerce_review_display_gravatar( $comment ) { 
  1039. echo get_avatar( $comment, apply_filters( 'woocommerce_review_gravatar_size', '60' ), '' ); 
  1040.  
  1041. if ( ! function_exists( 'woocommerce_review_display_rating' ) ) { 
  1042. /** 
  1043. * Display the reviewers star rating 
  1044. * 
  1045. * @return void 
  1046. */ 
  1047. function woocommerce_review_display_rating() { 
  1048. wc_get_template( 'single-product/review-rating.php' ); 
  1049.  
  1050. if ( ! function_exists( 'woocommerce_review_display_meta' ) ) { 
  1051. /** 
  1052. * Display the review authors meta (name, verified owner, review date) 
  1053. * 
  1054. * @return void 
  1055. */ 
  1056. function woocommerce_review_display_meta() { 
  1057. wc_get_template( 'single-product/review-meta.php' ); 
  1058.  
  1059. if ( ! function_exists( 'woocommerce_review_display_comment_text' ) ) { 
  1060.  
  1061. /** 
  1062. * Display the review content. 
  1063. */ 
  1064. function woocommerce_review_display_comment_text() { 
  1065. echo '<div class="description">'; 
  1066. comment_text(); 
  1067. echo '</div>'; 
  1068.  
  1069. if ( ! function_exists( 'woocommerce_output_related_products' ) ) { 
  1070.  
  1071. /** 
  1072. * Output the related products. 
  1073. * 
  1074. * @subpackage Product 
  1075. */ 
  1076. function woocommerce_output_related_products() { 
  1077.  
  1078. $args = array( 
  1079. 'posts_per_page' => 4,  
  1080. 'columns' => 4,  
  1081. 'orderby' => 'rand',  
  1082. ); 
  1083.  
  1084. woocommerce_related_products( apply_filters( 'woocommerce_output_related_products_args', $args ) ); 
  1085.  
  1086. if ( ! function_exists( 'woocommerce_related_products' ) ) { 
  1087.  
  1088. /** 
  1089. * Output the related products. 
  1090. * 
  1091. * @param array Provided arguments 
  1092. */ 
  1093. function woocommerce_related_products( $args = array() ) { 
  1094. global $product, $woocommerce_loop; 
  1095.  
  1096. if ( ! $product ) { 
  1097. return; 
  1098.  
  1099. $defaults = array( 
  1100. 'posts_per_page' => 2,  
  1101. 'columns' => 2,  
  1102. 'orderby' => 'rand',  
  1103. 'order' => 'desc',  
  1104. ); 
  1105.  
  1106. $args = wp_parse_args( $args, $defaults ); 
  1107.  
  1108. // Get visble related products then sort them at random. 
  1109. $args['related_products'] = array_filter( array_map( 'wc_get_product', wc_get_related_products( $product->get_id(), $args['posts_per_page'], $product->get_upsell_ids() ) ), 'wc_products_array_filter_visible' ); 
  1110.  
  1111. // Handle orderby. 
  1112. $args['related_products'] = wc_products_array_orderby( $args['related_products'], $args['orderby'], $args['order'] ); 
  1113.  
  1114. // Set global loop values. 
  1115. $woocommerce_loop['name'] = 'related'; 
  1116. $woocommerce_loop['columns'] = apply_filters( 'woocommerce_related_products_columns', $args['columns'] ); 
  1117.  
  1118. wc_get_template( 'single-product/related.php', $args ); 
  1119.  
  1120. if ( ! function_exists( 'woocommerce_upsell_display' ) ) { 
  1121.  
  1122. /** 
  1123. * Output product up sells. 
  1124. * 
  1125. * @param int $limit (default: -1) 
  1126. * @param int $columns (default: 4) 
  1127. * @param string $orderby Supported values - rand, title, ID, date, modified, menu_order, price. 
  1128. * @param string $order Sort direction. 
  1129. */ 
  1130. function woocommerce_upsell_display( $limit = '-1', $columns = 4, $orderby = 'rand', $order = 'desc' ) { 
  1131. global $product, $woocommerce_loop; 
  1132.  
  1133. if ( ! $product ) { 
  1134. return; 
  1135.  
  1136. // Handle the legacy filter which controlled posts per page etc. 
  1137. $args = apply_filters( 'woocommerce_upsell_display_args', array( 
  1138. 'posts_per_page' => $limit,  
  1139. 'orderby' => $orderby,  
  1140. 'columns' => $columns,  
  1141. ) ); 
  1142. $woocommerce_loop['name'] = 'up-sells'; 
  1143. $woocommerce_loop['columns'] = apply_filters( 'woocommerce_upsells_columns', isset( $args['columns'] ) ? $args['columns'] : $columns ); 
  1144. $orderby = apply_filters( 'woocommerce_upsells_orderby', isset( $args['orderby'] ) ? $args['orderby'] : $orderby ); 
  1145. $limit = apply_filters( 'woocommerce_upsells_total', isset( $args['posts_per_page'] ) ? $args['posts_per_page'] : $limit ); 
  1146.  
  1147. // Get visble upsells then sort them at random, then limit result set. 
  1148. $upsells = wc_products_array_orderby( array_filter( array_map( 'wc_get_product', $product->get_upsell_ids() ), 'wc_products_array_filter_visible' ), $orderby, $order ); 
  1149. $upsells = $limit > 0 ? array_slice( $upsells, 0, $limit ) : $upsells; 
  1150.  
  1151. wc_get_template( 'single-product/up-sells.php', array( 
  1152. 'upsells' => $upsells,  
  1153.  
  1154. // Not used now, but used in previous version of up-sells.php. 
  1155. 'posts_per_page' => $limit,  
  1156. 'orderby' => $orderby,  
  1157. 'columns' => $columns,  
  1158. ) ); 
  1159.  
  1160. /** Cart ******************************************************************/ 
  1161.  
  1162. if ( ! function_exists( 'woocommerce_shipping_calculator' ) ) { 
  1163.  
  1164. /** 
  1165. * Output the cart shipping calculator. 
  1166. * 
  1167. * @subpackage Cart 
  1168. */ 
  1169. function woocommerce_shipping_calculator() { 
  1170. wc_get_template( 'cart/shipping-calculator.php' ); 
  1171.  
  1172. if ( ! function_exists( 'woocommerce_cart_totals' ) ) { 
  1173.  
  1174. /** 
  1175. * Output the cart totals. 
  1176. * 
  1177. * @subpackage Cart 
  1178. */ 
  1179. function woocommerce_cart_totals() { 
  1180. if ( is_checkout() ) { 
  1181. return; 
  1182. wc_get_template( 'cart/cart-totals.php' ); 
  1183.  
  1184. if ( ! function_exists( 'woocommerce_cross_sell_display' ) ) { 
  1185.  
  1186. /** 
  1187. * Output the cart cross-sells. 
  1188. * 
  1189. * @param int $limit (default: 2) 
  1190. * @param int $columns (default: 2) 
  1191. * @param string $orderby (default: 'rand') 
  1192. * @param string $order (default: 'desc') 
  1193. */ 
  1194. function woocommerce_cross_sell_display( $limit = 2, $columns = 2, $orderby = 'rand', $order = 'desc' ) { 
  1195. global $woocommerce_loop; 
  1196.  
  1197. if ( is_checkout() ) { 
  1198. return; 
  1199. // Get visble cross sells then sort them at random. 
  1200. $cross_sells = array_filter( array_map( 'wc_get_product', WC()->cart->get_cross_sells() ), 'wc_products_array_filter_visible' ); 
  1201. $woocommerce_loop['name'] = 'cross-sells'; 
  1202. $woocommerce_loop['columns'] = apply_filters( 'woocommerce_cross_sells_columns', $columns ); 
  1203.  
  1204. // Handle orderby and limit results. 
  1205. $orderby = apply_filters( 'woocommerce_cross_sells_orderby', $orderby ); 
  1206. $cross_sells = wc_products_array_orderby( $cross_sells, $orderby, $order ); 
  1207. $limit = apply_filters( 'woocommerce_cross_sells_total', $limit ); 
  1208. $cross_sells = $limit > 0 ? array_slice( $cross_sells, 0, $limit ) : $cross_sells; 
  1209.  
  1210. wc_get_template( 'cart/cross-sells.php', array( 
  1211. 'cross_sells' => $cross_sells,  
  1212.  
  1213. // Not used now, but used in previous version of up-sells.php. 
  1214. 'posts_per_page' => $limit,  
  1215. 'orderby' => $orderby,  
  1216. 'columns' => $columns,  
  1217. ) ); 
  1218.  
  1219. if ( ! function_exists( 'woocommerce_button_proceed_to_checkout' ) ) { 
  1220.  
  1221. /** 
  1222. * Output the proceed to checkout button. 
  1223. * 
  1224. * @subpackage Cart 
  1225. */ 
  1226. function woocommerce_button_proceed_to_checkout() { 
  1227. wc_get_template( 'cart/proceed-to-checkout-button.php' ); 
  1228.  
  1229. if ( ! function_exists( 'woocommerce_widget_shopping_cart_button_view_cart' ) ) { 
  1230.  
  1231. /** 
  1232. * Output the proceed to checkout button. 
  1233. * 
  1234. * @subpackage Cart 
  1235. */ 
  1236. function woocommerce_widget_shopping_cart_button_view_cart() { 
  1237. echo '<a href="' . esc_url( wc_get_cart_url() ) . '" class="button wc-forward">' . esc_html__( 'View cart', 'woocommerce' ) . '</a>'; 
  1238.  
  1239. if ( ! function_exists( 'woocommerce_widget_shopping_cart_proceed_to_checkout' ) ) { 
  1240.  
  1241. /** 
  1242. * Output the proceed to checkout button. 
  1243. * 
  1244. * @subpackage Cart 
  1245. */ 
  1246. function woocommerce_widget_shopping_cart_proceed_to_checkout() { 
  1247. echo '<a href="' . esc_url( wc_get_checkout_url() ) . '" class="button checkout wc-forward">' . esc_html__( 'Checkout', 'woocommerce' ) . '</a>'; 
  1248.  
  1249. /** Mini-Cart *************************************************************/ 
  1250.  
  1251. if ( ! function_exists( 'woocommerce_mini_cart' ) ) { 
  1252.  
  1253. /** 
  1254. * Output the Mini-cart - used by cart widget. 
  1255. * 
  1256. * @param array $args 
  1257. */ 
  1258. function woocommerce_mini_cart( $args = array() ) { 
  1259.  
  1260. $defaults = array( 
  1261. 'list_class' => '',  
  1262. ); 
  1263.  
  1264. $args = wp_parse_args( $args, $defaults ); 
  1265.  
  1266. wc_get_template( 'cart/mini-cart.php', $args ); 
  1267.  
  1268. /** Login *****************************************************************/ 
  1269.  
  1270. if ( ! function_exists( 'woocommerce_login_form' ) ) { 
  1271.  
  1272. /** 
  1273. * Output the WooCommerce Login Form. 
  1274. * 
  1275. * @subpackage Forms 
  1276. * @param array $args 
  1277. */ 
  1278. function woocommerce_login_form( $args = array() ) { 
  1279.  
  1280. $defaults = array( 
  1281. 'message' => '',  
  1282. 'redirect' => '',  
  1283. 'hidden' => false,  
  1284. ); 
  1285.  
  1286. $args = wp_parse_args( $args, $defaults ); 
  1287.  
  1288. wc_get_template( 'global/form-login.php', $args ); 
  1289.  
  1290. if ( ! function_exists( 'woocommerce_checkout_login_form' ) ) { 
  1291.  
  1292. /** 
  1293. * Output the WooCommerce Checkout Login Form. 
  1294. * 
  1295. * @subpackage Checkout 
  1296. */ 
  1297. function woocommerce_checkout_login_form() { 
  1298. wc_get_template( 'checkout/form-login.php', array( 'checkout' => WC()->checkout() ) ); 
  1299.  
  1300. if ( ! function_exists( 'woocommerce_breadcrumb' ) ) { 
  1301.  
  1302. /** 
  1303. * Output the WooCommerce Breadcrumb. 
  1304. * 
  1305. * @param array $args 
  1306. */ 
  1307. function woocommerce_breadcrumb( $args = array() ) { 
  1308. $args = wp_parse_args( $args, apply_filters( 'woocommerce_breadcrumb_defaults', array( 
  1309. 'delimiter' => ' / ',  
  1310. 'wrap_before' => '<nav class="woocommerce-breadcrumb">',  
  1311. 'wrap_after' => '</nav>',  
  1312. 'before' => '',  
  1313. 'after' => '',  
  1314. 'home' => _x( 'Home', 'breadcrumb', 'woocommerce' ),  
  1315. ) ) ); 
  1316.  
  1317. $breadcrumbs = new WC_Breadcrumb(); 
  1318.  
  1319. if ( ! empty( $args['home'] ) ) { 
  1320. $breadcrumbs->add_crumb( $args['home'], apply_filters( 'woocommerce_breadcrumb_home_url', home_url() ) ); 
  1321.  
  1322. $args['breadcrumb'] = $breadcrumbs->generate(); 
  1323.  
  1324. /** 
  1325. * @hooked WC_Structured_Data::generate_breadcrumblist_data() - 10 
  1326. */ 
  1327. do_action( 'woocommerce_breadcrumb', $breadcrumbs, $args ); 
  1328.  
  1329. wc_get_template( 'global/breadcrumb.php', $args ); 
  1330.  
  1331. if ( ! function_exists( 'woocommerce_order_review' ) ) { 
  1332.  
  1333. /** 
  1334. * Output the Order review table for the checkout. 
  1335. * 
  1336. * @subpackage Checkout 
  1337. */ 
  1338. function woocommerce_order_review( $deprecated = false ) { 
  1339. wc_get_template( 'checkout/review-order.php', array( 'checkout' => WC()->checkout() ) ); 
  1340.  
  1341. if ( ! function_exists( 'woocommerce_checkout_payment' ) ) { 
  1342.  
  1343. /** 
  1344. * Output the Payment Methods on the checkout. 
  1345. * 
  1346. * @subpackage Checkout 
  1347. */ 
  1348. function woocommerce_checkout_payment() { 
  1349. if ( WC()->cart->needs_payment() ) { 
  1350. $available_gateways = WC()->payment_gateways()->get_available_payment_gateways(); 
  1351. WC()->payment_gateways()->set_current_gateway( $available_gateways ); 
  1352. } else { 
  1353. $available_gateways = array(); 
  1354.  
  1355. wc_get_template( 'checkout/payment.php', array( 
  1356. 'checkout' => WC()->checkout(),  
  1357. 'available_gateways' => $available_gateways,  
  1358. 'order_button_text' => apply_filters( 'woocommerce_order_button_text', __( 'Place order', 'woocommerce' ) ),  
  1359. ) ); 
  1360.  
  1361. if ( ! function_exists( 'woocommerce_checkout_coupon_form' ) ) { 
  1362.  
  1363. /** 
  1364. * Output the Coupon form for the checkout. 
  1365. * 
  1366. * @subpackage Checkout 
  1367. */ 
  1368. function woocommerce_checkout_coupon_form() { 
  1369. wc_get_template( 'checkout/form-coupon.php', array( 'checkout' => WC()->checkout() ) ); 
  1370.  
  1371. if ( ! function_exists( 'woocommerce_products_will_display' ) ) { 
  1372.  
  1373. /** 
  1374. * Check if we will be showing products or not (and not sub-categories only). 
  1375. * @subpackage Loop 
  1376. * @return bool 
  1377. */ 
  1378. function woocommerce_products_will_display() { 
  1379. global $wpdb; 
  1380.  
  1381. if ( is_shop() ) { 
  1382. return 'subcategories' !== get_option( 'woocommerce_shop_page_display' ) || is_search(); 
  1383.  
  1384. if ( ! is_product_taxonomy() ) { 
  1385. return false; 
  1386.  
  1387. if ( is_search() || is_filtered() || is_paged() ) { 
  1388. return true; 
  1389.  
  1390. $term = get_queried_object(); 
  1391.  
  1392. if ( is_product_category() ) { 
  1393. switch ( get_woocommerce_term_meta( $term->term_id, 'display_type', true ) ) { 
  1394. case 'subcategories' : 
  1395. // Nothing - we want to continue to see if there are products/subcats 
  1396. break; 
  1397. case 'products' : 
  1398. case 'both' : 
  1399. return true; 
  1400. break; 
  1401. default : 
  1402. // Default - no setting 
  1403. if ( get_option( 'woocommerce_category_archive_display' ) != 'subcategories' ) { 
  1404. return true; 
  1405. break; 
  1406.  
  1407. // Begin subcategory logic 
  1408. if ( empty( $term->term_id ) || empty( $term->taxonomy ) ) { 
  1409. return true; 
  1410.  
  1411. $transient_name = 'wc_products_will_display_' . $term->term_id . '_' . WC_Cache_Helper::get_transient_version( 'product_query' ); 
  1412.  
  1413. if ( false === ( $products_will_display = get_transient( $transient_name ) ) ) { 
  1414. $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 ) ); 
  1415.  
  1416. if ( $has_children ) { 
  1417. // Check terms have products inside - parents first. If products are found inside, subcats will be shown instead of products so we can return false. 
  1418. if ( sizeof( get_objects_in_term( $has_children, $term->taxonomy ) ) > 0 ) { 
  1419. $products_will_display = false; 
  1420. } else { 
  1421. // If we get here, the parents were empty so we're forced to check children 
  1422. foreach ( $has_children as $term_id ) { 
  1423. $children = get_term_children( $term_id, $term->taxonomy ); 
  1424.  
  1425. if ( sizeof( get_objects_in_term( $children, $term->taxonomy ) ) > 0 ) { 
  1426. $products_will_display = false; 
  1427. break; 
  1428. } else { 
  1429. $products_will_display = true; 
  1430.  
  1431. set_transient( $transient_name, $products_will_display, DAY_IN_SECONDS * 30 ); 
  1432.  
  1433. return $products_will_display; 
  1434.  
  1435. if ( ! function_exists( 'woocommerce_product_subcategories' ) ) { 
  1436.  
  1437. /** 
  1438. * Display product sub categories as thumbnails. 
  1439. * 
  1440. * @subpackage Loop 
  1441. * @param array $args 
  1442. * @return null|boolean 
  1443. */ 
  1444. function woocommerce_product_subcategories( $args = array() ) { 
  1445. global $wp_query; 
  1446.  
  1447. $defaults = array( 
  1448. 'before' => '',  
  1449. 'after' => '',  
  1450. 'force_display' => false,  
  1451. ); 
  1452.  
  1453. $args = wp_parse_args( $args, $defaults ); 
  1454.  
  1455. extract( $args ); 
  1456.  
  1457. // Main query only 
  1458. if ( ! is_main_query() && ! $force_display ) { 
  1459. return; 
  1460.  
  1461. // Don't show when filtering, searching or when on page > 1 and ensure we're on a product archive 
  1462. if ( is_search() || is_filtered() || is_paged() || ( ! is_product_category() && ! is_shop() ) ) { 
  1463. return; 
  1464.  
  1465. // Check categories are enabled 
  1466. if ( is_shop() && '' === get_option( 'woocommerce_shop_page_display' ) ) { 
  1467. return; 
  1468.  
  1469. // Find the category + category parent, if applicable 
  1470. $term = get_queried_object(); 
  1471. $parent_id = empty( $term->term_id ) ? 0 : $term->term_id; 
  1472.  
  1473. if ( is_product_category() ) { 
  1474. $display_type = get_woocommerce_term_meta( $term->term_id, 'display_type', true ); 
  1475.  
  1476. switch ( $display_type ) { 
  1477. case 'products' : 
  1478. return; 
  1479. break; 
  1480. case '' : 
  1481. if ( '' === get_option( 'woocommerce_category_archive_display' ) ) { 
  1482. return; 
  1483. break; 
  1484.  
  1485. // 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 
  1486. $product_categories = get_categories( apply_filters( 'woocommerce_product_subcategories_args', array( 
  1487. 'parent' => $parent_id,  
  1488. 'menu_order' => 'ASC',  
  1489. 'hide_empty' => 0,  
  1490. 'hierarchical' => 1,  
  1491. 'taxonomy' => 'product_cat',  
  1492. 'pad_counts' => 1,  
  1493. ) ) ); 
  1494.  
  1495. if ( apply_filters( 'woocommerce_product_subcategories_hide_empty', true ) ) { 
  1496. $product_categories = wp_list_filter( $product_categories, array( 'count' => 0 ), 'NOT' ); 
  1497.  
  1498. if ( $product_categories ) { 
  1499. echo $before; 
  1500.  
  1501. foreach ( $product_categories as $category ) { 
  1502. wc_get_template( 'content-product_cat.php', array( 
  1503. 'category' => $category,  
  1504. ) ); 
  1505.  
  1506. // If we are hiding products disable the loop and pagination 
  1507. if ( is_product_category() ) { 
  1508. $display_type = get_woocommerce_term_meta( $term->term_id, 'display_type', true ); 
  1509.  
  1510. switch ( $display_type ) { 
  1511. case 'subcategories' : 
  1512. $wp_query->post_count = 0; 
  1513. $wp_query->max_num_pages = 0; 
  1514. break; 
  1515. case '' : 
  1516. if ( 'subcategories' === get_option( 'woocommerce_category_archive_display' ) ) { 
  1517. $wp_query->post_count = 0; 
  1518. $wp_query->max_num_pages = 0; 
  1519. break; 
  1520.  
  1521. if ( is_shop() && 'subcategories' === get_option( 'woocommerce_shop_page_display' ) ) { 
  1522. $wp_query->post_count = 0; 
  1523. $wp_query->max_num_pages = 0; 
  1524.  
  1525. echo $after; 
  1526.  
  1527. return true; 
  1528.  
  1529. if ( ! function_exists( 'woocommerce_subcategory_thumbnail' ) ) { 
  1530.  
  1531. /** 
  1532. * Show subcategory thumbnails. 
  1533. * 
  1534. * @param mixed $category 
  1535. * @subpackage Loop 
  1536. */ 
  1537. function woocommerce_subcategory_thumbnail( $category ) { 
  1538. $small_thumbnail_size = apply_filters( 'subcategory_archive_thumbnail_size', 'shop_catalog' ); 
  1539. $dimensions = wc_get_image_size( $small_thumbnail_size ); 
  1540. $thumbnail_id = get_woocommerce_term_meta( $category->term_id, 'thumbnail_id', true ); 
  1541.  
  1542. if ( $thumbnail_id ) { 
  1543. $image = wp_get_attachment_image_src( $thumbnail_id, $small_thumbnail_size ); 
  1544. $image = $image[0]; 
  1545. $image_srcset = function_exists( 'wp_get_attachment_image_srcset' ) ? wp_get_attachment_image_srcset( $thumbnail_id, $small_thumbnail_size ) : false; 
  1546. $image_sizes = function_exists( 'wp_get_attachment_image_sizes' ) ? wp_get_attachment_image_sizes( $thumbnail_id, $small_thumbnail_size ) : false; 
  1547. } else { 
  1548. $image = wc_placeholder_img_src(); 
  1549. $image_srcset = $image_sizes = false; 
  1550.  
  1551. if ( $image ) { 
  1552. // Prevent esc_url from breaking spaces in urls for image embeds 
  1553. // Ref: https://core.trac.wordpress.org/ticket/23605 
  1554. $image = str_replace( ' ', '%20', $image ); 
  1555.  
  1556. // Add responsive image markup if available 
  1557. if ( $image_srcset && $image_sizes ) { 
  1558. echo '<img src="' . esc_url( $image ) . '" alt="' . esc_attr( $category->name ) . '" width="' . esc_attr( $dimensions['width'] ) . '" height="' . esc_attr( $dimensions['height'] ) . '" srcset="' . esc_attr( $image_srcset ) . '" sizes="' . esc_attr( $image_sizes ) . '" />'; 
  1559. } else { 
  1560. echo '<img src="' . esc_url( $image ) . '" alt="' . esc_attr( $category->name ) . '" width="' . esc_attr( $dimensions['width'] ) . '" height="' . esc_attr( $dimensions['height'] ) . '" />'; 
  1561.  
  1562. if ( ! function_exists( 'woocommerce_order_details_table' ) ) { 
  1563.  
  1564. /** 
  1565. * Displays order details in a table. 
  1566. * 
  1567. * @param mixed $order_id 
  1568. * @subpackage Orders 
  1569. */ 
  1570. function woocommerce_order_details_table( $order_id ) { 
  1571. if ( ! $order_id ) return; 
  1572.  
  1573. wc_get_template( 'order/order-details.php', array( 
  1574. 'order_id' => $order_id,  
  1575. ) ); 
  1576.  
  1577.  
  1578. if ( ! function_exists( 'woocommerce_order_again_button' ) ) { 
  1579.  
  1580. /** 
  1581. * Display an 'order again' button on the view order page. 
  1582. * 
  1583. * @param object $order 
  1584. * @subpackage Orders 
  1585. */ 
  1586. function woocommerce_order_again_button( $order ) { 
  1587. if ( ! $order || ! $order->has_status( 'completed' ) || ! is_user_logged_in() ) { 
  1588. return; 
  1589.  
  1590. wc_get_template( 'order/order-again.php', array( 
  1591. 'order' => $order,  
  1592. ) ); 
  1593.  
  1594. /** Forms ****************************************************************/ 
  1595.  
  1596. if ( ! function_exists( 'woocommerce_form_field' ) ) { 
  1597.  
  1598. /** 
  1599. * Outputs a checkout/address form field. 
  1600. * 
  1601. * @subpackage Forms 
  1602. * @param string $key 
  1603. * @param mixed $args 
  1604. * @param string $value (default: null) 
  1605. */ 
  1606. function woocommerce_form_field( $key, $args, $value = null ) { 
  1607. $defaults = array( 
  1608. 'type' => 'text',  
  1609. 'label' => '',  
  1610. 'description' => '',  
  1611. 'placeholder' => '',  
  1612. 'maxlength' => false,  
  1613. 'required' => false,  
  1614. 'autocomplete' => false,  
  1615. 'id' => $key,  
  1616. 'class' => array(),  
  1617. 'label_class' => array(),  
  1618. 'input_class' => array(),  
  1619. 'return' => false,  
  1620. 'options' => array(),  
  1621. 'custom_attributes' => array(),  
  1622. 'validate' => array(),  
  1623. 'default' => '',  
  1624. 'autofocus' => '',  
  1625. 'priority' => '',  
  1626. ); 
  1627.  
  1628. $args = wp_parse_args( $args, $defaults ); 
  1629. $args = apply_filters( 'woocommerce_form_field_args', $args, $key, $value ); 
  1630.  
  1631. if ( $args['required'] ) { 
  1632. $args['class'][] = 'validate-required'; 
  1633. $required = ' <abbr class="required" title="' . esc_attr__( 'required', 'woocommerce' ) . '">*</abbr>'; 
  1634. } else { 
  1635. $required = ''; 
  1636.  
  1637. if ( is_string( $args['label_class'] ) ) { 
  1638. $args['label_class'] = array( $args['label_class'] ); 
  1639.  
  1640. if ( is_null( $value ) ) { 
  1641. $value = $args['default']; 
  1642.  
  1643. // Custom attribute handling 
  1644. $custom_attributes = array(); 
  1645. $args['custom_attributes'] = array_filter( (array) $args['custom_attributes'] ); 
  1646.  
  1647. if ( $args['maxlength'] ) { 
  1648. $args['custom_attributes']['maxlength'] = absint( $args['maxlength'] ); 
  1649.  
  1650. if ( ! empty( $args['autocomplete'] ) ) { 
  1651. $args['custom_attributes']['autocomplete'] = $args['autocomplete']; 
  1652.  
  1653. if ( true === $args['autofocus'] ) { 
  1654. $args['custom_attributes']['autofocus'] = 'autofocus'; 
  1655.  
  1656. if ( ! empty( $args['custom_attributes'] ) && is_array( $args['custom_attributes'] ) ) { 
  1657. foreach ( $args['custom_attributes'] as $attribute => $attribute_value ) { 
  1658. $custom_attributes[] = esc_attr( $attribute ) . '="' . esc_attr( $attribute_value ) . '"'; 
  1659.  
  1660. if ( ! empty( $args['validate'] ) ) { 
  1661. foreach ( $args['validate'] as $validate ) { 
  1662. $args['class'][] = 'validate-' . $validate; 
  1663.  
  1664. $field = ''; 
  1665. $label_id = $args['id']; 
  1666. $sort = $args['priority'] ? $args['priority'] : ''; 
  1667. $field_container = '<p class="form-row %1$s" id="%2$s" data-sort="' . esc_attr( $sort ) . '">%3$s</p>'; 
  1668.  
  1669. switch ( $args['type'] ) { 
  1670. case 'country' : 
  1671.  
  1672. $countries = 'shipping_country' === $key ? WC()->countries->get_shipping_countries() : WC()->countries->get_allowed_countries(); 
  1673.  
  1674. if ( 1 === sizeof( $countries ) ) { 
  1675.  
  1676. $field .= '<strong>' . current( array_values( $countries ) ) . '</strong>'; 
  1677.  
  1678. $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" />'; 
  1679.  
  1680. } else { 
  1681.  
  1682. $field = '<select name="' . esc_attr( $key ) . '" id="' . esc_attr( $args['id'] ) . '" class="country_to_state country_select ' . esc_attr( implode( ' ', $args['input_class'] ) ) . '" ' . implode( ' ', $custom_attributes ) . '>' . '<option value="">' . esc_html__( 'Select a country…', 'woocommerce' ) . '</option>'; 
  1683.  
  1684. foreach ( $countries as $ckey => $cvalue ) { 
  1685. $field .= '<option value="' . esc_attr( $ckey ) . '" ' . selected( $value, $ckey, false ) . '>' . $cvalue . '</option>'; 
  1686.  
  1687. $field .= '</select>'; 
  1688.  
  1689. $field .= '<noscript><input type="submit" name="woocommerce_checkout_update_totals" value="' . esc_attr__( 'Update country', 'woocommerce' ) . '" /></noscript>'; 
  1690.  
  1691.  
  1692. break; 
  1693. case 'state' : 
  1694.  
  1695. /** Get Country */ 
  1696. $country_key = 'billing_state' === $key ? 'billing_country' : 'shipping_country'; 
  1697. $current_cc = WC()->checkout->get_value( $country_key ); 
  1698. $states = WC()->countries->get_states( $current_cc ); 
  1699.  
  1700. if ( is_array( $states ) && empty( $states ) ) { 
  1701.  
  1702. $field_container = '<p class="form-row %1$s" id="%2$s" style="display: none">%3$s</p>'; 
  1703.  
  1704. $field .= '<input type="hidden" class="hidden" name="' . esc_attr( $key ) . '" id="' . esc_attr( $args['id'] ) . '" value="" ' . implode( ' ', $custom_attributes ) . ' placeholder="' . esc_attr( $args['placeholder'] ) . '" />'; 
  1705.  
  1706. } elseif ( is_array( $states ) ) { 
  1707.  
  1708. $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'] ) . '"> 
  1709. <option value="">' . esc_html__( 'Select a state…', 'woocommerce' ) . '</option>'; 
  1710.  
  1711. foreach ( $states as $ckey => $cvalue ) { 
  1712. $field .= '<option value="' . esc_attr( $ckey ) . '" ' . selected( $value, $ckey, false ) . '>' . $cvalue . '</option>'; 
  1713.  
  1714. $field .= '</select>'; 
  1715.  
  1716. } else { 
  1717.  
  1718. $field .= '<input type="text" class="input-text ' . esc_attr( implode( ' ', $args['input_class'] ) ) . '" value="' . esc_attr( $value ) . '" placeholder="' . esc_attr( $args['placeholder'] ) . '" name="' . esc_attr( $key ) . '" id="' . esc_attr( $args['id'] ) . '" ' . implode( ' ', $custom_attributes ) . ' />'; 
  1719.  
  1720.  
  1721. break; 
  1722. case 'textarea' : 
  1723.  
  1724. $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'] ) . '" ' . ( empty( $args['custom_attributes']['rows'] ) ? ' rows="2"' : '' ) . ( empty( $args['custom_attributes']['cols'] ) ? ' cols="5"' : '' ) . implode( ' ', $custom_attributes ) . '>' . esc_textarea( $value ) . '</textarea>'; 
  1725.  
  1726. break; 
  1727. case 'checkbox' : 
  1728.  
  1729. $field = '<label class="checkbox ' . implode( ' ', $args['label_class'] ) . '" ' . implode( ' ', $custom_attributes ) . '> 
  1730. <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 ) . ' /> ' 
  1731. . $args['label'] . $required . '</label>'; 
  1732.  
  1733. break; 
  1734. case 'password' : 
  1735. case 'text' : 
  1736. case 'email' : 
  1737. case 'tel' : 
  1738. case 'number' : 
  1739.  
  1740. $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'] ) . '" value="' . esc_attr( $value ) . '" ' . implode( ' ', $custom_attributes ) . ' />'; 
  1741.  
  1742. break; 
  1743. case 'select' : 
  1744.  
  1745. $options = $field = ''; 
  1746.  
  1747. if ( ! empty( $args['options'] ) ) { 
  1748. foreach ( $args['options'] as $option_key => $option_text ) { 
  1749. if ( '' === $option_key ) { 
  1750. // If we have a blank option, select2 needs a placeholder 
  1751. if ( empty( $args['placeholder'] ) ) { 
  1752. $args['placeholder'] = $option_text ? $option_text : __( 'Choose an option', 'woocommerce' ); 
  1753. $custom_attributes[] = 'data-allow_clear="true"'; 
  1754. $options .= '<option value="' . esc_attr( $option_key ) . '" ' . selected( $value, $option_key, false ) . '>' . esc_attr( $option_text ) . '</option>'; 
  1755.  
  1756. $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'] ) . '"> 
  1757. ' . $options . ' 
  1758. </select>'; 
  1759.  
  1760. break; 
  1761. case 'radio' : 
  1762.  
  1763. $label_id = current( array_keys( $args['options'] ) ); 
  1764.  
  1765. if ( ! empty( $args['options'] ) ) { 
  1766. foreach ( $args['options'] as $option_key => $option_text ) { 
  1767. $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 ) . ' />'; 
  1768. $field .= '<label for="' . esc_attr( $args['id'] ) . '_' . esc_attr( $option_key ) . '" class="radio ' . implode( ' ', $args['label_class'] ) . '">' . $option_text . '</label>'; 
  1769.  
  1770. break; 
  1771.  
  1772. if ( ! empty( $field ) ) { 
  1773. $field_html = ''; 
  1774.  
  1775. if ( $args['label'] && 'checkbox' != $args['type'] ) { 
  1776. $field_html .= '<label for="' . esc_attr( $label_id ) . '" class="' . esc_attr( implode( ' ', $args['label_class'] ) ) . '">' . $args['label'] . $required . '</label>'; 
  1777.  
  1778. $field_html .= $field; 
  1779.  
  1780. if ( $args['description'] ) { 
  1781. $field_html .= '<span class="description">' . esc_html( $args['description'] ) . '</span>'; 
  1782.  
  1783. $container_class = esc_attr( implode( ' ', $args['class'] ) ); 
  1784. $container_id = esc_attr( $args['id'] ) . '_field'; 
  1785. $field = sprintf( $field_container, $container_class, $container_id, $field_html ); 
  1786.  
  1787. $field = apply_filters( 'woocommerce_form_field_' . $args['type'], $field, $key, $args, $value ); 
  1788.  
  1789. if ( $args['return'] ) { 
  1790. return $field; 
  1791. } else { 
  1792. echo $field; 
  1793.  
  1794. if ( ! function_exists( 'get_product_search_form' ) ) { 
  1795.  
  1796. /** 
  1797. * Display product search form. 
  1798. * 
  1799. * Will first attempt to locate the product-searchform.php file in either the child or. 
  1800. * the parent, then load it. If it doesn't exist, then the default search form. 
  1801. * will be displayed. 
  1802. * 
  1803. * The default searchform uses html5. 
  1804. * 
  1805. * @subpackage Forms 
  1806. * @param bool $echo (default: true) 
  1807. * @return string 
  1808. */ 
  1809. function get_product_search_form( $echo = true ) { 
  1810. global $product_search_form_index; 
  1811.  
  1812. ob_start(); 
  1813.  
  1814. if ( empty( $product_search_form_index ) ) { 
  1815. $product_search_form_index = 0; 
  1816.  
  1817. do_action( 'pre_get_product_search_form' ); 
  1818.  
  1819. wc_get_template( 'product-searchform.php', array( 
  1820. 'index' => $product_search_form_index++,  
  1821. ) ); 
  1822.  
  1823. $form = apply_filters( 'get_product_search_form', ob_get_clean() ); 
  1824.  
  1825. if ( $echo ) { 
  1826. echo $form; 
  1827. } else { 
  1828. return $form; 
  1829.  
  1830. if ( ! function_exists( 'woocommerce_output_auth_header' ) ) { 
  1831.  
  1832. /** 
  1833. * Output the Auth header. 
  1834. */ 
  1835. function woocommerce_output_auth_header() { 
  1836. wc_get_template( 'auth/header.php' ); 
  1837.  
  1838. if ( ! function_exists( 'woocommerce_output_auth_footer' ) ) { 
  1839.  
  1840. /** 
  1841. * Output the Auth footer. 
  1842. */ 
  1843. function woocommerce_output_auth_footer() { 
  1844. wc_get_template( 'auth/footer.php' ); 
  1845.  
  1846. if ( ! function_exists( 'woocommerce_single_variation' ) ) { 
  1847.  
  1848. /** 
  1849. * Output placeholders for the single variation. 
  1850. */ 
  1851. function woocommerce_single_variation() { 
  1852. echo '<div class="woocommerce-variation single_variation"></div>'; 
  1853.  
  1854. if ( ! function_exists( 'woocommerce_single_variation_add_to_cart_button' ) ) { 
  1855.  
  1856. /** 
  1857. * Output the add to cart button for variations. 
  1858. */ 
  1859. function woocommerce_single_variation_add_to_cart_button() { 
  1860. wc_get_template( 'single-product/add-to-cart/variation-add-to-cart-button.php' ); 
  1861.  
  1862. if ( ! function_exists( 'wc_dropdown_variation_attribute_options' ) ) { 
  1863.  
  1864. /** 
  1865. * Output a list of variation attributes for use in the cart forms. 
  1866. * 
  1867. * @param array $args 
  1868. * @since 2.4.0 
  1869. */ 
  1870. function wc_dropdown_variation_attribute_options( $args = array() ) { 
  1871. $args = wp_parse_args( apply_filters( 'woocommerce_dropdown_variation_attribute_options_args', $args ), array( 
  1872. 'options' => false,  
  1873. 'attribute' => false,  
  1874. 'product' => false,  
  1875. 'selected' => false,  
  1876. 'name' => '',  
  1877. 'id' => '',  
  1878. 'class' => '',  
  1879. 'show_option_none' => __( 'Choose an option', 'woocommerce' ),  
  1880. ) ); 
  1881.  
  1882. $options = $args['options']; 
  1883. $product = $args['product']; 
  1884. $attribute = $args['attribute']; 
  1885. $name = $args['name'] ? $args['name'] : 'attribute_' . sanitize_title( $attribute ); 
  1886. $id = $args['id'] ? $args['id'] : sanitize_title( $attribute ); 
  1887. $class = $args['class']; 
  1888. $show_option_none = $args['show_option_none'] ? true : false; 
  1889. $show_option_none_text = $args['show_option_none'] ? $args['show_option_none'] : __( 'Choose an option', 'woocommerce' ); // We'll do our best to hide the placeholder, but we'll need to show something when resetting options. 
  1890.  
  1891. if ( empty( $options ) && ! empty( $product ) && ! empty( $attribute ) ) { 
  1892. $attributes = $product->get_variation_attributes(); 
  1893. $options = $attributes[ $attribute ]; 
  1894.  
  1895. $html = '<select id="' . esc_attr( $id ) . '" class="' . esc_attr( $class ) . '" name="' . esc_attr( $name ) . '" data-attribute_name="attribute_' . esc_attr( sanitize_title( $attribute ) ) . '" data-show_option_none="' . ( $show_option_none ? 'yes' : 'no' ) . '">'; 
  1896. $html .= '<option value="">' . esc_html( $show_option_none_text ) . '</option>'; 
  1897.  
  1898. if ( ! empty( $options ) ) { 
  1899. if ( $product && taxonomy_exists( $attribute ) ) { 
  1900. // Get terms if this is a taxonomy - ordered. We need the names too. 
  1901. $terms = wc_get_product_terms( $product->get_id(), $attribute, array( 'fields' => 'all' ) ); 
  1902.  
  1903. foreach ( $terms as $term ) { 
  1904. if ( in_array( $term->slug, $options ) ) { 
  1905. $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>'; 
  1906. } else { 
  1907. foreach ( $options as $option ) { 
  1908. // This handles < 2.4.0 bw compatibility where text attributes were not sanitized. 
  1909. $selected = sanitize_title( $args['selected'] ) === $args['selected'] ? selected( $args['selected'], sanitize_title( $option ), false ) : selected( $args['selected'], $option, false ); 
  1910. $html .= '<option value="' . esc_attr( $option ) . '" ' . $selected . '>' . esc_html( apply_filters( 'woocommerce_variation_option_name', $option ) ) . '</option>'; 
  1911.  
  1912. $html .= '</select>'; 
  1913.  
  1914. echo apply_filters( 'woocommerce_dropdown_variation_attribute_options_html', $html, $args ); 
  1915.  
  1916. if ( ! function_exists( 'woocommerce_account_content' ) ) { 
  1917.  
  1918. /** 
  1919. * My Account content output. 
  1920. */ 
  1921. function woocommerce_account_content() { 
  1922. global $wp; 
  1923.  
  1924. foreach ( $wp->query_vars as $key => $value ) { 
  1925. // Ignore pagename param. 
  1926. if ( 'pagename' === $key ) { 
  1927. continue; 
  1928.  
  1929. if ( has_action( 'woocommerce_account_' . $key . '_endpoint' ) ) { 
  1930. do_action( 'woocommerce_account_' . $key . '_endpoint', $value ); 
  1931. return; 
  1932.  
  1933. // No endpoint found? Default to dashboard. 
  1934. wc_get_template( 'myaccount/dashboard.php', array( 
  1935. 'current_user' => get_user_by( 'id', get_current_user_id() ),  
  1936. ) ); 
  1937.  
  1938. if ( ! function_exists( 'woocommerce_account_navigation' ) ) { 
  1939.  
  1940. /** 
  1941. * My Account navigation template. 
  1942. */ 
  1943. function woocommerce_account_navigation() { 
  1944. wc_get_template( 'myaccount/navigation.php' ); 
  1945.  
  1946. if ( ! function_exists( 'woocommerce_account_orders' ) ) { 
  1947.  
  1948. /** 
  1949. * My Account > Orders template. 
  1950. * 
  1951. * @param int $current_page Current page number. 
  1952. */ 
  1953. function woocommerce_account_orders( $current_page ) { 
  1954. $current_page = empty( $current_page ) ? 1 : absint( $current_page ); 
  1955. $customer_orders = wc_get_orders( apply_filters( 'woocommerce_my_account_my_orders_query', array( 'customer' => get_current_user_id(), 'page' => $current_page, 'paginate' => true ) ) ); 
  1956.  
  1957. wc_get_template( 
  1958. 'myaccount/orders.php',  
  1959. array( 
  1960. 'current_page' => absint( $current_page ),  
  1961. 'customer_orders' => $customer_orders,  
  1962. 'has_orders' => 0 < $customer_orders->total,  
  1963. ); 
  1964.  
  1965. if ( ! function_exists( 'woocommerce_account_view_order' ) ) { 
  1966.  
  1967. /** 
  1968. * My Account > View order template. 
  1969. * 
  1970. * @param int $order_id Order ID. 
  1971. */ 
  1972. function woocommerce_account_view_order( $order_id ) { 
  1973. WC_Shortcode_My_Account::view_order( absint( $order_id ) ); 
  1974.  
  1975. if ( ! function_exists( 'woocommerce_account_downloads' ) ) { 
  1976.  
  1977. /** 
  1978. * My Account > Downloads template. 
  1979. */ 
  1980. function woocommerce_account_downloads() { 
  1981. wc_get_template( 'myaccount/downloads.php' ); 
  1982.  
  1983. if ( ! function_exists( 'woocommerce_account_edit_address' ) ) { 
  1984.  
  1985. /** 
  1986. * My Account > Edit address template. 
  1987. * 
  1988. * @param string $type Address type. 
  1989. */ 
  1990. function woocommerce_account_edit_address( $type ) { 
  1991. $type = wc_edit_address_i18n( sanitize_title( $type ), true ); 
  1992.  
  1993. WC_Shortcode_My_Account::edit_address( $type ); 
  1994.  
  1995. if ( ! function_exists( 'woocommerce_account_payment_methods' ) ) { 
  1996.  
  1997. /** 
  1998. * My Account > Downloads template. 
  1999. */ 
  2000. function woocommerce_account_payment_methods() { 
  2001. wc_get_template( 'myaccount/payment-methods.php' ); 
  2002.  
  2003. if ( ! function_exists( 'woocommerce_account_add_payment_method' ) ) { 
  2004.  
  2005. /** 
  2006. * My Account > Add payment method template. 
  2007. */ 
  2008. function woocommerce_account_add_payment_method() { 
  2009. WC_Shortcode_My_Account::add_payment_method(); 
  2010.  
  2011. if ( ! function_exists( 'woocommerce_account_edit_account' ) ) { 
  2012.  
  2013. /** 
  2014. * My Account > Edit account template. 
  2015. */ 
  2016. function woocommerce_account_edit_account() { 
  2017. WC_Shortcode_My_Account::edit_account(); 
  2018.  
  2019. if ( ! function_exists( 'wc_no_products_found' ) ) { 
  2020.  
  2021. /** 
  2022. * Show no products found message. 
  2023. */ 
  2024. function wc_no_products_found() { 
  2025. wc_get_template( 'loop/no-products-found.php' ); 
  2026.  
  2027.  
  2028. if ( ! function_exists( 'wc_get_email_order_items' ) ) { 
  2029. /** 
  2030. * Get HTML for the order items to be shown in emails. 
  2031. * @param WC_Order $order 
  2032. * @param array $args 
  2033. * @since 3.0.0 
  2034. */ 
  2035. function wc_get_email_order_items( $order, $args = array() ) { 
  2036. ob_start(); 
  2037.  
  2038. $defaults = array( 
  2039. 'show_sku' => false,  
  2040. 'show_image' => false,  
  2041. 'image_size' => array( 32, 32 ),  
  2042. 'plain_text' => false,  
  2043. 'sent_to_admin' => false,  
  2044. ); 
  2045.  
  2046. $args = wp_parse_args( $args, $defaults ); 
  2047. $template = $args['plain_text'] ? 'emails/plain/email-order-items.php' : 'emails/email-order-items.php'; 
  2048.  
  2049. wc_get_template( $template, apply_filters( 'woocommerce_email_order_items_args', array( 
  2050. 'order' => $order,  
  2051. 'items' => $order->get_items(),  
  2052. 'show_download_links' => $order->is_download_permitted() && ! $args['sent_to_admin'],  
  2053. 'show_sku' => $args['show_sku'],  
  2054. 'show_purchase_note' => $order->is_paid() && ! $args['sent_to_admin'],  
  2055. 'show_image' => $args['show_image'],  
  2056. 'image_size' => $args['image_size'],  
  2057. 'plain_text' => $args['plain_text'],  
  2058. 'sent_to_admin' => $args['sent_to_admin'],  
  2059. ) ) ); 
  2060.  
  2061. return apply_filters( 'woocommerce_email_order_items_table', ob_get_clean(), $order ); 
  2062.  
  2063. if ( ! function_exists( 'wc_display_item_meta' ) ) { 
  2064. /** 
  2065. * Display item meta data. 
  2066. * @since 3.0.0 
  2067. * @param WC_Item $item 
  2068. * @param array $args 
  2069. * @return string|void 
  2070. */ 
  2071. function wc_display_item_meta( $item, $args = array() ) { 
  2072. $strings = array(); 
  2073. $html = ''; 
  2074. $args = wp_parse_args( $args, array( 
  2075. 'before' => '<ul class="wc-item-meta"><li>',  
  2076. 'after' => '</li></ul>',  
  2077. 'separator' => '</li><li>',  
  2078. 'echo' => true,  
  2079. 'autop' => false,  
  2080. ) ); 
  2081.  
  2082. foreach ( $item->get_formatted_meta_data() as $meta_id => $meta ) { 
  2083. $value = $args['autop'] ? wp_kses_post( wpautop( make_clickable( $meta->display_value ) ) ) : wp_kses_post( make_clickable( $meta->display_value ) ); 
  2084. $strings[] = '<strong class="wc-item-meta-label">' . wp_kses_post( $meta->display_key ) . ':</strong> ' . $value; 
  2085.  
  2086. if ( $strings ) { 
  2087. $html = $args['before'] . implode( $args['separator'], $strings ) . $args['after']; 
  2088.  
  2089. $html = apply_filters( 'woocommerce_display_item_meta', $html, $item, $args ); 
  2090.  
  2091. if ( $args['echo'] ) { 
  2092. echo $html; 
  2093. } else { 
  2094. return $html; 
  2095.  
  2096. if ( ! function_exists( 'wc_display_item_downloads' ) ) { 
  2097. /** 
  2098. * Display item download links. 
  2099. * @since 3.0.0 
  2100. * @param WC_Item $item 
  2101. * @param array $args 
  2102. * @return string|void 
  2103. */ 
  2104. function wc_display_item_downloads( $item, $args = array() ) { 
  2105. $strings = array(); 
  2106. $html = ''; 
  2107. $args = wp_parse_args( $args, array( 
  2108. 'before' => '<ul class ="wc-item-downloads"><li>',  
  2109. 'after' => '</li></ul>',  
  2110. 'separator' => '</li><li>',  
  2111. 'echo' => true,  
  2112. 'show_url' => false,  
  2113. ) ); 
  2114.  
  2115. if ( is_object( $item ) && $item->is_type( 'line_item' ) && ( $downloads = $item->get_item_downloads() ) ) { 
  2116. $i = 0; 
  2117. foreach ( $downloads as $file ) { 
  2118. $i ++; 
  2119.  
  2120. if ( $args['show_url'] ) { 
  2121. $strings[] = '<strong class="wc-item-download-label">' . esc_html( $file['name'] ) . ':</strong> ' . esc_html( $file['download_url'] ); 
  2122. } else { 
  2123. $prefix = sizeof( $downloads ) > 1 ? sprintf( __( 'Download %d', 'woocommerce' ), $i ) : __( 'Download', 'woocommerce' ); 
  2124. $strings[] = '<strong class="wc-item-download-label">' . $prefix . ':</strong> <a href="' . esc_url( $file['download_url'] ) . '" target="_blank">' . esc_html( $file['name'] ) . '</a>'; 
  2125.  
  2126. if ( $strings ) { 
  2127. $html = $args['before'] . implode( $args['separator'], $strings ) . $args['after']; 
  2128.  
  2129. $html = apply_filters( 'woocommerce_display_item_downloads', $html, $item, $args ); 
  2130.  
  2131. if ( $args['echo'] ) { 
  2132. echo $html; 
  2133. } else { 
  2134. return $html; 
  2135.  
  2136. if ( ! function_exists( 'woocommerce_photoswipe' ) ) { 
  2137.  
  2138. /** 
  2139. * Get the shop sidebar template. 
  2140. * 
  2141. */ 
  2142. function woocommerce_photoswipe() { 
  2143. if ( current_theme_supports( 'wc-product-gallery-lightbox' ) ) { 
  2144. wc_get_template( 'single-product/photoswipe.php' ); 
  2145.  
  2146. /** 
  2147. * Outputs a list of product attributes for a product. 
  2148. * @since 3.0.0 
  2149. * @param WC_Product $product 
  2150. */ 
  2151. function wc_display_product_attributes( $product ) { 
  2152. wc_get_template( 'single-product/product-attributes.php', array( 
  2153. 'product' => $product,  
  2154. 'attributes' => array_filter( $product->get_attributes(), 'wc_attributes_array_filter_visible' ),  
  2155. 'display_dimensions' => apply_filters( 'wc_product_enable_dimensions_display', $product->has_weight() || $product->has_dimensions() ),  
  2156. ) ); 
  2157.  
  2158. /** 
  2159. * Get HTML to show product stock. 
  2160. * @since 3.0.0 
  2161. * @param WC_Product $product 
  2162. * @return string 
  2163. */ 
  2164. function wc_get_stock_html( $product ) { 
  2165.  
  2166. $html = ''; 
  2167. $availability = $product->get_availability(); 
  2168.  
  2169. if ( ! empty( $availability['availability'] ) ) { 
  2170. ob_start(); 
  2171.  
  2172. wc_get_template( 'single-product/stock.php', array( 
  2173. 'product' => $product,  
  2174. 'class' => $availability['class'],  
  2175. 'availability' => $availability['availability'],  
  2176. ) ); 
  2177.  
  2178. $html = ob_get_clean(); 
  2179.  
  2180. if ( has_filter( 'woocommerce_stock_html' ) ) { 
  2181. wc_deprecated_function( 'The woocommerce_stock_html filter', '', 'woocommerce_get_stock_html' ); 
  2182. $html = apply_filters( 'woocommerce_stock_html', $html, $availability['availability'], $product ); 
  2183.  
  2184. return apply_filters( 'woocommerce_get_stock_html', $html, $product ); 
  2185.  
  2186. /** 
  2187. * Get HTML for ratings. 
  2188. * 
  2189. * @since 3.0.0 
  2190. * @param float $rating Rating being shown. 
  2191. * @return string 
  2192. */ 
  2193. function wc_get_rating_html( $rating ) { 
  2194. if ( $rating > 0 ) { 
  2195. $rating_html = '<div class="star-rating" title="' . sprintf( esc_attr__( 'Rated %s out of 5', 'woocommerce' ), $rating ) . '">'; 
  2196. $rating_html .= '<span style="width:' . ( ( $rating / 5 ) * 100 ) . '%"><strong class="rating">' . $rating . '</strong> ' . esc_html__( 'out of 5', 'woocommerce' ) . '</span>'; 
  2197. $rating_html .= '</div>'; 
  2198. } else { 
  2199. $rating_html = ''; 
  2200. return apply_filters( 'woocommerce_product_get_rating_html', $rating_html, $rating ); 
  2201.  
  2202. /** 
  2203. * Returns a 'from' prefix if you want to show where prices start at. 
  2204. * 
  2205. * @since 3.0.0 
  2206. * @return string 
  2207. */ 
  2208. function wc_get_price_html_from_text() { 
  2209. return apply_filters( 'woocommerce_get_price_html_from_text', '<span class="from">' . _x( 'From:', 'min_price', 'woocommerce' ) . ' </span>' ); 
  2210.  
  2211. /** 
  2212. * Get logout endpoint. 
  2213. * 
  2214. * @since 2.6.9 
  2215. * @return string 
  2216. */ 
  2217. function wc_logout_url( $redirect = '' ) { 
  2218. $logout_endpoint = get_option( 'woocommerce_logout_endpoint' ); 
  2219. $redirect = $redirect ? $redirect : wc_get_page_permalink( 'myaccount' ); 
  2220.  
  2221. if ( $logout_endpoint ) { 
  2222. return wc_get_endpoint_url( 'customer-logout', '', $redirect ); 
  2223. } else { 
  2224. return wp_logout_url( $redirect ); 
.