2016-05-09 21:16:48 +00:00
< ? php
2018-03-05 12:52:49 +00:00
/**
* REST Controller
*
2018-05-22 16:44:00 +00:00
* This class extend `WP_REST_Controller` in order to include / batch endpoint
* for almost all endpoints in WooCommerce REST API .
*
* It ' s required to follow " Controller Classes " guide before extending this class :
* < https :// developer . wordpress . org / rest - api / extending - the - rest - api / controller - classes />
*
* NOTE THAT ONLY CODE RELEVANT FOR MOST ENDPOINTS SHOULD BE INCLUDED INTO THIS CLASS .
* If necessary extend this class and create new abstract classes like `WC_REST_CRUD_Controller` or `WC_REST_Terms_Controller` .
*
* @ class WC_REST_Controller
2018-03-05 12:52:49 +00:00
* @ package WooCommerce / Abstracts
2018-05-22 16:44:00 +00:00
* @ see https :// developer . wordpress . org / rest - api / extending - the - rest - api / controller - classes /
2018-03-05 12:52:49 +00:00
*/
2016-05-09 21:16:48 +00:00
if ( ! defined ( 'ABSPATH' ) ) {
exit ;
}
/**
2017-03-28 17:58:51 +00:00
* Abstract Rest Controller Class
2016-05-09 21:16:48 +00:00
*
* @ package WooCommerce / Abstracts
2016-05-11 19:34:53 +00:00
* @ extends WP_REST_Controller
2016-05-09 21:16:48 +00:00
* @ version 2.6 . 0
*/
abstract class WC_REST_Controller extends WP_REST_Controller {
/**
* Endpoint namespace .
*
* @ var string
*/
protected $namespace = 'wc/v1' ;
/**
* Route base .
*
* @ var string
*/
protected $rest_base = '' ;
2016-06-03 17:56:25 +00:00
/**
* Add the schema from additional fields to an schema array .
*
* The type of object is inferred from the passed schema .
*
* @ param array $schema Schema array .
2017-05-12 08:48:46 +00:00
*
* @ return array
2016-06-03 17:56:25 +00:00
*/
protected function add_additional_fields_schema ( $schema ) {
if ( empty ( $schema [ 'title' ] ) ) {
return $schema ;
}
/**
* Can ' t use $this -> get_object_type otherwise we cause an inf loop .
*/
$object_type = $schema [ 'title' ];
$additional_fields = $this -> get_additional_fields ( $object_type );
foreach ( $additional_fields as $field_name => $field_options ) {
if ( ! $field_options [ 'schema' ] ) {
continue ;
}
$schema [ 'properties' ][ $field_name ] = $field_options [ 'schema' ];
}
$schema [ 'properties' ] = apply_filters ( 'woocommerce_rest_' . $object_type . '_schema' , $schema [ 'properties' ] );
return $schema ;
}
2016-05-09 21:16:48 +00:00
/**
* Get normalized rest base .
*
* @ return string
*/
protected function get_normalized_rest_base () {
return preg_replace ( '/\(.*\)\//i' , '' , $this -> rest_base );
}
/**
* Check batch limit .
*
* @ param array $items Request items .
* @ return bool | WP_Error
*/
protected function check_batch_limit ( $items ) {
$limit = apply_filters ( 'woocommerce_rest_batch_items_limit' , 100 , $this -> get_normalized_rest_base () );
$total = 0 ;
if ( ! empty ( $items [ 'create' ] ) ) {
$total += count ( $items [ 'create' ] );
}
if ( ! empty ( $items [ 'update' ] ) ) {
$total += count ( $items [ 'update' ] );
}
if ( ! empty ( $items [ 'delete' ] ) ) {
$total += count ( $items [ 'delete' ] );
}
if ( $total > $limit ) {
2016-10-29 10:16:03 +00:00
/* translators: %s: items limit */
2016-05-09 21:16:48 +00:00
return new WP_Error ( 'woocommerce_rest_request_entity_too_large' , sprintf ( __ ( 'Unable to accept more than %s items for this request.' , 'woocommerce' ), $limit ), array ( 'status' => 413 ) );
}
return true ;
}
/**
* Bulk create , update and delete items .
*
* @ param WP_REST_Request $request Full details about the request .
* @ return array Of WP_Error or WP_REST_Response .
*/
public function batch_items ( $request ) {
2018-03-05 12:52:49 +00:00
/**
* REST Server
*
* @ var WP_REST_Server $wp_rest_server
*/
2016-05-09 21:16:48 +00:00
global $wp_rest_server ;
// Get the request params.
$items = array_filter ( $request -> get_params () );
$response = array ();
// Check batch limit.
$limit = $this -> check_batch_limit ( $items );
if ( is_wp_error ( $limit ) ) {
return $limit ;
}
if ( ! empty ( $items [ 'create' ] ) ) {
foreach ( $items [ 'create' ] as $item ) {
$_item = new WP_REST_Request ( 'POST' );
2016-05-30 23:15:50 +00:00
// Default parameters.
$defaults = array ();
$schema = $this -> get_public_item_schema ();
foreach ( $schema [ 'properties' ] as $arg => $options ) {
if ( isset ( $options [ 'default' ] ) ) {
$defaults [ $arg ] = $options [ 'default' ];
}
}
$_item -> set_default_params ( $defaults );
// Set request parameters.
2016-05-09 21:16:48 +00:00
$_item -> set_body_params ( $item );
$_response = $this -> create_item ( $_item );
if ( is_wp_error ( $_response ) ) {
2016-05-09 21:21:36 +00:00
$response [ 'create' ][] = array (
2016-05-09 21:16:48 +00:00
'id' => 0 ,
2018-03-05 12:52:49 +00:00
'error' => array (
'code' => $_response -> get_error_code (),
'message' => $_response -> get_error_message (),
'data' => $_response -> get_error_data (),
),
2016-05-09 21:16:48 +00:00
);
} else {
$response [ 'create' ][] = $wp_rest_server -> response_to_data ( $_response , '' );
}
}
}
if ( ! empty ( $items [ 'update' ] ) ) {
foreach ( $items [ 'update' ] as $item ) {
$_item = new WP_REST_Request ( 'PUT' );
$_item -> set_body_params ( $item );
$_response = $this -> update_item ( $_item );
if ( is_wp_error ( $_response ) ) {
2016-05-09 21:21:36 +00:00
$response [ 'update' ][] = array (
2016-05-09 21:16:48 +00:00
'id' => $item [ 'id' ],
2018-03-05 12:52:49 +00:00
'error' => array (
'code' => $_response -> get_error_code (),
'message' => $_response -> get_error_message (),
'data' => $_response -> get_error_data (),
),
2016-05-09 21:16:48 +00:00
);
} else {
$response [ 'update' ][] = $wp_rest_server -> response_to_data ( $_response , '' );
}
}
}
if ( ! empty ( $items [ 'delete' ] ) ) {
foreach ( $items [ 'delete' ] as $id ) {
2017-02-02 18:09:12 +00:00
$id = ( int ) $id ;
if ( 0 === $id ) {
continue ;
}
2016-05-09 21:16:48 +00:00
$_item = new WP_REST_Request ( 'DELETE' );
2018-03-05 12:52:49 +00:00
$_item -> set_query_params ( array (
'id' => $id ,
'force' => true ,
) );
2016-05-09 21:16:48 +00:00
$_response = $this -> delete_item ( $_item );
if ( is_wp_error ( $_response ) ) {
2016-05-09 21:21:36 +00:00
$response [ 'delete' ][] = array (
2016-05-09 21:16:48 +00:00
'id' => $id ,
2018-03-05 12:52:49 +00:00
'error' => array (
'code' => $_response -> get_error_code (),
'message' => $_response -> get_error_message (),
'data' => $_response -> get_error_data (),
),
2016-05-09 21:16:48 +00:00
);
} else {
$response [ 'delete' ][] = $wp_rest_server -> response_to_data ( $_response , '' );
}
}
}
return $response ;
}
2016-09-08 22:14:40 +00:00
/**
* Validate a text value for a text based setting .
*
2017-03-15 16:36:53 +00:00
* @ since 3.0 . 0
2018-03-05 12:52:49 +00:00
* @ param string $value Value .
* @ param array $setting Setting .
2016-09-08 22:14:40 +00:00
* @ return string
*/
public function validate_setting_text_field ( $value , $setting ) {
$value = is_null ( $value ) ? '' : $value ;
return wp_kses_post ( trim ( stripslashes ( $value ) ) );
}
/**
* Validate select based settings .
*
2017-03-15 16:36:53 +00:00
* @ since 3.0 . 0
2018-03-05 12:52:49 +00:00
* @ param string $value Value .
* @ param array $setting Setting .
2016-09-08 22:14:40 +00:00
* @ return string | WP_Error
*/
public function validate_setting_select_field ( $value , $setting ) {
if ( array_key_exists ( $value , $setting [ 'options' ] ) ) {
return $value ;
} else {
return new WP_Error ( 'rest_setting_value_invalid' , __ ( 'An invalid setting value was passed.' , 'woocommerce' ), array ( 'status' => 400 ) );
}
}
/**
* Validate multiselect based settings .
*
2017-03-15 16:36:53 +00:00
* @ since 3.0 . 0
2018-03-05 12:52:49 +00:00
* @ param array $values Values .
* @ param array $setting Setting .
2017-05-15 11:50:52 +00:00
* @ return array | WP_Error
2016-09-08 22:14:40 +00:00
*/
public function validate_setting_multiselect_field ( $values , $setting ) {
if ( empty ( $values ) ) {
return array ();
}
if ( ! is_array ( $values ) ) {
return new WP_Error ( 'rest_setting_value_invalid' , __ ( 'An invalid setting value was passed.' , 'woocommerce' ), array ( 'status' => 400 ) );
}
$final_values = array ();
foreach ( $values as $value ) {
if ( array_key_exists ( $value , $setting [ 'options' ] ) ) {
$final_values [] = $value ;
}
}
return $final_values ;
}
/**
* Validate image_width based settings .
*
2017-03-15 16:36:53 +00:00
* @ since 3.0 . 0
2018-03-05 12:52:49 +00:00
* @ param array $values Values .
* @ param array $setting Setting .
2016-09-08 22:14:40 +00:00
* @ return string | WP_Error
*/
public function validate_setting_image_width_field ( $values , $setting ) {
if ( ! is_array ( $values ) ) {
return new WP_Error ( 'rest_setting_value_invalid' , __ ( 'An invalid setting value was passed.' , 'woocommerce' ), array ( 'status' => 400 ) );
}
$current = $setting [ 'value' ];
if ( isset ( $values [ 'width' ] ) ) {
$current [ 'width' ] = intval ( $values [ 'width' ] );
}
if ( isset ( $values [ 'height' ] ) ) {
$current [ 'height' ] = intval ( $values [ 'height' ] );
}
if ( isset ( $values [ 'crop' ] ) ) {
$current [ 'crop' ] = ( bool ) $values [ 'crop' ];
}
return $current ;
}
/**
* Validate radio based settings .
*
2017-03-15 16:36:53 +00:00
* @ since 3.0 . 0
2018-03-05 12:52:49 +00:00
* @ param string $value Value .
* @ param array $setting Setting .
2016-09-08 22:14:40 +00:00
* @ return string | WP_Error
*/
public function validate_setting_radio_field ( $value , $setting ) {
return $this -> validate_setting_select_field ( $value , $setting );
}
/**
* Validate checkbox based settings .
*
2017-03-15 16:36:53 +00:00
* @ since 3.0 . 0
2018-03-05 12:52:49 +00:00
* @ param string $value Value .
* @ param array $setting Setting .
2016-09-08 22:14:40 +00:00
* @ return string | WP_Error
*/
public function validate_setting_checkbox_field ( $value , $setting ) {
if ( in_array ( $value , array ( 'yes' , 'no' ) ) ) {
return $value ;
} elseif ( empty ( $value ) ) {
$value = isset ( $setting [ 'default' ] ) ? $setting [ 'default' ] : 'no' ;
return $value ;
} else {
return new WP_Error ( 'rest_setting_value_invalid' , __ ( 'An invalid setting value was passed.' , 'woocommerce' ), array ( 'status' => 400 ) );
}
}
/**
* Validate textarea based settings .
*
2017-03-15 16:36:53 +00:00
* @ since 3.0 . 0
2018-03-05 12:52:49 +00:00
* @ param string $value Value .
* @ param array $setting Setting .
2016-09-08 22:14:40 +00:00
* @ return string
*/
public function validate_setting_textarea_field ( $value , $setting ) {
$value = is_null ( $value ) ? '' : $value ;
return wp_kses ( trim ( stripslashes ( $value ) ),
array_merge (
array (
2018-03-05 12:52:49 +00:00
'iframe' => array (
'src' => true ,
'style' => true ,
'id' => true ,
'class' => true ,
),
2016-09-08 22:14:40 +00:00
),
wp_kses_allowed_html ( 'post' )
)
);
}
2016-10-11 02:09:47 +00:00
/**
* Add meta query .
*
2017-03-15 16:36:53 +00:00
* @ since 3.0 . 0
2016-10-11 02:09:47 +00:00
* @ param array $args Query args .
* @ param array $meta_query Meta query .
* @ return array
*/
protected function add_meta_query ( $args , $meta_query ) {
2018-12-03 10:52:36 +00:00
if ( empty ( $args [ 'meta_query' ] ) ) {
2016-10-11 02:09:47 +00:00
$args [ 'meta_query' ] = array ();
}
$args [ 'meta_query' ][] = $meta_query ;
return $args [ 'meta_query' ];
}
2016-05-09 21:16:48 +00:00
/**
* Get the batch schema , conforming to JSON Schema .
*
* @ return array
*/
public function get_public_batch_schema () {
$schema = array (
'$schema' => 'http://json-schema.org/draft-04/schema#' ,
'title' => 'batch' ,
'type' => 'object' ,
'properties' => array (
'create' => array (
'description' => __ ( 'List of created resources.' , 'woocommerce' ),
'type' => 'array' ,
'context' => array ( 'view' , 'edit' ),
2017-01-26 19:22:57 +00:00
'items' => array (
'type' => 'object' ,
),
2016-05-09 21:16:48 +00:00
),
'update' => array (
'description' => __ ( 'List of updated resources.' , 'woocommerce' ),
'type' => 'array' ,
'context' => array ( 'view' , 'edit' ),
2017-01-26 19:22:57 +00:00
'items' => array (
'type' => 'object' ,
),
2016-05-09 21:16:48 +00:00
),
'delete' => array (
'description' => __ ( 'List of delete resources.' , 'woocommerce' ),
'type' => 'array' ,
'context' => array ( 'view' , 'edit' ),
2017-01-26 19:22:57 +00:00
'items' => array (
2017-02-02 18:09:12 +00:00
'type' => 'integer' ,
2017-01-26 19:22:57 +00:00
),
2016-05-09 21:16:48 +00:00
),
),
);
return $schema ;
}
2018-07-24 18:52:48 +00:00
/**
* Gets an array of fields to be included on the response .
* Included fields are based on item schema and `_fields=` request argument .
* Introduced to support WordPress 4.9 . 6 changes .
*
* @ since 3.5 . 0
* @ param WP_REST_Request $request Full details about the request .
* @ return array Fields to be included in the response .
*/
public function get_fields_for_response ( $request ) {
$schema = $this -> get_item_schema ();
$fields = isset ( $schema [ 'properties' ] ) ? array_keys ( $schema [ 'properties' ] ) : array ();
if ( ! isset ( $request [ '_fields' ] ) ) {
return $fields ;
}
$requested_fields = is_array ( $request [ '_fields' ] ) ? $request [ '_fields' ] : preg_split ( '/[\s,]+/' , $request [ '_fields' ] );
if ( 0 === count ( $requested_fields ) ) {
return $fields ;
}
// Trim off outside whitespace from the comma delimited list.
$requested_fields = array_map ( 'trim' , $requested_fields );
// Always persist 'id', because it can be needed for add_additional_fields_to_object().
if ( in_array ( 'id' , $fields , true ) ) {
$requested_fields [] = 'id' ;
}
return array_intersect ( $fields , $requested_fields );
}
2016-05-09 21:16:48 +00:00
}