PageRenderTime 29ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/wp-content/plugins/woocommerce/includes/api/v1/class-wc-api-customers.php

https://gitlab.com/webkod3r/tripolis
PHP | 504 lines | 247 code | 96 blank | 161 comment | 28 complexity | 473242137b2e79c3b2eece516609f261 MD5 | raw file
  1. <?php
  2. /**
  3. * WooCommerce API Customers Class
  4. *
  5. * Handles requests to the /customers endpoint
  6. *
  7. * @author WooThemes
  8. * @category API
  9. * @package WooCommerce/API
  10. * @since 2.1
  11. * @version 2.1
  12. */
  13. if ( ! defined( 'ABSPATH' ) ) {
  14. exit; // Exit if accessed directly
  15. }
  16. class WC_API_Customers extends WC_API_Resource {
  17. /** @var string $base the route base */
  18. protected $base = '/customers';
  19. /** @var string $created_at_min for date filtering */
  20. private $created_at_min = null;
  21. /** @var string $created_at_max for date filtering */
  22. private $created_at_max = null;
  23. /**
  24. * Setup class, overridden to provide customer data to order response
  25. *
  26. * @since 2.1
  27. * @param WC_API_Server $server
  28. * @return WC_API_Customers
  29. */
  30. public function __construct( WC_API_Server $server ) {
  31. parent::__construct( $server );
  32. // add customer data to order responses
  33. add_filter( 'woocommerce_api_order_response', array( $this, 'add_customer_data' ), 10, 2 );
  34. // modify WP_User_Query to support created_at date filtering
  35. add_action( 'pre_user_query', array( $this, 'modify_user_query' ) );
  36. }
  37. /**
  38. * Register the routes for this class
  39. *
  40. * GET /customers
  41. * GET /customers/count
  42. * GET /customers/<id>
  43. * GET /customers/<id>/orders
  44. *
  45. * @since 2.1
  46. * @param array $routes
  47. * @return array
  48. */
  49. public function register_routes( $routes ) {
  50. # GET /customers
  51. $routes[ $this->base ] = array(
  52. array( array( $this, 'get_customers' ), WC_API_SERVER::READABLE ),
  53. );
  54. # GET /customers/count
  55. $routes[ $this->base . '/count'] = array(
  56. array( array( $this, 'get_customers_count' ), WC_API_SERVER::READABLE ),
  57. );
  58. # GET /customers/<id>
  59. $routes[ $this->base . '/(?P<id>\d+)' ] = array(
  60. array( array( $this, 'get_customer' ), WC_API_SERVER::READABLE ),
  61. );
  62. # GET /customers/<id>/orders
  63. $routes[ $this->base . '/(?P<id>\d+)/orders' ] = array(
  64. array( array( $this, 'get_customer_orders' ), WC_API_SERVER::READABLE ),
  65. );
  66. return $routes;
  67. }
  68. /**
  69. * Get all customers
  70. *
  71. * @since 2.1
  72. * @param array $fields
  73. * @param array $filter
  74. * @param int $page
  75. * @return array
  76. */
  77. public function get_customers( $fields = null, $filter = array(), $page = 1 ) {
  78. $filter['page'] = $page;
  79. $query = $this->query_customers( $filter );
  80. $customers = array();
  81. foreach( $query->get_results() as $user_id ) {
  82. if ( ! $this->is_readable( $user_id ) )
  83. continue;
  84. $customers[] = current( $this->get_customer( $user_id, $fields ) );
  85. }
  86. $this->server->add_pagination_headers( $query );
  87. return array( 'customers' => $customers );
  88. }
  89. /**
  90. * Get the customer for the given ID
  91. *
  92. * @since 2.1
  93. * @param int $id the customer ID
  94. * @param string $fields
  95. * @return array
  96. */
  97. public function get_customer( $id, $fields = null ) {
  98. global $wpdb;
  99. $id = $this->validate_request( $id, 'customer', 'read' );
  100. if ( is_wp_error( $id ) )
  101. return $id;
  102. $customer = new WP_User( $id );
  103. // get info about user's last order
  104. $last_order = $wpdb->get_row( "SELECT id, post_date_gmt
  105. FROM $wpdb->posts AS posts
  106. LEFT JOIN {$wpdb->postmeta} AS meta on posts.ID = meta.post_id
  107. WHERE meta.meta_key = '_customer_user'
  108. AND meta.meta_value = {$customer->ID}
  109. AND posts.post_type = 'shop_order'
  110. AND posts.post_status IN ( '" . implode( "','", array_keys( wc_get_order_statuses() ) ) . "' )
  111. " );
  112. $customer_data = array(
  113. 'id' => $customer->ID,
  114. 'created_at' => $this->server->format_datetime( $customer->user_registered ),
  115. 'email' => $customer->user_email,
  116. 'first_name' => $customer->first_name,
  117. 'last_name' => $customer->last_name,
  118. 'username' => $customer->user_login,
  119. 'last_order_id' => is_object( $last_order ) ? $last_order->id : null,
  120. 'last_order_date' => is_object( $last_order ) ? $this->server->format_datetime( $last_order->post_date_gmt ) : null,
  121. 'orders_count' => (int) $customer->_order_count,
  122. 'total_spent' => wc_format_decimal( $customer->_money_spent, 2 ),
  123. 'avatar_url' => $this->get_avatar_url( $customer->customer_email ),
  124. 'billing_address' => array(
  125. 'first_name' => $customer->billing_first_name,
  126. 'last_name' => $customer->billing_last_name,
  127. 'company' => $customer->billing_company,
  128. 'address_1' => $customer->billing_address_1,
  129. 'address_2' => $customer->billing_address_2,
  130. 'city' => $customer->billing_city,
  131. 'state' => $customer->billing_state,
  132. 'postcode' => $customer->billing_postcode,
  133. 'country' => $customer->billing_country,
  134. 'email' => $customer->billing_email,
  135. 'phone' => $customer->billing_phone,
  136. ),
  137. 'shipping_address' => array(
  138. 'first_name' => $customer->shipping_first_name,
  139. 'last_name' => $customer->shipping_last_name,
  140. 'company' => $customer->shipping_company,
  141. 'address_1' => $customer->shipping_address_1,
  142. 'address_2' => $customer->shipping_address_2,
  143. 'city' => $customer->shipping_city,
  144. 'state' => $customer->shipping_state,
  145. 'postcode' => $customer->shipping_postcode,
  146. 'country' => $customer->shipping_country,
  147. ),
  148. );
  149. return array( 'customer' => apply_filters( 'woocommerce_api_customer_response', $customer_data, $customer, $fields, $this->server ) );
  150. }
  151. /**
  152. * Get the total number of customers
  153. *
  154. * @since 2.1
  155. * @param array $filter
  156. * @return array
  157. */
  158. public function get_customers_count( $filter = array() ) {
  159. $query = $this->query_customers( $filter );
  160. if ( ! current_user_can( 'list_users' ) )
  161. return new WP_Error( 'woocommerce_api_user_cannot_read_customers_count', __( 'You do not have permission to read the customers count', 'woocommerce' ), array( 'status' => 401 ) );
  162. return array( 'count' => count( $query->get_results() ) );
  163. }
  164. /**
  165. * Create a customer
  166. *
  167. * @TODO implement in 2.2 with woocommerce_create_new_customer()
  168. * @param array $data
  169. * @return array
  170. */
  171. public function create_customer( $data ) {
  172. if ( ! current_user_can( 'create_users' ) )
  173. return new WP_Error( 'woocommerce_api_user_cannot_create_customer', __( 'You do not have permission to create this customer', 'woocommerce' ), array( 'status' => 401 ) );
  174. return array();
  175. }
  176. /**
  177. * Edit a customer
  178. *
  179. * @TODO implement in 2.2
  180. * @param int $id the customer ID
  181. * @param array $data
  182. * @return array
  183. */
  184. public function edit_customer( $id, $data ) {
  185. $id = $this->validate_request( $id, 'customer', 'edit' );
  186. if ( ! is_wp_error( $id ) )
  187. return $id;
  188. return $this->get_customer( $id );
  189. }
  190. /**
  191. * Delete a customer
  192. *
  193. * @TODO enable along with PUT/POST in 2.2
  194. * @param int $id the customer ID
  195. * @return array
  196. */
  197. public function delete_customer( $id ) {
  198. $id = $this->validate_request( $id, 'customer', 'delete' );
  199. if ( ! is_wp_error( $id ) )
  200. return $id;
  201. return $this->delete( $id, 'customer' );
  202. }
  203. /**
  204. * Get the orders for a customer
  205. *
  206. * @since 2.1
  207. * @param int $id the customer ID
  208. * @param string $fields fields to include in response
  209. * @return array
  210. */
  211. public function get_customer_orders( $id, $fields = null ) {
  212. global $wpdb;
  213. $id = $this->validate_request( $id, 'customer', 'read' );
  214. if ( is_wp_error( $id ) )
  215. return $id;
  216. $order_ids = $wpdb->get_col( $wpdb->prepare( "SELECT id
  217. FROM $wpdb->posts AS posts
  218. LEFT JOIN {$wpdb->postmeta} AS meta on posts.ID = meta.post_id
  219. WHERE meta.meta_key = '_customer_user'
  220. AND meta.meta_value = '%s'
  221. AND posts.post_type = 'shop_order'
  222. AND posts.post_status = IN ( '" . implode( "','", array_keys( wc_get_order_statuses() ) ) . "' )
  223. ", $id ) );
  224. if ( empty( $order_ids ) )
  225. return array( 'orders' => array() );
  226. $orders = array();
  227. foreach ( $order_ids as $order_id ) {
  228. $orders[] = current( WC()->api->WC_API_Orders->get_order( $order_id, $fields ) );
  229. }
  230. return array( 'orders' => apply_filters( 'woocommerce_api_customer_orders_response', $orders, $id, $fields, $order_ids, $this->server ) );
  231. }
  232. /**
  233. * Helper method to get customer user objects
  234. *
  235. * Note that WP_User_Query does not have built-in pagination so limit & offset are used to provide limited
  236. * pagination support
  237. *
  238. * @since 2.1
  239. * @param array $args request arguments for filtering query
  240. * @return WP_User_Query
  241. */
  242. private function query_customers( $args = array() ) {
  243. // default users per page
  244. $users_per_page = get_option( 'posts_per_page' );
  245. // set base query arguments
  246. $query_args = array(
  247. 'fields' => 'ID',
  248. 'role' => 'customer',
  249. 'orderby' => 'registered',
  250. 'number' => $users_per_page,
  251. );
  252. // search
  253. if ( ! empty( $args['q'] ) ) {
  254. $query_args['search'] = $args['q'];
  255. }
  256. // limit number of users returned
  257. if ( ! empty( $args['limit'] ) ) {
  258. $query_args['number'] = absint( $args['limit'] );
  259. $users_per_page = absint( $args['limit'] );
  260. }
  261. // page
  262. $page = ( isset( $args['page'] ) ) ? absint( $args['page'] ) : 1;
  263. // offset
  264. if ( ! empty( $args['offset'] ) ) {
  265. $query_args['offset'] = absint( $args['offset'] );
  266. } else {
  267. $query_args['offset'] = $users_per_page * ( $page - 1 );
  268. }
  269. // created date
  270. if ( ! empty( $args['created_at_min'] ) ) {
  271. $this->created_at_min = $this->server->parse_datetime( $args['created_at_min'] );
  272. }
  273. if ( ! empty( $args['created_at_max'] ) ) {
  274. $this->created_at_max = $this->server->parse_datetime( $args['created_at_max'] );
  275. }
  276. $query = new WP_User_Query( $query_args );
  277. // helper members for pagination headers
  278. $query->total_pages = ceil( $query->get_total() / $users_per_page );
  279. $query->page = $page;
  280. return $query;
  281. }
  282. /**
  283. * Add customer data to orders
  284. *
  285. * @since 2.1
  286. * @param $order_data
  287. * @param $order
  288. * @return array
  289. */
  290. public function add_customer_data( $order_data, $order ) {
  291. if ( 0 == $order->customer_user ) {
  292. // add customer data from order
  293. $order_data['customer'] = array(
  294. 'id' => 0,
  295. 'email' => $order->billing_email,
  296. 'first_name' => $order->billing_first_name,
  297. 'last_name' => $order->billing_last_name,
  298. 'billing_address' => array(
  299. 'first_name' => $order->billing_first_name,
  300. 'last_name' => $order->billing_last_name,
  301. 'company' => $order->billing_company,
  302. 'address_1' => $order->billing_address_1,
  303. 'address_2' => $order->billing_address_2,
  304. 'city' => $order->billing_city,
  305. 'state' => $order->billing_state,
  306. 'postcode' => $order->billing_postcode,
  307. 'country' => $order->billing_country,
  308. 'email' => $order->billing_email,
  309. 'phone' => $order->billing_phone,
  310. ),
  311. 'shipping_address' => array(
  312. 'first_name' => $order->shipping_first_name,
  313. 'last_name' => $order->shipping_last_name,
  314. 'company' => $order->shipping_company,
  315. 'address_1' => $order->shipping_address_1,
  316. 'address_2' => $order->shipping_address_2,
  317. 'city' => $order->shipping_city,
  318. 'state' => $order->shipping_state,
  319. 'postcode' => $order->shipping_postcode,
  320. 'country' => $order->shipping_country,
  321. ),
  322. );
  323. } else {
  324. $order_data['customer'] = current( $this->get_customer( $order->customer_user ) );
  325. }
  326. return $order_data;
  327. }
  328. /**
  329. * Modify the WP_User_Query to support filtering on the date the customer was created
  330. *
  331. * @since 2.1
  332. * @param WP_User_Query $query
  333. */
  334. public function modify_user_query( $query ) {
  335. if ( $this->created_at_min )
  336. $query->query_where .= sprintf( " AND user_registered >= STR_TO_DATE( '%s', '%%Y-%%m-%%d %%h:%%i:%%s' )", esc_sql( $this->created_at_min ) );
  337. if ( $this->created_at_max )
  338. $query->query_where .= sprintf( " AND user_registered <= STR_TO_DATE( '%s', '%%Y-%%m-%%d %%h:%%i:%%s' )", esc_sql( $this->created_at_max ) );
  339. }
  340. /**
  341. * Wrapper for @see get_avatar() which doesn't simply return
  342. * the URL so we need to pluck it from the HTML img tag
  343. *
  344. * @since 2.1
  345. * @param string $email the customer's email
  346. * @return string the URL to the customer's avatar
  347. */
  348. private function get_avatar_url( $email ) {
  349. $avatar_html = get_avatar( $email );
  350. // Get the URL of the avatar from the provided HTML
  351. preg_match( '/src=["|\'](.+)[\&|"|\']/U', $avatar_html, $matches );
  352. if ( isset( $matches[1] ) && ! empty( $matches[1] ) ) {
  353. return esc_url_raw( $matches[1] );
  354. }
  355. return null;
  356. }
  357. /**
  358. * Validate the request by checking:
  359. *
  360. * 1) the ID is a valid integer
  361. * 2) the ID returns a valid WP_User
  362. * 3) the current user has the proper permissions
  363. *
  364. * @since 2.1
  365. * @see WC_API_Resource::validate_request()
  366. * @param string|int $id the customer ID
  367. * @param string $type the request type, unused because this method overrides the parent class
  368. * @param string $context the context of the request, either `read`, `edit` or `delete`
  369. * @return int|WP_Error valid user ID or WP_Error if any of the checks fails
  370. */
  371. protected function validate_request( $id, $type, $context ) {
  372. $id = absint( $id );
  373. // validate ID
  374. if ( empty( $id ) )
  375. return new WP_Error( 'woocommerce_api_invalid_customer_id', __( 'Invalid customer ID', 'woocommerce' ), array( 'status' => 404 ) );
  376. // non-existent IDs return a valid WP_User object with the user ID = 0
  377. $customer = new WP_User( $id );
  378. if ( 0 === $customer->ID )
  379. return new WP_Error( 'woocommerce_api_invalid_customer', __( 'Invalid customer', 'woocommerce' ), array( 'status' => 404 ) );
  380. // validate permissions
  381. switch ( $context ) {
  382. case 'read':
  383. if ( ! current_user_can( 'list_users' ) )
  384. return new WP_Error( 'woocommerce_api_user_cannot_read_customer', __( 'You do not have permission to read this customer', 'woocommerce' ), array( 'status' => 401 ) );
  385. break;
  386. case 'edit':
  387. if ( ! current_user_can( 'edit_users' ) )
  388. return new WP_Error( 'woocommerce_api_user_cannot_edit_customer', __( 'You do not have permission to edit this customer', 'woocommerce' ), array( 'status' => 401 ) );
  389. break;
  390. case 'delete':
  391. if ( ! current_user_can( 'delete_users' ) )
  392. return new WP_Error( 'woocommerce_api_user_cannot_delete_customer', __( 'You do not have permission to delete this customer', 'woocommerce' ), array( 'status' => 401 ) );
  393. break;
  394. }
  395. return $id;
  396. }
  397. /**
  398. * Check if the current user can read users
  399. *
  400. * @since 2.1
  401. * @see WC_API_Resource::is_readable()
  402. * @param int|WP_Post $post unused
  403. * @return bool true if the current user can read users, false otherwise
  404. */
  405. protected function is_readable( $post ) {
  406. return current_user_can( 'list_users' );
  407. }
  408. }