/includes/wc-user-functions.php

  1. <?php 
  2. /** 
  3. * WooCommerce Customer Functions 
  4. * 
  5. * Functions for customers. 
  6. * 
  7. * @author WooThemes 
  8. * @category Core 
  9. * @package WooCommerce/Functions 
  10. * @version 2.2.0 
  11. */ 
  12.  
  13. if ( ! defined( 'ABSPATH' ) ) { 
  14. exit; // Exit if accessed directly 
  15.  
  16. /** 
  17. * Prevent any user who cannot 'edit_posts' (subscribers, customers etc) from seeing the admin bar. 
  18. * 
  19. * Note: get_option( 'woocommerce_lock_down_admin', true ) is a deprecated option here for backwards compat. Defaults to true. 
  20. * 
  21. * @access public 
  22. * @param bool $show_admin_bar 
  23. * @return bool 
  24. */ 
  25. function wc_disable_admin_bar( $show_admin_bar ) { 
  26. if ( apply_filters( 'woocommerce_disable_admin_bar', get_option( 'woocommerce_lock_down_admin', 'yes' ) === 'yes' ) && ! ( current_user_can( 'edit_posts' ) || current_user_can( 'manage_woocommerce' ) ) ) { 
  27. $show_admin_bar = false; 
  28.  
  29. return $show_admin_bar; 
  30. add_filter( 'show_admin_bar', 'wc_disable_admin_bar', 10, 1 ); 
  31.  
  32. if ( ! function_exists( 'wc_create_new_customer' ) ) { 
  33.  
  34. /** 
  35. * Create a new customer. 
  36. * 
  37. * @param string $email Customer email. 
  38. * @param string $username Customer username. 
  39. * @param string $password Customer password. 
  40. * @return int|WP_Error Returns WP_Error on failure, Int (user ID) on success. 
  41. */ 
  42. function wc_create_new_customer( $email, $username = '', $password = '' ) { 
  43.  
  44. // Check the email address. 
  45. if ( empty( $email ) || ! is_email( $email ) ) { 
  46. return new WP_Error( 'registration-error-invalid-email', __( 'Please provide a valid email address.', 'woocommerce' ) ); 
  47.  
  48. if ( email_exists( $email ) ) { 
  49. return new WP_Error( 'registration-error-email-exists', __( 'An account is already registered with your email address. Please login.', 'woocommerce' ) ); 
  50.  
  51. // Handle username creation. 
  52. if ( 'no' === get_option( 'woocommerce_registration_generate_username' ) || ! empty( $username ) ) { 
  53. $username = sanitize_user( $username ); 
  54.  
  55. if ( empty( $username ) || ! validate_username( $username ) ) { 
  56. return new WP_Error( 'registration-error-invalid-username', __( 'Please enter a valid account username.', 'woocommerce' ) ); 
  57.  
  58. if ( username_exists( $username ) ) { 
  59. return new WP_Error( 'registration-error-username-exists', __( 'An account is already registered with that username. Please choose another.', 'woocommerce' ) ); 
  60. } else { 
  61. $username = sanitize_user( current( explode( '@', $email ) ), true ); 
  62.  
  63. // Ensure username is unique. 
  64. $append = 1; 
  65. $o_username = $username; 
  66.  
  67. while ( username_exists( $username ) ) { 
  68. $username = $o_username . $append; 
  69. $append++; 
  70.  
  71. // Handle password creation. 
  72. if ( 'yes' === get_option( 'woocommerce_registration_generate_password' ) && empty( $password ) ) { 
  73. $password = wp_generate_password(); 
  74. $password_generated = true; 
  75. } elseif ( empty( $password ) ) { 
  76. return new WP_Error( 'registration-error-missing-password', __( 'Please enter an account password.', 'woocommerce' ) ); 
  77. } else { 
  78. $password_generated = false; 
  79.  
  80. // Use WP_Error to handle registration errors. 
  81. $errors = new WP_Error(); 
  82.  
  83. do_action( 'woocommerce_register_post', $username, $email, $errors ); 
  84.  
  85. $errors = apply_filters( 'woocommerce_registration_errors', $errors, $username, $email ); 
  86.  
  87. if ( $errors->get_error_code() ) { 
  88. return $errors; 
  89.  
  90. $new_customer_data = apply_filters( 'woocommerce_new_customer_data', array( 
  91. 'user_login' => $username,  
  92. 'user_pass' => $password,  
  93. 'user_email' => $email,  
  94. 'role' => 'customer',  
  95. ) ); 
  96.  
  97. $customer_id = wp_insert_user( $new_customer_data ); 
  98.  
  99. if ( is_wp_error( $customer_id ) ) { 
  100. return new WP_Error( 'registration-error', '<strong>' . __( 'Error:', 'woocommerce' ) . '</strong> ' . __( 'Couldn’t register you… please contact us if you continue to have problems.', 'woocommerce' ) ); 
  101.  
  102. do_action( 'woocommerce_created_customer', $customer_id, $new_customer_data, $password_generated ); 
  103.  
  104. return $customer_id; 
  105.  
  106. /** 
  107. * Login a customer (set auth cookie and set global user object). 
  108. * 
  109. * @param int $customer_id 
  110. */ 
  111. function wc_set_customer_auth_cookie( $customer_id ) { 
  112. global $current_user; 
  113.  
  114. $current_user = get_user_by( 'id', $customer_id ); 
  115.  
  116. wp_set_auth_cookie( $customer_id, true ); 
  117.  
  118. /** 
  119. * Get past orders (by email) and update them. 
  120. * 
  121. * @param int $customer_id 
  122. * @return int 
  123. */ 
  124. function wc_update_new_customer_past_orders( $customer_id ) { 
  125. $linked = 0; 
  126. $complete = 0; 
  127. $customer = get_user_by( 'id', absint( $customer_id ) ); 
  128. $customer_orders = wc_get_orders( array( 
  129. 'limit' => -1,  
  130. 'customer' => array( array( 0, $customer->user_email ) ),  
  131. 'return' => 'ids',  
  132. ) ); 
  133.  
  134. if ( ! empty( $customer_orders ) ) { 
  135. foreach ( $customer_orders as $order_id ) { 
  136. update_post_meta( $order_id, '_customer_user', $customer->ID ); 
  137.  
  138. do_action( 'woocommerce_update_new_customer_past_order', $order_id, $customer ); 
  139.  
  140. if ( get_post_status( $order_id ) === 'wc-completed' ) { 
  141. $complete++; 
  142.  
  143. $linked++; 
  144.  
  145. if ( $complete ) { 
  146. update_user_meta( $customer_id, 'paying_customer', 1 ); 
  147. update_user_meta( $customer_id, '_order_count', '' ); 
  148. update_user_meta( $customer_id, '_money_spent', '' ); 
  149.  
  150. return $linked; 
  151.  
  152. /** 
  153. * Order Status completed - This is a paying customer. 
  154. * 
  155. * @access public 
  156. * @param int $order_id 
  157. */ 
  158. function wc_paying_customer( $order_id ) { 
  159. $order = wc_get_order( $order_id ); 
  160. $customer_id = $order->get_customer_id(); 
  161.  
  162. if ( $customer_id > 0 && 'shop_order_refund' !== $order->get_type() ) { 
  163. $customer = new WC_Customer( $customer_id ); 
  164. $customer->set_is_paying_customer( true ); 
  165. $customer->save(); 
  166. add_action( 'woocommerce_order_status_completed', 'wc_paying_customer' ); 
  167.  
  168. /** 
  169. * Checks if a user (by email or ID or both) has bought an item. 
  170. * @param string $customer_email 
  171. * @param int $user_id 
  172. * @param int $product_id 
  173. * @return bool 
  174. */ 
  175. function wc_customer_bought_product( $customer_email, $user_id, $product_id ) { 
  176. global $wpdb; 
  177.  
  178. $transient_name = 'wc_cbp_' . md5( $customer_email . $user_id . WC_Cache_Helper::get_transient_version( 'orders' ) ); 
  179.  
  180. if ( false === ( $result = get_transient( $transient_name ) ) ) { 
  181. $customer_data = array( $user_id ); 
  182.  
  183. if ( $user_id ) { 
  184. $user = get_user_by( 'id', $user_id ); 
  185.  
  186. if ( isset( $user->user_email ) ) { 
  187. $customer_data[] = $user->user_email; 
  188.  
  189. if ( is_email( $customer_email ) ) { 
  190. $customer_data[] = $customer_email; 
  191.  
  192. $customer_data = array_map( 'esc_sql', array_filter( array_unique( $customer_data ) ) ); 
  193. $statuses = array_map( 'esc_sql', wc_get_is_paid_statuses() ); 
  194.  
  195. if ( sizeof( $customer_data ) == 0 ) { 
  196. return false; 
  197.  
  198. $result = $wpdb->get_col( " 
  199. SELECT im.meta_value FROM {$wpdb->posts} AS p 
  200. INNER JOIN {$wpdb->postmeta} AS pm ON p.ID = pm.post_id 
  201. INNER JOIN {$wpdb->prefix}woocommerce_order_items AS i ON p.ID = i.order_id 
  202. INNER JOIN {$wpdb->prefix}woocommerce_order_itemmeta AS im ON i.order_item_id = im.order_item_id 
  203. WHERE p.post_status IN ( 'wc-" . implode( "', 'wc-", $statuses ) . "' ) 
  204. AND pm.meta_key IN ( '_billing_email', '_customer_user' ) 
  205. AND im.meta_key IN ( '_product_id', '_variation_id' ) 
  206. AND im.meta_value != 0 
  207. AND pm.meta_value IN ( '" . implode( "', '", $customer_data ) . "' ) 
  208. " ); 
  209. $result = array_map( 'absint', $result ); 
  210.  
  211. set_transient( $transient_name, $result, DAY_IN_SECONDS * 30 ); 
  212. return in_array( absint( $product_id ), $result ); 
  213.  
  214. /** 
  215. * Checks if a user has a certain capability. 
  216. * 
  217. * @access public 
  218. * @param array $allcaps 
  219. * @param array $caps 
  220. * @param array $args 
  221. * @return bool 
  222. */ 
  223. function wc_customer_has_capability( $allcaps, $caps, $args ) { 
  224. if ( isset( $caps[0] ) ) { 
  225. switch ( $caps[0] ) { 
  226. case 'view_order' : 
  227. $user_id = $args[1]; 
  228. $order = wc_get_order( $args[2] ); 
  229.  
  230. if ( $order && $user_id == $order->get_user_id() ) { 
  231. $allcaps['view_order'] = true; 
  232. break; 
  233. case 'pay_for_order' : 
  234. $user_id = $args[1]; 
  235. $order_id = isset( $args[2] ) ? $args[2] : null; 
  236.  
  237. // When no order ID, we assume it's a new order 
  238. // and thus, customer can pay for it 
  239. if ( ! $order_id ) { 
  240. $allcaps['pay_for_order'] = true; 
  241. break; 
  242.  
  243. $order = wc_get_order( $order_id ); 
  244.  
  245. if ( $order && ( $user_id == $order->get_user_id() || ! $order->get_user_id() ) ) { 
  246. $allcaps['pay_for_order'] = true; 
  247. break; 
  248. case 'order_again' : 
  249. $user_id = $args[1]; 
  250. $order = wc_get_order( $args[2] ); 
  251.  
  252. if ( $order && $user_id == $order->get_user_id() ) { 
  253. $allcaps['order_again'] = true; 
  254. break; 
  255. case 'cancel_order' : 
  256. $user_id = $args[1]; 
  257. $order = wc_get_order( $args[2] ); 
  258.  
  259. if ( $order && $user_id == $order->get_user_id() ) { 
  260. $allcaps['cancel_order'] = true; 
  261. break; 
  262. case 'download_file' : 
  263. $user_id = $args[1]; 
  264. $download = $args[2]; 
  265.  
  266. if ( $download && $user_id == $download->get_user_id() ) { 
  267. $allcaps['download_file'] = true; 
  268. break; 
  269. return $allcaps; 
  270. add_filter( 'user_has_cap', 'wc_customer_has_capability', 10, 3 ); 
  271.  
  272. /** 
  273. * Modify the list of editable roles to prevent non-admin adding admin users. 
  274. * @param array $roles 
  275. * @return array 
  276. */ 
  277. function wc_modify_editable_roles( $roles ) { 
  278. if ( ! current_user_can( 'administrator' ) ) { 
  279. unset( $roles['administrator'] ); 
  280. return $roles; 
  281. add_filter( 'editable_roles', 'wc_modify_editable_roles' ); 
  282.  
  283. /** 
  284. * Modify capabiltiies to prevent non-admin users editing admin users. 
  285. * 
  286. * $args[0] will be the user being edited in this case. 
  287. * 
  288. * @param array $caps Array of caps 
  289. * @param string $cap Name of the cap we are checking 
  290. * @param int $user_id ID of the user being checked against 
  291. * @param array $args 
  292. * @return array 
  293. */ 
  294. function wc_modify_map_meta_cap( $caps, $cap, $user_id, $args ) { 
  295. switch ( $cap ) { 
  296. case 'edit_user' : 
  297. case 'remove_user' : 
  298. case 'promote_user' : 
  299. case 'delete_user' : 
  300. if ( ! isset( $args[0] ) || $args[0] === $user_id ) { 
  301. break; 
  302. } else { 
  303. if ( user_can( $args[0], 'administrator' ) && ! current_user_can( 'administrator' ) ) { 
  304. $caps[] = 'do_not_allow'; 
  305. break; 
  306. return $caps; 
  307. add_filter( 'map_meta_cap', 'wc_modify_map_meta_cap', 10, 4 ); 
  308.  
  309. /** 
  310. * Get customer download permissions from the database. 
  311. * 
  312. * @param int $customer_id Customer/User ID 
  313. * @return array 
  314. */ 
  315. function wc_get_customer_download_permissions( $customer_id ) { 
  316. $data_store = WC_Data_Store::load( 'customer-download' ); 
  317. return apply_filters( 'woocommerce_permission_list', $data_store->get_downloads_for_customer( $customer_id ), $customer_id ); 
  318.  
  319. /** 
  320. * Get customer available downloads. 
  321. * 
  322. * @param int $customer_id Customer/User ID 
  323. * @return array 
  324. */ 
  325. function wc_get_customer_available_downloads( $customer_id ) { 
  326. $downloads = array(); 
  327. $_product = null; 
  328. $order = null; 
  329. $file_number = 0; 
  330.  
  331. // Get results from valid orders only 
  332. $results = wc_get_customer_download_permissions( $customer_id ); 
  333.  
  334. if ( $results ) { 
  335. foreach ( $results as $result ) { 
  336. if ( ! $order || $order->get_id() != $result->order_id ) { 
  337. // new order 
  338. $order = wc_get_order( $result->order_id ); 
  339. $_product = null; 
  340.  
  341. // Make sure the order exists for this download 
  342. if ( ! $order ) { 
  343. continue; 
  344.  
  345. // Downloads permitted? 
  346. if ( ! $order->is_download_permitted() ) { 
  347. continue; 
  348.  
  349. $product_id = intval( $result->product_id ); 
  350.  
  351. if ( ! $_product || $_product->get_id() != $product_id ) { 
  352. // new product 
  353. $file_number = 0; 
  354. $_product = wc_get_product( $product_id ); 
  355.  
  356. // Check product exists and has the file 
  357. if ( ! $_product || ! $_product->exists() || ! $_product->has_file( $result->download_id ) ) { 
  358. continue; 
  359.  
  360. $download_file = $_product->get_file( $result->download_id ); 
  361.  
  362. // Download name will be 'Product Name' for products with a single downloadable file, and 'Product Name - File X' for products with multiple files. 
  363. $download_name = apply_filters( 
  364. 'woocommerce_downloadable_product_name',  
  365. $_product->get_name() . ' – ' . $download_file['name'],  
  366. $_product,  
  367. $result->download_id,  
  368. $file_number 
  369. ); 
  370.  
  371. $downloads[] = array( 
  372. 'download_url' => add_query_arg( 
  373. array( 
  374. 'download_file' => $product_id,  
  375. 'order' => $result->order_key,  
  376. 'email' => urlencode( $result->user_email ),  
  377. 'key' => $result->download_id,  
  378. ),  
  379. home_url( '/' ) 
  380. ),  
  381. 'download_id' => $result->download_id,  
  382. 'product_id' => $_product->get_id(),  
  383. 'product_name' => $_product->get_name(),  
  384. 'download_name' => $download_name,  
  385. 'order_id' => $order->get_id(),  
  386. 'order_key' => $order->get_order_key(),  
  387. 'downloads_remaining' => $result->downloads_remaining,  
  388. 'access_expires' => $result->access_expires,  
  389. 'file' => array( 
  390. 'name' => $download_file->get_name(),  
  391. 'file' => $download_file->get_file(),  
  392. ),  
  393. ); 
  394.  
  395. $file_number++; 
  396.  
  397. return apply_filters( 'woocommerce_customer_available_downloads', $downloads, $customer_id ); 
  398.  
  399. /** 
  400. * Get total spent by customer. 
  401. * @param int $user_id 
  402. * @return string 
  403. */ 
  404. function wc_get_customer_total_spent( $user_id ) { 
  405. $customer = new WC_Customer( $user_id ); 
  406. return $customer->get_total_spent(); 
  407.  
  408. /** 
  409. * Get total orders by customer. 
  410. * @param int $user_id 
  411. * @return int 
  412. */ 
  413. function wc_get_customer_order_count( $user_id ) { 
  414. $customer = new WC_Customer( $user_id ); 
  415. return $customer->get_order_count(); 
  416.  
  417. /** 
  418. * Reset _customer_user on orders when a user is deleted. 
  419. * @param int $user_id 
  420. */ 
  421. function wc_reset_order_customer_id_on_deleted_user( $user_id ) { 
  422. global $wpdb; 
  423.  
  424. $wpdb->update( $wpdb->postmeta, array( 'meta_value' => 0 ), array( 'meta_key' => '_customer_user', 'meta_value' => $user_id ) ); 
  425.  
  426. add_action( 'deleted_user', 'wc_reset_order_customer_id_on_deleted_user' ); 
  427.  
  428. /** 
  429. * Get review verification status. 
  430. * @param int $comment_id 
  431. * @return bool 
  432. */ 
  433. function wc_review_is_from_verified_owner( $comment_id ) { 
  434. $verified = get_comment_meta( $comment_id, 'verified', true ); 
  435.  
  436. // If no "verified" meta is present, generate it (if this is a product review). 
  437. if ( '' === $verified ) { 
  438. $verified = WC_Comments::add_comment_purchase_verification( $comment_id ); 
  439.  
  440. return (bool) $verified; 
  441.  
  442. /** 
  443. * Disable author archives for customers. 
  444. * 
  445. * @since 2.5.0 
  446. */ 
  447. function wc_disable_author_archives_for_customers() { 
  448. global $wp_query, $author; 
  449.  
  450. if ( is_author() ) { 
  451. $user = get_user_by( 'id', $author ); 
  452.  
  453. if ( isset( $user->roles[0] ) && 'customer' === $user->roles[0] ) { 
  454. wp_redirect( wc_get_page_permalink( 'shop' ) ); 
  455.  
  456. add_action( 'template_redirect', 'wc_disable_author_archives_for_customers' ); 
  457.  
  458. /** 
  459. * Hooks into the `profile_update` hook to set the user last updated timestamp. 
  460. * 
  461. * @since 2.6.0 
  462. * @param int $user_id The user that was updated. 
  463. * @param array $old The profile fields pre-change. 
  464. */ 
  465. function wc_update_profile_last_update_time( $user_id, $old ) { 
  466. wc_set_user_last_update_time( $user_id ); 
  467.  
  468. add_action( 'profile_update', 'wc_update_profile_last_update_time', 10, 2 ); 
  469.  
  470. /** 
  471. * Hooks into the update user meta function to set the user last updated timestamp. 
  472. * 
  473. * @since 2.6.0 
  474. * @param int $meta_id ID of the meta object that was changed. 
  475. * @param int $user_id The user that was updated. 
  476. * @param string $meta_key Name of the meta key that was changed. 
  477. * @param string $_meta_value Value of the meta that was changed. 
  478. */ 
  479. function wc_meta_update_last_update_time( $meta_id, $user_id, $meta_key, $_meta_value ) { 
  480. $keys_to_track = apply_filters( 'woocommerce_user_last_update_fields', array( 'first_name', 'last_name' ) ); 
  481. $update_time = false; 
  482. if ( in_array( $meta_key, $keys_to_track ) ) { 
  483. $update_time = true; 
  484. if ( 'billing_' === substr( $meta_key, 0, 8 ) ) { 
  485. $update_time = true; 
  486. if ( 'shipping_' === substr( $meta_key, 0, 9 ) ) { 
  487. $update_time = true; 
  488.  
  489. if ( $update_time ) { 
  490. wc_set_user_last_update_time( $user_id ); 
  491.  
  492. add_action( 'update_user_meta', 'wc_meta_update_last_update_time', 10, 4 ); 
  493.  
  494. /** 
  495. * Sets a user's "last update" time to the current timestamp. 
  496. * 
  497. * @since 2.6.0 
  498. * @param int $user_id The user to set a timestamp for. 
  499. */ 
  500. function wc_set_user_last_update_time( $user_id ) { 
  501. update_user_meta( $user_id, 'last_update', gmdate( 'U' ) ); 
  502.  
  503. /** 
  504. * Get customer saved payment methods list. 
  505. * 
  506. * @since 2.6.0 
  507. * @param int $customer_id 
  508. * @return array 
  509. */ 
  510. function wc_get_customer_saved_methods_list( $customer_id ) { 
  511. return apply_filters( 'woocommerce_saved_payment_methods_list', array(), $customer_id ); 
  512.  
  513. /** 
  514. * Get info about customer's last order. 
  515. * 
  516. * @since 2.6.0 
  517. * @param int $customer_id Customer ID. 
  518. * @return WC_Order Order object if successful or false. 
  519. */ 
  520. function wc_get_customer_last_order( $customer_id ) { 
  521. global $wpdb; 
  522.  
  523. $customer_id = absint( $customer_id ); 
  524.  
  525. $id = $wpdb->get_var( "SELECT id 
  526. FROM $wpdb->posts AS posts 
  527. LEFT JOIN {$wpdb->postmeta} AS meta on posts.ID = meta.post_id 
  528. WHERE meta.meta_key = '_customer_user' 
  529. AND meta.meta_value = {$customer_id} 
  530. AND posts.post_type = 'shop_order' 
  531. AND posts.post_status IN ( '" . implode( "', '", array_keys( wc_get_order_statuses() ) ) . "' ) 
  532. ORDER BY posts.ID DESC 
  533. " ); 
  534.  
  535. return wc_get_order( $id ); 
  536.  
  537. /** 
  538. * Wrapper for @see get_avatar() which doesn't simply return 
  539. * the URL so we need to pluck it from the HTML img tag. 
  540. * 
  541. * Kudos to https://github.com/WP-API/WP-API for offering a better solution. 
  542. * 
  543. * @since 2.6.0 
  544. * @param string $email the customer's email. 
  545. * @return string the URL to the customer's avatar. 
  546. */ 
  547. function wc_get_customer_avatar_url( $email ) { 
  548. $avatar_html = get_avatar( $email ); 
  549.  
  550. // Get the URL of the avatar from the provided HTML. 
  551. preg_match( '/src=["|\'](.+)[\&|"|\']/U', $avatar_html, $matches ); 
  552.  
  553. if ( isset( $matches[1] ) && ! empty( $matches[1] ) ) { 
  554. return esc_url_raw( $matches[1] ); 
  555.  
  556. return null; 
.