class-wc-api-customers.php 24 KB

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