class-wc-api-customers.php 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837
  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.2
  11. */
  12. if ( ! defined( 'ABSPATH' ) ) {
  13. exit; // Exit if accessed directly
  14. }
  15. class WC_API_Customers extends WC_API_Resource {
  16. /** @var string $base the route base */
  17. protected $base = '/customers';
  18. /** @var string $created_at_min for date filtering */
  19. private $created_at_min = null;
  20. /** @var string $created_at_max for date filtering */
  21. private $created_at_max = null;
  22. /**
  23. * Setup class, overridden to provide customer data to order response
  24. *
  25. * @since 2.1
  26. * @param WC_API_Server $server
  27. */
  28. public function __construct( WC_API_Server $server ) {
  29. parent::__construct( $server );
  30. // add customer data to order responses
  31. add_filter( 'woocommerce_api_order_response', array( $this, 'add_customer_data' ), 10, 2 );
  32. // modify WP_User_Query to support created_at date filtering
  33. add_action( 'pre_user_query', array( $this, 'modify_user_query' ) );
  34. }
  35. /**
  36. * Register the routes for this class
  37. *
  38. * GET /customers
  39. * GET /customers/count
  40. * GET /customers/<id>
  41. * GET /customers/<id>/orders
  42. *
  43. * @since 2.2
  44. * @param array $routes
  45. * @return array
  46. */
  47. public function register_routes( $routes ) {
  48. # GET/POST /customers
  49. $routes[ $this->base ] = array(
  50. array( array( $this, 'get_customers' ), WC_API_SERVER::READABLE ),
  51. array( array( $this, 'create_customer' ), WC_API_SERVER::CREATABLE | WC_API_Server::ACCEPT_DATA ),
  52. );
  53. # GET /customers/count
  54. $routes[ $this->base . '/count' ] = array(
  55. array( array( $this, 'get_customers_count' ), WC_API_SERVER::READABLE ),
  56. );
  57. # GET/PUT/DELETE /customers/<id>
  58. $routes[ $this->base . '/(?P<id>\d+)' ] = array(
  59. array( array( $this, 'get_customer' ), WC_API_SERVER::READABLE ),
  60. array( array( $this, 'edit_customer' ), WC_API_SERVER::EDITABLE | WC_API_SERVER::ACCEPT_DATA ),
  61. array( array( $this, 'delete_customer' ), WC_API_SERVER::DELETABLE ),
  62. );
  63. # GET /customers/email/<email>
  64. $routes[ $this->base . '/email/(?P<email>.+)' ] = array(
  65. array( array( $this, 'get_customer_by_email' ), WC_API_SERVER::READABLE ),
  66. );
  67. # GET /customers/<id>/orders
  68. $routes[ $this->base . '/(?P<id>\d+)/orders' ] = array(
  69. array( array( $this, 'get_customer_orders' ), WC_API_SERVER::READABLE ),
  70. );
  71. # GET /customers/<id>/downloads
  72. $routes[ $this->base . '/(?P<id>\d+)/downloads' ] = array(
  73. array( array( $this, 'get_customer_downloads' ), WC_API_SERVER::READABLE ),
  74. );
  75. # POST|PUT /customers/bulk
  76. $routes[ $this->base . '/bulk' ] = array(
  77. array( array( $this, 'bulk' ), WC_API_Server::EDITABLE | WC_API_Server::ACCEPT_DATA ),
  78. );
  79. return $routes;
  80. }
  81. /**
  82. * Get all customers
  83. *
  84. * @since 2.1
  85. * @param array $fields
  86. * @param array $filter
  87. * @param int $page
  88. * @return array
  89. */
  90. public function get_customers( $fields = null, $filter = array(), $page = 1 ) {
  91. $filter['page'] = $page;
  92. $query = $this->query_customers( $filter );
  93. $customers = array();
  94. foreach ( $query->get_results() as $user_id ) {
  95. if ( ! $this->is_readable( $user_id ) ) {
  96. continue;
  97. }
  98. $customers[] = current( $this->get_customer( $user_id, $fields ) );
  99. }
  100. $this->server->add_pagination_headers( $query );
  101. return array( 'customers' => $customers );
  102. }
  103. /**
  104. * Get the customer for the given ID
  105. *
  106. * @since 2.1
  107. * @param int $id the customer ID
  108. * @param array $fields
  109. * @return array|WP_Error
  110. */
  111. public function get_customer( $id, $fields = null ) {
  112. global $wpdb;
  113. $id = $this->validate_request( $id, 'customer', 'read' );
  114. if ( is_wp_error( $id ) ) {
  115. return $id;
  116. }
  117. $customer = new WC_Customer( $id );
  118. $last_order = $customer->get_last_order();
  119. $customer_data = array(
  120. 'id' => $customer->get_id(),
  121. 'created_at' => $this->server->format_datetime( $customer->get_date_created() ? $customer->get_date_created()->getTimestamp() : 0 ), // API gives UTC times.
  122. 'email' => $customer->get_email(),
  123. 'first_name' => $customer->get_first_name(),
  124. 'last_name' => $customer->get_last_name(),
  125. 'username' => $customer->get_username(),
  126. 'role' => $customer->get_role(),
  127. 'last_order_id' => is_object( $last_order ) ? $last_order->get_id() : null,
  128. 'last_order_date' => is_object( $last_order ) ? $this->server->format_datetime( $last_order->get_date_created() ? $last_order->get_date_created()->getTimestamp() : 0 ) : null, // API gives UTC times.
  129. 'orders_count' => $customer->get_order_count(),
  130. 'total_spent' => wc_format_decimal( $customer->get_total_spent(), 2 ),
  131. 'avatar_url' => $customer->get_avatar_url(),
  132. 'billing_address' => array(
  133. 'first_name' => $customer->get_billing_first_name(),
  134. 'last_name' => $customer->get_billing_last_name(),
  135. 'company' => $customer->get_billing_company(),
  136. 'address_1' => $customer->get_billing_address_1(),
  137. 'address_2' => $customer->get_billing_address_2(),
  138. 'city' => $customer->get_billing_city(),
  139. 'state' => $customer->get_billing_state(),
  140. 'postcode' => $customer->get_billing_postcode(),
  141. 'country' => $customer->get_billing_country(),
  142. 'email' => $customer->get_billing_email(),
  143. 'phone' => $customer->get_billing_phone(),
  144. ),
  145. 'shipping_address' => array(
  146. 'first_name' => $customer->get_shipping_first_name(),
  147. 'last_name' => $customer->get_shipping_last_name(),
  148. 'company' => $customer->get_shipping_company(),
  149. 'address_1' => $customer->get_shipping_address_1(),
  150. 'address_2' => $customer->get_shipping_address_2(),
  151. 'city' => $customer->get_shipping_city(),
  152. 'state' => $customer->get_shipping_state(),
  153. 'postcode' => $customer->get_shipping_postcode(),
  154. 'country' => $customer->get_shipping_country(),
  155. ),
  156. );
  157. return array( 'customer' => apply_filters( 'woocommerce_api_customer_response', $customer_data, $customer, $fields, $this->server ) );
  158. }
  159. /**
  160. * Get the customer for the given email
  161. *
  162. * @since 2.1
  163. *
  164. * @param string $email the customer email
  165. * @param array $fields
  166. *
  167. * @return array|WP_Error
  168. */
  169. public function get_customer_by_email( $email, $fields = null ) {
  170. try {
  171. if ( is_email( $email ) ) {
  172. $customer = get_user_by( 'email', $email );
  173. if ( ! is_object( $customer ) ) {
  174. throw new WC_API_Exception( 'woocommerce_api_invalid_customer_email', __( 'Invalid customer email', 'woocommerce' ), 404 );
  175. }
  176. } else {
  177. throw new WC_API_Exception( 'woocommerce_api_invalid_customer_email', __( 'Invalid customer email', 'woocommerce' ), 404 );
  178. }
  179. return $this->get_customer( $customer->ID, $fields );
  180. } catch ( WC_API_Exception $e ) {
  181. return new WP_Error( $e->getErrorCode(), $e->getMessage(), array( 'status' => $e->getCode() ) );
  182. }
  183. }
  184. /**
  185. * Get the total number of customers
  186. *
  187. * @since 2.1
  188. *
  189. * @param array $filter
  190. *
  191. * @return array|WP_Error
  192. */
  193. public function get_customers_count( $filter = array() ) {
  194. try {
  195. if ( ! current_user_can( 'list_users' ) ) {
  196. throw new WC_API_Exception( 'woocommerce_api_user_cannot_read_customers_count', __( 'You do not have permission to read the customers count', 'woocommerce' ), 401 );
  197. }
  198. $query = $this->query_customers( $filter );
  199. return array( 'count' => $query->get_total() );
  200. } catch ( WC_API_Exception $e ) {
  201. return new WP_Error( $e->getErrorCode(), $e->getMessage(), array( 'status' => $e->getCode() ) );
  202. }
  203. }
  204. /**
  205. * Get customer billing address fields.
  206. *
  207. * @since 2.2
  208. * @return array
  209. */
  210. protected function get_customer_billing_address() {
  211. $billing_address = apply_filters( 'woocommerce_api_customer_billing_address', array(
  212. 'first_name',
  213. 'last_name',
  214. 'company',
  215. 'address_1',
  216. 'address_2',
  217. 'city',
  218. 'state',
  219. 'postcode',
  220. 'country',
  221. 'email',
  222. 'phone',
  223. ) );
  224. return $billing_address;
  225. }
  226. /**
  227. * Get customer shipping address fields.
  228. *
  229. * @since 2.2
  230. * @return array
  231. */
  232. protected function get_customer_shipping_address() {
  233. $shipping_address = apply_filters( 'woocommerce_api_customer_shipping_address', array(
  234. 'first_name',
  235. 'last_name',
  236. 'company',
  237. 'address_1',
  238. 'address_2',
  239. 'city',
  240. 'state',
  241. 'postcode',
  242. 'country',
  243. ) );
  244. return $shipping_address;
  245. }
  246. /**
  247. * Add/Update customer data.
  248. *
  249. * @since 2.2
  250. * @param int $id the customer ID
  251. * @param array $data
  252. * @param WC_Customer $customer
  253. */
  254. protected function update_customer_data( $id, $data, $customer ) {
  255. // Customer first name.
  256. if ( isset( $data['first_name'] ) ) {
  257. $customer->set_first_name( wc_clean( $data['first_name'] ) );
  258. }
  259. // Customer last name.
  260. if ( isset( $data['last_name'] ) ) {
  261. $customer->set_last_name( wc_clean( $data['last_name'] ) );
  262. }
  263. // Customer billing address.
  264. if ( isset( $data['billing_address'] ) ) {
  265. foreach ( $this->get_customer_billing_address() as $field ) {
  266. if ( isset( $data['billing_address'][ $field ] ) ) {
  267. if ( is_callable( array( $customer, "set_billing_{$field}" ) ) ) {
  268. $customer->{"set_billing_{$field}"}( $data['billing_address'][ $field ] );
  269. } else {
  270. $customer->update_meta_data( 'billing_' . $field, wc_clean( $data['billing_address'][ $field ] ) );
  271. }
  272. }
  273. }
  274. }
  275. // Customer shipping address.
  276. if ( isset( $data['shipping_address'] ) ) {
  277. foreach ( $this->get_customer_shipping_address() as $field ) {
  278. if ( isset( $data['shipping_address'][ $field ] ) ) {
  279. if ( is_callable( array( $customer, "set_shipping_{$field}" ) ) ) {
  280. $customer->{"set_shipping_{$field}"}( $data['shipping_address'][ $field ] );
  281. } else {
  282. $customer->update_meta_data( 'shipping_' . $field, wc_clean( $data['shipping_address'][ $field ] ) );
  283. }
  284. }
  285. }
  286. }
  287. do_action( 'woocommerce_api_update_customer_data', $id, $data, $customer );
  288. }
  289. /**
  290. * Create a customer
  291. *
  292. * @since 2.2
  293. *
  294. * @param array $data
  295. *
  296. * @return array|WP_Error
  297. */
  298. public function create_customer( $data ) {
  299. try {
  300. if ( ! isset( $data['customer'] ) ) {
  301. throw new WC_API_Exception( 'woocommerce_api_missing_customer_data', sprintf( __( 'No %1$s data specified to create %1$s', 'woocommerce' ), 'customer' ), 400 );
  302. }
  303. $data = $data['customer'];
  304. // Checks with can create new users.
  305. if ( ! current_user_can( 'create_users' ) ) {
  306. throw new WC_API_Exception( 'woocommerce_api_user_cannot_create_customer', __( 'You do not have permission to create this customer', 'woocommerce' ), 401 );
  307. }
  308. $data = apply_filters( 'woocommerce_api_create_customer_data', $data, $this );
  309. // Checks with the email is missing.
  310. if ( ! isset( $data['email'] ) ) {
  311. throw new WC_API_Exception( 'woocommerce_api_missing_customer_email', sprintf( __( 'Missing parameter %s', 'woocommerce' ), 'email' ), 400 );
  312. }
  313. // Create customer.
  314. $customer = new WC_Customer;
  315. $customer->set_username( ! empty( $data['username'] ) ? $data['username'] : '' );
  316. $customer->set_password( ! empty( $data['password'] ) ? $data['password'] : '' );
  317. $customer->set_email( $data['email'] );
  318. $customer->save();
  319. if ( ! $customer->get_id() ) {
  320. throw new WC_API_Exception( 'woocommerce_api_user_cannot_create_customer', __( 'This resource cannot be created.', 'woocommerce' ), 400 );
  321. }
  322. // Added customer data.
  323. $this->update_customer_data( $customer->get_id(), $data, $customer );
  324. $customer->save();
  325. do_action( 'woocommerce_api_create_customer', $customer->get_id(), $data );
  326. $this->server->send_status( 201 );
  327. return $this->get_customer( $customer->get_id() );
  328. } catch ( Exception $e ) {
  329. return new WP_Error( $e->getErrorCode(), $e->getMessage(), array( 'status' => $e->getCode() ) );
  330. }
  331. }
  332. /**
  333. * Edit a customer
  334. *
  335. * @since 2.2
  336. *
  337. * @param int $id the customer ID
  338. * @param array $data
  339. *
  340. * @return array|WP_Error
  341. */
  342. public function edit_customer( $id, $data ) {
  343. try {
  344. if ( ! isset( $data['customer'] ) ) {
  345. throw new WC_API_Exception( 'woocommerce_api_missing_customer_data', sprintf( __( 'No %1$s data specified to edit %1$s', 'woocommerce' ), 'customer' ), 400 );
  346. }
  347. $data = $data['customer'];
  348. // Validate the customer ID.
  349. $id = $this->validate_request( $id, 'customer', 'edit' );
  350. // Return the validate error.
  351. if ( is_wp_error( $id ) ) {
  352. throw new WC_API_Exception( $id->get_error_code(), $id->get_error_message(), 400 );
  353. }
  354. $data = apply_filters( 'woocommerce_api_edit_customer_data', $data, $this );
  355. $customer = new WC_Customer( $id );
  356. // Customer email.
  357. if ( isset( $data['email'] ) ) {
  358. $customer->set_email( $data['email'] );
  359. }
  360. // Customer password.
  361. if ( isset( $data['password'] ) ) {
  362. $customer->set_password( $data['password'] );
  363. }
  364. // Update customer data.
  365. $this->update_customer_data( $customer->get_id(), $data, $customer );
  366. $customer->save();
  367. do_action( 'woocommerce_api_edit_customer', $customer->get_id(), $data );
  368. return $this->get_customer( $customer->get_id() );
  369. } catch ( Exception $e ) {
  370. return new WP_Error( $e->getErrorCode(), $e->getMessage(), array( 'status' => $e->getCode() ) );
  371. }
  372. }
  373. /**
  374. * Delete a customer
  375. *
  376. * @since 2.2
  377. * @param int $id the customer ID
  378. * @return array|WP_Error
  379. */
  380. public function delete_customer( $id ) {
  381. // Validate the customer ID.
  382. $id = $this->validate_request( $id, 'customer', 'delete' );
  383. // Return the validate error.
  384. if ( is_wp_error( $id ) ) {
  385. return $id;
  386. }
  387. do_action( 'woocommerce_api_delete_customer', $id, $this );
  388. return $this->delete( $id, 'customer' );
  389. }
  390. /**
  391. * Get the orders for a customer
  392. *
  393. * @since 2.1
  394. * @param int $id the customer ID
  395. * @param string $fields fields to include in response
  396. * @return array|WP_Error
  397. */
  398. public function get_customer_orders( $id, $fields = null ) {
  399. global $wpdb;
  400. $id = $this->validate_request( $id, 'customer', 'read' );
  401. if ( is_wp_error( $id ) ) {
  402. return $id;
  403. }
  404. $order_ids = wc_get_orders( array(
  405. 'customer' => $id,
  406. 'limit' => -1,
  407. 'orderby' => 'date',
  408. 'order' => 'ASC',
  409. 'return' => 'ids',
  410. ) );
  411. if ( empty( $order_ids ) ) {
  412. return array( 'orders' => array() );
  413. }
  414. $orders = array();
  415. foreach ( $order_ids as $order_id ) {
  416. $orders[] = current( WC()->api->WC_API_Orders->get_order( $order_id, $fields ) );
  417. }
  418. return array( 'orders' => apply_filters( 'woocommerce_api_customer_orders_response', $orders, $id, $fields, $order_ids, $this->server ) );
  419. }
  420. /**
  421. * Get the available downloads for a customer
  422. *
  423. * @since 2.2
  424. * @param int $id the customer ID
  425. * @param string $fields fields to include in response
  426. * @return array|WP_Error
  427. */
  428. public function get_customer_downloads( $id, $fields = null ) {
  429. $id = $this->validate_request( $id, 'customer', 'read' );
  430. if ( is_wp_error( $id ) ) {
  431. return $id;
  432. }
  433. $downloads = array();
  434. $_downloads = wc_get_customer_available_downloads( $id );
  435. foreach ( $_downloads as $key => $download ) {
  436. $downloads[] = array(
  437. 'download_url' => $download['download_url'],
  438. 'download_id' => $download['download_id'],
  439. 'product_id' => $download['product_id'],
  440. 'download_name' => $download['download_name'],
  441. 'order_id' => $download['order_id'],
  442. 'order_key' => $download['order_key'],
  443. 'downloads_remaining' => $download['downloads_remaining'],
  444. 'access_expires' => $download['access_expires'] ? $this->server->format_datetime( $download['access_expires'] ) : null,
  445. 'file' => $download['file'],
  446. );
  447. }
  448. return array( 'downloads' => apply_filters( 'woocommerce_api_customer_downloads_response', $downloads, $id, $fields, $this->server ) );
  449. }
  450. /**
  451. * Helper method to get customer user objects
  452. *
  453. * Note that WP_User_Query does not have built-in pagination so limit & offset are used to provide limited
  454. * pagination support
  455. *
  456. * The filter for role can only be a single role in a string.
  457. *
  458. * @since 2.3
  459. * @param array $args request arguments for filtering query
  460. * @return WP_User_Query
  461. */
  462. private function query_customers( $args = array() ) {
  463. // default users per page
  464. $users_per_page = get_option( 'posts_per_page' );
  465. // Set base query arguments
  466. $query_args = array(
  467. 'fields' => 'ID',
  468. 'role' => 'customer',
  469. 'orderby' => 'registered',
  470. 'number' => $users_per_page,
  471. );
  472. // Custom Role
  473. if ( ! empty( $args['role'] ) ) {
  474. $query_args['role'] = $args['role'];
  475. }
  476. // Search
  477. if ( ! empty( $args['q'] ) ) {
  478. $query_args['search'] = $args['q'];
  479. }
  480. // Limit number of users returned
  481. if ( ! empty( $args['limit'] ) ) {
  482. if ( -1 == $args['limit'] ) {
  483. unset( $query_args['number'] );
  484. } else {
  485. $query_args['number'] = absint( $args['limit'] );
  486. $users_per_page = absint( $args['limit'] );
  487. }
  488. } else {
  489. $args['limit'] = $query_args['number'];
  490. }
  491. // Page
  492. $page = ( isset( $args['page'] ) ) ? absint( $args['page'] ) : 1;
  493. // Offset
  494. if ( ! empty( $args['offset'] ) ) {
  495. $query_args['offset'] = absint( $args['offset'] );
  496. } else {
  497. $query_args['offset'] = $users_per_page * ( $page - 1 );
  498. }
  499. // Created date
  500. if ( ! empty( $args['created_at_min'] ) ) {
  501. $this->created_at_min = $this->server->parse_datetime( $args['created_at_min'] );
  502. }
  503. if ( ! empty( $args['created_at_max'] ) ) {
  504. $this->created_at_max = $this->server->parse_datetime( $args['created_at_max'] );
  505. }
  506. // Order (ASC or DESC, ASC by default)
  507. if ( ! empty( $args['order'] ) ) {
  508. $query_args['order'] = $args['order'];
  509. }
  510. // Order by
  511. if ( ! empty( $args['orderby'] ) ) {
  512. $query_args['orderby'] = $args['orderby'];
  513. // Allow sorting by meta value
  514. if ( ! empty( $args['orderby_meta_key'] ) ) {
  515. $query_args['meta_key'] = $args['orderby_meta_key'];
  516. }
  517. }
  518. $query = new WP_User_Query( $query_args );
  519. // Helper members for pagination headers
  520. $query->total_pages = ( -1 == $args['limit'] ) ? 1 : ceil( $query->get_total() / $users_per_page );
  521. $query->page = $page;
  522. return $query;
  523. }
  524. /**
  525. * Add customer data to orders
  526. *
  527. * @since 2.1
  528. * @param $order_data
  529. * @param $order
  530. * @return array
  531. */
  532. public function add_customer_data( $order_data, $order ) {
  533. if ( 0 == $order->get_user_id() ) {
  534. // add customer data from order
  535. $order_data['customer'] = array(
  536. 'id' => 0,
  537. 'email' => $order->get_billing_email(),
  538. 'first_name' => $order->get_billing_first_name(),
  539. 'last_name' => $order->get_billing_last_name(),
  540. 'billing_address' => array(
  541. 'first_name' => $order->get_billing_first_name(),
  542. 'last_name' => $order->get_billing_last_name(),
  543. 'company' => $order->get_billing_company(),
  544. 'address_1' => $order->get_billing_address_1(),
  545. 'address_2' => $order->get_billing_address_2(),
  546. 'city' => $order->get_billing_city(),
  547. 'state' => $order->get_billing_state(),
  548. 'postcode' => $order->get_billing_postcode(),
  549. 'country' => $order->get_billing_country(),
  550. 'email' => $order->get_billing_email(),
  551. 'phone' => $order->get_billing_phone(),
  552. ),
  553. 'shipping_address' => array(
  554. 'first_name' => $order->get_shipping_first_name(),
  555. 'last_name' => $order->get_shipping_last_name(),
  556. 'company' => $order->get_shipping_company(),
  557. 'address_1' => $order->get_shipping_address_1(),
  558. 'address_2' => $order->get_shipping_address_2(),
  559. 'city' => $order->get_shipping_city(),
  560. 'state' => $order->get_shipping_state(),
  561. 'postcode' => $order->get_shipping_postcode(),
  562. 'country' => $order->get_shipping_country(),
  563. ),
  564. );
  565. } else {
  566. $order_data['customer'] = current( $this->get_customer( $order->get_user_id() ) );
  567. }
  568. return $order_data;
  569. }
  570. /**
  571. * Modify the WP_User_Query to support filtering on the date the customer was created
  572. *
  573. * @since 2.1
  574. * @param WP_User_Query $query
  575. */
  576. public function modify_user_query( $query ) {
  577. if ( $this->created_at_min ) {
  578. $query->query_where .= sprintf( " AND user_registered >= STR_TO_DATE( '%s', '%%Y-%%m-%%d %%H:%%i:%%s' )", esc_sql( $this->created_at_min ) );
  579. }
  580. if ( $this->created_at_max ) {
  581. $query->query_where .= sprintf( " AND user_registered <= STR_TO_DATE( '%s', '%%Y-%%m-%%d %%H:%%i:%%s' )", esc_sql( $this->created_at_max ) );
  582. }
  583. }
  584. /**
  585. * Validate the request by checking:
  586. *
  587. * 1) the ID is a valid integer
  588. * 2) the ID returns a valid WP_User
  589. * 3) the current user has the proper permissions
  590. *
  591. * @since 2.1
  592. * @see WC_API_Resource::validate_request()
  593. * @param integer $id the customer ID
  594. * @param string $type the request type, unused because this method overrides the parent class
  595. * @param string $context the context of the request, either `read`, `edit` or `delete`
  596. * @return int|WP_Error valid user ID or WP_Error if any of the checks fails
  597. */
  598. protected function validate_request( $id, $type, $context ) {
  599. try {
  600. $id = absint( $id );
  601. // validate ID
  602. if ( empty( $id ) ) {
  603. throw new WC_API_Exception( 'woocommerce_api_invalid_customer_id', __( 'Invalid customer ID', 'woocommerce' ), 404 );
  604. }
  605. // non-existent IDs return a valid WP_User object with the user ID = 0
  606. $customer = new WP_User( $id );
  607. if ( 0 === $customer->ID ) {
  608. throw new WC_API_Exception( 'woocommerce_api_invalid_customer', __( 'Invalid customer', 'woocommerce' ), 404 );
  609. }
  610. // validate permissions
  611. switch ( $context ) {
  612. case 'read':
  613. if ( ! current_user_can( 'list_users' ) ) {
  614. throw new WC_API_Exception( 'woocommerce_api_user_cannot_read_customer', __( 'You do not have permission to read this customer', 'woocommerce' ), 401 );
  615. }
  616. break;
  617. case 'edit':
  618. if ( ! current_user_can( 'edit_users' ) ) {
  619. throw new WC_API_Exception( 'woocommerce_api_user_cannot_edit_customer', __( 'You do not have permission to edit this customer', 'woocommerce' ), 401 );
  620. }
  621. break;
  622. case 'delete':
  623. if ( ! current_user_can( 'delete_users' ) ) {
  624. throw new WC_API_Exception( 'woocommerce_api_user_cannot_delete_customer', __( 'You do not have permission to delete this customer', 'woocommerce' ), 401 );
  625. }
  626. break;
  627. }
  628. return $id;
  629. } catch ( WC_API_Exception $e ) {
  630. return new WP_Error( $e->getErrorCode(), $e->getMessage(), array( 'status' => $e->getCode() ) );
  631. }
  632. }
  633. /**
  634. * Check if the current user can read users
  635. *
  636. * @since 2.1
  637. * @see WC_API_Resource::is_readable()
  638. * @param int|WP_Post $post unused
  639. * @return bool true if the current user can read users, false otherwise
  640. */
  641. protected function is_readable( $post ) {
  642. return current_user_can( 'list_users' );
  643. }
  644. /**
  645. * Bulk update or insert customers
  646. * Accepts an array with customers in the formats supported by
  647. * WC_API_Customers->create_customer() and WC_API_Customers->edit_customer()
  648. *
  649. * @since 2.4.0
  650. *
  651. * @param array $data
  652. *
  653. * @return array|WP_Error
  654. */
  655. public function bulk( $data ) {
  656. try {
  657. if ( ! isset( $data['customers'] ) ) {
  658. throw new WC_API_Exception( 'woocommerce_api_missing_customers_data', sprintf( __( 'No %1$s data specified to create/edit %1$s', 'woocommerce' ), 'customers' ), 400 );
  659. }
  660. $data = $data['customers'];
  661. $limit = apply_filters( 'woocommerce_api_bulk_limit', 100, 'customers' );
  662. // Limit bulk operation
  663. if ( count( $data ) > $limit ) {
  664. throw new WC_API_Exception( 'woocommerce_api_customers_request_entity_too_large', sprintf( __( 'Unable to accept more than %s items for this request.', 'woocommerce' ), $limit ), 413 );
  665. }
  666. $customers = array();
  667. foreach ( $data as $_customer ) {
  668. $customer_id = 0;
  669. // Try to get the customer ID
  670. if ( isset( $_customer['id'] ) ) {
  671. $customer_id = intval( $_customer['id'] );
  672. }
  673. // Customer exists / edit customer
  674. if ( $customer_id ) {
  675. $edit = $this->edit_customer( $customer_id, array( 'customer' => $_customer ) );
  676. if ( is_wp_error( $edit ) ) {
  677. $customers[] = array(
  678. 'id' => $customer_id,
  679. 'error' => array( 'code' => $edit->get_error_code(), 'message' => $edit->get_error_message() ),
  680. );
  681. } else {
  682. $customers[] = $edit['customer'];
  683. }
  684. } else {
  685. // Customer don't exists / create customer
  686. $new = $this->create_customer( array( 'customer' => $_customer ) );
  687. if ( is_wp_error( $new ) ) {
  688. $customers[] = array(
  689. 'id' => $customer_id,
  690. 'error' => array( 'code' => $new->get_error_code(), 'message' => $new->get_error_message() ),
  691. );
  692. } else {
  693. $customers[] = $new['customer'];
  694. }
  695. }
  696. }
  697. return array( 'customers' => apply_filters( 'woocommerce_api_customers_bulk_response', $customers, $this ) );
  698. } catch ( WC_API_Exception $e ) {
  699. return new WP_Error( $e->getErrorCode(), $e->getMessage(), array( 'status' => $e->getCode() ) );
  700. }
  701. }
  702. }