/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. $products = array_filter( array_map( 'wc_get_product', $product->get_children() ) ); 
  840.  
  841. if ( $products ) { 
  842. usort( $products, 'wc_products_array_orderby_menu_order' ); 
  843.  
  844. wc_get_template( 'single-product/add-to-cart/grouped.php', array( 
  845. 'grouped_product' => $product,  
  846. 'grouped_products' => $products,  
  847. 'quantites_required' => false,  
  848. ) ); 
  849. if ( ! function_exists( 'woocommerce_variable_add_to_cart' ) ) { 
  850.  
  851. /** 
  852. * Output the variable product add to cart area. 
  853. * 
  854. * @subpackage Product 
  855. */ 
  856. function woocommerce_variable_add_to_cart() { 
  857. global $product; 
  858.  
  859. // Enqueue variation scripts 
  860. wp_enqueue_script( 'wc-add-to-cart-variation' ); 
  861.  
  862. // Get Available variations? 
  863. $get_variations = sizeof( $product->get_children() ) <= apply_filters( 'woocommerce_ajax_variation_threshold', 30, $product ); 
  864.  
  865. // Load the template 
  866. wc_get_template( 'single-product/add-to-cart/variable.php', array( 
  867. 'available_variations' => $get_variations ? $product->get_available_variations() : false,  
  868. 'attributes' => $product->get_variation_attributes(),  
  869. 'selected_attributes' => $product->get_default_attributes(),  
  870. ) ); 
  871. if ( ! function_exists( 'woocommerce_external_add_to_cart' ) ) { 
  872.  
  873. /** 
  874. * Output the external product add to cart area. 
  875. * 
  876. * @subpackage Product 
  877. */ 
  878. function woocommerce_external_add_to_cart() { 
  879. global $product; 
  880.  
  881. if ( ! $product->add_to_cart_url() ) { 
  882. return; 
  883.  
  884. wc_get_template( 'single-product/add-to-cart/external.php', array( 
  885. 'product_url' => $product->add_to_cart_url(),  
  886. 'button_text' => $product->single_add_to_cart_text(),  
  887. ) ); 
  888.  
  889. if ( ! function_exists( 'woocommerce_quantity_input' ) ) { 
  890.  
  891. /** 
  892. * Output the quantity input for add to cart forms. 
  893. * 
  894. * @param array $args Args for the input 
  895. * @param WC_Product|null $product 
  896. * @param boolean $echo Whether to return or echo|string 
  897. */ 
  898. function woocommerce_quantity_input( $args = array(), $product = null, $echo = true ) { 
  899. if ( is_null( $product ) ) { 
  900. $product = $GLOBALS['product']; 
  901.  
  902. $defaults = array( 
  903. 'input_name' => 'quantity',  
  904. 'input_value' => '1',  
  905. 'max_value' => apply_filters( 'woocommerce_quantity_input_max', -1, $product ),  
  906. 'min_value' => apply_filters( 'woocommerce_quantity_input_min', 0, $product ),  
  907. 'step' => apply_filters( 'woocommerce_quantity_input_step', 1, $product ),  
  908. 'pattern' => apply_filters( 'woocommerce_quantity_input_pattern', has_filter( 'woocommerce_stock_amount', 'intval' ) ? '[0-9]*' : '' ),  
  909. 'inputmode' => apply_filters( 'woocommerce_quantity_input_inputmode', has_filter( 'woocommerce_stock_amount', 'intval' ) ? 'numeric' : '' ),  
  910. ); 
  911.  
  912. $args = apply_filters( 'woocommerce_quantity_input_args', wp_parse_args( $args, $defaults ), $product ); 
  913.  
  914. // Apply sanity to min/max args - min cannot be lower than 0. 
  915. $args['min_value'] = max( $args['min_value'], 0 ); 
  916. $args['max_value'] = 0 < $args['max_value'] ? $args['max_value'] : ''; 
  917.  
  918. // Max cannot be lower than min if defined. 
  919. if ( '' !== $args['max_value'] && $args['max_value'] < $args['min_value'] ) { 
  920. $args['max_value'] = $args['min_value']; 
  921.  
  922. ob_start(); 
  923.  
  924. wc_get_template( 'global/quantity-input.php', $args ); 
  925.  
  926. if ( $echo ) { 
  927. echo ob_get_clean(); 
  928. } else { 
  929. return ob_get_clean(); 
  930.  
  931. if ( ! function_exists( 'woocommerce_product_description_tab' ) ) { 
  932.  
  933. /** 
  934. * Output the description tab content. 
  935. * 
  936. * @subpackage Product/Tabs 
  937. */ 
  938. function woocommerce_product_description_tab() { 
  939. wc_get_template( 'single-product/tabs/description.php' ); 
  940. if ( ! function_exists( 'woocommerce_product_additional_information_tab' ) ) { 
  941.  
  942. /** 
  943. * Output the attributes tab content. 
  944. * 
  945. * @subpackage Product/Tabs 
  946. */ 
  947. function woocommerce_product_additional_information_tab() { 
  948. wc_get_template( 'single-product/tabs/additional-information.php' ); 
  949. if ( ! function_exists( 'woocommerce_product_reviews_tab' ) ) { 
  950.  
  951. /** 
  952. * Output the reviews tab content. 
  953. * @deprecated 2.4.0 Unused 
  954. * @subpackage Product/Tabs 
  955. */ 
  956. function woocommerce_product_reviews_tab() { 
  957. wc_deprecated_function( 'woocommerce_product_reviews_tab', '2.4' ); 
  958.  
  959. if ( ! function_exists( 'woocommerce_default_product_tabs' ) ) { 
  960.  
  961. /** 
  962. * Add default product tabs to product pages. 
  963. * 
  964. * @param array $tabs 
  965. * @return array 
  966. */ 
  967. function woocommerce_default_product_tabs( $tabs = array() ) { 
  968. global $product, $post; 
  969.  
  970. // Description tab - shows product content 
  971. if ( $post->post_content ) { 
  972. $tabs['description'] = array( 
  973. 'title' => __( 'Description', 'woocommerce' ),  
  974. 'priority' => 10,  
  975. 'callback' => 'woocommerce_product_description_tab',  
  976. ); 
  977.  
  978. // Additional information tab - shows attributes 
  979. if ( $product && ( $product->has_attributes() || apply_filters( 'wc_product_enable_dimensions_display', $product->has_weight() || $product->has_dimensions() ) ) ) { 
  980. $tabs['additional_information'] = array( 
  981. 'title' => __( 'Additional information', 'woocommerce' ),  
  982. 'priority' => 20,  
  983. 'callback' => 'woocommerce_product_additional_information_tab',  
  984. ); 
  985.  
  986. // Reviews tab - shows comments 
  987. if ( comments_open() ) { 
  988. $tabs['reviews'] = array( 
  989. 'title' => sprintf( __( 'Reviews (%d)', 'woocommerce' ), $product->get_review_count() ),  
  990. 'priority' => 30,  
  991. 'callback' => 'comments_template',  
  992. ); 
  993.  
  994. return $tabs; 
  995.  
  996. if ( ! function_exists( 'woocommerce_sort_product_tabs' ) ) { 
  997.  
  998. /** 
  999. * Sort tabs by priority. 
  1000. * 
  1001. * @param array $tabs 
  1002. * @return array 
  1003. */ 
  1004. function woocommerce_sort_product_tabs( $tabs = array() ) { 
  1005.  
  1006. // Make sure the $tabs parameter is an array 
  1007. if ( ! is_array( $tabs ) ) { 
  1008. trigger_error( "Function woocommerce_sort_product_tabs() expects an array as the first parameter. Defaulting to empty array." ); 
  1009. $tabs = array(); 
  1010.  
  1011. // Re-order tabs by priority 
  1012. if ( ! function_exists( '_sort_priority_callback' ) ) { 
  1013. function _sort_priority_callback( $a, $b ) { 
  1014. if ( $a['priority'] === $b['priority'] ) 
  1015. return 0; 
  1016. return ( $a['priority'] < $b['priority'] ) ? -1 : 1; 
  1017.  
  1018. uasort( $tabs, '_sort_priority_callback' ); 
  1019.  
  1020. return $tabs; 
  1021.  
  1022. if ( ! function_exists( 'woocommerce_comments' ) ) { 
  1023.  
  1024. /** 
  1025. * Output the Review comments template. 
  1026. * 
  1027. * @subpackage Product 
  1028. * @param WP_Comment $comment 
  1029. * @param array $args 
  1030. * @param int $depth 
  1031. */ 
  1032. function woocommerce_comments( $comment, $args, $depth ) { 
  1033. $GLOBALS['comment'] = $comment; 
  1034. wc_get_template( 'single-product/review.php', array( 'comment' => $comment, 'args' => $args, 'depth' => $depth ) ); 
  1035.  
  1036. if ( ! function_exists( 'woocommerce_review_display_gravatar' ) ) { 
  1037. /** 
  1038. * Display the review authors gravatar 
  1039. * 
  1040. * @param array $comment WP_Comment. 
  1041. * @return void 
  1042. */ 
  1043. function woocommerce_review_display_gravatar( $comment ) { 
  1044. echo get_avatar( $comment, apply_filters( 'woocommerce_review_gravatar_size', '60' ), '' ); 
  1045.  
  1046. if ( ! function_exists( 'woocommerce_review_display_rating' ) ) { 
  1047. /** 
  1048. * Display the reviewers star rating 
  1049. * 
  1050. * @return void 
  1051. */ 
  1052. function woocommerce_review_display_rating() { 
  1053. wc_get_template( 'single-product/review-rating.php' ); 
  1054.  
  1055. if ( ! function_exists( 'woocommerce_review_display_meta' ) ) { 
  1056. /** 
  1057. * Display the review authors meta (name, verified owner, review date) 
  1058. * 
  1059. * @return void 
  1060. */ 
  1061. function woocommerce_review_display_meta() { 
  1062. wc_get_template( 'single-product/review-meta.php' ); 
  1063.  
  1064. if ( ! function_exists( 'woocommerce_review_display_comment_text' ) ) { 
  1065.  
  1066. /** 
  1067. * Display the review content. 
  1068. */ 
  1069. function woocommerce_review_display_comment_text() { 
  1070. echo '<div class="description">'; 
  1071. comment_text(); 
  1072. echo '</div>'; 
  1073.  
  1074. if ( ! function_exists( 'woocommerce_output_related_products' ) ) { 
  1075.  
  1076. /** 
  1077. * Output the related products. 
  1078. * 
  1079. * @subpackage Product 
  1080. */ 
  1081. function woocommerce_output_related_products() { 
  1082.  
  1083. $args = array( 
  1084. 'posts_per_page' => 4,  
  1085. 'columns' => 4,  
  1086. 'orderby' => 'rand',  
  1087. ); 
  1088.  
  1089. woocommerce_related_products( apply_filters( 'woocommerce_output_related_products_args', $args ) ); 
  1090.  
  1091. if ( ! function_exists( 'woocommerce_related_products' ) ) { 
  1092.  
  1093. /** 
  1094. * Output the related products. 
  1095. * 
  1096. * @param array Provided arguments 
  1097. */ 
  1098. function woocommerce_related_products( $args = array() ) { 
  1099. global $product, $woocommerce_loop; 
  1100.  
  1101. if ( ! $product ) { 
  1102. return; 
  1103.  
  1104. $defaults = array( 
  1105. 'posts_per_page' => 2,  
  1106. 'columns' => 2,  
  1107. 'orderby' => 'rand',  
  1108. 'order' => 'desc',  
  1109. ); 
  1110.  
  1111. $args = wp_parse_args( $args, $defaults ); 
  1112.  
  1113. // Get visble related products then sort them at random. 
  1114. $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' ); 
  1115.  
  1116. // Handle orderby. 
  1117. $args['related_products'] = wc_products_array_orderby( $args['related_products'], $args['orderby'], $args['order'] ); 
  1118.  
  1119. // Set global loop values. 
  1120. $woocommerce_loop['name'] = 'related'; 
  1121. $woocommerce_loop['columns'] = apply_filters( 'woocommerce_related_products_columns', $args['columns'] ); 
  1122.  
  1123. wc_get_template( 'single-product/related.php', $args ); 
  1124.  
  1125. if ( ! function_exists( 'woocommerce_upsell_display' ) ) { 
  1126.  
  1127. /** 
  1128. * Output product up sells. 
  1129. * 
  1130. * @param int $limit (default: -1) 
  1131. * @param int $columns (default: 4) 
  1132. * @param string $orderby Supported values - rand, title, ID, date, modified, menu_order, price. 
  1133. * @param string $order Sort direction. 
  1134. */ 
  1135. function woocommerce_upsell_display( $limit = '-1', $columns = 4, $orderby = 'rand', $order = 'desc' ) { 
  1136. global $product, $woocommerce_loop; 
  1137.  
  1138. if ( ! $product ) { 
  1139. return; 
  1140.  
  1141. // Handle the legacy filter which controlled posts per page etc. 
  1142. $args = apply_filters( 'woocommerce_upsell_display_args', array( 
  1143. 'posts_per_page' => $limit,  
  1144. 'orderby' => $orderby,  
  1145. 'columns' => $columns,  
  1146. ) ); 
  1147. $woocommerce_loop['name'] = 'up-sells'; 
  1148. $woocommerce_loop['columns'] = apply_filters( 'woocommerce_upsells_columns', isset( $args['columns'] ) ? $args['columns'] : $columns ); 
  1149. $orderby = apply_filters( 'woocommerce_upsells_orderby', isset( $args['orderby'] ) ? $args['orderby'] : $orderby ); 
  1150. $limit = apply_filters( 'woocommerce_upsells_total', isset( $args['posts_per_page'] ) ? $args['posts_per_page'] : $limit ); 
  1151.  
  1152. // Get visble upsells then sort them at random, then limit result set. 
  1153. $upsells = wc_products_array_orderby( array_filter( array_map( 'wc_get_product', $product->get_upsell_ids() ), 'wc_products_array_filter_visible' ), $orderby, $order ); 
  1154. $upsells = $limit > 0 ? array_slice( $upsells, 0, $limit ) : $upsells; 
  1155.  
  1156. wc_get_template( 'single-product/up-sells.php', array( 
  1157. 'upsells' => $upsells,  
  1158.  
  1159. // Not used now, but used in previous version of up-sells.php. 
  1160. 'posts_per_page' => $limit,  
  1161. 'orderby' => $orderby,  
  1162. 'columns' => $columns,  
  1163. ) ); 
  1164.  
  1165. /** Cart ******************************************************************/ 
  1166.  
  1167. if ( ! function_exists( 'woocommerce_shipping_calculator' ) ) { 
  1168.  
  1169. /** 
  1170. * Output the cart shipping calculator. 
  1171. * 
  1172. * @subpackage Cart 
  1173. */ 
  1174. function woocommerce_shipping_calculator() { 
  1175. wc_get_template( 'cart/shipping-calculator.php' ); 
  1176.  
  1177. if ( ! function_exists( 'woocommerce_cart_totals' ) ) { 
  1178.  
  1179. /** 
  1180. * Output the cart totals. 
  1181. * 
  1182. * @subpackage Cart 
  1183. */ 
  1184. function woocommerce_cart_totals() { 
  1185. if ( is_checkout() ) { 
  1186. return; 
  1187. wc_get_template( 'cart/cart-totals.php' ); 
  1188.  
  1189. if ( ! function_exists( 'woocommerce_cross_sell_display' ) ) { 
  1190.  
  1191. /** 
  1192. * Output the cart cross-sells. 
  1193. * 
  1194. * @param int $limit (default: 2) 
  1195. * @param int $columns (default: 2) 
  1196. * @param string $orderby (default: 'rand') 
  1197. * @param string $order (default: 'desc') 
  1198. */ 
  1199. function woocommerce_cross_sell_display( $limit = 2, $columns = 2, $orderby = 'rand', $order = 'desc' ) { 
  1200. global $woocommerce_loop; 
  1201.  
  1202. if ( is_checkout() ) { 
  1203. return; 
  1204. // Get visble cross sells then sort them at random. 
  1205. $cross_sells = array_filter( array_map( 'wc_get_product', WC()->cart->get_cross_sells() ), 'wc_products_array_filter_visible' ); 
  1206. $woocommerce_loop['name'] = 'cross-sells'; 
  1207. $woocommerce_loop['columns'] = apply_filters( 'woocommerce_cross_sells_columns', $columns ); 
  1208.  
  1209. // Handle orderby and limit results. 
  1210. $orderby = apply_filters( 'woocommerce_cross_sells_orderby', $orderby ); 
  1211. $cross_sells = wc_products_array_orderby( $cross_sells, $orderby, $order ); 
  1212. $limit = apply_filters( 'woocommerce_cross_sells_total', $limit ); 
  1213. $cross_sells = $limit > 0 ? array_slice( $cross_sells, 0, $limit ) : $cross_sells; 
  1214.  
  1215. wc_get_template( 'cart/cross-sells.php', array( 
  1216. 'cross_sells' => $cross_sells,  
  1217.  
  1218. // Not used now, but used in previous version of up-sells.php. 
  1219. 'posts_per_page' => $limit,  
  1220. 'orderby' => $orderby,  
  1221. 'columns' => $columns,  
  1222. ) ); 
  1223.  
  1224. if ( ! function_exists( 'woocommerce_button_proceed_to_checkout' ) ) { 
  1225.  
  1226. /** 
  1227. * Output the proceed to checkout button. 
  1228. * 
  1229. * @subpackage Cart 
  1230. */ 
  1231. function woocommerce_button_proceed_to_checkout() { 
  1232. wc_get_template( 'cart/proceed-to-checkout-button.php' ); 
  1233.  
  1234. if ( ! function_exists( 'woocommerce_widget_shopping_cart_button_view_cart' ) ) { 
  1235.  
  1236. /** 
  1237. * Output the proceed to checkout button. 
  1238. * 
  1239. * @subpackage Cart 
  1240. */ 
  1241. function woocommerce_widget_shopping_cart_button_view_cart() { 
  1242. echo '<a href="' . esc_url( wc_get_cart_url() ) . '" class="button wc-forward">' . esc_html__( 'View cart', 'woocommerce' ) . '</a>'; 
  1243.  
  1244. if ( ! function_exists( 'woocommerce_widget_shopping_cart_proceed_to_checkout' ) ) { 
  1245.  
  1246. /** 
  1247. * Output the proceed to checkout button. 
  1248. * 
  1249. * @subpackage Cart 
  1250. */ 
  1251. function woocommerce_widget_shopping_cart_proceed_to_checkout() { 
  1252. echo '<a href="' . esc_url( wc_get_checkout_url() ) . '" class="button checkout wc-forward">' . esc_html__( 'Checkout', 'woocommerce' ) . '</a>'; 
  1253.  
  1254. /** Mini-Cart *************************************************************/ 
  1255.  
  1256. if ( ! function_exists( 'woocommerce_mini_cart' ) ) { 
  1257.  
  1258. /** 
  1259. * Output the Mini-cart - used by cart widget. 
  1260. * 
  1261. * @param array $args 
  1262. */ 
  1263. function woocommerce_mini_cart( $args = array() ) { 
  1264.  
  1265. $defaults = array( 
  1266. 'list_class' => '',  
  1267. ); 
  1268.  
  1269. $args = wp_parse_args( $args, $defaults ); 
  1270.  
  1271. wc_get_template( 'cart/mini-cart.php', $args ); 
  1272.  
  1273. /** Login *****************************************************************/ 
  1274.  
  1275. if ( ! function_exists( 'woocommerce_login_form' ) ) { 
  1276.  
  1277. /** 
  1278. * Output the WooCommerce Login Form. 
  1279. * 
  1280. * @subpackage Forms 
  1281. * @param array $args 
  1282. */ 
  1283. function woocommerce_login_form( $args = array() ) { 
  1284.  
  1285. $defaults = array( 
  1286. 'message' => '',  
  1287. 'redirect' => '',  
  1288. 'hidden' => false,  
  1289. ); 
  1290.  
  1291. $args = wp_parse_args( $args, $defaults ); 
  1292.  
  1293. wc_get_template( 'global/form-login.php', $args ); 
  1294.  
  1295. if ( ! function_exists( 'woocommerce_checkout_login_form' ) ) { 
  1296.  
  1297. /** 
  1298. * Output the WooCommerce Checkout Login Form. 
  1299. * 
  1300. * @subpackage Checkout 
  1301. */ 
  1302. function woocommerce_checkout_login_form() { 
  1303. wc_get_template( 'checkout/form-login.php', array( 'checkout' => WC()->checkout() ) ); 
  1304.  
  1305. if ( ! function_exists( 'woocommerce_breadcrumb' ) ) { 
  1306.  
  1307. /** 
  1308. * Output the WooCommerce Breadcrumb. 
  1309. * 
  1310. * @param array $args 
  1311. */ 
  1312. function woocommerce_breadcrumb( $args = array() ) { 
  1313. $args = wp_parse_args( $args, apply_filters( 'woocommerce_breadcrumb_defaults', array( 
  1314. 'delimiter' => ' / ',  
  1315. 'wrap_before' => '<nav class="woocommerce-breadcrumb">',  
  1316. 'wrap_after' => '</nav>',  
  1317. 'before' => '',  
  1318. 'after' => '',  
  1319. 'home' => _x( 'Home', 'breadcrumb', 'woocommerce' ),  
  1320. ) ) ); 
  1321.  
  1322. $breadcrumbs = new WC_Breadcrumb(); 
  1323.  
  1324. if ( ! empty( $args['home'] ) ) { 
  1325. $breadcrumbs->add_crumb( $args['home'], apply_filters( 'woocommerce_breadcrumb_home_url', home_url() ) ); 
  1326.  
  1327. $args['breadcrumb'] = $breadcrumbs->generate(); 
  1328.  
  1329. /** 
  1330. * @hooked WC_Structured_Data::generate_breadcrumblist_data() - 10 
  1331. */ 
  1332. do_action( 'woocommerce_breadcrumb', $breadcrumbs, $args ); 
  1333.  
  1334. wc_get_template( 'global/breadcrumb.php', $args ); 
  1335.  
  1336. if ( ! function_exists( 'woocommerce_order_review' ) ) { 
  1337.  
  1338. /** 
  1339. * Output the Order review table for the checkout. 
  1340. * 
  1341. * @subpackage Checkout 
  1342. */ 
  1343. function woocommerce_order_review( $deprecated = false ) { 
  1344. wc_get_template( 'checkout/review-order.php', array( 'checkout' => WC()->checkout() ) ); 
  1345.  
  1346. if ( ! function_exists( 'woocommerce_checkout_payment' ) ) { 
  1347.  
  1348. /** 
  1349. * Output the Payment Methods on the checkout. 
  1350. * 
  1351. * @subpackage Checkout 
  1352. */ 
  1353. function woocommerce_checkout_payment() { 
  1354. if ( WC()->cart->needs_payment() ) { 
  1355. $available_gateways = WC()->payment_gateways()->get_available_payment_gateways(); 
  1356. WC()->payment_gateways()->set_current_gateway( $available_gateways ); 
  1357. } else { 
  1358. $available_gateways = array(); 
  1359.  
  1360. wc_get_template( 'checkout/payment.php', array( 
  1361. 'checkout' => WC()->checkout(),  
  1362. 'available_gateways' => $available_gateways,  
  1363. 'order_button_text' => apply_filters( 'woocommerce_order_button_text', __( 'Place order', 'woocommerce' ) ),  
  1364. ) ); 
  1365.  
  1366. if ( ! function_exists( 'woocommerce_checkout_coupon_form' ) ) { 
  1367.  
  1368. /** 
  1369. * Output the Coupon form for the checkout. 
  1370. * 
  1371. * @subpackage Checkout 
  1372. */ 
  1373. function woocommerce_checkout_coupon_form() { 
  1374. wc_get_template( 'checkout/form-coupon.php', array( 'checkout' => WC()->checkout() ) ); 
  1375.  
  1376. if ( ! function_exists( 'woocommerce_products_will_display' ) ) { 
  1377.  
  1378. /** 
  1379. * Check if we will be showing products or not (and not sub-categories only). 
  1380. * @subpackage Loop 
  1381. * @return bool 
  1382. */ 
  1383. function woocommerce_products_will_display() { 
  1384. global $wpdb; 
  1385.  
  1386. if ( is_shop() ) { 
  1387. return 'subcategories' !== get_option( 'woocommerce_shop_page_display' ) || is_search(); 
  1388.  
  1389. if ( ! is_product_taxonomy() ) { 
  1390. return false; 
  1391.  
  1392. if ( is_search() || is_filtered() || is_paged() ) { 
  1393. return true; 
  1394.  
  1395. $term = get_queried_object(); 
  1396.  
  1397. if ( is_product_category() ) { 
  1398. switch ( get_woocommerce_term_meta( $term->term_id, 'display_type', true ) ) { 
  1399. case 'subcategories' : 
  1400. // Nothing - we want to continue to see if there are products/subcats 
  1401. break; 
  1402. case 'products' : 
  1403. case 'both' : 
  1404. return true; 
  1405. break; 
  1406. default : 
  1407. // Default - no setting 
  1408. if ( get_option( 'woocommerce_category_archive_display' ) != 'subcategories' ) { 
  1409. return true; 
  1410. break; 
  1411.  
  1412. // Begin subcategory logic 
  1413. if ( empty( $term->term_id ) || empty( $term->taxonomy ) ) { 
  1414. return true; 
  1415.  
  1416. $transient_name = 'wc_products_will_display_' . $term->term_id . '_' . WC_Cache_Helper::get_transient_version( 'product_query' ); 
  1417.  
  1418. if ( false === ( $products_will_display = get_transient( $transient_name ) ) ) { 
  1419. $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 ) ); 
  1420.  
  1421. if ( $has_children ) { 
  1422. // Check terms have products inside - parents first. If products are found inside, subcats will be shown instead of products so we can return false. 
  1423. if ( sizeof( get_objects_in_term( $has_children, $term->taxonomy ) ) > 0 ) { 
  1424. $products_will_display = false; 
  1425. } else { 
  1426. // If we get here, the parents were empty so we're forced to check children 
  1427. foreach ( $has_children as $term_id ) { 
  1428. $children = get_term_children( $term_id, $term->taxonomy ); 
  1429.  
  1430. if ( sizeof( get_objects_in_term( $children, $term->taxonomy ) ) > 0 ) { 
  1431. $products_will_display = false; 
  1432. break; 
  1433. } else { 
  1434. $products_will_display = true; 
  1435.  
  1436. set_transient( $transient_name, $products_will_display, DAY_IN_SECONDS * 30 ); 
  1437.  
  1438. return $products_will_display; 
  1439.  
  1440. if ( ! function_exists( 'woocommerce_product_subcategories' ) ) { 
  1441.  
  1442. /** 
  1443. * Display product sub categories as thumbnails. 
  1444. * 
  1445. * @subpackage Loop 
  1446. * @param array $args 
  1447. * @return null|boolean 
  1448. */ 
  1449. function woocommerce_product_subcategories( $args = array() ) { 
  1450. global $wp_query; 
  1451.  
  1452. $defaults = array( 
  1453. 'before' => '',  
  1454. 'after' => '',  
  1455. 'force_display' => false,  
  1456. ); 
  1457.  
  1458. $args = wp_parse_args( $args, $defaults ); 
  1459.  
  1460. extract( $args ); 
  1461.  
  1462. // Main query only 
  1463. if ( ! is_main_query() && ! $force_display ) { 
  1464. return; 
  1465.  
  1466. // Don't show when filtering, searching or when on page > 1 and ensure we're on a product archive 
  1467. if ( is_search() || is_filtered() || is_paged() || ( ! is_product_category() && ! is_shop() ) ) { 
  1468. return; 
  1469.  
  1470. // Check categories are enabled 
  1471. if ( is_shop() && '' === get_option( 'woocommerce_shop_page_display' ) ) { 
  1472. return; 
  1473.  
  1474. // Find the category + category parent, if applicable 
  1475. $term = get_queried_object(); 
  1476. $parent_id = empty( $term->term_id ) ? 0 : $term->term_id; 
  1477.  
  1478. if ( is_product_category() ) { 
  1479. $display_type = get_woocommerce_term_meta( $term->term_id, 'display_type', true ); 
  1480.  
  1481. switch ( $display_type ) { 
  1482. case 'products' : 
  1483. return; 
  1484. break; 
  1485. case '' : 
  1486. if ( '' === get_option( 'woocommerce_category_archive_display' ) ) { 
  1487. return; 
  1488. break; 
  1489.  
  1490. // 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 
  1491. $product_categories = get_categories( apply_filters( 'woocommerce_product_subcategories_args', array( 
  1492. 'parent' => $parent_id,  
  1493. 'menu_order' => 'ASC',  
  1494. 'hide_empty' => 0,  
  1495. 'hierarchical' => 1,  
  1496. 'taxonomy' => 'product_cat',  
  1497. 'pad_counts' => 1,  
  1498. ) ) ); 
  1499.  
  1500. if ( apply_filters( 'woocommerce_product_subcategories_hide_empty', true ) ) { 
  1501. $product_categories = wp_list_filter( $product_categories, array( 'count' => 0 ), 'NOT' ); 
  1502.  
  1503. if ( $product_categories ) { 
  1504. echo $before; 
  1505.  
  1506. foreach ( $product_categories as $category ) { 
  1507. wc_get_template( 'content-product_cat.php', array( 
  1508. 'category' => $category,  
  1509. ) ); 
  1510.  
  1511. // If we are hiding products disable the loop and pagination 
  1512. if ( is_product_category() ) { 
  1513. $display_type = get_woocommerce_term_meta( $term->term_id, 'display_type', true ); 
  1514.  
  1515. switch ( $display_type ) { 
  1516. case 'subcategories' : 
  1517. $wp_query->post_count = 0; 
  1518. $wp_query->max_num_pages = 0; 
  1519. break; 
  1520. case '' : 
  1521. if ( 'subcategories' === get_option( 'woocommerce_category_archive_display' ) ) { 
  1522. $wp_query->post_count = 0; 
  1523. $wp_query->max_num_pages = 0; 
  1524. break; 
  1525.  
  1526. if ( is_shop() && 'subcategories' === get_option( 'woocommerce_shop_page_display' ) ) { 
  1527. $wp_query->post_count = 0; 
  1528. $wp_query->max_num_pages = 0; 
  1529.  
  1530. echo $after; 
  1531.  
  1532. return true; 
  1533.  
  1534. if ( ! function_exists( 'woocommerce_subcategory_thumbnail' ) ) { 
  1535.  
  1536. /** 
  1537. * Show subcategory thumbnails. 
  1538. * 
  1539. * @param mixed $category 
  1540. * @subpackage Loop 
  1541. */ 
  1542. function woocommerce_subcategory_thumbnail( $category ) { 
  1543. $small_thumbnail_size = apply_filters( 'subcategory_archive_thumbnail_size', 'shop_catalog' ); 
  1544. $dimensions = wc_get_image_size( $small_thumbnail_size ); 
  1545. $thumbnail_id = get_woocommerce_term_meta( $category->term_id, 'thumbnail_id', true ); 
  1546.  
  1547. if ( $thumbnail_id ) { 
  1548. $image = wp_get_attachment_image_src( $thumbnail_id, $small_thumbnail_size ); 
  1549. $image = $image[0]; 
  1550. $image_srcset = function_exists( 'wp_get_attachment_image_srcset' ) ? wp_get_attachment_image_srcset( $thumbnail_id, $small_thumbnail_size ) : false; 
  1551. $image_sizes = function_exists( 'wp_get_attachment_image_sizes' ) ? wp_get_attachment_image_sizes( $thumbnail_id, $small_thumbnail_size ) : false; 
  1552. } else { 
  1553. $image = wc_placeholder_img_src(); 
  1554. $image_srcset = $image_sizes = false; 
  1555.  
  1556. if ( $image ) { 
  1557. // Prevent esc_url from breaking spaces in urls for image embeds 
  1558. // Ref: https://core.trac.wordpress.org/ticket/23605 
  1559. $image = str_replace( ' ', '%20', $image ); 
  1560.  
  1561. // Add responsive image markup if available 
  1562. if ( $image_srcset && $image_sizes ) { 
  1563. 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 ) . '" />'; 
  1564. } else { 
  1565. echo '<img src="' . esc_url( $image ) . '" alt="' . esc_attr( $category->name ) . '" width="' . esc_attr( $dimensions['width'] ) . '" height="' . esc_attr( $dimensions['height'] ) . '" />'; 
  1566.  
  1567. if ( ! function_exists( 'woocommerce_order_details_table' ) ) { 
  1568.  
  1569. /** 
  1570. * Displays order details in a table. 
  1571. * 
  1572. * @param mixed $order_id 
  1573. * @subpackage Orders 
  1574. */ 
  1575. function woocommerce_order_details_table( $order_id ) { 
  1576. if ( ! $order_id ) return; 
  1577.  
  1578. wc_get_template( 'order/order-details.php', array( 
  1579. 'order_id' => $order_id,  
  1580. ) ); 
  1581.  
  1582.  
  1583. if ( ! function_exists( 'woocommerce_order_again_button' ) ) { 
  1584.  
  1585. /** 
  1586. * Display an 'order again' button on the view order page. 
  1587. * 
  1588. * @param object $order 
  1589. * @subpackage Orders 
  1590. */ 
  1591. function woocommerce_order_again_button( $order ) { 
  1592. if ( ! $order || ! $order->has_status( 'completed' ) || ! is_user_logged_in() ) { 
  1593. return; 
  1594.  
  1595. wc_get_template( 'order/order-again.php', array( 
  1596. 'order' => $order,  
  1597. ) ); 
  1598.  
  1599. /** Forms ****************************************************************/ 
  1600.  
  1601. if ( ! function_exists( 'woocommerce_form_field' ) ) { 
  1602.  
  1603. /** 
  1604. * Outputs a checkout/address form field. 
  1605. * 
  1606. * @subpackage Forms 
  1607. * @param string $key 
  1608. * @param mixed $args 
  1609. * @param string $value (default: null) 
  1610. */ 
  1611. function woocommerce_form_field( $key, $args, $value = null ) { 
  1612. $defaults = array( 
  1613. 'type' => 'text',  
  1614. 'label' => '',  
  1615. 'description' => '',  
  1616. 'placeholder' => '',  
  1617. 'maxlength' => false,  
  1618. 'required' => false,  
  1619. 'autocomplete' => false,  
  1620. 'id' => $key,  
  1621. 'class' => array(),  
  1622. 'label_class' => array(),  
  1623. 'input_class' => array(),  
  1624. 'return' => false,  
  1625. 'options' => array(),  
  1626. 'custom_attributes' => array(),  
  1627. 'validate' => array(),  
  1628. 'default' => '',  
  1629. 'autofocus' => '',  
  1630. 'priority' => '',  
  1631. ); 
  1632.  
  1633. $args = wp_parse_args( $args, $defaults ); 
  1634. $args = apply_filters( 'woocommerce_form_field_args', $args, $key, $value ); 
  1635.  
  1636. if ( $args['required'] ) { 
  1637. $args['class'][] = 'validate-required'; 
  1638. $required = ' <abbr class="required" title="' . esc_attr__( 'required', 'woocommerce' ) . '">*</abbr>'; 
  1639. } else { 
  1640. $required = ''; 
  1641.  
  1642. if ( is_string( $args['label_class'] ) ) { 
  1643. $args['label_class'] = array( $args['label_class'] ); 
  1644.  
  1645. if ( is_null( $value ) ) { 
  1646. $value = $args['default']; 
  1647.  
  1648. // Custom attribute handling 
  1649. $custom_attributes = array(); 
  1650. $args['custom_attributes'] = array_filter( (array) $args['custom_attributes'] ); 
  1651.  
  1652. if ( $args['maxlength'] ) { 
  1653. $args['custom_attributes']['maxlength'] = absint( $args['maxlength'] ); 
  1654.  
  1655. if ( ! empty( $args['autocomplete'] ) ) { 
  1656. $args['custom_attributes']['autocomplete'] = $args['autocomplete']; 
  1657.  
  1658. if ( true === $args['autofocus'] ) { 
  1659. $args['custom_attributes']['autofocus'] = 'autofocus'; 
  1660.  
  1661. if ( ! empty( $args['custom_attributes'] ) && is_array( $args['custom_attributes'] ) ) { 
  1662. foreach ( $args['custom_attributes'] as $attribute => $attribute_value ) { 
  1663. $custom_attributes[] = esc_attr( $attribute ) . '="' . esc_attr( $attribute_value ) . '"'; 
  1664.  
  1665. if ( ! empty( $args['validate'] ) ) { 
  1666. foreach ( $args['validate'] as $validate ) { 
  1667. $args['class'][] = 'validate-' . $validate; 
  1668.  
  1669. $field = ''; 
  1670. $label_id = $args['id']; 
  1671. $sort = $args['priority'] ? $args['priority'] : ''; 
  1672. $field_container = '<p class="form-row %1$s" id="%2$s" data-priority="' . esc_attr( $sort ) . '">%3$s</p>'; 
  1673.  
  1674. switch ( $args['type'] ) { 
  1675. case 'country' : 
  1676.  
  1677. $countries = 'shipping_country' === $key ? WC()->countries->get_shipping_countries() : WC()->countries->get_allowed_countries(); 
  1678.  
  1679. if ( 1 === sizeof( $countries ) ) { 
  1680.  
  1681. $field .= '<strong>' . current( array_values( $countries ) ) . '</strong>'; 
  1682.  
  1683. $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" />'; 
  1684.  
  1685. } else { 
  1686.  
  1687. $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>'; 
  1688.  
  1689. foreach ( $countries as $ckey => $cvalue ) { 
  1690. $field .= '<option value="' . esc_attr( $ckey ) . '" ' . selected( $value, $ckey, false ) . '>' . $cvalue . '</option>'; 
  1691.  
  1692. $field .= '</select>'; 
  1693.  
  1694. $field .= '<noscript><input type="submit" name="woocommerce_checkout_update_totals" value="' . esc_attr__( 'Update country', 'woocommerce' ) . '" /></noscript>'; 
  1695.  
  1696.  
  1697. break; 
  1698. case 'state' : 
  1699.  
  1700. /** Get Country */ 
  1701. $country_key = 'billing_state' === $key ? 'billing_country' : 'shipping_country'; 
  1702. $current_cc = WC()->checkout->get_value( $country_key ); 
  1703. $states = WC()->countries->get_states( $current_cc ); 
  1704.  
  1705. if ( is_array( $states ) && empty( $states ) ) { 
  1706.  
  1707. $field_container = '<p class="form-row %1$s" id="%2$s" style="display: none">%3$s</p>'; 
  1708.  
  1709. $field .= '<input type="hidden" class="hidden" name="' . esc_attr( $key ) . '" id="' . esc_attr( $args['id'] ) . '" value="" ' . implode( ' ', $custom_attributes ) . ' placeholder="' . esc_attr( $args['placeholder'] ) . '" />'; 
  1710.  
  1711. } elseif ( is_array( $states ) ) { 
  1712.  
  1713. $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'] ) . '"> 
  1714. <option value="">' . esc_html__( 'Select a state…', 'woocommerce' ) . '</option>'; 
  1715.  
  1716. foreach ( $states as $ckey => $cvalue ) { 
  1717. $field .= '<option value="' . esc_attr( $ckey ) . '" ' . selected( $value, $ckey, false ) . '>' . $cvalue . '</option>'; 
  1718.  
  1719. $field .= '</select>'; 
  1720.  
  1721. } else { 
  1722.  
  1723. $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 ) . ' />'; 
  1724.  
  1725.  
  1726. break; 
  1727. case 'textarea' : 
  1728.  
  1729. $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>'; 
  1730.  
  1731. break; 
  1732. case 'checkbox' : 
  1733.  
  1734. $field = '<label class="checkbox ' . implode( ' ', $args['label_class'] ) . '" ' . implode( ' ', $custom_attributes ) . '> 
  1735. <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 ) . ' /> ' 
  1736. . $args['label'] . $required . '</label>'; 
  1737.  
  1738. break; 
  1739. case 'password' : 
  1740. case 'text' : 
  1741. case 'email' : 
  1742. case 'tel' : 
  1743. case 'number' : 
  1744.  
  1745. $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 ) . ' />'; 
  1746.  
  1747. break; 
  1748. case 'select' : 
  1749.  
  1750. $options = $field = ''; 
  1751.  
  1752. if ( ! empty( $args['options'] ) ) { 
  1753. foreach ( $args['options'] as $option_key => $option_text ) { 
  1754. if ( '' === $option_key ) { 
  1755. // If we have a blank option, select2 needs a placeholder 
  1756. if ( empty( $args['placeholder'] ) ) { 
  1757. $args['placeholder'] = $option_text ? $option_text : __( 'Choose an option', 'woocommerce' ); 
  1758. $custom_attributes[] = 'data-allow_clear="true"'; 
  1759. $options .= '<option value="' . esc_attr( $option_key ) . '" ' . selected( $value, $option_key, false ) . '>' . esc_attr( $option_text ) . '</option>'; 
  1760.  
  1761. $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'] ) . '"> 
  1762. ' . $options . ' 
  1763. </select>'; 
  1764.  
  1765. break; 
  1766. case 'radio' : 
  1767.  
  1768. $label_id = current( array_keys( $args['options'] ) ); 
  1769.  
  1770. if ( ! empty( $args['options'] ) ) { 
  1771. foreach ( $args['options'] as $option_key => $option_text ) { 
  1772. $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 ) . ' />'; 
  1773. $field .= '<label for="' . esc_attr( $args['id'] ) . '_' . esc_attr( $option_key ) . '" class="radio ' . implode( ' ', $args['label_class'] ) . '">' . $option_text . '</label>'; 
  1774.  
  1775. break; 
  1776.  
  1777. if ( ! empty( $field ) ) { 
  1778. $field_html = ''; 
  1779.  
  1780. if ( $args['label'] && 'checkbox' != $args['type'] ) { 
  1781. $field_html .= '<label for="' . esc_attr( $label_id ) . '" class="' . esc_attr( implode( ' ', $args['label_class'] ) ) . '">' . $args['label'] . $required . '</label>'; 
  1782.  
  1783. $field_html .= $field; 
  1784.  
  1785. if ( $args['description'] ) { 
  1786. $field_html .= '<span class="description">' . esc_html( $args['description'] ) . '</span>'; 
  1787.  
  1788. $container_class = esc_attr( implode( ' ', $args['class'] ) ); 
  1789. $container_id = esc_attr( $args['id'] ) . '_field'; 
  1790. $field = sprintf( $field_container, $container_class, $container_id, $field_html ); 
  1791.  
  1792. $field = apply_filters( 'woocommerce_form_field_' . $args['type'], $field, $key, $args, $value ); 
  1793.  
  1794. if ( $args['return'] ) { 
  1795. return $field; 
  1796. } else { 
  1797. echo $field; 
  1798.  
  1799. if ( ! function_exists( 'get_product_search_form' ) ) { 
  1800.  
  1801. /** 
  1802. * Display product search form. 
  1803. * 
  1804. * Will first attempt to locate the product-searchform.php file in either the child or. 
  1805. * the parent, then load it. If it doesn't exist, then the default search form. 
  1806. * will be displayed. 
  1807. * 
  1808. * The default searchform uses html5. 
  1809. * 
  1810. * @subpackage Forms 
  1811. * @param bool $echo (default: true) 
  1812. * @return string 
  1813. */ 
  1814. function get_product_search_form( $echo = true ) { 
  1815. global $product_search_form_index; 
  1816.  
  1817. ob_start(); 
  1818.  
  1819. if ( empty( $product_search_form_index ) ) { 
  1820. $product_search_form_index = 0; 
  1821.  
  1822. do_action( 'pre_get_product_search_form' ); 
  1823.  
  1824. wc_get_template( 'product-searchform.php', array( 
  1825. 'index' => $product_search_form_index++,  
  1826. ) ); 
  1827.  
  1828. $form = apply_filters( 'get_product_search_form', ob_get_clean() ); 
  1829.  
  1830. if ( $echo ) { 
  1831. echo $form; 
  1832. } else { 
  1833. return $form; 
  1834.  
  1835. if ( ! function_exists( 'woocommerce_output_auth_header' ) ) { 
  1836.  
  1837. /** 
  1838. * Output the Auth header. 
  1839. */ 
  1840. function woocommerce_output_auth_header() { 
  1841. wc_get_template( 'auth/header.php' ); 
  1842.  
  1843. if ( ! function_exists( 'woocommerce_output_auth_footer' ) ) { 
  1844.  
  1845. /** 
  1846. * Output the Auth footer. 
  1847. */ 
  1848. function woocommerce_output_auth_footer() { 
  1849. wc_get_template( 'auth/footer.php' ); 
  1850.  
  1851. if ( ! function_exists( 'woocommerce_single_variation' ) ) { 
  1852.  
  1853. /** 
  1854. * Output placeholders for the single variation. 
  1855. */ 
  1856. function woocommerce_single_variation() { 
  1857. echo '<div class="woocommerce-variation single_variation"></div>'; 
  1858.  
  1859. if ( ! function_exists( 'woocommerce_single_variation_add_to_cart_button' ) ) { 
  1860.  
  1861. /** 
  1862. * Output the add to cart button for variations. 
  1863. */ 
  1864. function woocommerce_single_variation_add_to_cart_button() { 
  1865. wc_get_template( 'single-product/add-to-cart/variation-add-to-cart-button.php' ); 
  1866.  
  1867. if ( ! function_exists( 'wc_dropdown_variation_attribute_options' ) ) { 
  1868.  
  1869. /** 
  1870. * Output a list of variation attributes for use in the cart forms. 
  1871. * 
  1872. * @param array $args 
  1873. * @since 2.4.0 
  1874. */ 
  1875. function wc_dropdown_variation_attribute_options( $args = array() ) { 
  1876. $args = wp_parse_args( apply_filters( 'woocommerce_dropdown_variation_attribute_options_args', $args ), array( 
  1877. 'options' => false,  
  1878. 'attribute' => false,  
  1879. 'product' => false,  
  1880. 'selected' => false,  
  1881. 'name' => '',  
  1882. 'id' => '',  
  1883. 'class' => '',  
  1884. 'show_option_none' => __( 'Choose an option', 'woocommerce' ),  
  1885. ) ); 
  1886.  
  1887. $options = $args['options']; 
  1888. $product = $args['product']; 
  1889. $attribute = $args['attribute']; 
  1890. $name = $args['name'] ? $args['name'] : 'attribute_' . sanitize_title( $attribute ); 
  1891. $id = $args['id'] ? $args['id'] : sanitize_title( $attribute ); 
  1892. $class = $args['class']; 
  1893. $show_option_none = $args['show_option_none'] ? true : false; 
  1894. $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. 
  1895.  
  1896. if ( empty( $options ) && ! empty( $product ) && ! empty( $attribute ) ) { 
  1897. $attributes = $product->get_variation_attributes(); 
  1898. $options = $attributes[ $attribute ]; 
  1899.  
  1900. $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' ) . '">'; 
  1901. $html .= '<option value="">' . esc_html( $show_option_none_text ) . '</option>'; 
  1902.  
  1903. if ( ! empty( $options ) ) { 
  1904. if ( $product && taxonomy_exists( $attribute ) ) { 
  1905. // Get terms if this is a taxonomy - ordered. We need the names too. 
  1906. $terms = wc_get_product_terms( $product->get_id(), $attribute, array( 'fields' => 'all' ) ); 
  1907.  
  1908. foreach ( $terms as $term ) { 
  1909. if ( in_array( $term->slug, $options ) ) { 
  1910. $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>'; 
  1911. } else { 
  1912. foreach ( $options as $option ) { 
  1913. // This handles < 2.4.0 bw compatibility where text attributes were not sanitized. 
  1914. $selected = sanitize_title( $args['selected'] ) === $args['selected'] ? selected( $args['selected'], sanitize_title( $option ), false ) : selected( $args['selected'], $option, false ); 
  1915. $html .= '<option value="' . esc_attr( $option ) . '" ' . $selected . '>' . esc_html( apply_filters( 'woocommerce_variation_option_name', $option ) ) . '</option>'; 
  1916.  
  1917. $html .= '</select>'; 
  1918.  
  1919. echo apply_filters( 'woocommerce_dropdown_variation_attribute_options_html', $html, $args ); 
  1920.  
  1921. if ( ! function_exists( 'woocommerce_account_content' ) ) { 
  1922.  
  1923. /** 
  1924. * My Account content output. 
  1925. */ 
  1926. function woocommerce_account_content() { 
  1927. global $wp; 
  1928.  
  1929. foreach ( $wp->query_vars as $key => $value ) { 
  1930. // Ignore pagename param. 
  1931. if ( 'pagename' === $key ) { 
  1932. continue; 
  1933.  
  1934. if ( has_action( 'woocommerce_account_' . $key . '_endpoint' ) ) { 
  1935. do_action( 'woocommerce_account_' . $key . '_endpoint', $value ); 
  1936. return; 
  1937.  
  1938. // No endpoint found? Default to dashboard. 
  1939. wc_get_template( 'myaccount/dashboard.php', array( 
  1940. 'current_user' => get_user_by( 'id', get_current_user_id() ),  
  1941. ) ); 
  1942.  
  1943. if ( ! function_exists( 'woocommerce_account_navigation' ) ) { 
  1944.  
  1945. /** 
  1946. * My Account navigation template. 
  1947. */ 
  1948. function woocommerce_account_navigation() { 
  1949. wc_get_template( 'myaccount/navigation.php' ); 
  1950.  
  1951. if ( ! function_exists( 'woocommerce_account_orders' ) ) { 
  1952.  
  1953. /** 
  1954. * My Account > Orders template. 
  1955. * 
  1956. * @param int $current_page Current page number. 
  1957. */ 
  1958. function woocommerce_account_orders( $current_page ) { 
  1959. $current_page = empty( $current_page ) ? 1 : absint( $current_page ); 
  1960. $customer_orders = wc_get_orders( apply_filters( 'woocommerce_my_account_my_orders_query', array( 'customer' => get_current_user_id(), 'page' => $current_page, 'paginate' => true ) ) ); 
  1961.  
  1962. wc_get_template( 
  1963. 'myaccount/orders.php',  
  1964. array( 
  1965. 'current_page' => absint( $current_page ),  
  1966. 'customer_orders' => $customer_orders,  
  1967. 'has_orders' => 0 < $customer_orders->total,  
  1968. ); 
  1969.  
  1970. if ( ! function_exists( 'woocommerce_account_view_order' ) ) { 
  1971.  
  1972. /** 
  1973. * My Account > View order template. 
  1974. * 
  1975. * @param int $order_id Order ID. 
  1976. */ 
  1977. function woocommerce_account_view_order( $order_id ) { 
  1978. WC_Shortcode_My_Account::view_order( absint( $order_id ) ); 
  1979.  
  1980. if ( ! function_exists( 'woocommerce_account_downloads' ) ) { 
  1981.  
  1982. /** 
  1983. * My Account > Downloads template. 
  1984. */ 
  1985. function woocommerce_account_downloads() { 
  1986. wc_get_template( 'myaccount/downloads.php' ); 
  1987.  
  1988. if ( ! function_exists( 'woocommerce_account_edit_address' ) ) { 
  1989.  
  1990. /** 
  1991. * My Account > Edit address template. 
  1992. * 
  1993. * @param string $type Address type. 
  1994. */ 
  1995. function woocommerce_account_edit_address( $type ) { 
  1996. $type = wc_edit_address_i18n( sanitize_title( $type ), true ); 
  1997.  
  1998. WC_Shortcode_My_Account::edit_address( $type ); 
  1999.  
  2000. if ( ! function_exists( 'woocommerce_account_payment_methods' ) ) { 
  2001.  
  2002. /** 
  2003. * My Account > Downloads template. 
  2004. */ 
  2005. function woocommerce_account_payment_methods() { 
  2006. wc_get_template( 'myaccount/payment-methods.php' ); 
  2007.  
  2008. if ( ! function_exists( 'woocommerce_account_add_payment_method' ) ) { 
  2009.  
  2010. /** 
  2011. * My Account > Add payment method template. 
  2012. */ 
  2013. function woocommerce_account_add_payment_method() { 
  2014. WC_Shortcode_My_Account::add_payment_method(); 
  2015.  
  2016. if ( ! function_exists( 'woocommerce_account_edit_account' ) ) { 
  2017.  
  2018. /** 
  2019. * My Account > Edit account template. 
  2020. */ 
  2021. function woocommerce_account_edit_account() { 
  2022. WC_Shortcode_My_Account::edit_account(); 
  2023.  
  2024. if ( ! function_exists( 'wc_no_products_found' ) ) { 
  2025.  
  2026. /** 
  2027. * Show no products found message. 
  2028. */ 
  2029. function wc_no_products_found() { 
  2030. wc_get_template( 'loop/no-products-found.php' ); 
  2031.  
  2032.  
  2033. if ( ! function_exists( 'wc_get_email_order_items' ) ) { 
  2034. /** 
  2035. * Get HTML for the order items to be shown in emails. 
  2036. * @param WC_Order $order 
  2037. * @param array $args 
  2038. * @since 3.0.0 
  2039. */ 
  2040. function wc_get_email_order_items( $order, $args = array() ) { 
  2041. ob_start(); 
  2042.  
  2043. $defaults = array( 
  2044. 'show_sku' => false,  
  2045. 'show_image' => false,  
  2046. 'image_size' => array( 32, 32 ),  
  2047. 'plain_text' => false,  
  2048. 'sent_to_admin' => false,  
  2049. ); 
  2050.  
  2051. $args = wp_parse_args( $args, $defaults ); 
  2052. $template = $args['plain_text'] ? 'emails/plain/email-order-items.php' : 'emails/email-order-items.php'; 
  2053.  
  2054. wc_get_template( $template, apply_filters( 'woocommerce_email_order_items_args', array( 
  2055. 'order' => $order,  
  2056. 'items' => $order->get_items(),  
  2057. 'show_download_links' => $order->is_download_permitted() && ! $args['sent_to_admin'],  
  2058. 'show_sku' => $args['show_sku'],  
  2059. 'show_purchase_note' => $order->is_paid() && ! $args['sent_to_admin'],  
  2060. 'show_image' => $args['show_image'],  
  2061. 'image_size' => $args['image_size'],  
  2062. 'plain_text' => $args['plain_text'],  
  2063. 'sent_to_admin' => $args['sent_to_admin'],  
  2064. ) ) ); 
  2065.  
  2066. return apply_filters( 'woocommerce_email_order_items_table', ob_get_clean(), $order ); 
  2067.  
  2068. if ( ! function_exists( 'wc_display_item_meta' ) ) { 
  2069. /** 
  2070. * Display item meta data. 
  2071. * @since 3.0.0 
  2072. * @param WC_Item $item 
  2073. * @param array $args 
  2074. * @return string|void 
  2075. */ 
  2076. function wc_display_item_meta( $item, $args = array() ) { 
  2077. $strings = array(); 
  2078. $html = ''; 
  2079. $args = wp_parse_args( $args, array( 
  2080. 'before' => '<ul class="wc-item-meta"><li>',  
  2081. 'after' => '</li></ul>',  
  2082. 'separator' => '</li><li>',  
  2083. 'echo' => true,  
  2084. 'autop' => false,  
  2085. ) ); 
  2086.  
  2087. foreach ( $item->get_formatted_meta_data() as $meta_id => $meta ) { 
  2088. $value = $args['autop'] ? wp_kses_post( wpautop( make_clickable( $meta->display_value ) ) ) : wp_kses_post( make_clickable( $meta->display_value ) ); 
  2089. $strings[] = '<strong class="wc-item-meta-label">' . wp_kses_post( $meta->display_key ) . ':</strong> ' . $value; 
  2090.  
  2091. if ( $strings ) { 
  2092. $html = $args['before'] . implode( $args['separator'], $strings ) . $args['after']; 
  2093.  
  2094. $html = apply_filters( 'woocommerce_display_item_meta', $html, $item, $args ); 
  2095.  
  2096. if ( $args['echo'] ) { 
  2097. echo $html; 
  2098. } else { 
  2099. return $html; 
  2100.  
  2101. if ( ! function_exists( 'wc_display_item_downloads' ) ) { 
  2102. /** 
  2103. * Display item download links. 
  2104. * @since 3.0.0 
  2105. * @param WC_Item $item 
  2106. * @param array $args 
  2107. * @return string|void 
  2108. */ 
  2109. function wc_display_item_downloads( $item, $args = array() ) { 
  2110. $strings = array(); 
  2111. $html = ''; 
  2112. $args = wp_parse_args( $args, array( 
  2113. 'before' => '<ul class ="wc-item-downloads"><li>',  
  2114. 'after' => '</li></ul>',  
  2115. 'separator' => '</li><li>',  
  2116. 'echo' => true,  
  2117. 'show_url' => false,  
  2118. ) ); 
  2119.  
  2120. if ( is_object( $item ) && $item->is_type( 'line_item' ) && ( $downloads = $item->get_item_downloads() ) ) { 
  2121. $i = 0; 
  2122. foreach ( $downloads as $file ) { 
  2123. $i ++; 
  2124.  
  2125. if ( $args['show_url'] ) { 
  2126. $strings[] = '<strong class="wc-item-download-label">' . esc_html( $file['name'] ) . ':</strong> ' . esc_html( $file['download_url'] ); 
  2127. } else { 
  2128. $prefix = sizeof( $downloads ) > 1 ? sprintf( __( 'Download %d', 'woocommerce' ), $i ) : __( 'Download', 'woocommerce' ); 
  2129. $strings[] = '<strong class="wc-item-download-label">' . $prefix . ':</strong> <a href="' . esc_url( $file['download_url'] ) . '" target="_blank">' . esc_html( $file['name'] ) . '</a>'; 
  2130.  
  2131. if ( $strings ) { 
  2132. $html = $args['before'] . implode( $args['separator'], $strings ) . $args['after']; 
  2133.  
  2134. $html = apply_filters( 'woocommerce_display_item_downloads', $html, $item, $args ); 
  2135.  
  2136. if ( $args['echo'] ) { 
  2137. echo $html; 
  2138. } else { 
  2139. return $html; 
  2140.  
  2141. if ( ! function_exists( 'woocommerce_photoswipe' ) ) { 
  2142.  
  2143. /** 
  2144. * Get the shop sidebar template. 
  2145. * 
  2146. */ 
  2147. function woocommerce_photoswipe() { 
  2148. if ( current_theme_supports( 'wc-product-gallery-lightbox' ) ) { 
  2149. wc_get_template( 'single-product/photoswipe.php' ); 
  2150.  
  2151. /** 
  2152. * Outputs a list of product attributes for a product. 
  2153. * @since 3.0.0 
  2154. * @param WC_Product $product 
  2155. */ 
  2156. function wc_display_product_attributes( $product ) { 
  2157. wc_get_template( 'single-product/product-attributes.php', array( 
  2158. 'product' => $product,  
  2159. 'attributes' => array_filter( $product->get_attributes(), 'wc_attributes_array_filter_visible' ),  
  2160. 'display_dimensions' => apply_filters( 'wc_product_enable_dimensions_display', $product->has_weight() || $product->has_dimensions() ),  
  2161. ) ); 
  2162.  
  2163. /** 
  2164. * Get HTML to show product stock. 
  2165. * @since 3.0.0 
  2166. * @param WC_Product $product 
  2167. * @return string 
  2168. */ 
  2169. function wc_get_stock_html( $product ) { 
  2170.  
  2171. $html = ''; 
  2172. $availability = $product->get_availability(); 
  2173.  
  2174. if ( ! empty( $availability['availability'] ) ) { 
  2175. ob_start(); 
  2176.  
  2177. wc_get_template( 'single-product/stock.php', array( 
  2178. 'product' => $product,  
  2179. 'class' => $availability['class'],  
  2180. 'availability' => $availability['availability'],  
  2181. ) ); 
  2182.  
  2183. $html = ob_get_clean(); 
  2184.  
  2185. if ( has_filter( 'woocommerce_stock_html' ) ) { 
  2186. wc_deprecated_function( 'The woocommerce_stock_html filter', '', 'woocommerce_get_stock_html' ); 
  2187. $html = apply_filters( 'woocommerce_stock_html', $html, $availability['availability'], $product ); 
  2188.  
  2189. return apply_filters( 'woocommerce_get_stock_html', $html, $product ); 
  2190.  
  2191. /** 
  2192. * Get HTML for ratings. 
  2193. * 
  2194. * @since 3.0.0 
  2195. * @param float $rating Rating being shown. 
  2196. * @return string 
  2197. */ 
  2198. function wc_get_rating_html( $rating ) { 
  2199. if ( $rating > 0 ) { 
  2200. $rating_html = '<div class="star-rating" title="' . sprintf( esc_attr__( 'Rated %s out of 5', 'woocommerce' ), $rating ) . '">'; 
  2201. $rating_html .= '<span style="width:' . ( ( $rating / 5 ) * 100 ) . '%"><strong class="rating">' . $rating . '</strong> ' . esc_html__( 'out of 5', 'woocommerce' ) . '</span>'; 
  2202. $rating_html .= '</div>'; 
  2203. } else { 
  2204. $rating_html = ''; 
  2205. return apply_filters( 'woocommerce_product_get_rating_html', $rating_html, $rating ); 
  2206.  
  2207. /** 
  2208. * Returns a 'from' prefix if you want to show where prices start at. 
  2209. * 
  2210. * @since 3.0.0 
  2211. * @return string 
  2212. */ 
  2213. function wc_get_price_html_from_text() { 
  2214. return apply_filters( 'woocommerce_get_price_html_from_text', '<span class="from">' . _x( 'From:', 'min_price', 'woocommerce' ) . ' </span>' ); 
  2215.  
  2216. /** 
  2217. * Get logout endpoint. 
  2218. * 
  2219. * @since 2.6.9 
  2220. * @return string 
  2221. */ 
  2222. function wc_logout_url( $redirect = '' ) { 
  2223. $logout_endpoint = get_option( 'woocommerce_logout_endpoint' ); 
  2224. $redirect = $redirect ? $redirect : wc_get_page_permalink( 'myaccount' ); 
  2225.  
  2226. if ( $logout_endpoint ) { 
  2227. return wc_get_endpoint_url( 'customer-logout', '', $redirect ); 
  2228. } else { 
  2229. return wp_logout_url( $redirect ); 
.