2013-11-04 06:36:31 +00:00
< ? php
/**
* WooCommerce API Customers Class
*
* Handles requests to the / customers endpoint
*
* @ author WooThemes
* @ category API
* @ package WooCommerce / API
* @ since 2.1
*/
if ( ! defined ( 'ABSPATH' ) ) exit ; // Exit if accessed directly
2013-11-09 21:20:23 +00:00
class WC_API_Customers extends WC_API_Resource {
2013-11-04 06:36:31 +00:00
/** @var string $base the route base */
protected $base = '/customers' ;
2013-11-10 23:28:58 +00:00
/** @var string $created_at_min for date filtering */
private $created_at_min = null ;
/** @var string $created_at_max for date filtering */
private $created_at_max = null ;
2013-11-04 06:36:31 +00:00
/**
* Setup class , overridden to provide customer data to order response
*
* @ since 2.1
2013-11-06 06:54:19 +00:00
* @ param WC_API_Server $server
2013-11-04 06:36:31 +00:00
* @ return WC_API_Customers
*/
2013-11-06 06:54:19 +00:00
public function __construct ( WC_API_Server $server ) {
2013-11-04 06:36:31 +00:00
parent :: __construct ( $server );
// add customer data to order responses
2013-11-11 00:29:36 +00:00
add_filter ( 'woocommerce_api_order_response' , array ( $this , 'add_customer_data' ), 10 , 2 );
2013-11-10 23:28:58 +00:00
// modify WP_User_Query to support created_at date filtering
add_action ( 'pre_user_query' , array ( $this , 'modify_user_query' ) );
2013-11-04 06:36:31 +00:00
}
/**
* Register the routes for this class
*
* GET | POST / customers
* GET / customers / count
* GET | PUT | DELETE / customers /< id >
* GET / customers /< id >/ orders
*
* @ since 2.1
* @ param array $routes
* @ return array
*/
2013-11-11 00:29:36 +00:00
public function register_routes ( $routes ) {
2013-11-04 06:36:31 +00:00
# GET|POST /customers
$routes [ $this -> base ] = array (
2013-11-11 00:29:36 +00:00
array ( array ( $this , 'get_customers' ), WC_API_SERVER :: READABLE ),
array ( array ( $this , 'create_customer' ), WC_API_SERVER :: CREATABLE | WC_API_SERVER :: ACCEPT_DATA ),
2013-11-04 06:36:31 +00:00
);
# GET /customers/count
$routes [ $this -> base . '/count' ] = array (
2013-11-11 00:29:36 +00:00
array ( array ( $this , 'get_customers_count' ), WC_API_SERVER :: READABLE ),
2013-11-04 06:36:31 +00:00
);
# GET|PUT|DELETE /customers/<id>
$routes [ $this -> base . '/(?P<id>\d+)' ] = array (
2013-11-11 00:29:36 +00:00
array ( array ( $this , 'get_customer' ), WC_API_SERVER :: READABLE ),
array ( array ( $this , 'edit_customer' ), WC_API_SERVER :: EDITABLE | WC_API_SERVER :: ACCEPT_DATA ),
array ( array ( $this , 'delete_customer' ), WC_API_SERVER :: DELETABLE ),
2013-11-04 06:36:31 +00:00
);
# GET /customers/<id>/orders
$routes [ $this -> base . '/(?P<id>\d+)/orders' ] = array (
2013-11-11 00:29:36 +00:00
array ( array ( $this , 'get_customer_orders' ), WC_API_SERVER :: READABLE ),
2013-11-04 06:36:31 +00:00
);
return $routes ;
}
/**
* Get all customers
*
* @ since 2.1
* @ param array $fields
2013-11-11 00:29:36 +00:00
* @ param array $filter
2013-11-04 06:36:31 +00:00
* @ return array
*/
2013-11-11 00:29:36 +00:00
public function get_customers ( $fields = null , $filter = array () ) {
2013-11-04 06:36:31 +00:00
2013-11-11 00:29:36 +00:00
$query = $this -> query_customers ( $filter );
2013-11-04 06:36:31 +00:00
$customers = array ();
foreach ( $query -> results as $user_id ) {
2013-11-11 00:29:36 +00:00
if ( ! $this -> is_readable ( $user_id ) )
continue ;
$customers [] = $this -> get_customer ( $user_id , $fields );
2013-11-04 06:36:31 +00:00
}
2013-11-11 00:29:36 +00:00
// TODO: add navigation/total count headers for pagination
2013-11-04 06:36:31 +00:00
return array ( 'customers' => $customers );
}
/**
* Get the customer for the given ID
*
* @ since 2.1
* @ param int $id the customer ID
* @ param string $fields
* @ return array
*/
2013-11-11 00:29:36 +00:00
public function get_customer ( $id , $fields = null ) {
2013-11-04 06:36:31 +00:00
global $wpdb ;
2013-11-11 00:29:36 +00:00
$id = $this -> validate_request ( $id , 'customer' , 'read' );
2013-11-04 06:36:31 +00:00
2013-11-11 00:29:36 +00:00
if ( is_wp_error ( $id ) )
return $id ;
2013-11-04 06:36:31 +00:00
$customer = new WP_User ( $id );
// get info about user's last order
$last_order = $wpdb -> get_row ( " SELECT id, post_date
FROM $wpdb -> posts AS posts
LEFT JOIN { $wpdb -> postmeta } AS meta on posts . ID = meta . post_id
WHERE meta . meta_key = '_customer_user'
AND meta . meta_value = { $customer -> ID }
AND posts . post_type = 'shop_order'
AND posts . post_status = 'publish'
" );
$customer_data = array (
'id' => $customer -> ID ,
'created_at' => $customer -> user_registered ,
'email' => $customer -> user_email ,
'first_name' => $customer -> first_name ,
'last_name' => $customer -> last_name ,
'username' => $customer -> user_login ,
'last_order_id' => is_object ( $last_order ) ? $last_order -> id : null ,
'last_order_date' => is_object ( $last_order ) ? $last_order -> post_date : null ,
'orders_count' => $customer -> _order_count ,
2013-11-11 00:29:36 +00:00
'total_spent' => ( string ) number_format ( $customer -> _money_spent , 2 ),
2013-11-06 06:54:19 +00:00
'avatar_url' => $this -> get_avatar_url ( $customer -> customer_email ),
2013-11-04 06:36:31 +00:00
'billing_address' => array (
'first_name' => $customer -> billing_first_name ,
'last_name' => $customer -> billing_last_name ,
'company' => $customer -> billing_company ,
'address_1' => $customer -> billing_address_1 ,
'address_2' => $customer -> billing_address_2 ,
'city' => $customer -> billing_city ,
'state' => $customer -> billing_state ,
'postcode' => $customer -> billing_postcode ,
'country' => $customer -> billing_country ,
'email' => $customer -> billing_email ,
'phone' => $customer -> billing_phone ,
),
'shipping_address' => array (
'first_name' => $customer -> shipping_first_name ,
'last_name' => $customer -> shipping_last_name ,
'company' => $customer -> shipping_company ,
'address_1' => $customer -> shipping_address_1 ,
'address_2' => $customer -> shipping_address_2 ,
'city' => $customer -> shipping_city ,
'state' => $customer -> shipping_state ,
'postcode' => $customer -> shipping_postcode ,
'country' => $customer -> shipping_country ,
),
);
return apply_filters ( 'woocommerce_api_customer_response' , $customer_data , $customer , $fields );
}
/**
* Get the total number of customers
*
* @ since 2.1
2013-11-11 00:29:36 +00:00
* @ param array $filter
2013-11-04 06:36:31 +00:00
* @ return array
*/
2013-11-11 00:29:36 +00:00
public function get_customers_count ( $filter = array () ) {
2013-11-04 06:36:31 +00:00
2013-11-11 00:29:36 +00:00
$query = $this -> query_customers ( $filter );
// TODO: permissions?
2013-11-04 06:36:31 +00:00
return array ( 'count' => $query -> get_total () );
}
/**
* Create a customer
*
* @ since 2.1
* @ param array $data
* @ return array
*/
2013-11-11 00:29:36 +00:00
public function create_customer ( $data ) {
if ( ! current_user_can ( 'create_users' ) )
return new WP_Error ( 'woocommerce_api_user_cannot_create_customer' , __ ( 'You do not have permission to create this customer' , 'woocommerce' ), array ( 'status' => 401 ) );
2013-11-04 06:36:31 +00:00
2013-11-11 00:29:36 +00:00
// TODO: implement - woocommerce_create_new_customer()
2013-11-04 06:36:31 +00:00
return array ();
}
/**
* Edit a customer
*
* @ since 2.1
* @ param int $id the customer ID
* @ param array $data
* @ return array
*/
2013-11-11 00:29:36 +00:00
public function edit_customer ( $id , $data ) {
$id = $this -> validate_request ( $id , 'customer' , 'edit' );
if ( ! is_wp_error ( $id ) )
return $id ;
2013-11-04 06:36:31 +00:00
// TODO: implement
2013-11-11 00:29:36 +00:00
return $this -> get_customer ( $id );
2013-11-04 06:36:31 +00:00
}
/**
* Delete a customer
*
* @ since 2.1
* @ param int $id the customer ID
* @ return array
*/
2013-11-11 00:29:36 +00:00
public function delete_customer ( $id ) {
$id = $this -> validate_request ( $id , 'customer' , 'delete' );
if ( ! is_wp_error ( $id ) )
return $id ;
2013-11-04 06:36:31 +00:00
2013-11-11 00:29:36 +00:00
return $this -> delete ( $id , 'customer' );
2013-11-04 06:36:31 +00:00
}
/**
* Get the orders for a customer
*
* @ since 2.1
* @ param int $id the customer ID
2013-11-11 00:29:36 +00:00
* @ param string $fields fields to include in response
2013-11-04 06:36:31 +00:00
* @ return array
*/
2013-11-11 00:29:36 +00:00
public function get_customer_orders ( $id , $fields = null ) {
2013-11-04 06:36:31 +00:00
global $wpdb ;
2013-11-11 00:29:36 +00:00
$id = $this -> validate_request ( $id , 'customer' , 'read' );
2013-11-04 06:36:31 +00:00
2013-11-11 00:29:36 +00:00
if ( is_wp_error ( $id ) )
return $id ;
2013-11-04 06:36:31 +00:00
2013-11-11 00:29:36 +00:00
$order_ids = $wpdb -> get_col ( $wpdb -> prepare ( " SELECT id
2013-11-04 06:36:31 +00:00
FROM $wpdb -> posts AS posts
LEFT JOIN { $wpdb -> postmeta } AS meta on posts . ID = meta . post_id
WHERE meta . meta_key = '_customer_user'
2013-11-11 00:29:36 +00:00
AND meta . meta_value = '%s'
2013-11-04 06:36:31 +00:00
AND posts . post_type = 'shop_order'
AND posts . post_status = 'publish'
2013-11-11 00:29:36 +00:00
" , $id ) );
2013-11-04 06:36:31 +00:00
if ( empty ( $order_ids ) )
return array ( 'orders' => array () );
$orders = array ();
foreach ( $order_ids as $order_id ) {
2013-11-11 00:29:36 +00:00
$orders [] = WC () -> api -> WC_API_Orders -> get_order ( $order_id , $fields );
2013-11-04 06:36:31 +00:00
}
return array ( 'orders' => $orders );
}
/**
* Helper method to get customer user objects
*
* @ since 2.1
* @ param array $args request arguments for filtering query
* @ return array
*/
2013-11-11 00:29:36 +00:00
private function query_customers ( $args = array () ) {
2013-11-04 06:36:31 +00:00
// set base query arguments
$query_args = array (
'fields' => 'ID' ,
'role' => 'customer' ,
'orderby' => 'registered' ,
);
if ( ! empty ( $args [ 'q' ] ) )
$query_args [ 'search' ] = $args [ 'q' ];
if ( ! empty ( $args [ 'limit' ] ) )
$query_args [ 'number' ] = $args [ 'limit' ];
if ( ! empty ( $args [ 'offset' ] ) )
$query_args [ 'offset' ] = $args [ 'offset' ];
2013-11-10 23:28:58 +00:00
if ( ! empty ( $args [ 'created_at_min' ] ) )
$this -> created_at_min = $args [ 'created_at_min' ];
if ( ! empty ( $args [ 'created_at_max' ] ) )
$this -> created_at_max = $args [ 'created_at_max' ];
// TODO: support page argument - requires custom implementation as WP_User_Query has no built-in pagination like WP_Query
2013-11-04 06:36:31 +00:00
return new WP_User_Query ( $query_args );
}
/**
* Add customer data to orders
*
* @ since 2.1
* @ param $order_data
* @ param $order
2013-11-11 00:29:36 +00:00
* @ return array
2013-11-04 06:36:31 +00:00
*/
2013-11-11 00:29:36 +00:00
public function add_customer_data ( $order_data , $order ) {
2013-11-04 06:36:31 +00:00
if ( 0 == $order -> customer_user ) {
$order_data [ 'customer' ] = 'guest' ;
} else {
2013-11-11 00:29:36 +00:00
$order_data [ 'customer' ] = $this -> get_customer ( $order -> customer_user );
2013-11-04 06:36:31 +00:00
}
return $order_data ;
}
2013-11-10 23:28:58 +00:00
/**
* Modify the WP_User_Query to support filtering on the date the customer was created
*
* @ since 2.1
* @ param WP_User_Query $query
*/
public function modify_user_query ( $query ) {
if ( $this -> created_at_min )
$query -> query_where .= sprintf ( " AND DATE(user_registered) >= '%s' " , date ( 'Y-m-d H:i:s' , strtotime ( $this -> created_at_min ) ) ); // TODO: date formatting
if ( $this -> created_at_max )
$query -> query_where .= sprintf ( " AND DATE(user_registered) <= '%s' " , date ( 'Y-m-d H:i:s' , strtotime ( $this -> created_at_max ) ) ); // TODO: date formatting
}
2013-11-06 06:54:19 +00:00
/**
* Wrapper for @ see get_avatar () which doesn ' t simply return
* the URL so we need to pluck it from the HTML img tag
*
2013-11-11 00:29:36 +00:00
* @ since 2.1
2013-11-06 06:54:19 +00:00
* @ param string $email the customer ' s email
* @ return string the URL to the customer ' s avatar
*/
private function get_avatar_url ( $email ) {
$dom = new DOMDocument ();
$dom -> loadHTML ( get_avatar ( $email ) );
2013-11-11 00:29:36 +00:00
$url = $dom -> getElementsByTagName ( 'img' ) -> item ( 0 ) -> getAttribute ( 'src' );
2013-11-06 06:54:19 +00:00
return ( ! empty ( $url ) ) ? $url : null ;
}
2013-11-11 00:29:36 +00:00
/**
* Validate the request by checking :
*
* 1 ) the ID is a valid integer
* 2 ) the ID returns a valid WP_User
* 3 ) the current user has the proper permissions
*
* @ since 2.1
* @ see WC_API_Resource :: validate_request ()
* @ param string | int $id the customer ID
* @ param string $type the request type , unused because this method overrides the parent class
* @ param string $context the context of the request , either `read` , `edit` or `delete`
* @ return int | WP_Error valid user ID or WP_Error if any of the checks fails
*/
protected function validate_request ( $id , $type , $context ) {
$id = absint ( $id );
// validate ID
if ( empty ( $id ) )
return new WP_Error ( 'woocommerce_api_invalid_customer_id' , __ ( 'Invalid customer ID' , 'woocommerce' ), array ( 'status' => 404 ) );
// non-existent IDs return a valid WP_User object with the user ID = 0
$customer = new WP_User ( $id );
if ( 0 === $customer -> ID )
return new WP_Error ( 'woocommerce_api_invalid_customer' , __ ( 'Invalid customer' , 'woocommerce' ), array ( 'status' => 404 ) );
// validate permissions
switch ( $context ) {
case 'read' :
if ( ! current_user_can ( 'list_users' ) )
return new WP_Error ( 'woocommerce_api_user_cannot_read_customer' , __ ( 'You do not have permission to read this customer' , 'woocommerce' ), array ( 'status' => 401 ) );
break ;
case 'edit' :
if ( ! current_user_can ( 'edit_users' ) )
return new WP_Error ( 'woocommerce_api_user_cannot_edit_customer' , __ ( 'You do not have permission to edit this customer' , 'woocommerce' ), array ( 'status' => 401 ) );
break ;
case 'delete' :
if ( ! current_user_can ( 'delete_users' ) )
return new WP_Error ( 'woocommerce_api_user_cannot_delete_customer' , __ ( 'You do not have permission to delete this customer' , 'woocommerce' ), array ( 'status' => 401 ) );
break ;
}
return $id ;
}
/**
* Check if the current user can read users
*
* @ since 2.1
* @ see WC_API_Resource :: is_readable ()
* @ param int | WP_Post $post unused
* @ return bool true if the current user can read users , false otherwise
*/
protected function is_readable ( $post ) {
return current_user_can ( 'list_users' );
}
2013-11-04 06:36:31 +00:00
}