PageRenderTime 56ms CodeModel.GetById 15ms RepoModel.GetById 1ms app.codeStats 0ms

/woocommerce-core-functions.php

https://github.com/CammoKing/woocommerce
PHP | 1848 lines | 907 code | 319 blank | 622 comment | 167 complexity | b04f9d7e55896fde5af5dda864a60542 MD5 | raw file
Possible License(s): GPL-3.0
  1. <?php
  2. /**
  3. * WooCommerce Core Functions
  4. *
  5. * Functions available on both the front-end and admin.
  6. *
  7. * @author WooThemes
  8. * @category Core
  9. * @package WooCommerce/Functions
  10. * @version 1.6.4
  11. */
  12. if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
  13. /**
  14. * Hooks used in admin and frontend
  15. */
  16. add_filter( 'woocommerce_coupon_code', 'sanitize_text_field' );
  17. add_filter( 'woocommerce_coupon_code', 'strtolower' ); // Coupons case-insensitive by default
  18. add_filter( 'woocommerce_stock_amount', 'absint' ); // Stock amounts are integers by default
  19. /**
  20. * Main function for returning products, uses the WC_Product_Factory class.
  21. *
  22. * @access public
  23. * @param mixed $the_product Post object or post ID of the product.
  24. * @param array $args (default: array()) Contains all arguments to be used to get this product.
  25. * @return void
  26. */
  27. function get_product( $the_product = false, $args = array() ) {
  28. global $woocommerce;
  29. return $woocommerce->product_factory->get_product( $the_product, $args );
  30. }
  31. /**
  32. * woocommerce_get_dimension function.
  33. *
  34. * Normalise dimensions, unify to cm then convert to wanted unit value
  35. *
  36. * Usage: woocommerce_get_dimension(55, 'in');
  37. *
  38. * @access public
  39. * @param mixed $dim
  40. * @param mixed $to_unit 'in', 'm', 'cm', 'm'
  41. * @return float
  42. */
  43. function woocommerce_get_dimension( $dim, $to_unit ) {
  44. $from_unit = strtolower( get_option( 'woocommerce_dimension_unit' ) );
  45. $to_unit = strtolower( $to_unit );
  46. // Unify all units to cm first
  47. if ( $from_unit !== $to_unit ) {
  48. switch ( $from_unit ) {
  49. case 'in':
  50. $dim *= 2.54;
  51. break;
  52. case 'm':
  53. $dim *= 100;
  54. break;
  55. case 'mm':
  56. $dim *= 0.1;
  57. break;
  58. case 'yd':
  59. $dim *= 0.010936133;
  60. break;
  61. }
  62. // Output desired unit
  63. switch ( $to_unit ) {
  64. case 'in':
  65. $dim *= 0.3937;
  66. break;
  67. case 'm':
  68. $dim *= 0.01;
  69. break;
  70. case 'mm':
  71. $dim *= 10;
  72. break;
  73. case 'yd':
  74. $dim *= 91.44;
  75. break;
  76. }
  77. }
  78. return ( $dim < 0 ) ? 0 : $dim;
  79. }
  80. /**
  81. * woocommerce_get_weight function.
  82. *
  83. * Normalise weights, unify to cm then convert to wanted unit value
  84. *
  85. * Usage: woocommerce_get_weight(55, 'kg');
  86. *
  87. * @access public
  88. * @param mixed $weight
  89. * @param mixed $to_unit 'g', 'kg', 'lbs'
  90. * @return float
  91. */
  92. function woocommerce_get_weight( $weight, $to_unit ) {
  93. $from_unit = strtolower( get_option('woocommerce_weight_unit') );
  94. $to_unit = strtolower( $to_unit );
  95. //Unify all units to kg first
  96. if ( $from_unit !== $to_unit ) {
  97. switch ( $from_unit ) {
  98. case 'g':
  99. $weight *= 0.001;
  100. break;
  101. case 'lbs':
  102. $weight *= 0.4536;
  103. break;
  104. case 'oz':
  105. $weight *= 0.0283;
  106. break;
  107. }
  108. // Output desired unit
  109. switch ( $to_unit ) {
  110. case 'g':
  111. $weight *= 1000;
  112. break;
  113. case 'lbs':
  114. $weight *= 2.2046;
  115. break;
  116. case 'oz':
  117. $weight *= 35.274;
  118. break;
  119. }
  120. }
  121. return ( $weight < 0 ) ? 0 : $weight;
  122. }
  123. /**
  124. * Get the placeholder for products etc
  125. *
  126. * @access public
  127. * @return string
  128. */
  129. function woocommerce_placeholder_img_src() {
  130. global $woocommerce;
  131. return apply_filters('woocommerce_placeholder_img_src', $woocommerce->plugin_url() . '/assets/images/placeholder.png' );
  132. }
  133. /**
  134. * Send HTML emails from WooCommerce
  135. *
  136. * @access public
  137. * @param mixed $to
  138. * @param mixed $subject
  139. * @param mixed $message
  140. * @param string $headers (default: "Content-Type: text/html\r\n")
  141. * @param string $attachments (default: "")
  142. * @return void
  143. */
  144. function woocommerce_mail( $to, $subject, $message, $headers = "Content-Type: text/html\r\n", $attachments = "" ) {
  145. global $woocommerce;
  146. $mailer = $woocommerce->mailer();
  147. $mailer->send( $to, $subject, $message, $headers, $attachments );
  148. }
  149. if ( ! function_exists( 'woocommerce_get_page_id' ) ) {
  150. /**
  151. * WooCommerce page IDs
  152. *
  153. * retrieve page ids - used for myaccount, edit_address, change_password, shop, cart, checkout, pay, view_order, thanks, terms, order_tracking
  154. *
  155. * returns -1 if no page is found
  156. *
  157. * @access public
  158. * @param string $page
  159. * @return int
  160. */
  161. function woocommerce_get_page_id( $page ) {
  162. $page = apply_filters('woocommerce_get_' . $page . '_page_id', get_option('woocommerce_' . $page . '_page_id'));
  163. return ( $page ) ? $page : -1;
  164. }
  165. }
  166. if ( ! function_exists( 'woocommerce_empty_cart' ) ) {
  167. /**
  168. * WooCommerce clear cart
  169. *
  170. * Clears the cart session when called
  171. *
  172. * @access public
  173. * @return void
  174. */
  175. function woocommerce_empty_cart() {
  176. global $woocommerce;
  177. if ( ! isset( $woocommerce->cart ) || $woocommerce->cart == '' )
  178. $woocommerce->cart = new WC_Cart();
  179. $woocommerce->cart->empty_cart( false );
  180. }
  181. }
  182. if ( ! function_exists( 'woocommerce_disable_admin_bar' ) ) {
  183. /**
  184. * WooCommerce disable admin bar
  185. *
  186. * @access public
  187. * @param bool $show_admin_bar
  188. * @return bool
  189. */
  190. function woocommerce_disable_admin_bar( $show_admin_bar ) {
  191. if ( get_option('woocommerce_lock_down_admin')=='yes' && ! ( current_user_can('edit_posts') || current_user_can('manage_woocommerce') ) ) {
  192. $show_admin_bar = false;
  193. }
  194. return $show_admin_bar;
  195. }
  196. }
  197. /**
  198. * Load the cart upon login
  199. *
  200. * @access public
  201. * @param mixed $user_login
  202. * @param mixed $user
  203. * @return void
  204. */
  205. function woocommerce_load_persistent_cart( $user_login, $user ) {
  206. global $woocommerce;
  207. $saved_cart = get_user_meta( $user->ID, '_woocommerce_persistent_cart', true );
  208. if ( $saved_cart )
  209. if ( empty( $woocommerce->session->cart ) || ! is_array( $woocommerce->session->cart ) || sizeof( $woocommerce->session->cart ) == 0 )
  210. $woocommerce->session->cart = $saved_cart['cart'];
  211. }
  212. /**
  213. * is_woocommerce - Returns true if on a page which uses WooCommerce templates (cart and checkout are standard pages with shortcodes and thus are not included)
  214. *
  215. * @access public
  216. * @return bool
  217. */
  218. function is_woocommerce() {
  219. return ( is_shop() || is_product_category() || is_product_tag() || is_product() ) ? true : false;
  220. }
  221. if ( ! function_exists( 'is_shop' ) ) {
  222. /**
  223. * is_shop - Returns true when viewing the product type archive (shop).
  224. *
  225. * @access public
  226. * @return bool
  227. */
  228. function is_shop() {
  229. return ( is_post_type_archive( 'product' ) || is_page( woocommerce_get_page_id( 'shop' ) ) ) ? true : false;
  230. }
  231. }
  232. if ( ! function_exists( 'is_product_category' ) ) {
  233. /**
  234. * is_product_category - Returns true when viewing a product category.
  235. *
  236. * @access public
  237. * @param string $term (default: '') The term slug your checking for. Leave blank to return true on any.
  238. * @return bool
  239. */
  240. function is_product_category( $term = '' ) {
  241. return is_tax( 'product_cat', $term );
  242. }
  243. }
  244. if ( ! function_exists( 'is_product_tag' ) ) {
  245. /**
  246. * is_product_tag - Returns true when viewing a product tag.
  247. *
  248. * @access public
  249. * @param string $term (default: '') The term slug your checking for. Leave blank to return true on any.
  250. * @return bool
  251. */
  252. function is_product_tag( $term = '' ) {
  253. return is_tax( 'product_tag', $term );
  254. }
  255. }
  256. if ( ! function_exists( 'is_product' ) ) {
  257. /**
  258. * is_product - Returns true when viewing a single product.
  259. *
  260. * @access public
  261. * @return bool
  262. */
  263. function is_product() {
  264. return is_singular( array( 'product' ) );
  265. }
  266. }
  267. if ( ! function_exists( 'is_cart' ) ) {
  268. /**
  269. * is_cart - Returns true when viewing the cart page.
  270. *
  271. * @access public
  272. * @return bool
  273. */
  274. function is_cart() {
  275. return is_page( woocommerce_get_page_id( 'cart' ) );
  276. }
  277. }
  278. if ( ! function_exists( 'is_checkout' ) ) {
  279. /**
  280. * is_checkout - Returns true when viewing the checkout page.
  281. *
  282. * @access public
  283. * @return bool
  284. */
  285. function is_checkout() {
  286. return ( is_page( woocommerce_get_page_id( 'checkout' ) ) || is_page( woocommerce_get_page_id( 'pay' ) ) ) ? true : false;
  287. }
  288. }
  289. if ( ! function_exists( 'is_account_page' ) ) {
  290. /**
  291. * is_account_page - Returns true when viewing an account page.
  292. *
  293. * @access public
  294. * @return bool
  295. */
  296. function is_account_page() {
  297. return ( is_page( woocommerce_get_page_id( 'myaccount' ) ) || is_page( woocommerce_get_page_id( 'edit_address' ) ) || is_page( woocommerce_get_page_id( 'view_order' ) ) || is_page( woocommerce_get_page_id( 'change_password' ) ) ) ? true : false;
  298. }
  299. }
  300. if ( ! function_exists( 'is_order_received_page' ) ) {
  301. /**
  302. * is_order_received_page - Returns true when viewing the order received page.
  303. *
  304. * @access public
  305. * @return bool
  306. */
  307. function is_order_received_page() {
  308. return ( is_page( woocommerce_get_page_id( 'thanks' ) ) ) ? true : false;
  309. }
  310. }
  311. if ( ! function_exists( 'is_ajax' ) ) {
  312. /**
  313. * is_ajax - Returns true when the page is loaded via ajax.
  314. *
  315. * @access public
  316. * @return bool
  317. */
  318. function is_ajax() {
  319. if ( defined('DOING_AJAX') )
  320. return true;
  321. return ( isset( $_SERVER['HTTP_X_REQUESTED_WITH'] ) && strtolower( $_SERVER['HTTP_X_REQUESTED_WITH'] ) == 'xmlhttprequest' ) ? true : false;
  322. }
  323. }
  324. if ( ! function_exists( 'is_filtered' ) ) {
  325. /**
  326. * is_filtered - Returns true when filtering products using layered nav or price sliders.
  327. *
  328. * @access public
  329. * @return bool
  330. */
  331. function is_filtered() {
  332. global $_chosen_attributes;
  333. return ( sizeof( $_chosen_attributes ) > 0 || ( isset( $_GET['max_price'] ) && isset( $_GET['min_price'] ) ) ) ? true : false;
  334. }
  335. }
  336. /**
  337. * Get template part (for templates like the shop-loop).
  338. *
  339. * @access public
  340. * @param mixed $slug
  341. * @param string $name (default: '')
  342. * @return void
  343. */
  344. function woocommerce_get_template_part( $slug, $name = '' ) {
  345. global $woocommerce;
  346. $template = '';
  347. // Look in yourtheme/slug-name.php and yourtheme/woocommerce/slug-name.php
  348. if ( $name )
  349. $template = locate_template( array ( "{$slug}-{$name}.php", "{$woocommerce->template_url}{$slug}-{$name}.php" ) );
  350. // Get default slug-name.php
  351. if ( !$template && $name && file_exists( $woocommerce->plugin_path() . "/templates/{$slug}-{$name}.php" ) )
  352. $template = $woocommerce->plugin_path() . "/templates/{$slug}-{$name}.php";
  353. // If template file doesn't exist, look in yourtheme/slug.php and yourtheme/woocommerce/slug.php
  354. if ( !$template )
  355. $template = locate_template( array ( "{$slug}.php", "{$woocommerce->template_url}{$slug}.php" ) );
  356. if ( $template )
  357. load_template( $template, false );
  358. }
  359. /**
  360. * Get other templates (e.g. product attributes) passing attributes and including the file.
  361. *
  362. * @access public
  363. * @param mixed $template_name
  364. * @param array $args (default: array())
  365. * @param string $template_path (default: '')
  366. * @param string $default_path (default: '')
  367. * @return void
  368. */
  369. function woocommerce_get_template( $template_name, $args = array(), $template_path = '', $default_path = '' ) {
  370. global $woocommerce;
  371. if ( $args && is_array($args) )
  372. extract( $args );
  373. $located = woocommerce_locate_template( $template_name, $template_path, $default_path );
  374. do_action( 'woocommerce_before_template_part', $template_name, $template_path, $located );
  375. include( $located );
  376. do_action( 'woocommerce_after_template_part', $template_name, $template_path, $located );
  377. }
  378. /**
  379. * Locate a template and return the path for inclusion.
  380. *
  381. * This is the load order:
  382. *
  383. * yourtheme / $template_path / $template_name
  384. * yourtheme / $template_name
  385. * $default_path / $template_name
  386. *
  387. * @access public
  388. * @param mixed $template_name
  389. * @param string $template_path (default: '')
  390. * @param string $default_path (default: '')
  391. * @return string
  392. */
  393. function woocommerce_locate_template( $template_name, $template_path = '', $default_path = '' ) {
  394. global $woocommerce;
  395. if ( ! $template_path ) $template_path = $woocommerce->template_url;
  396. if ( ! $default_path ) $default_path = $woocommerce->plugin_path() . '/templates/';
  397. // Look within passed path within the theme - this is priority
  398. $template = locate_template(
  399. array(
  400. $template_path . $template_name,
  401. $template_name
  402. )
  403. );
  404. // Get default template
  405. if ( ! $template )
  406. $template = $default_path . $template_name;
  407. // Return what we found
  408. return apply_filters('woocommerce_locate_template', $template, $template_name, $template_path);
  409. }
  410. /**
  411. * Get Currency.
  412. *
  413. * @access public
  414. * @return string
  415. */
  416. function get_woocommerce_currency() {
  417. return apply_filters( 'woocommerce_currency', get_option('woocommerce_currency') );
  418. }
  419. /**
  420. * Get Currency symbol.
  421. *
  422. * @access public
  423. * @param string $currency (default: '')
  424. * @return string
  425. */
  426. function get_woocommerce_currency_symbol( $currency = '' ) {
  427. if ( ! $currency ) $currency = get_woocommerce_currency();
  428. $currency_symbol = '';
  429. switch ($currency) :
  430. case 'BRL' : $currency_symbol = '&#82;&#36;'; break;
  431. case 'AUD' : $currency_symbol = '&#36;'; break;
  432. case 'CAD' : $currency_symbol = '&#36;'; break;
  433. case 'MXN' : $currency_symbol = '&#36;'; break;
  434. case 'NZD' : $currency_symbol = '&#36;'; break;
  435. case 'HKD' : $currency_symbol = '&#36;'; break;
  436. case 'SGD' : $currency_symbol = '&#36;'; break;
  437. case 'USD' : $currency_symbol = '&#36;'; break;
  438. case 'EUR' : $currency_symbol = '&euro;'; break;
  439. case 'CNY' : $currency_symbol = '&yen;'; break;
  440. case 'RMB' : $currency_symbol = '&yen;'; break;
  441. case 'JPY' : $currency_symbol = '&yen;'; break;
  442. case 'TRY' : $currency_symbol = '&#84;&#76;'; break;
  443. case 'NOK' : $currency_symbol = '&#107;&#114;'; break;
  444. case 'ZAR' : $currency_symbol = '&#82;'; break;
  445. case 'CZK' : $currency_symbol = '&#75;&#269;'; break;
  446. case 'MYR' : $currency_symbol = '&#82;&#77;'; break;
  447. case 'DKK' : $currency_symbol = '&#107;&#114;'; break;
  448. case 'HUF' : $currency_symbol = '&#70;&#116;'; break;
  449. case 'ILS' : $currency_symbol = '&#8362;'; break;
  450. case 'PHP' : $currency_symbol = '&#8369;'; break;
  451. case 'PLN' : $currency_symbol = '&#122;&#322;'; break;
  452. case 'SEK' : $currency_symbol = '&#107;&#114;'; break;
  453. case 'CHF' : $currency_symbol = '&#67;&#72;&#70;'; break;
  454. case 'TWD' : $currency_symbol = '&#78;&#84;&#36;'; break;
  455. case 'THB' : $currency_symbol = '&#3647;'; break;
  456. case 'GBP' : $currency_symbol = '&pound;'; break;
  457. case 'RON' : $currency_symbol = 'lei'; break;
  458. default : $currency_symbol = ''; break;
  459. endswitch;
  460. return apply_filters( 'woocommerce_currency_symbol', $currency_symbol, $currency );
  461. }
  462. /**
  463. * Format the price with a currency symbol.
  464. *
  465. * @access public
  466. * @param float $price
  467. * @param array $args (default: array())
  468. * @return string
  469. */
  470. function woocommerce_price( $price, $args = array() ) {
  471. global $woocommerce;
  472. extract( shortcode_atts( array(
  473. 'ex_tax_label' => '0'
  474. ), $args ) );
  475. $return = '';
  476. $num_decimals = (int) get_option( 'woocommerce_price_num_decimals' );
  477. $currency_pos = get_option( 'woocommerce_currency_pos' );
  478. $currency_symbol = get_woocommerce_currency_symbol();
  479. $price = apply_filters( 'raw_woocommerce_price', (double) $price );
  480. $price = number_format( $price, $num_decimals, stripslashes( get_option( 'woocommerce_price_decimal_sep' ) ), stripslashes( get_option( 'woocommerce_price_thousand_sep' ) ) );
  481. if ( get_option( 'woocommerce_price_trim_zeros' ) == 'yes' && $num_decimals > 0 )
  482. $price = woocommerce_trim_zeros( $price );
  483. $return = '<span class="amount">' . sprintf( get_woocommerce_price_format(), $currency_symbol, $price ) . '</span>';
  484. if ( $ex_tax_label && get_option( 'woocommerce_calc_taxes' ) == 'yes' )
  485. $return .= ' <small>' . $woocommerce->countries->ex_tax_or_vat() . '</small>';
  486. return $return;
  487. }
  488. function get_woocommerce_price_format() {
  489. $currency_pos = get_option( 'woocommerce_currency_pos' );
  490. switch ( $currency_pos ) {
  491. case 'left' :
  492. return '%1$s%2$s';
  493. case 'right' :
  494. return '%2$s%1$s';
  495. case 'left_space' :
  496. return '%1$s&nbsp;%2$s';
  497. case 'right_space' :
  498. return '%2$s&nbsp;%1$s';
  499. }
  500. }
  501. /**
  502. * Trim trailing zeros off prices.
  503. *
  504. * @access public
  505. * @param mixed $price
  506. * @return string
  507. */
  508. function woocommerce_trim_zeros( $price ) {
  509. return preg_replace( '/' . preg_quote( get_option( 'woocommerce_price_decimal_sep' ), '/' ) . '0++$/', '', $price );
  510. }
  511. /**
  512. * Formal decimal numbers - format to 4 dp and remove trailing zeros.
  513. *
  514. * @access public
  515. * @param mixed $number
  516. * @return string
  517. */
  518. function woocommerce_format_decimal( $number ) {
  519. $number = number_format( (float) $number, get_option( 'woocommerce_price_num_decimals' ), '.', '' );
  520. if ( strstr( $number, '.' ) )
  521. $number = rtrim( rtrim( $number, '0' ), '.' );
  522. return $number;
  523. }
  524. /**
  525. * Formal total costs - format to the number of decimal places for the base currency.
  526. *
  527. * @access public
  528. * @param mixed $number
  529. * @return float
  530. */
  531. function woocommerce_format_total( $number ) {
  532. return number_format( (float) $number, get_option( 'woocommerce_price_num_decimals' ), '.', '' );
  533. }
  534. /**
  535. * Clean variables
  536. *
  537. * @access public
  538. * @param string $var
  539. * @return string
  540. */
  541. function woocommerce_clean( $var ) {
  542. return sanitize_text_field( $var );
  543. }
  544. /**
  545. * Merge two arrays
  546. *
  547. * @access public
  548. * @param array $a1
  549. * @param array $a2
  550. * @return array
  551. */
  552. function woocommerce_array_overlay( $a1, $a2 ) {
  553. foreach( $a1 as $k => $v ) {
  554. if ( ! array_key_exists( $k, $a2 ) )
  555. continue;
  556. if ( is_array( $v ) && is_array( $a2[ $k ] ) ) {
  557. $a1[ $k ] = woocommerce_array_overlay( $v, $a2[ $k ] );
  558. } else {
  559. $a1[ $k ] = $a2[ $k ];
  560. }
  561. }
  562. return $a1;
  563. }
  564. /**
  565. * Get top term
  566. * http://wordpress.stackexchange.com/questions/24794/get-the-the-top-level-parent-of-a-custom-taxonomy-term
  567. *
  568. * @access public
  569. * @param int $term_id
  570. * @param string $taxonomy
  571. * @return int
  572. */
  573. function woocommerce_get_term_top_most_parent( $term_id, $taxonomy ) {
  574. // start from the current term
  575. $parent = get_term_by( 'id', $term_id, $taxonomy );
  576. // climb up the hierarchy until we reach a term with parent = '0'
  577. while ( $parent->parent != '0' ) {
  578. $term_id = $parent->parent;
  579. $parent = get_term_by( 'id', $term_id, $taxonomy);
  580. }
  581. return $parent;
  582. }
  583. /**
  584. * Variation Formatting
  585. *
  586. * Gets a formatted version of variation data or item meta
  587. *
  588. * @access public
  589. * @param string $variation (default: '')
  590. * @param bool $flat (default: false)
  591. * @return string
  592. */
  593. function woocommerce_get_formatted_variation( $variation = '', $flat = false ) {
  594. global $woocommerce;
  595. if ( is_array( $variation ) ) {
  596. if ( ! $flat )
  597. $return = '<dl class="variation">';
  598. else
  599. $return = '';
  600. $variation_list = array();
  601. foreach ( $variation as $name => $value ) {
  602. if ( ! $value )
  603. continue;
  604. // If this is a term slug, get the term's nice name
  605. if ( taxonomy_exists( esc_attr( str_replace( 'attribute_', '', $name ) ) ) ) {
  606. $term = get_term_by( 'slug', $value, esc_attr( str_replace( 'attribute_', '', $name ) ) );
  607. if ( ! is_wp_error( $term ) && $term->name )
  608. $value = $term->name;
  609. } else {
  610. $value = ucfirst($value);
  611. }
  612. if ( $flat )
  613. $variation_list[] = $woocommerce->attribute_label(str_replace('attribute_', '', $name)).': '.$value;
  614. else
  615. $variation_list[] = '<dt>'.$woocommerce->attribute_label(str_replace('attribute_', '', $name)).':</dt><dd>'.$value.'</dd>';
  616. }
  617. if ( $flat )
  618. $return .= implode( ', ', $variation_list );
  619. else
  620. $return .= implode( '', $variation_list );
  621. if ( ! $flat )
  622. $return .= '</dl>';
  623. return $return;
  624. }
  625. }
  626. if ( ! function_exists( 'woocommerce_rgb_from_hex' ) ) {
  627. /**
  628. * Hex darker/lighter/contrast functions for colours
  629. *
  630. * @access public
  631. * @param mixed $color
  632. * @return string
  633. */
  634. function woocommerce_rgb_from_hex( $color ) {
  635. $color = str_replace( '#', '', $color );
  636. // Convert shorthand colors to full format, e.g. "FFF" -> "FFFFFF"
  637. $color = preg_replace( '~^(.)(.)(.)$~', '$1$1$2$2$3$3', $color );
  638. $rgb['R'] = hexdec( $color{0}.$color{1} );
  639. $rgb['G'] = hexdec( $color{2}.$color{3} );
  640. $rgb['B'] = hexdec( $color{4}.$color{5} );
  641. return $rgb;
  642. }
  643. }
  644. if ( ! function_exists( 'woocommerce_hex_darker' ) ) {
  645. /**
  646. * Hex darker/lighter/contrast functions for colours
  647. *
  648. * @access public
  649. * @param mixed $color
  650. * @param int $factor (default: 30)
  651. * @return string
  652. */
  653. function woocommerce_hex_darker( $color, $factor = 30 ) {
  654. $base = woocommerce_rgb_from_hex( $color );
  655. $color = '#';
  656. foreach ($base as $k => $v) :
  657. $amount = $v / 100;
  658. $amount = round($amount * $factor);
  659. $new_decimal = $v - $amount;
  660. $new_hex_component = dechex($new_decimal);
  661. if(strlen($new_hex_component) < 2) :
  662. $new_hex_component = "0".$new_hex_component;
  663. endif;
  664. $color .= $new_hex_component;
  665. endforeach;
  666. return $color;
  667. }
  668. }
  669. if ( ! function_exists( 'woocommerce_hex_lighter' ) ) {
  670. /**
  671. * Hex darker/lighter/contrast functions for colours
  672. *
  673. * @access public
  674. * @param mixed $color
  675. * @param int $factor (default: 30)
  676. * @return string
  677. */
  678. function woocommerce_hex_lighter( $color, $factor = 30 ) {
  679. $base = woocommerce_rgb_from_hex( $color );
  680. $color = '#';
  681. foreach ($base as $k => $v) :
  682. $amount = 255 - $v;
  683. $amount = $amount / 100;
  684. $amount = round($amount * $factor);
  685. $new_decimal = $v + $amount;
  686. $new_hex_component = dechex($new_decimal);
  687. if(strlen($new_hex_component) < 2) :
  688. $new_hex_component = "0".$new_hex_component;
  689. endif;
  690. $color .= $new_hex_component;
  691. endforeach;
  692. return $color;
  693. }
  694. }
  695. if ( ! function_exists( 'woocommerce_light_or_dark' ) ) {
  696. /**
  697. * Detect if we should use a light or dark colour on a background colour
  698. *
  699. * @access public
  700. * @param mixed $color
  701. * @param string $dark (default: '#000000')
  702. * @param string $light (default: '#FFFFFF')
  703. * @return string
  704. */
  705. function woocommerce_light_or_dark( $color, $dark = '#000000', $light = '#FFFFFF' ) {
  706. //return ( hexdec( $color ) > 0xffffff / 2 ) ? $dark : $light;
  707. $hex = str_replace( '#', '', $color );
  708. $c_r = hexdec( substr( $hex, 0, 2 ) );
  709. $c_g = hexdec( substr( $hex, 2, 2 ) );
  710. $c_b = hexdec( substr( $hex, 4, 2 ) );
  711. $brightness = ( ( $c_r * 299 ) + ( $c_g * 587 ) + ( $c_b * 114 ) ) / 1000;
  712. return $brightness > 155 ? $dark : $light;
  713. }
  714. }
  715. if ( ! function_exists( 'woocommerce_format_hex' ) ) {
  716. /**
  717. * Format string as hex
  718. *
  719. * @access public
  720. * @param string $hex
  721. * @return string
  722. */
  723. function woocommerce_format_hex( $hex ) {
  724. $hex = trim( str_replace( '#', '', $hex ) );
  725. if ( strlen( $hex ) == 3 ) {
  726. $hex = $hex[0] . $hex[0] . $hex[1] . $hex[1] . $hex[2] . $hex[2];
  727. }
  728. if ( $hex ) return '#' . $hex;
  729. }
  730. }
  731. /**
  732. * Exclude order comments from queries and RSS
  733. *
  734. * This code should exclude shop_order comments from queries. Some queries (like the recent comments widget on the dashboard) are hardcoded
  735. * and are not filtered, however, the code current_user_can( 'read_post', $comment->comment_post_ID ) should keep them safe since only admin and
  736. * shop managers can view orders anyway.
  737. *
  738. * The frontend view order pages get around this filter by using remove_filter('comments_clauses', 'woocommerce_exclude_order_comments');
  739. *
  740. * @access public
  741. * @param array $clauses
  742. * @return array
  743. */
  744. function woocommerce_exclude_order_comments( $clauses ) {
  745. global $wpdb, $typenow, $pagenow;
  746. if ( is_admin() && ( $typenow == 'shop_order' || $pagenow == 'edit-comments.php' ) && current_user_can( 'manage_woocommerce' ) )
  747. return $clauses; // Don't hide when viewing orders in admin
  748. if ( ! $clauses['join'] )
  749. $clauses['join'] = '';
  750. if ( ! strstr( $clauses['join'], "JOIN $wpdb->posts" ) )
  751. $clauses['join'] .= " LEFT JOIN $wpdb->posts ON $wpdb->comments.comment_post_ID = $wpdb->posts.ID ";
  752. if ( $clauses['where'] )
  753. $clauses['where'] .= ' AND ';
  754. $clauses['where'] .= " $wpdb->posts.post_type NOT IN ('shop_order') ";
  755. return $clauses;
  756. }
  757. add_filter( 'comments_clauses', 'woocommerce_exclude_order_comments', 10, 1);
  758. /**
  759. * Exclude order comments from queries and RSS
  760. *
  761. * @access public
  762. * @param string $join
  763. * @return string
  764. */
  765. function woocommerce_exclude_order_comments_from_feed_join( $join ) {
  766. global $wpdb;
  767. if ( ! $join )
  768. $join = " LEFT JOIN $wpdb->posts ON $wpdb->comments.comment_post_ID = $wpdb->posts.ID ";
  769. return $join;
  770. }
  771. add_action( 'comment_feed_join', 'woocommerce_exclude_order_comments_from_feed_join' );
  772. /**
  773. * Exclude order comments from queries and RSS
  774. *
  775. * @access public
  776. * @param string $where
  777. * @return string
  778. */
  779. function woocommerce_exclude_order_comments_from_feed_where( $where ) {
  780. global $wpdb;
  781. if ( $where )
  782. $where .= ' AND ';
  783. $where .= " $wpdb->posts.post_type NOT IN ('shop_order') ";
  784. return $where;
  785. }
  786. add_action( 'comment_feed_where', 'woocommerce_exclude_order_comments_from_feed_where' );
  787. /**
  788. * Order Status completed - GIVE DOWNLOADABLE PRODUCT ACCESS TO CUSTOMER
  789. *
  790. * @access public
  791. * @param int $order_id
  792. * @return void
  793. */
  794. function woocommerce_downloadable_product_permissions( $order_id ) {
  795. global $wpdb;
  796. if (get_post_meta( $order_id, __( 'Download Permissions Granted', 'woocommerce' ), true)==1) return; // Only do this once
  797. $order = new WC_Order( $order_id );
  798. if (sizeof($order->get_items())>0) foreach ($order->get_items() as $item) :
  799. if ($item['product_id']>0) :
  800. $_product = $order->get_product_from_item( $item );
  801. if ( $_product->exists() && $_product->is_downloadable() ) :
  802. $product_id = ($item['variation_id']>0) ? $item['variation_id'] : $item['product_id'];
  803. $file_download_paths = apply_filters( 'woocommerce_file_download_paths', get_post_meta( $product_id, '_file_paths', true ), $product_id, $order_id, $item );
  804. foreach ( $file_download_paths as $download_id => $file_path ) {
  805. woocommerce_downloadable_file_permission( $download_id, $product_id, $order );
  806. }
  807. endif;
  808. endif;
  809. endforeach;
  810. update_post_meta( $order_id, __( 'Download Permissions Granted', 'woocommerce' ), 1);
  811. }
  812. add_action('woocommerce_order_status_completed', 'woocommerce_downloadable_product_permissions');
  813. /**
  814. * Grant downloadable product access to the file identified by $download_id
  815. *
  816. * @access public
  817. * @param string $download_id file identifier
  818. * @param int $product_id product identifier
  819. * @param WC_Order $order the order
  820. */
  821. function woocommerce_downloadable_file_permission( $download_id, $product_id, $order ) {
  822. global $wpdb;
  823. $user_email = $order->billing_email;
  824. $limit = trim( get_post_meta( $product_id, '_download_limit', true ) );
  825. $expiry = trim( get_post_meta( $product_id, '_download_expiry', true ) );
  826. $limit = empty( $limit ) ? '' : (int) $limit;
  827. // Default value is NULL in the table schema
  828. $expiry = empty( $expiry ) ? null : (int) $expiry;
  829. if ( $expiry ) $expiry = date_i18n( "Y-m-d", strtotime( 'NOW + ' . $expiry . ' DAY' ) );
  830. $data = array(
  831. 'download_id' => $download_id,
  832. 'product_id' => $product_id,
  833. 'user_id' => $order->user_id,
  834. 'user_email' => $user_email,
  835. 'order_id' => $order->id,
  836. 'order_key' => $order->order_key,
  837. 'downloads_remaining' => $limit,
  838. 'access_granted' => current_time( 'mysql' ),
  839. 'download_count' => 0
  840. );
  841. $format = array(
  842. '%s',
  843. '%s',
  844. '%s',
  845. '%s',
  846. '%s',
  847. '%s',
  848. '%s',
  849. '%s',
  850. '%d'
  851. );
  852. if ( ! is_null( $expiry ) ) {
  853. $data['access_expires'] = $expiry;
  854. $format[] = '%s';
  855. }
  856. // Downloadable product - give access to the customer
  857. $wpdb->insert( $wpdb->prefix . 'woocommerce_downloadable_product_permissions',
  858. $data,
  859. $format
  860. );
  861. }
  862. if ( get_option('woocommerce_downloads_grant_access_after_payment') == 'yes' )
  863. add_action( 'woocommerce_order_status_processing', 'woocommerce_downloadable_product_permissions' );
  864. /**
  865. * Order Status completed - This is a paying customer
  866. *
  867. * @access public
  868. * @param int $order_id
  869. * @return void
  870. */
  871. function woocommerce_paying_customer( $order_id ) {
  872. $order = new WC_Order( $order_id );
  873. if ( $order->user_id > 0 ) update_user_meta( $order->user_id, 'paying_customer', 1 );
  874. }
  875. add_action('woocommerce_order_status_completed', 'woocommerce_paying_customer');
  876. /**
  877. * Filter to allow product_cat in the permalinks for products.
  878. *
  879. * @access public
  880. * @param string $permalink The existing permalink URL.
  881. * @param object $post
  882. * @return string
  883. */
  884. function woocommerce_product_post_type_link( $permalink, $post ) {
  885. // Abort if post is not a product
  886. if ( $post->post_type !== 'product' )
  887. return $permalink;
  888. // Abort early if the placeholder rewrite tag isn't in the generated URL
  889. if ( false === strpos( $permalink, '%' ) )
  890. return $permalink;
  891. // Get the custom taxonomy terms in use by this post
  892. $terms = get_the_terms( $post->ID, 'product_cat' );
  893. if ( empty( $terms ) ) {
  894. // If no terms are assigned to this post, use a string instead (can't leave the placeholder there)
  895. $product_cat = _x( 'uncategorized', 'slug', 'woocommerce' );
  896. } else {
  897. // Replace the placeholder rewrite tag with the first term's slug
  898. $first_term = array_shift( $terms );
  899. $product_cat = $first_term->slug;
  900. }
  901. $find = array(
  902. '%year%',
  903. '%monthnum%',
  904. '%day%',
  905. '%hour%',
  906. '%minute%',
  907. '%second%',
  908. '%post_id%',
  909. '%category%',
  910. '%product_cat%'
  911. );
  912. $replace = array(
  913. date_i18n( 'Y', strtotime( $post->post_date ) ),
  914. date_i18n( 'm', strtotime( $post->post_date ) ),
  915. date_i18n( 'd', strtotime( $post->post_date ) ),
  916. date_i18n( 'H', strtotime( $post->post_date ) ),
  917. date_i18n( 'i', strtotime( $post->post_date ) ),
  918. date_i18n( 's', strtotime( $post->post_date ) ),
  919. $post->ID,
  920. $product_cat,
  921. $product_cat
  922. );
  923. $replace = array_map( 'sanitize_title', $replace );
  924. $permalink = str_replace( $find, $replace, $permalink );
  925. return $permalink;
  926. }
  927. add_filter( 'post_type_link', 'woocommerce_product_post_type_link', 10, 2 );
  928. /**
  929. * Add term ordering to get_terms
  930. *
  931. * It enables the support a 'menu_order' parameter to get_terms for the product_cat taxonomy.
  932. * By default it is 'ASC'. It accepts 'DESC' too
  933. *
  934. * To disable it, set it ot false (or 0)
  935. *
  936. * @access public
  937. * @param array $clauses
  938. * @param array $taxonomies
  939. * @param array $args
  940. * @return array
  941. */
  942. function woocommerce_terms_clauses( $clauses, $taxonomies, $args ) {
  943. global $wpdb, $woocommerce;
  944. // No sorting when menu_order is false
  945. if ( isset($args['menu_order']) && $args['menu_order'] == false ) return $clauses;
  946. // No sorting when orderby is non default
  947. if ( isset($args['orderby']) && $args['orderby'] != 'name' ) return $clauses;
  948. // No sorting in admin when sorting by a column
  949. if ( is_admin() && isset($_GET['orderby']) ) return $clauses;
  950. // wordpress should give us the taxonomies asked when calling the get_terms function. Only apply to categories and pa_ attributes
  951. $found = false;
  952. foreach ( (array) $taxonomies as $taxonomy ) :
  953. if ( strstr($taxonomy, 'pa_') || in_array( $taxonomy, apply_filters( 'woocommerce_sortable_taxonomies', array( 'product_cat' ) ) ) ) :
  954. $found = true;
  955. break;
  956. endif;
  957. endforeach;
  958. if (!$found) return $clauses;
  959. // Meta name
  960. if ( ! empty( $taxonomies[0] ) && strstr($taxonomies[0], 'pa_') ) {
  961. $meta_name = 'order_' . esc_attr($taxonomies[0]);
  962. } else {
  963. $meta_name = 'order';
  964. }
  965. // query fields
  966. if ( strpos('COUNT(*)', $clauses['fields']) === false ) $clauses['fields'] .= ', tm.* ';
  967. //query join
  968. $clauses['join'] .= " LEFT JOIN {$wpdb->woocommerce_termmeta} AS tm ON (t.term_id = tm.woocommerce_term_id AND tm.meta_key = '". $meta_name ."') ";
  969. // default to ASC
  970. if ( ! isset($args['menu_order']) || ! in_array( strtoupper($args['menu_order']), array('ASC', 'DESC')) ) $args['menu_order'] = 'ASC';
  971. $order = "ORDER BY CAST(tm.meta_value AS SIGNED) " . $args['menu_order'];
  972. if ( $clauses['orderby'] ):
  973. $clauses['orderby'] = str_replace('ORDER BY', $order . ',', $clauses['orderby'] );
  974. else:
  975. $clauses['orderby'] = $order;
  976. endif;
  977. return $clauses;
  978. }
  979. add_filter( 'terms_clauses', 'woocommerce_terms_clauses', 10, 3);
  980. /**
  981. * woocommerce_get_product_terms function.
  982. *
  983. * Gets product terms in the order they are defined in the backend.
  984. *
  985. * @access public
  986. * @param mixed $object_id
  987. * @param mixed $taxonomy
  988. * @param mixed $fields ids, names, slugs, all
  989. * @return array
  990. */
  991. function woocommerce_get_product_terms( $object_id, $taxonomy, $fields = 'all' ) {
  992. if ( ! taxonomy_exists( $taxonomy ) )
  993. return array();
  994. $terms = array();
  995. $object_terms = get_the_terms( $object_id, $taxonomy );
  996. $all_terms = array_flip( get_terms( $taxonomy, array( 'menu_order' => 'ASC', 'fields' => 'ids' ) ) );
  997. switch ( $fields ) {
  998. case 'names' :
  999. foreach ( $object_terms as $term )
  1000. $terms[ $all_terms[ $term->term_id ] ] = $term->name;
  1001. break;
  1002. case 'ids' :
  1003. foreach ( $object_terms as $term )
  1004. $terms[ $all_terms[ $term->term_id ] ] = $term->term_id;
  1005. break;
  1006. case 'slugs' :
  1007. foreach ( $object_terms as $term )
  1008. $terms[ $all_terms[ $term->term_id ] ] = $term->slug;
  1009. break;
  1010. case 'all' :
  1011. foreach ( $object_terms as $term )
  1012. $terms[ $all_terms[ $term->term_id ] ] = $term;
  1013. break;
  1014. }
  1015. ksort( $terms );
  1016. return $terms;
  1017. }
  1018. /**
  1019. * WooCommerce Dropdown categories
  1020. *
  1021. * Stuck with this until a fix for http://core.trac.wordpress.org/ticket/13258
  1022. * We use a custom walker, just like WordPress does
  1023. *
  1024. * @access public
  1025. * @param int $show_counts (default: 1)
  1026. * @param int $hierarchal (default: 1)
  1027. * @param int $show_uncategorized (default: 1)
  1028. * @return string
  1029. */
  1030. function woocommerce_product_dropdown_categories( $show_counts = 1, $hierarchal = 1, $show_uncategorized = 1 ) {
  1031. global $wp_query, $woocommerce;
  1032. include_once( $woocommerce->plugin_path() . '/classes/walkers/class-product-cat-dropdown-walker.php' );
  1033. $r = array();
  1034. $r['pad_counts'] = 1;
  1035. $r['hierarchal'] = $hierarchal;
  1036. $r['hide_empty'] = 1;
  1037. $r['show_count'] = 1;
  1038. $r['selected'] = ( isset( $wp_query->query['product_cat'] ) ) ? $wp_query->query['product_cat'] : '';
  1039. $terms = get_terms( 'product_cat', $r );
  1040. if (!$terms) return;
  1041. $output = "<select name='product_cat' id='dropdown_product_cat'>";
  1042. $output .= '<option value="" ' . selected( isset( $_GET['product_cat'] ) ? $_GET['product_cat'] : '', '', false ) . '>'.__( 'Select a category', 'woocommerce' ).'</option>';
  1043. $output .= woocommerce_walk_category_dropdown_tree( $terms, 0, $r );
  1044. if ( $show_uncategorized )
  1045. $output .= '<option value="0" ' . selected( isset( $_GET['product_cat'] ) ? $_GET['product_cat'] : '', '0', false ) . '>' . __( 'Uncategorized', 'woocommerce' ) . '</option>';
  1046. $output .="</select>";
  1047. echo $output;
  1048. }
  1049. /**
  1050. * Walk the Product Categories.
  1051. *
  1052. * @access public
  1053. * @return void
  1054. */
  1055. function woocommerce_walk_category_dropdown_tree() {
  1056. $args = func_get_args();
  1057. // the user's options are the third parameter
  1058. if ( empty($args[2]['walker']) || !is_a($args[2]['walker'], 'Walker') )
  1059. $walker = new WC_Product_Cat_Dropdown_Walker;
  1060. else
  1061. $walker = $args[2]['walker'];
  1062. return call_user_func_array(array( &$walker, 'walk' ), $args );
  1063. }
  1064. /**
  1065. * WooCommerce Term/Order item Meta API - set table name
  1066. *
  1067. * @access public
  1068. * @return void
  1069. */
  1070. function woocommerce_taxonomy_metadata_wpdbfix() {
  1071. global $wpdb;
  1072. $termmeta_name = 'woocommerce_termmeta';
  1073. $itemmeta_name = 'woocommerce_order_itemmeta';
  1074. $wpdb->woocommerce_termmeta = $wpdb->prefix . $termmeta_name;
  1075. $wpdb->order_itemmeta = $wpdb->prefix . $itemmeta_name;
  1076. $wpdb->tables[] = 'woocommerce_termmeta';
  1077. $wpdb->tables[] = 'order_itemmeta';
  1078. }
  1079. add_action( 'init', 'woocommerce_taxonomy_metadata_wpdbfix', 0 );
  1080. add_action( 'switch_blog', 'woocommerce_taxonomy_metadata_wpdbfix', 0 );
  1081. /**
  1082. * WooCommerce Term Meta API - Update term meta
  1083. *
  1084. * @access public
  1085. * @param mixed $term_id
  1086. * @param mixed $meta_key
  1087. * @param mixed $meta_value
  1088. * @param string $prev_value (default: '')
  1089. * @return bool
  1090. */
  1091. function update_woocommerce_term_meta( $term_id, $meta_key, $meta_value, $prev_value = '' ) {
  1092. return update_metadata( 'woocommerce_term', $term_id, $meta_key, $meta_value, $prev_value );
  1093. }
  1094. /**
  1095. * WooCommerce Term Meta API - Add term meta
  1096. *
  1097. * @access public
  1098. * @param mixed $term_id
  1099. * @param mixed $meta_key
  1100. * @param mixed $meta_value
  1101. * @param bool $unique (default: false)
  1102. * @return bool
  1103. */
  1104. function add_woocommerce_term_meta( $term_id, $meta_key, $meta_value, $unique = false ){
  1105. return add_metadata( 'woocommerce_term', $term_id, $meta_key, $meta_value, $unique );
  1106. }
  1107. /**
  1108. * WooCommerce Term Meta API - Delete term meta
  1109. *
  1110. * @access public
  1111. * @param mixed $term_id
  1112. * @param mixed $meta_key
  1113. * @param string $meta_value (default: '')
  1114. * @param bool $delete_all (default: false)
  1115. * @return bool
  1116. */
  1117. function delete_woocommerce_term_meta( $term_id, $meta_key, $meta_value = '', $delete_all = false ) {
  1118. return delete_metadata( 'woocommerce_term', $term_id, $meta_key, $meta_value, $delete_all );
  1119. }
  1120. /**
  1121. * WooCommerce Term Meta API - Get term meta
  1122. *
  1123. * @access public
  1124. * @param mixed $term_id
  1125. * @param mixed $key
  1126. * @param bool $single (default: true)
  1127. * @return mixed
  1128. */
  1129. function get_woocommerce_term_meta( $term_id, $key, $single = true ) {
  1130. return get_metadata( 'woocommerce_term', $term_id, $key, $single );
  1131. }
  1132. /**
  1133. * Move a term before the a given element of its hierarchy level
  1134. *
  1135. * @access public
  1136. * @param int $the_term
  1137. * @param int $next_id the id of the next slibling element in save hierachy level
  1138. * @param string $taxonomy
  1139. * @param int $index (default: 0)
  1140. * @param mixed $terms (default: null)
  1141. * @return int
  1142. */
  1143. function woocommerce_order_terms( $the_term, $next_id, $taxonomy, $index = 0, $terms = null ) {
  1144. if( ! $terms ) $terms = get_terms($taxonomy, 'menu_order=ASC&hide_empty=0&parent=0' );
  1145. if( empty( $terms ) ) return $index;
  1146. $id = $the_term->term_id;
  1147. $term_in_level = false; // flag: is our term to order in this level of terms
  1148. foreach ($terms as $term) {
  1149. if( $term->term_id == $id ) { // our term to order, we skip
  1150. $term_in_level = true;
  1151. continue; // our term to order, we skip
  1152. }
  1153. // the nextid of our term to order, lets move our term here
  1154. if(null !== $next_id && $term->term_id == $next_id) {
  1155. $index++;
  1156. $index = woocommerce_set_term_order($id, $index, $taxonomy, true);
  1157. }
  1158. // set order
  1159. $index++;
  1160. $index = woocommerce_set_term_order($term->term_id, $index, $taxonomy);
  1161. // if that term has children we walk through them
  1162. $children = get_terms($taxonomy, "parent={$term->term_id}&menu_order=ASC&hide_empty=0");
  1163. if( !empty($children) ) {
  1164. $index = woocommerce_order_terms( $the_term, $next_id, $taxonomy, $index, $children );
  1165. }
  1166. }
  1167. // no nextid meaning our term is in last position
  1168. if( $term_in_level && null === $next_id )
  1169. $index = woocommerce_set_term_order($id, $index+1, $taxonomy, true);
  1170. return $index;
  1171. }
  1172. /**
  1173. * Set the sort order of a term
  1174. *
  1175. * @access public
  1176. * @param int $term_id
  1177. * @param int $index
  1178. * @param string $taxonomy
  1179. * @param bool $recursive (default: false)
  1180. * @return int
  1181. */
  1182. function woocommerce_set_term_order( $term_id, $index, $taxonomy, $recursive = false ) {
  1183. global $wpdb;
  1184. $term_id = (int) $term_id;
  1185. $index = (int) $index;
  1186. // Meta name
  1187. if (strstr($taxonomy, 'pa_')) :
  1188. $meta_name = 'order_' . esc_attr($taxonomy);
  1189. else :
  1190. $meta_name = 'order';
  1191. endif;
  1192. update_woocommerce_term_meta( $term_id, $meta_name, $index );
  1193. if( ! $recursive ) return $index;
  1194. $children = get_terms($taxonomy, "parent=$term_id&menu_order=ASC&hide_empty=0");
  1195. foreach ( $children as $term ) {
  1196. $index ++;
  1197. $index = woocommerce_set_term_order($term->term_id, $index, $taxonomy, true);
  1198. }
  1199. clean_term_cache( $term_id, $taxonomy );
  1200. return $index;
  1201. }
  1202. /**
  1203. * let_to_num function.
  1204. *
  1205. * This function transforms the php.ini notation for numbers (like '2M') to an integer.
  1206. *
  1207. * @access public
  1208. * @param $size
  1209. * @return int
  1210. */
  1211. function woocommerce_let_to_num( $size ) {
  1212. $l = substr( $size, -1 );
  1213. $ret = substr( $size, 0, -1 );
  1214. switch( strtoupper( $l ) ) {
  1215. case 'P':
  1216. $ret *= 1024;
  1217. case 'T':
  1218. $ret *= 1024;
  1219. case 'G':
  1220. $ret *= 1024;
  1221. case 'M':
  1222. $ret *= 1024;
  1223. case 'K':
  1224. $ret *= 1024;
  1225. }
  1226. return $ret;
  1227. }
  1228. /**
  1229. * woocommerce_customer_bought_product
  1230. *
  1231. * Checks if a user (by email) has bought an item
  1232. *
  1233. * @access public
  1234. * @param string $customer_email
  1235. * @param int $user_id
  1236. * @param int $product_id
  1237. * @return bool
  1238. */
  1239. function woocommerce_customer_bought_product( $customer_email, $user_id, $product_id ) {
  1240. global $wpdb;
  1241. $emails = array();
  1242. if ( $user_id ) {
  1243. $user = get_user_by( 'id', $user_id );
  1244. $emails[] = $user->user_email;
  1245. }
  1246. if ( is_email( $customer_email ) )
  1247. $emails[] = $customer_email;
  1248. if ( sizeof( $emails ) == 0 )
  1249. return false;
  1250. return $wpdb->get_var( $wpdb->prepare( "
  1251. SELECT COUNT( order_items.order_item_id )
  1252. FROM {$wpdb->prefix}woocommerce_order_items as order_items
  1253. LEFT JOIN {$wpdb->prefix}woocommerce_order_itemmeta AS itemmeta ON order_items.order_item_id = itemmeta.order_item_id
  1254. LEFT JOIN {$wpdb->postmeta} AS postmeta ON order_items.order_id = postmeta.post_id
  1255. LEFT JOIN {$wpdb->term_relationships} AS rel ON postmeta.post_id = rel.object_ID
  1256. LEFT JOIN {$wpdb->term_taxonomy} AS tax USING( term_taxonomy_id )
  1257. LEFT JOIN {$wpdb->terms} AS term USING( term_id )
  1258. WHERE term.slug IN ('" . implode( "','", apply_filters( 'woocommerce_reports_order_statuses', array( 'completed', 'processing', 'on-hold' ) ) ) . "')
  1259. AND tax.taxonomy = 'shop_order_status'
  1260. AND (
  1261. (
  1262. itemmeta.meta_key = '_variation_id'
  1263. AND itemmeta.meta_value = %s
  1264. ) OR (
  1265. itemmeta.meta_key = '_product_id'
  1266. AND itemmeta.meta_value = %s
  1267. )
  1268. )
  1269. AND (
  1270. (
  1271. postmeta.meta_key = '_billing_email'
  1272. AND postmeta.meta_value IN ( '" . implode( "','", array_unique( $emails ) ) . "' )
  1273. ) OR (
  1274. postmeta.meta_key = '_customer_user'
  1275. AND postmeta.meta_value = %s AND postmeta.meta_value > 0
  1276. )
  1277. )
  1278. ", $product_id, $product_id, $user_id ) );
  1279. }
  1280. /**
  1281. * Return the count of processing orders.
  1282. *
  1283. * @access public
  1284. * @return int
  1285. */
  1286. function woocommerce_processing_order_count() {
  1287. if ( false === ( $order_count = get_transient( 'woocommerce_processing_order_count' ) ) ) {
  1288. $order_statuses = get_terms( 'shop_order_status' );
  1289. $order_count = false;
  1290. foreach ( $order_statuses as $status ) {
  1291. if( $status->slug === 'processing' ) {
  1292. $order_count += $status->count;
  1293. break;
  1294. }
  1295. }
  1296. $order_count = apply_filters( 'woocommerce_admin_menu_count', intval( $order_count ) );
  1297. set_transient( 'woocommerce_processing_order_count', $order_count );
  1298. }
  1299. return $order_count;
  1300. }
  1301. /**
  1302. * Get capabilities for WooCommerce - these are assigned to admin/shop manager during installation or reset
  1303. *
  1304. * @access public
  1305. * @return void
  1306. */
  1307. function woocommerce_get_core_capabilities() {
  1308. $capabilities = array();
  1309. $capabilities['core'] = array(
  1310. "manage_woocommerce",
  1311. "view_woocommerce_reports"
  1312. );
  1313. $capability_types = array( 'product', 'shop_order', 'shop_coupon' );
  1314. foreach( $capability_types as $capability_type ) {
  1315. $capabilities[ $capability_type ] = array(
  1316. // Post type
  1317. "edit_{$capability_type}",
  1318. "read_{$capability_type}",
  1319. "delete_{$capability_type}",
  1320. "edit_{$capability_type}s",
  1321. "edit_others_{$capability_type}s",
  1322. "publish_{$capability_type}s",
  1323. "read_private_{$capability_type}s",
  1324. "delete_{$capability_type}s",
  1325. "delete_private_{$capability_type}s",
  1326. "delete_published_{$capability_type}s",
  1327. "delete_others_{$capability_type}s",
  1328. "edit_private_{$capability_type}s",
  1329. "edit_published_{$capability_type}s",
  1330. // Terms
  1331. "manage_{$capability_type}_terms",
  1332. "edit_{$capability_type}_terms",
  1333. "delete_{$capability_type}_terms",
  1334. "assign_{$capability_type}_terms"
  1335. );
  1336. }
  1337. return $capabilities;
  1338. }
  1339. /**
  1340. * woocommerce_init_roles function.
  1341. *
  1342. * @access public
  1343. * @return void
  1344. */
  1345. function woocommerce_init_roles() {
  1346. global $wp_roles;
  1347. if ( class_exists('WP_Roles') )
  1348. if ( ! isset( $wp_roles ) )
  1349. $wp_roles = new WP_Roles();
  1350. if ( is_object( $wp_roles ) ) {
  1351. // Customer role
  1352. add_role( 'customer', __( 'Customer', 'woocommerce' ), array(
  1353. 'read' => true,
  1354. 'edit_posts' => false,
  1355. 'delete_posts' => false
  1356. ) );
  1357. // Shop manager role
  1358. add_role( 'shop_manager', __( 'Shop Manager', 'woocommerce' ), array(
  1359. 'read' => true,
  1360. 'read_private_pages' => true,
  1361. 'read_private_posts' => true,
  1362. 'edit_users' => true,
  1363. 'edit_posts' => true,
  1364. 'edit_pages' => true,
  1365. 'edit_published_posts' => true,
  1366. 'edit_published_pages' => true,
  1367. 'edit_private_pages' => true,
  1368. 'edit_private_posts' => true,
  1369. 'edit_others_posts' => true,
  1370. 'edit_others_pages' => true,
  1371. 'publish_posts' => true,
  1372. 'publish_pages' => true,
  1373. 'delete_posts' => true,
  1374. 'delete_pages' => true,
  1375. 'delete_private_pages' => true,
  1376. 'delete_private_posts' => true,
  1377. 'delete_published_pages' => true,
  1378. 'delete_published_posts' => true,
  1379. 'delete_others_posts' => true,
  1380. 'delete_others_pages' => true,
  1381. 'manage_categories' => true,
  1382. 'manage_links' => true,
  1383. 'moderate_comments' => true,
  1384. 'unfiltered_html' => true,
  1385. 'upload_files' => true,
  1386. 'export' => true,
  1387. 'import' => true
  1388. ) );
  1389. $capabilities = woocommerce_get_core_capabilities();
  1390. foreach( $capabilities as $cap_group ) {
  1391. foreach( $cap_group as $cap ) {
  1392. $wp_roles->add_cap( 'shop_manager', $cap );
  1393. $wp_roles->add_cap( 'administrator', $cap );
  1394. }
  1395. }
  1396. }
  1397. }
  1398. /**
  1399. * woocommerce_remove_roles function.
  1400. *
  1401. * @access public
  1402. * @return void
  1403. */
  1404. function woocommerce_remove_roles() {
  1405. global $wp_roles;
  1406. if ( class_exists('WP_Roles') )
  1407. if ( ! isset( $wp_roles ) )
  1408. $wp_roles = new WP_Roles();
  1409. if ( is_object( $wp_roles ) ) {
  1410. $capabilities = woocommerce_get_core_capabilities();
  1411. foreach( $capabilities as $cap_group ) {
  1412. foreach( $cap_group as $cap ) {
  1413. $wp_roles->remove_cap( 'shop_manager', $cap );
  1414. $wp_roles->remove_cap( 'administrator', $cap );
  1415. }
  1416. }
  1417. remove_role( 'customer' );
  1418. remove_role( 'shop_manager' );
  1419. }
  1420. }
  1421. /**
  1422. * Add a item to an order (for example a line item).
  1423. *
  1424. * @access public
  1425. * @param int $order_id
  1426. * @param array $data
  1427. * @return mixed
  1428. */
  1429. function woocommerce_add_order_item( $order_id, $item ) {
  1430. global $wpdb;
  1431. $order_id = absint( $order_id );
  1432. if ( ! $order_id )
  1433. return false;
  1434. $defaults = array(
  1435. 'order_item_name' => '',
  1436. 'order_item_type' => 'line_item',
  1437. );
  1438. $item = wp_parse_args( $item, $defaults );
  1439. $wpdb->insert(
  1440. $wpdb->prefix . "woocommerce_order_items",
  1441. array(
  1442. 'order_item_name' => $item['order_item_name'],
  1443. 'order_item_type' => $item['order_item_type'],
  1444. 'order_id' => $order_id
  1445. ),
  1446. array(
  1447. '%s', '%s', '%d'
  1448. )
  1449. );
  1450. do_action( 'woocommerce_new_order_item', absint( $wpdb->insert_id ) );
  1451. return absint( $wpdb->insert_id );
  1452. }
  1453. /**
  1454. * woocommerce_delete_order_item function.
  1455. *
  1456. * @access public
  1457. * @param int $item_id
  1458. * @return bool
  1459. */
  1460. function woocommerce_delete_order_item( $item_id ) {
  1461. global $wpdb;
  1462. $item_id = absint( $item_id );
  1463. if ( ! $item_id )
  1464. return false;
  1465. $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}woocommerce_order_items WHERE order_item_id = %d", $item_id ) );
  1466. $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}woocommerce_order_itemmeta WHERE order_item_id = %d", $item_id ) );
  1467. do_action( 'woocommerce_delete_order_item', $item_id );
  1468. return true;
  1469. }
  1470. /**
  1471. * WooCommerce Order Item Meta API - Update term meta
  1472. *
  1473. * @access public
  1474. * @param mixed $item_id
  1475. * @param mixed $meta_key
  1476. * @param mixed $meta_value
  1477. * @param string $prev_value (default: '')
  1478. * @return bool
  1479. */
  1480. function woocommerce_update_order_item_meta( $item_id, $meta_key, $meta_value, $prev_value = '' ) {
  1481. return update_metadata( 'order_item', $item_id, $meta_key, $meta_value, $prev_value );
  1482. }
  1483. /**
  1484. * WooCommerce Order Item Meta API - Add term meta
  1485. *
  1486. * @access public
  1487. * @param mixed $item_id
  1488. * @param mixed $meta_key
  1489. * @param mixed $meta_value
  1490. * @param bool $unique (default: false)
  1491. * @return bool
  1492. */
  1493. function woocommerce_add_order_item_meta( $item_id, $meta_key, $meta_value, $unique = false ){
  1494. return add_metadata( 'order_item', $item_id, $meta_key, $meta_value, $unique );
  1495. }
  1496. /**
  1497. * WooCommerce Order Item Meta API - Delete term meta
  1498. *
  1499. * @access public
  1500. * @param mixed $item_id
  1501. * @param mixed $meta_key
  1502. * @param string $meta_value (default: '')
  1503. * @param bool $delete_all (default: false)
  1504. * @return bool
  1505. */
  1506. function woocommerce_delete_order_item_meta( $item_id, $meta_key, $meta_value = '', $delete_all = false ) {
  1507. return delete_metadata( 'order_item', $item_id, $meta_key, $meta_value, $delete_all );
  1508. }
  1509. /**
  1510. * WooCommerce Order Item Meta API - Get term meta
  1511. *
  1512. * @access public
  1513. * @param mixed $item_id
  1514. * @param mixed $key
  1515. * @param bool $single (default: true)
  1516. * @return mixed
  1517. */
  1518. function woocommerce_get_order_item_meta( $item_id, $key, $single = true ) {
  1519. return get_metadata( 'order_item', $item_id, $key, $single );
  1520. }
  1521. /**
  1522. * WooCommerce Date Format - Allows to change date format for everything WooCommerce
  1523. *
  1524. * @access public
  1525. * @return string
  1526. */
  1527. function woocommerce_date_format() {
  1528. return apply_filters( 'woocommerce_date_format', get_option( 'date_format' ) );
  1529. }