PageRenderTime 50ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 1ms

/woocommerce-functions.php

https://github.com/CammoKing/woocommerce
PHP | 1229 lines | 682 code | 304 blank | 243 comment | 236 complexity | 19571e08fa64dcc03c28b55f6b7504aa MD5 | raw file
Possible License(s): GPL-3.0
  1. <?php
  2. /**
  3. * WooCommerce Functions
  4. *
  5. * Hooked-in functions for WooCommerce related events on the front-end.
  6. *
  7. * @author WooThemes
  8. * @category Core
  9. * @package WooCommerce/Functions
  10. * @version 1.6.4
  11. */
  12. /**
  13. * Handle redirects before content is output - hooked into template_redirect so is_page works.
  14. *
  15. * @access public
  16. * @return void
  17. */
  18. function woocommerce_redirects() {
  19. global $woocommerce, $wp_query;
  20. // When default permalinks are enabled, redirect shop page to post type archive url
  21. if ( isset($_GET['page_id']) && $_GET['page_id'] > 0 && get_option( 'permalink_structure' )=="" && $_GET['page_id'] == woocommerce_get_page_id('shop') ) :
  22. wp_safe_redirect( get_post_type_archive_link('product') );
  23. exit;
  24. endif;
  25. // When on the checkout with an empty cart, redirect to cart page
  26. if (is_page(woocommerce_get_page_id('checkout')) && sizeof($woocommerce->cart->get_cart())==0) :
  27. wp_redirect(get_permalink(woocommerce_get_page_id('cart')));
  28. exit;
  29. endif;
  30. // When on pay page with no query string, redirect to checkout
  31. if (is_page(woocommerce_get_page_id('pay')) && !isset($_GET['order'])) :
  32. wp_redirect(get_permalink(woocommerce_get_page_id('checkout')));
  33. exit;
  34. endif;
  35. // My account page redirects (logged out)
  36. if (!is_user_logged_in() && ( is_page(woocommerce_get_page_id('edit_address')) || is_page(woocommerce_get_page_id('view_order')) || is_page(woocommerce_get_page_id('change_password')) )) :
  37. wp_redirect(get_permalink(woocommerce_get_page_id('myaccount')));
  38. exit;
  39. endif;
  40. // Redirect to the product page if we have a single product
  41. if (is_search() && is_post_type_archive('product') && get_option('woocommerce_redirect_on_single_search_result')=='yes') {
  42. if ($wp_query->post_count==1) {
  43. $product = get_product( $wp_query->post );
  44. if ($product->is_visible()) wp_safe_redirect( get_permalink($product->id), 302 );
  45. exit;
  46. }
  47. }
  48. }
  49. /**
  50. * Fix active class in nav for shop page.
  51. *
  52. * @access public
  53. * @param array $menu_items
  54. * @param array $args
  55. * @return array
  56. */
  57. function woocommerce_nav_menu_item_classes( $menu_items, $args ) {
  58. if ( ! is_woocommerce() ) return $menu_items;
  59. $shop_page = (int) woocommerce_get_page_id('shop');
  60. $page_for_posts = (int) get_option( 'page_for_posts' );
  61. foreach ( (array) $menu_items as $key => $menu_item ) {
  62. $classes = (array) $menu_item->classes;
  63. // Unset active class for blog page
  64. if ( $page_for_posts == $menu_item->object_id ) {
  65. $menu_items[$key]->current = false;
  66. unset( $classes[ array_search('current_page_parent', $classes) ] );
  67. unset( $classes[ array_search('current-menu-item', $classes) ] );
  68. // Set active state if this is the shop page link
  69. } elseif ( is_shop() && $shop_page == $menu_item->object_id ) {
  70. $menu_items[$key]->current = true;
  71. $classes[] = 'current-menu-item';
  72. $classes[] = 'current_page_item';
  73. // Set parent state if this is a product page
  74. } elseif ( is_singular( 'product' ) && $shop_page == $menu_item->object_id ) {
  75. $classes[] = 'current_page_parent';
  76. }
  77. $menu_items[$key]->classes = array_unique( $classes );
  78. }
  79. return $menu_items;
  80. }
  81. /**
  82. * Fix active class in wp_list_pages for shop page.
  83. *
  84. * https://github.com/woothemes/woocommerce/issues/177
  85. *
  86. * @author Jessor, Peter Sterling
  87. * @access public
  88. * @param string $pages
  89. * @return string
  90. */
  91. function woocommerce_list_pages( $pages ){
  92. global $post;
  93. if (is_woocommerce()) {
  94. $pages = str_replace( 'current_page_parent', '', $pages); // remove current_page_parent class from any item
  95. $shop_page = 'page-item-' . woocommerce_get_page_id('shop'); // find shop_page_id through woocommerce options
  96. if (is_shop()) :
  97. $pages = str_replace($shop_page, $shop_page . ' current_page_item', $pages); // add current_page_item class to shop page
  98. else :
  99. $pages = str_replace($shop_page, $shop_page . ' current_page_parent', $pages); // add current_page_parent class to shop page
  100. endif;
  101. }
  102. return $pages;
  103. }
  104. /**
  105. * Add logout link to my account menu.
  106. *
  107. * @access public
  108. * @param string $items
  109. * @param array $args
  110. * @return string
  111. */
  112. function woocommerce_nav_menu_items( $items, $args ) {
  113. if ( get_option('woocommerce_menu_logout_link')=='yes' && strstr($items, get_permalink(woocommerce_get_page_id('myaccount'))) && is_user_logged_in() )
  114. $items .= '<li class="logout"><a href="'. wp_logout_url(home_url()) .'">'.__( 'Logout', 'woocommerce' ).'</a></li>';
  115. return $items;
  116. }
  117. /**
  118. * Update catalog ordering if posted.
  119. *
  120. * @access public
  121. * @return void
  122. */
  123. function woocommerce_update_catalog_ordering() {
  124. global $woocommerce;
  125. if ( isset( $_REQUEST['sort'] ) && $_REQUEST['sort'] != '' )
  126. $woocommerce->session->orderby = esc_attr( $_REQUEST['sort'] );
  127. }
  128. /**
  129. * Remove from cart/update.
  130. *
  131. * @access public
  132. * @return void
  133. */
  134. function woocommerce_update_cart_action() {
  135. global $woocommerce;
  136. // Remove from cart
  137. if ( isset($_GET['remove_item']) && $_GET['remove_item'] && $woocommerce->verify_nonce('cart', '_GET')) {
  138. $woocommerce->cart->set_quantity( $_GET['remove_item'], 0 );
  139. $woocommerce->add_message( __( 'Cart updated.', 'woocommerce' ) );
  140. $referer = ( wp_get_referer() ) ? wp_get_referer() : $woocommerce->cart->get_cart_url();
  141. wp_safe_redirect( $referer );
  142. exit;
  143. // Update Cart
  144. } elseif ( ( ! empty( $_POST['update_cart'] ) || ! empty( $_POST['proceed'] ) ) && $woocommerce->verify_nonce('cart')) {
  145. $cart_totals = isset( $_POST['cart'] ) ? $_POST['cart'] : '';
  146. if ( sizeof( $woocommerce->cart->get_cart() ) > 0 ) {
  147. foreach ( $woocommerce->cart->get_cart() as $cart_item_key => $values ) {
  148. $_product = $values['data'];
  149. // Skip product if no updated quantity was posted
  150. if ( ! isset( $cart_totals[$cart_item_key]['qty'] ) )
  151. continue;
  152. // Sanitize
  153. $quantity = preg_replace( "/[^0-9\.]/", "", $cart_totals[ $cart_item_key ]['qty'] );
  154. if ( $quantity == "" )
  155. continue;
  156. // Update cart validation
  157. $passed_validation = apply_filters( 'woocommerce_update_cart_validation', true, $cart_item_key, $values, $quantity );
  158. // Check downloadable items
  159. if ( get_option('woocommerce_limit_downloadable_product_qty') == 'yes' ) {
  160. if ( $_product->is_downloadable() && $_product->is_virtual() && $quantity > 1 ) {
  161. $woocommerce->add_error( sprintf(__( 'You can only have 1 %s in your cart.', 'woocommerce' ), $_product->get_title()) );
  162. $passed_validation = false;
  163. }
  164. }
  165. if ( $passed_validation )
  166. $woocommerce->cart->set_quantity( $cart_item_key, $quantity );
  167. }
  168. }
  169. if ( ! empty( $_POST['proceed'] ) ) {
  170. wp_safe_redirect( $woocommerce->cart->get_checkout_url() );
  171. exit;
  172. } else {
  173. $woocommerce->add_message( __( 'Cart updated.', 'woocommerce' ) );
  174. $referer = ( wp_get_referer() ) ? wp_get_referer() : $woocommerce->cart->get_cart_url();
  175. $referer = remove_query_arg( 'remove_discounts', $referer );
  176. wp_safe_redirect( $referer );
  177. exit;
  178. }
  179. }
  180. }
  181. /**
  182. * Add to cart action
  183. *
  184. * Checks for a valid request, does validation (via hooks) and then redirects if valid.
  185. *
  186. * @access public
  187. * @param bool $url (default: false)
  188. * @return void
  189. */
  190. function woocommerce_add_to_cart_action( $url = false ) {
  191. if ( empty( $_REQUEST['add-to-cart'] ) || ! is_numeric( $_REQUEST['add-to-cart'] ) )
  192. return;
  193. global $woocommerce;
  194. $product_id = apply_filters('woocommerce_add_to_cart_product_id', absint( $_REQUEST['add-to-cart'] ) );
  195. $was_added_to_cart = false;
  196. $adding_to_cart = get_product( $product_id );
  197. // Variable product handling
  198. if ( $adding_to_cart->is_type( 'variable' ) ) {
  199. $variation_id = empty( $_REQUEST['variation_id'] ) ? '' : absint( $_REQUEST['variation_id'] );
  200. $quantity = empty( $_REQUEST['quantity'] ) ? 1 : apply_filters( 'woocommerce_stock_amount', $_REQUEST['quantity'] );
  201. $all_variations_set = true;
  202. $variations = array();
  203. // Only allow integer variation ID - if its not set, redirect to the product page
  204. if ( empty( $variation_id ) ) {
  205. $woocommerce->add_error( __( 'Please choose product options&hellip;', 'woocommerce' ) );
  206. wp_redirect( get_permalink( $product_id ) );
  207. exit;
  208. }
  209. $attributes = (array) maybe_unserialize( get_post_meta( $product_id, '_product_attributes', true ) );
  210. // Verify all attributes for the variable product were set
  211. foreach ( $attributes as $attribute ) {
  212. if ( ! $attribute['is_variation'] )
  213. continue;
  214. $taxonomy = 'attribute_' . sanitize_title( $attribute['name'] );
  215. if ( ! empty( $_REQUEST[$taxonomy] ) ) {
  216. // Get value from post data
  217. $value = esc_attr( stripslashes( $_REQUEST[ $taxonomy ] ) );
  218. // Use name so it looks nicer in the cart widget/order page etc - instead of a sanitized string
  219. $variations[ esc_attr( $attribute['name'] ) ] = $value;
  220. } else {
  221. $all_variations_set = false;
  222. }
  223. }
  224. if ( $all_variations_set ) {
  225. // Add to cart validation
  226. $passed_validation = apply_filters( 'woocommerce_add_to_cart_validation', true, $product_id, $quantity );
  227. if ( $passed_validation ) {
  228. if ( $woocommerce->cart->add_to_cart( $product_id, $quantity, $variation_id, $variations ) ) {
  229. woocommerce_add_to_cart_message( $product_id );
  230. $was_added_to_cart = true;
  231. }
  232. }
  233. } else {
  234. $woocommerce->add_error( __( 'Please choose product options&hellip;', 'woocommerce' ) );
  235. wp_redirect( get_permalink( $product_id ) );
  236. exit;
  237. }
  238. // Grouped Products
  239. } elseif ( $adding_to_cart->is_type( 'grouped' ) ) {
  240. if ( ! empty( $_REQUEST['quantity'] ) && is_array( $_REQUEST['quantity'] ) ) {
  241. $quantity_set = false;
  242. $added_to_cart = array();
  243. foreach ( $_REQUEST['quantity'] as $item => $quantity ) {
  244. if ( $quantity <= 0 )
  245. continue;
  246. $quantity_set = true;
  247. // Add to cart validation
  248. $passed_validation = apply_filters( 'woocommerce_add_to_cart_validation', true, $item, $quantity );
  249. if ( $passed_validation ) {
  250. if ( $woocommerce->cart->add_to_cart( $item, $quantity ) ) {
  251. $was_added_to_cart = true;
  252. $added_to_cart[] = $item;
  253. }
  254. }
  255. }
  256. if ( $was_added_to_cart ) {
  257. woocommerce_add_to_cart_message( $added_to_cart );
  258. }
  259. if ( ! $was_added_to_cart && ! $quantity_set ) {
  260. $woocommerce->add_error( __( 'Please choose the quantity of items you wish to add to your cart&hellip;', 'woocommerce' ) );
  261. wp_redirect( get_permalink( $product_id ) );
  262. exit;
  263. }
  264. } elseif ( $product_id ) {
  265. /* Link on product archives */
  266. $woocommerce->add_error( __( 'Please choose a product to add to your cart&hellip;', 'woocommerce' ) );
  267. wp_redirect( get_permalink( $product_id ) );
  268. exit;
  269. }
  270. // Simple Products
  271. } else {
  272. $quantity = empty( $_REQUEST['quantity'] ) ? 1 : apply_filters( 'woocommerce_stock_amount', $_REQUEST['quantity'] );
  273. // Add to cart validation
  274. $passed_validation = apply_filters( 'woocommerce_add_to_cart_validation', true, $product_id, $quantity );
  275. if ( $passed_validation ) {
  276. // Add the product to the cart
  277. if ( $woocommerce->cart->add_to_cart( $product_id, $quantity ) ) {
  278. woocommerce_add_to_cart_message( $product_id );
  279. $was_added_to_cart = true;
  280. }
  281. }
  282. }
  283. // If we added the product to the cart we can now do a redirect, otherwise just continue loading the page to show errors
  284. if ( $was_added_to_cart ) {
  285. $url = apply_filters( 'add_to_cart_redirect', $url );
  286. // If has custom URL redirect there
  287. if ( $url ) {
  288. wp_safe_redirect( $url );
  289. exit;
  290. }
  291. // Redirect to cart option
  292. elseif ( get_option('woocommerce_cart_redirect_after_add') == 'yes' && $woocommerce->error_count() == 0 ) {
  293. wp_safe_redirect( $woocommerce->cart->get_cart_url() );
  294. exit;
  295. }
  296. // Redirect to page without querystring args
  297. elseif ( wp_get_referer() ) {
  298. wp_safe_redirect( remove_query_arg( array( 'add-to-cart', 'quantity', 'product_id' ), wp_get_referer() ) );
  299. exit;
  300. }
  301. }
  302. }
  303. /**
  304. * Add to cart messages.
  305. *
  306. * @access public
  307. * @return void
  308. */
  309. function woocommerce_add_to_cart_message( $product_id ) {
  310. global $woocommerce;
  311. if ( is_array( $product_id ) ) {
  312. $titles = array();
  313. foreach ( $product_id as $id ) {
  314. $titles[] = get_the_title( $id );
  315. }
  316. $added_text = sprintf( __( 'Added &quot;%s&quot; to your cart.', 'woocommerce' ), join( __('&quot; and &quot;'), array_filter( array_merge( array( join( '&quot;, &quot;', array_slice( $titles, 0, -1 ) ) ), array_slice( $titles, -1 ) ) ) ) );
  317. } else {
  318. $added_text = sprintf( __( '&quot;%s&quot; was successfully added to your cart.', 'woocommerce' ), get_the_title( $product_id ) );
  319. }
  320. // Output success messages
  321. if ( get_option( 'woocommerce_cart_redirect_after_add' ) == 'yes' ) :
  322. $return_to = wp_get_referer() ? wp_get_referer() : home_url();
  323. $message = sprintf('<a href="%s" class="button">%s</a> %s', $return_to, __( 'Continue Shopping &rarr;', 'woocommerce' ), $added_text );
  324. else :
  325. $message = sprintf('<a href="%s" class="button">%s</a> %s', get_permalink(woocommerce_get_page_id('cart')), __( 'View Cart &rarr;', 'woocommerce' ), $added_text );
  326. endif;
  327. $woocommerce->add_message( apply_filters('woocommerce_add_to_cart_message', $message) );
  328. }
  329. /**
  330. * Clear cart after payment.
  331. *
  332. * @access public
  333. * @return void
  334. */
  335. function woocommerce_clear_cart_after_payment() {
  336. global $woocommerce;
  337. if ( is_page( woocommerce_get_page_id( 'thanks' ) ) ) {
  338. if ( isset( $_GET['order'] ) )
  339. $order_id = $_GET['order'];
  340. else
  341. $order_id = 0;
  342. if ( isset( $_GET['key'] ) )
  343. $order_key = $_GET['key'];
  344. else
  345. $order_key = '';
  346. if ( $order_id > 0 ) {
  347. $order = new WC_Order( $order_id );
  348. if ( $order->order_key == $order_key ) {
  349. $woocommerce->cart->empty_cart();
  350. }
  351. }
  352. }
  353. if ( $woocommerce->session->order_awaiting_payment > 0 ) {
  354. $order = new WC_Order( $woocommerce->session->order_awaiting_payment );
  355. if ( $order->id > 0 && $order->status !== 'pending' ) {
  356. $woocommerce->cart->empty_cart();
  357. }
  358. }
  359. }
  360. /**
  361. * Process the checkout form.
  362. *
  363. * @access public
  364. * @return void
  365. */
  366. function woocommerce_checkout_action() {
  367. global $woocommerce;
  368. if ( isset( $_POST['woocommerce_checkout_place_order'] ) || isset( $_POST['woocommerce_checkout_update_totals'] ) ) {
  369. if ( sizeof( $woocommerce->cart->get_cart() ) == 0 ) {
  370. wp_redirect( get_permalink( woocommerce_get_page_id( 'cart' ) ) );
  371. exit;
  372. }
  373. if ( ! defined( 'WOOCOMMERCE_CHECKOUT' ) )
  374. define( 'WOOCOMMERCE_CHECKOUT', true );
  375. $woocommerce_checkout = $woocommerce->checkout();
  376. $woocommerce_checkout->process_checkout();
  377. }
  378. }
  379. /**
  380. * Process the pay form.
  381. *
  382. * @access public
  383. * @return void
  384. */
  385. function woocommerce_pay_action() {
  386. global $woocommerce;
  387. if ( isset( $_POST['woocommerce_pay'] ) && $woocommerce->verify_nonce( 'pay' ) ) {
  388. ob_start();
  389. // Pay for existing order
  390. $order_key = urldecode( $_GET['order'] );
  391. $order_id = absint( $_GET['order_id'] );
  392. $order = new WC_Order( $order_id );
  393. if ( $order->id == $order_id && $order->order_key == $order_key && in_array( $order->status, array( 'pending', 'failed' ) ) ) {
  394. // Set customer location to order location
  395. if ( $order->billing_country )
  396. $woocommerce->customer->set_country( $order->billing_country );
  397. if ( $order->billing_state )
  398. $woocommerce->customer->set_state( $order->billing_state );
  399. if ( $order->billing_postcode )
  400. $woocommerce->customer->set_postcode( $order->billing_postcode );
  401. if ( $order->billing_city )
  402. $woocommerce->customer->set_city( $order->billing_city );
  403. // Update payment method
  404. if ( $order->order_total > 0 ) {
  405. $payment_method = woocommerce_clean( $_POST['payment_method'] );
  406. $available_gateways = $woocommerce->payment_gateways->get_available_payment_gateways();
  407. // Update meta
  408. update_post_meta( $order_id, '_payment_method', $payment_method );
  409. if ( isset( $available_gateways[ $payment_method ] ) )
  410. $payment_method_title = $available_gateways[ $payment_method ]->get_title();
  411. update_post_meta( $order_id, '_payment_method_title', $payment_method_title);
  412. // Validate
  413. $available_gateways[ $payment_method ]->validate_fields();
  414. // Process
  415. if ( $woocommerce->error_count() == 0 ) {
  416. $result = $available_gateways[ $payment_method ]->process_payment( $order_id );
  417. // Redirect to success/confirmation/payment page
  418. if ( $result['result'] == 'success' ) {
  419. wp_redirect( $result['redirect'] );
  420. exit;
  421. }
  422. }
  423. } else {
  424. // No payment was required for order
  425. $order->payment_complete();
  426. wp_safe_redirect( get_permalink( woocommerce_get_page_id( 'thanks' ) ) );
  427. exit;
  428. }
  429. }
  430. }
  431. }
  432. /**
  433. * Process the login form.
  434. *
  435. * @access public
  436. * @return void
  437. */
  438. function woocommerce_process_login() {
  439. global $woocommerce;
  440. if (isset($_POST['login']) && $_POST['login']) :
  441. $woocommerce->verify_nonce('login');
  442. if ( !isset($_POST['username']) || empty($_POST['username']) ) $woocommerce->add_error( __( 'Username is required.', 'woocommerce' ) );
  443. if ( !isset($_POST['password']) || empty($_POST['password']) ) $woocommerce->add_error( __( 'Password is required.', 'woocommerce' ) );
  444. if ($woocommerce->error_count()==0) :
  445. $creds = array();
  446. $creds['user_login'] = $_POST['username'];
  447. $creds['user_password'] = $_POST['password'];
  448. $creds['remember'] = true;
  449. $secure_cookie = is_ssl() ? true : false;
  450. $user = wp_signon( $creds, $secure_cookie );
  451. if ( is_wp_error($user) ) :
  452. $woocommerce->add_error( $user->get_error_message() );
  453. else :
  454. if (isset($_POST['redirect']) && $_POST['redirect']) :
  455. wp_safe_redirect( esc_attr($_POST['redirect']) );
  456. exit;
  457. endif;
  458. if ( wp_get_referer() ) :
  459. wp_safe_redirect( wp_get_referer() );
  460. exit;
  461. endif;
  462. wp_redirect(get_permalink(woocommerce_get_page_id('myaccount')));
  463. exit;
  464. endif;
  465. endif;
  466. endif;
  467. }
  468. /**
  469. * Process the registration form.
  470. *
  471. * @access public
  472. * @return void
  473. */
  474. function woocommerce_process_registration() {
  475. global $woocommerce;
  476. if (isset($_POST['register']) && $_POST['register']) :
  477. $woocommerce->verify_nonce('register');
  478. // Get fields
  479. $user_email = isset( $_POST['email'] ) ? trim( $_POST['email'] ) : '';
  480. $password = isset( $_POST['password'] ) ? trim( $_POST['password'] ) : '';
  481. $password2 = isset( $_POST['password2'] ) ? trim( $_POST['password2'] ) : '';
  482. $user_email = apply_filters( 'user_registration_email', $user_email );
  483. if ( get_option( 'woocommerce_registration_email_for_username' ) == 'no' ) {
  484. $username = isset( $_POST['username'] ) ? trim( $_POST['username'] ) : '';
  485. $sanitized_user_login = sanitize_user( $username );
  486. // Check the username
  487. if ( $sanitized_user_login == '' ) {
  488. $woocommerce->add_error( '<strong>' . __( 'ERROR', 'woocommerce' ) . '</strong>: ' . __( 'Please enter a username.', 'woocommerce' ) );
  489. } elseif ( ! validate_username( $username ) ) {
  490. $woocommerce->add_error( '<strong>' . __( 'ERROR', 'woocommerce' ) . '</strong>: ' . __( 'This username is invalid because it uses illegal characters. Please enter a valid username.', 'woocommerce' ) );
  491. $sanitized_user_login = '';
  492. } elseif ( username_exists( $sanitized_user_login ) ) {
  493. $woocommerce->add_error( '<strong>' . __( 'ERROR', 'woocommerce' ) . '</strong>: ' . __( 'This username is already registered, please choose another one.', 'woocommerce' ) );
  494. }
  495. } else {
  496. $username = $user_email;
  497. $sanitized_user_login = sanitize_user( $username );
  498. }
  499. // Check the e-mail address
  500. if ( $user_email == '' ) {
  501. $woocommerce->add_error( '<strong>' . __( 'ERROR', 'woocommerce' ) . '</strong>: ' . __( 'Please type your e-mail address.', 'woocommerce' ) );
  502. } elseif ( ! is_email( $user_email ) ) {
  503. $woocommerce->add_error( '<strong>' . __( 'ERROR', 'woocommerce' ) . '</strong>: ' . __( 'The email address isn&#8217;t correct.', 'woocommerce' ) );
  504. $user_email = '';
  505. } elseif ( email_exists( $user_email ) ) {
  506. $woocommerce->add_error( '<strong>' . __( 'ERROR', 'woocommerce' ) . '</strong>: ' . __( 'This email is already registered, please choose another one.', 'woocommerce' ) );
  507. }
  508. // Password
  509. if ( !$password ) $woocommerce->add_error( __( 'Password is required.', 'woocommerce' ) );
  510. if ( !$password2 ) $woocommerce->add_error( __( 'Re-enter your password.', 'woocommerce' ) );
  511. if ( $password != $password2 ) $woocommerce->add_error( __( 'Passwords do not match.', 'woocommerce' ) );
  512. // Spam trap
  513. if (isset($_POST['email_2']) && $_POST['email_2']) $woocommerce->add_error( __( 'Anti-spam field was filled in.', 'woocommerce' ) );
  514. if ($woocommerce->error_count()==0) :
  515. $reg_errors = new WP_Error();
  516. do_action('register_post', $sanitized_user_login, $user_email, $reg_errors);
  517. $reg_errors = apply_filters( 'registration_errors', $reg_errors, $sanitized_user_login, $user_email );
  518. // if there are no errors, let's create the user account
  519. if ( !$reg_errors->get_error_code() ) :
  520. $user_id = wp_create_user( $sanitized_user_login, $password, $user_email );
  521. if ( !$user_id ) {
  522. $woocommerce->add_error( '<strong>' . __( 'ERROR', 'woocommerce' ) . '</strong>: ' . __( 'Couldn&#8217;t register you&hellip; please contact us if you continue to have problems.', 'woocommerce' ) );
  523. return;
  524. }
  525. // Change role
  526. wp_update_user( array ('ID' => $user_id, 'role' => 'customer') ) ;
  527. // Action
  528. do_action( 'woocommerce_created_customer', $user_id );
  529. // send the user a confirmation and their login details
  530. $mailer = $woocommerce->mailer();
  531. $mailer->customer_new_account( $user_id, $password );
  532. // set the WP login cookie
  533. $secure_cookie = is_ssl() ? true : false;
  534. wp_set_auth_cookie($user_id, true, $secure_cookie);
  535. // Redirect
  536. if ( wp_get_referer() ) :
  537. wp_safe_redirect( wp_get_referer() );
  538. exit;
  539. endif;
  540. wp_redirect(get_permalink(woocommerce_get_page_id('myaccount')));
  541. exit;
  542. else :
  543. $woocommerce->add_error( $reg_errors->get_error_message() );
  544. return;
  545. endif;
  546. endif;
  547. endif;
  548. }
  549. /**
  550. * Place a previous order again.
  551. *
  552. * @access public
  553. * @return void
  554. */
  555. function woocommerce_order_again() {
  556. global $woocommerce;
  557. // Nothing to do
  558. if ( ! isset( $_GET['order_again'] ) || ! is_user_logged_in() || get_option('woocommerce_allow_customers_to_reorder') == 'no' ) return;
  559. // Nonce security check
  560. if ( ! $woocommerce->verify_nonce( 'order_again', '_GET' ) ) return;
  561. // Clear current cart
  562. $woocommerce->cart->empty_cart();
  563. // Load the previous order - Stop if the order does not exist
  564. $order = new WC_Order( (int) $_GET['order_again'] );
  565. if ( empty( $order->id ) ) return;
  566. if ( $order->status!='completed' ) return;
  567. // Make sure the previous order belongs to the current customer
  568. if ( $order->user_id != get_current_user_id() ) return;
  569. // Copy products from the order to the cart
  570. foreach ( $order->get_items() as $item ) {
  571. // Load all product info including variation data
  572. $product_id = (int) apply_filters( 'woocommerce_add_to_cart_product_id', $item['product_id'] );
  573. $quantity = (int) $item['qty'];
  574. $variation_id = (int) $item['variation_id'];
  575. $variations = array();
  576. foreach ( $item['item_meta'] as $meta ) {
  577. if ( ! substr( $meta['meta_name'], 0, 3) === 'pa_' ) continue;
  578. $variations[$meta['meta_name']] = $meta['meta_value'];
  579. }
  580. // Add to cart validation
  581. if ( ! apply_filters( 'woocommerce_add_to_cart_validation', true, $product_id, $quantity ) ) continue;
  582. $woocommerce->cart->add_to_cart( $product_id, $quantity, $variation_id, $variations );
  583. }
  584. do_action( 'woocommerce_ordered_again', $order->id );
  585. // Redirect to cart
  586. $woocommerce->add_message( __( 'The cart has been filled with the items from your previous order.', 'woocommerce' ) );
  587. wp_safe_redirect( $woocommerce->cart->get_cart_url() );
  588. exit;
  589. }
  590. /**
  591. * Cancel a pending order.
  592. *
  593. * @access public
  594. * @return void
  595. */
  596. function woocommerce_cancel_order() {
  597. global $woocommerce;
  598. if ( isset($_GET['cancel_order']) && isset($_GET['order']) && isset($_GET['order_id']) ) :
  599. $order_key = urldecode( $_GET['order'] );
  600. $order_id = (int) $_GET['order_id'];
  601. $order = new WC_Order( $order_id );
  602. if ($order->id == $order_id && $order->order_key == $order_key && in_array($order->status, array('pending', 'failed')) && $woocommerce->verify_nonce('cancel_order', '_GET')) :
  603. // Cancel the order + restore stock
  604. $order->cancel_order( __('Order cancelled by customer.', 'woocommerce' ) );
  605. // Message
  606. $woocommerce->add_message( __( 'Your order was cancelled.', 'woocommerce' ) );
  607. do_action( 'woocommerce_cancelled_order', $order->id );
  608. elseif ($order->status!='pending') :
  609. $woocommerce->add_error( __( 'Your order is no longer pending and could not be cancelled. Please contact us if you need assistance.', 'woocommerce' ) );
  610. else :
  611. $woocommerce->add_error( __( 'Invalid order.', 'woocommerce' ) );
  612. endif;
  613. wp_safe_redirect($woocommerce->cart->get_cart_url());
  614. exit;
  615. endif;
  616. }
  617. /**
  618. * Download a file - hook into init function.
  619. *
  620. * @access public
  621. * @return void
  622. */
  623. function woocommerce_download_product() {
  624. if ( isset( $_GET['download_file'] ) && isset( $_GET['order'] ) && isset( $_GET['email'] ) ) {
  625. global $wpdb;
  626. $product_id = (int) urldecode($_GET['download_file']);
  627. $order_key = urldecode( $_GET['order'] );
  628. $email = sanitize_email( str_replace( ' ', '+', urldecode( $_GET['email'] ) ) );
  629. $download_id = isset( $_GET['key'] ) ? urldecode( $_GET['key'] ) : ''; // backwards compatibility for existing download URLs
  630. $_product = get_product( $product_id );
  631. if ( ! is_email( $email) )
  632. wp_die( __( 'Invalid email address.', 'woocommerce' ) . ' <a href="' . home_url() . '">' . __( 'Go to homepage &rarr;', 'woocommerce' ) . '</a>' );
  633. $query = "
  634. SELECT order_id,downloads_remaining,user_id,download_count,access_expires,download_id
  635. FROM " . $wpdb->prefix . "woocommerce_downloadable_product_permissions
  636. WHERE user_email = %s
  637. AND order_key = %s
  638. AND product_id = %s";
  639. $args = array(
  640. $email,
  641. $order_key,
  642. $product_id
  643. );
  644. if ( $download_id ) {
  645. // backwards compatibility for existing download URLs
  646. $query .= " AND download_id = %s";
  647. $args[] = $download_id;
  648. }
  649. $download_result = $wpdb->get_row( $wpdb->prepare( $query, $args ) );
  650. if ( ! $download_result )
  651. wp_die( __( 'Invalid download.', 'woocommerce' ) . ' <a href="'.home_url().'">' . __( 'Go to homepage &rarr;', 'woocommerce' ) . '</a>' );
  652. $download_id = $download_result->download_id;
  653. $order_id = $download_result->order_id;
  654. $downloads_remaining = $download_result->downloads_remaining;
  655. $download_count = $download_result->download_count;
  656. $user_id = $download_result->user_id;
  657. $access_expires = $download_result->access_expires;
  658. if ( $user_id && get_option( 'woocommerce_downloads_require_login' ) == 'yes' ) {
  659. if ( ! is_user_logged_in() )
  660. wp_die( __( 'You must be logged in to download files.', 'woocommerce' ) . ' <a href="' . wp_login_url( get_permalink( woocommerce_get_page_id( 'myaccount' ) ) ) . '">' . __( 'Login &rarr;', 'woocommerce' ) . '</a>' );
  661. elseif ( $user_id != get_current_user_id() )
  662. wp_die( __( 'This is not your download link.', 'woocommerce' ) );
  663. }
  664. if ( ! get_post( $product_id ) )
  665. wp_die( __( 'Product no longer exists.', 'woocommerce' ) . ' <a href="' . home_url() . '">' . __( 'Go to homepage &rarr;', 'woocommerce' ) . '</a>' );
  666. if ( $order_id ) {
  667. $order = new WC_Order( $order_id );
  668. if ( ! $order->is_download_permitted() && $order->status != 'publish' )
  669. wp_die( __( 'Invalid order.', 'woocommerce' ) . ' <a href="' . home_url() . '">' . __( 'Go to homepage &rarr;', 'woocommerce' ) . '</a>' );
  670. }
  671. if ( $downloads_remaining == '0' )
  672. wp_die( __( 'Sorry, you have reached your download limit for this file', 'woocommerce' ) . ' <a href="'.home_url().'">' . __( 'Go to homepage &rarr;', 'woocommerce' ) . '</a>' );
  673. if ( $access_expires > 0 && strtotime( $access_expires) < current_time( 'timestamp' ) )
  674. wp_die( __( 'Sorry, this download has expired', 'woocommerce' ) . ' <a href="' . home_url() . '">' . __( 'Go to homepage &rarr;', 'woocommerce' ) . '</a>' );
  675. if ( $downloads_remaining > 0 ) {
  676. $wpdb->update( $wpdb->prefix . "woocommerce_downloadable_product_permissions", array(
  677. 'downloads_remaining' => $downloads_remaining - 1,
  678. ), array(
  679. 'user_email' => $email,
  680. 'order_key' => $order_key,
  681. 'product_id' => $product_id,
  682. 'download_id' => $download_id
  683. ), array( '%d' ), array( '%s', '%s', '%d', '%s' ) );
  684. }
  685. // Count the download
  686. $wpdb->update( $wpdb->prefix . "woocommerce_downloadable_product_permissions", array(
  687. 'download_count' => $download_count + 1,
  688. ), array(
  689. 'user_email' => $email,
  690. 'order_key' => $order_key,
  691. 'product_id' => $product_id,
  692. 'download_id' => $download_id
  693. ), array( '%d' ), array( '%s', '%s', '%d', '%s' ) );
  694. // Get the download URL and try to replace the url with a path
  695. $file_path = $_product->get_file_download_path( $download_id );
  696. if ( ! $file_path ) exit;
  697. $file_download_method = apply_filters( 'woocommerce_file_download_method', get_option( 'woocommerce_file_download_method' ), $product_id );
  698. // Redirect to download location
  699. if ( $file_download_method == 'redirect' ) {
  700. header( 'Location: ' . $file_path );
  701. exit;
  702. }
  703. // Get URLS with https
  704. $site_url = site_url();
  705. $network_url = network_admin_url();
  706. if ( is_ssl() ) {
  707. $site_url = str_replace( 'https:', 'http:', $site_url );
  708. $network_url = str_replace( 'https:', 'http:', $network_url );
  709. }
  710. if ( ! is_multisite() ) {
  711. $file_path = str_replace( trailingslashit( $site_url ), ABSPATH, $file_path );
  712. } else {
  713. $upload_dir = wp_upload_dir();
  714. // Try to replace network url
  715. $file_path = str_replace( trailingslashit( $network_url ), ABSPATH, $file_path );
  716. // Now try to replace upload URL
  717. $file_path = str_replace( $upload_dir['baseurl'], $upload_dir['basedir'], $file_path );
  718. }
  719. // See if its local or remote
  720. if ( strstr( $file_path, 'http:' ) || strstr( $file_path, 'https:' ) || strstr( $file_path, 'ftp:' ) ) {
  721. $remote_file = true;
  722. } else {
  723. $remote_file = false;
  724. $file_path = realpath( $file_path );
  725. }
  726. // Download the file
  727. $file_extension = strtolower( substr( strrchr( $file_path, "." ), 1 ) );
  728. $ctype = "application/force-download";
  729. foreach ( get_allowed_mime_types() as $mime => $type ) {
  730. $mimes = explode( '|', $mime );
  731. if ( in_array( $file_extension, $mimes ) ) {
  732. $ctype = $type;
  733. break;
  734. }
  735. }
  736. if ( $file_download_method == 'xsendfile' ) {
  737. // Path fix - kudos to Jason Judge
  738. if ( getcwd() )
  739. $file_path = trim( preg_replace( '`^' . getcwd() . '`' , '', $file_path ), '/' );
  740. header( "Content-Disposition: attachment; filename=\"" . basename( $file_path ) . "\";" );
  741. if ( function_exists( 'apache_get_modules' ) && in_array( 'mod_xsendfile', apache_get_modules() ) ) {
  742. header("X-Sendfile: $file_path");
  743. exit;
  744. } elseif ( stristr( getenv( 'SERVER_SOFTWARE' ), 'lighttpd' ) ) {
  745. header( "X-Lighttpd-Sendfile: $file_path" );
  746. exit;
  747. } elseif ( stristr( getenv( 'SERVER_SOFTWARE' ), 'nginx' ) || stristr( getenv( 'SERVER_SOFTWARE' ), 'cherokee' ) ) {
  748. header( "X-Accel-Redirect: $file_path" );
  749. exit;
  750. }
  751. }
  752. if ( ! function_exists('readfile_chunked')) {
  753. /**
  754. * readfile_chunked
  755. *
  756. * Reads file in chunks so big downloads are possible without changing PHP.INI - http://codeigniter.com/wiki/Download_helper_for_large_files/
  757. *
  758. * @access public
  759. * @param string file
  760. * @param boolean return bytes of file
  761. * @return void
  762. */
  763. function readfile_chunked( $file, $retbytes = true ) {
  764. $chunksize = 1 * ( 1024 * 1024 );
  765. $buffer = '';
  766. $cnt = 0;
  767. $handle = fopen( $file, 'r' );
  768. if ( $handle === FALSE )
  769. return FALSE;
  770. while ( ! feof( $handle ) ) {
  771. $buffer = fread( $handle, $chunksize );
  772. echo $buffer;
  773. ob_flush();
  774. flush();
  775. if ( $retbytes )
  776. $cnt += strlen( $buffer );
  777. }
  778. $status = fclose( $handle );
  779. if ( $retbytes && $status )
  780. return $cnt;
  781. return $status;
  782. }
  783. }
  784. @session_write_close();
  785. if ( function_exists( 'apache_setenv' ) )
  786. @apache_setenv( 'no-gzip', 1 );
  787. @ini_set( 'zlib.output_compression', 'Off' );
  788. @set_time_limit(0);
  789. @set_magic_quotes_runtime(0);
  790. @ob_end_clean();
  791. if ( ob_get_level() )
  792. @ob_end_clean(); // Zip corruption fix
  793. header( "Pragma: no-cache" );
  794. header( "Expires: 0" );
  795. header( "Cache-Control: must-revalidate, post-check=0, pre-check=0" );
  796. header( "Robots: none" );
  797. header( "Content-Type: " . $ctype );
  798. header( "Content-Description: File Transfer" );
  799. header( "Content-Disposition: attachment; filename=\"" . basename( $file_path ) . "\";" );
  800. header( "Content-Transfer-Encoding: binary" );
  801. if ( $size = @filesize( $file_path ) )
  802. header( "Content-Length: " . $size );
  803. // Serve it
  804. if ( $remote_file ) {
  805. @readfile_chunked( "$file_path" ) or header( 'Location: ' . $file_path );
  806. } else {
  807. @readfile_chunked( "$file_path" ) or wp_die( __( 'File not found', 'woocommerce' ) . ' <a href="' . home_url() . '">' . __( 'Go to homepage &rarr;', 'woocommerce' ) . '</a>' );
  808. }
  809. exit;
  810. }
  811. }
  812. /**
  813. * ecommerce tracking with piwik.
  814. *
  815. * @access public
  816. * @param int $order_id
  817. * @return void
  818. */
  819. function woocommerce_ecommerce_tracking_piwik( $order_id ) {
  820. global $woocommerce;
  821. if (is_admin()) return; // Don't track admin
  822. // Call the Piwik ecommerce function if WP-Piwik is configured to add tracking codes to the page
  823. $wp_piwik_global_settings = get_option('wp-piwik_global-settings');
  824. // Return if Piwik settings are not here, or if global is not set
  825. if ( ! isset( $wp_piwik_global_settings['add_tracking_code'] ) || ! $wp_piwik_global_settings['add_tracking_code'] ) return;
  826. if ( ! isset( $GLOBALS['wp_piwik'] ) ) return;
  827. // Remove WP-Piwik from wp_footer and run it here instead, to get Piwik
  828. // loaded *before* we do our ecommerce tracking calls
  829. remove_action('wp_footer', array($GLOBALS['wp_piwik'],'footer'));
  830. $GLOBALS['wp_piwik']->footer();
  831. // Get the order and output tracking code
  832. $order = new WC_Order($order_id);
  833. ?>
  834. <script type="text/javascript">
  835. try {
  836. // Add order items
  837. <?php if ($order->get_items()) foreach($order->get_items() as $item) : $_product = $order->get_product_from_item( $item ); ?>
  838. piwikTracker.addEcommerceItem(
  839. "<?php echo esc_js( $_product->sku ); ?>", // (required) SKU: Product unique identifier
  840. "<?php echo esc_js( $item['name'] ); ?>", // (optional) Product name
  841. "<?php if (isset($_product->variation_data)) echo esc_js( woocommerce_get_formatted_variation( $_product->variation_data, true ) ); ?>", // (optional) Product category. You can also specify an array of up to 5 categories eg. ["Books", "New releases", "Biography"]
  842. <?php echo esc_js( ( $item['line_cost'] / $item['qty'] ) ); ?>, // (recommended) Product price
  843. <?php echo esc_js( $item['qty'] ); ?> // (optional, default to 1) Product quantity
  844. );
  845. <?php endforeach; ?>
  846. // Track order
  847. piwikTracker.trackEcommerceOrder(
  848. "<?php echo esc_js( $order_id ); ?>", // (required) Unique Order ID
  849. <?php echo esc_js( $order->order_total ); ?>, // (required) Order Revenue grand total (includes tax, shipping, and subtracted discount)
  850. false, // (optional) Order sub total (excludes shipping)
  851. <?php echo esc_js( $order->get_total_tax() ); ?>, // (optional) Tax amount
  852. <?php echo esc_js( $order->get_shipping() ); ?>, // (optional) Shipping amount
  853. false // (optional) Discount offered (set to false for unspecified parameter)
  854. );
  855. } catch( err ) {}
  856. </script>
  857. <?php
  858. }
  859. /**
  860. * Products RSS Feed.
  861. *
  862. * @access public
  863. * @return void
  864. */
  865. function woocommerce_products_rss_feed() {
  866. // Product RSS
  867. if ( is_post_type_archive( 'product' ) || is_singular( 'product' ) ) {
  868. $feed = get_post_type_archive_feed_link( 'product' );
  869. echo '<link rel="alternate" type="application/rss+xml" title="' . __( 'New products', 'woocommerce' ) . '" href="' . esc_attr( $feed ) . '" />';
  870. } elseif ( is_tax( 'product_cat' ) ) {
  871. $term = get_term_by('slug', esc_attr( get_query_var('product_cat') ), 'product_cat');
  872. $feed = add_query_arg('product_cat', $term->slug, get_post_type_archive_feed_link( 'product' ));
  873. echo '<link rel="alternate" type="application/rss+xml" title="' . sprintf(__( 'New products added to %s', 'woocommerce' ), urlencode($term->name)) . '" href="' . esc_attr( $feed ) . '" />';
  874. } elseif ( is_tax( 'product_tag' ) ) {
  875. $term = get_term_by('slug', esc_attr( get_query_var('product_tag') ), 'product_tag');
  876. $feed = add_query_arg('product_tag', $term->slug, get_post_type_archive_feed_link( 'product' ));
  877. echo '<link rel="alternate" type="application/rss+xml" title="' . sprintf(__( 'New products tagged %s', 'woocommerce' ), urlencode($term->name)) . '" href="' . esc_attr( $feed ) . '" />';
  878. }
  879. }
  880. /**
  881. * Rating field for comments.
  882. *
  883. * @access public
  884. * @param mixed $comment_id
  885. * @return void
  886. */
  887. function woocommerce_add_comment_rating($comment_id) {
  888. if ( isset($_POST['rating']) ) :
  889. global $post;
  890. if ( ! $_POST['rating'] || $_POST['rating'] > 5 || $_POST['rating'] < 0 ) return;
  891. add_comment_meta( $comment_id, 'rating', (int) esc_attr($_POST['rating']), true );
  892. delete_transient( 'wc_average_rating_' . esc_attr($post->ID) );
  893. endif;
  894. }
  895. /**
  896. * Validate the comment ratings.
  897. *
  898. * @access public
  899. * @param array $comment_data
  900. * @return array
  901. */
  902. function woocommerce_check_comment_rating($comment_data) {
  903. global $woocommerce;
  904. // If posting a comment (not trackback etc) and not logged in
  905. if ( isset( $_POST['rating'] ) && ! $woocommerce->verify_nonce('comment_rating') )
  906. wp_die( __( 'You have taken too long. Please go back and refresh the page.', 'woocommerce' ) );
  907. elseif ( isset( $_POST['rating'] ) && empty( $_POST['rating'] ) && $comment_data['comment_type'] == '' && get_option('woocommerce_review_rating_required') == 'yes' ) {
  908. wp_die( __( 'Please rate the product.', 'woocommerce' ) );
  909. exit;
  910. }
  911. return $comment_data;
  912. }
  913. /**
  914. * Finds an Order ID based on an order key.
  915. *
  916. * @access public
  917. * @param string $order_key An order key has generated by
  918. * @return int The ID of an order, or 0 if the order could not be found
  919. */
  920. function woocommerce_get_order_id_by_order_key( $order_key ) {
  921. global $wpdb;
  922. // Faster than get_posts()
  923. $order_id = $wpdb->get_var( "SELECT post_id FROM {$wpdb->prefix}postmeta WHERE meta_key = '_order_key' AND meta_value = '{$order_key}'" );
  924. return $order_id;
  925. }