Merge pull request #4177 from maxrice/rest-api-xml-issue-4165
API: Add XML generation
This commit is contained in:
commit
8485c76023
|
@ -79,7 +79,7 @@ class WC_API_Coupons extends WC_API_Resource {
|
|||
if ( ! $this->is_readable( $coupon_id ) )
|
||||
continue;
|
||||
|
||||
$coupons[] = $this->get_coupon( $coupon_id, $fields );
|
||||
$coupons[] = current( $this->get_coupon( $coupon_id, $fields ) );
|
||||
}
|
||||
|
||||
$this->server->add_pagination_headers( $query );
|
||||
|
@ -137,7 +137,7 @@ class WC_API_Coupons extends WC_API_Resource {
|
|||
'customer_email' => $coupon->customer_email,
|
||||
);
|
||||
|
||||
return apply_filters( 'woocommerce_api_coupon_response', $coupon_data, $coupon, $fields, $this->server );
|
||||
return array( 'coupon' => apply_filters( 'woocommerce_api_coupon_response', $coupon_data, $coupon, $fields, $this->server ) );
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -103,7 +103,7 @@ class WC_API_Customers extends WC_API_Resource {
|
|||
if ( ! $this->is_readable( $user_id ) )
|
||||
continue;
|
||||
|
||||
$customers[] = $this->get_customer( $user_id, $fields );
|
||||
$customers[] = current( $this->get_customer( $user_id, $fields ) );
|
||||
}
|
||||
|
||||
$this->server->add_pagination_headers( $query );
|
||||
|
@ -177,7 +177,7 @@ class WC_API_Customers extends WC_API_Resource {
|
|||
),
|
||||
);
|
||||
|
||||
return apply_filters( 'woocommerce_api_customer_response', $customer_data, $customer, $fields, $this->server );
|
||||
return array( 'customer' => apply_filters( 'woocommerce_api_customer_response', $customer_data, $customer, $fields, $this->server ) );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -283,7 +283,7 @@ class WC_API_Customers extends WC_API_Resource {
|
|||
$orders = array();
|
||||
|
||||
foreach ( $order_ids as $order_id ) {
|
||||
$orders[] = WC()->api->WC_API_Orders->get_order( $order_id, $fields );
|
||||
$orders[] = current( WC()->api->WC_API_Orders->get_order( $order_id, $fields ) );
|
||||
}
|
||||
|
||||
return array( 'orders' => apply_filters( 'woocommerce_api_customer_orders_response', $orders, $id, $fields, $order_ids, $this->server ) );
|
||||
|
@ -326,7 +326,7 @@ class WC_API_Customers extends WC_API_Resource {
|
|||
}
|
||||
|
||||
// page
|
||||
$page = absint( $args['page'] );
|
||||
$page = ( isset( $args['page'] ) ) ? absint( $args['page'] ) : 1;
|
||||
|
||||
// offset
|
||||
if ( ! empty( $args['offset'] ) ) {
|
||||
|
@ -369,7 +369,7 @@ class WC_API_Customers extends WC_API_Resource {
|
|||
|
||||
} else {
|
||||
|
||||
$order_data['customer'] = $this->get_customer( $order->customer_user );
|
||||
$order_data['customer'] = current( $this->get_customer( $order->customer_user ) );
|
||||
}
|
||||
|
||||
return $order_data;
|
||||
|
|
|
@ -82,7 +82,7 @@ class WC_API_Orders extends WC_API_Resource {
|
|||
if ( ! $this->is_readable( $order_id ) )
|
||||
continue;
|
||||
|
||||
$orders[] = $this->get_order( $order_id, $fields );
|
||||
$orders[] = current( $this->get_order( $order_id, $fields ) );
|
||||
}
|
||||
|
||||
$this->server->add_pagination_headers( $query );
|
||||
|
@ -232,7 +232,7 @@ class WC_API_Orders extends WC_API_Resource {
|
|||
);
|
||||
}
|
||||
|
||||
return apply_filters( 'woocommerce_api_order_response', $order_data, $order, $fields, $this->server );
|
||||
return array( 'order' => apply_filters( 'woocommerce_api_order_response', $order_data, $order, $fields, $this->server ) );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -302,7 +302,7 @@ class WC_API_Orders extends WC_API_Resource {
|
|||
public function get_order_notes( $id, $fields = null ) {
|
||||
|
||||
// ensure ID is valid order ID
|
||||
$id = $this->validate_request( $id, 'order', 'read' );
|
||||
$id = $this->validate_request( $id, 'shop_order', 'read' );
|
||||
|
||||
if ( is_wp_error( $id ) )
|
||||
return $id;
|
||||
|
|
|
@ -82,7 +82,7 @@ class WC_API_Products extends WC_API_Resource {
|
|||
if ( ! $this->is_readable( $product_id ) )
|
||||
continue;
|
||||
|
||||
$products[] = $this->get_product( $product_id, $fields );
|
||||
$products[] = current( $this->get_product( $product_id, $fields ) );
|
||||
}
|
||||
|
||||
$this->server->add_pagination_headers( $query );
|
||||
|
@ -122,7 +122,7 @@ class WC_API_Products extends WC_API_Resource {
|
|||
$product_data['parent'] = $this->get_product_data( $product->parent );
|
||||
}
|
||||
|
||||
return apply_filters( 'woocommerce_api_product_response', $product_data, $product, $fields, $this->server );
|
||||
return array( 'product' => apply_filters( 'woocommerce_api_product_response', $product_data, $product, $fields, $this->server ) );
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -312,7 +312,7 @@ class WC_API_Reports extends WC_API_Resource {
|
|||
'totals' => $period_totals,
|
||||
);
|
||||
|
||||
return array( 'sales' => apply_filters( 'woocommerce_api_report_response', $sales_data, 'sales', $fields, $this->report, $this->server ) );
|
||||
return array( 'sales' => apply_filters( 'woocommerce_api_report_response', $sales_data, $this->report, $fields, $this->server ) );
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -152,7 +152,7 @@ class WC_API_Resource {
|
|||
$args['offset'] = $request_args['offset'];
|
||||
|
||||
// resource page
|
||||
$args['paged'] = absint( $request_args['page'] );
|
||||
$args['paged'] = ( isset( $request_args['page'] ) ) ? absint( $request_args['page'] ) : 1;
|
||||
|
||||
return array_merge( $base_args, $args );
|
||||
}
|
||||
|
@ -234,7 +234,7 @@ class WC_API_Resource {
|
|||
*/
|
||||
public function filter_response_fields( $data, $resource, $fields ) {
|
||||
|
||||
if ( empty( $fields ) )
|
||||
if ( ! is_array( $data ) || empty( $fields ) )
|
||||
return $data;
|
||||
|
||||
$fields = explode( ',', $fields );
|
||||
|
|
|
@ -185,7 +185,7 @@ class WC_API_Server {
|
|||
$errors[] = array( 'code' => $code, 'message' => $message );
|
||||
}
|
||||
}
|
||||
return $errors;
|
||||
return array( 'errors' => $errors );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -208,7 +208,7 @@ class WC_API_Server {
|
|||
|
||||
$this->send_status( 404 );
|
||||
|
||||
echo $this->handler->generate_response( array( array( 'code' => 'woocommerce_api_disabled', 'message' => 'The WooCommerce API is disabled on this site' ) ) );
|
||||
echo $this->handler->generate_response( array( 'errors' => array( 'code' => 'woocommerce_api_disabled', 'message' => 'The WooCommerce API is disabled on this site' ) ) );
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -418,7 +418,7 @@ class WC_API_Server {
|
|||
public function get_index() {
|
||||
|
||||
// General site data
|
||||
$available = array(
|
||||
$available = array( 'store' => array(
|
||||
'name' => get_option( 'blogname' ),
|
||||
'description' => get_option( 'blogdescription' ),
|
||||
'URL' => get_option( 'siteurl' ),
|
||||
|
@ -436,7 +436,7 @@ class WC_API_Server {
|
|||
'profile' => 'https://raw.github.com/rmccue/WP-API/master/docs/schema.json', // TODO: update this
|
||||
),
|
||||
),
|
||||
);
|
||||
) );
|
||||
|
||||
// Find the available routes
|
||||
foreach ( $this->get_routes() as $route => $callbacks ) {
|
||||
|
@ -464,7 +464,7 @@ class WC_API_Server {
|
|||
}
|
||||
}
|
||||
}
|
||||
$available['routes'][$route] = apply_filters( 'woocommerce_api_endpoints_description', $data );
|
||||
$available['store']['routes'][ $route ] = apply_filters( 'woocommerce_api_endpoints_description', $data );
|
||||
}
|
||||
return apply_filters( 'woocommerce_api_index', $available );
|
||||
}
|
||||
|
|
|
@ -14,6 +14,23 @@ if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
|
|||
|
||||
class WC_API_XML_Handler implements WC_API_Handler {
|
||||
|
||||
/** @var XMLWriter instance */
|
||||
private $xml;
|
||||
|
||||
/**
|
||||
* Add some response filters
|
||||
*
|
||||
* @since 2.1
|
||||
*/
|
||||
public function __construct() {
|
||||
|
||||
// tweak sales report response data
|
||||
add_filter( 'woocommerce_api_report_response', array( $this, 'format_sales_report_data' ), 100 );
|
||||
|
||||
// tweak product response data
|
||||
add_filter( 'woocommerce_api_product_response', array( $this, 'format_product_data' ), 100 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the content type for the response
|
||||
*
|
||||
|
@ -29,7 +46,7 @@ class WC_API_XML_Handler implements WC_API_Handler {
|
|||
* Parse the raw request body entity
|
||||
*
|
||||
* @since 2.1
|
||||
* @param string $body the raw request body
|
||||
* @param string $data the raw request body
|
||||
* @return array
|
||||
*/
|
||||
public function parse_body( $data ) {
|
||||
|
@ -46,7 +63,247 @@ class WC_API_XML_Handler implements WC_API_Handler {
|
|||
*/
|
||||
public function generate_response( $data ) {
|
||||
|
||||
// TODO: implement array to XML
|
||||
$this->xml = new XMLWriter();
|
||||
|
||||
$this->xml->openMemory();
|
||||
|
||||
$this->xml->setIndent(true);
|
||||
|
||||
$this->xml->startDocument( '1.0', 'UTF-8' );
|
||||
|
||||
$root_element = key( $data );
|
||||
|
||||
$data = $data[ $root_element ];
|
||||
|
||||
switch ( $root_element ) {
|
||||
|
||||
case 'orders':
|
||||
$data = array( 'order' => $data );
|
||||
break;
|
||||
|
||||
case 'order_notes':
|
||||
$data = array( 'order_note' => $data );
|
||||
break;
|
||||
|
||||
case 'customers':
|
||||
$data = array( 'customer' => $data );
|
||||
break;
|
||||
|
||||
case 'coupons':
|
||||
$data = array( 'coupon' => $data );
|
||||
break;
|
||||
|
||||
case 'products':
|
||||
$data = array( 'product' => $data );
|
||||
break;
|
||||
|
||||
case 'product_reviews':
|
||||
$data = array( 'product_review' => $data );
|
||||
break;
|
||||
|
||||
default:
|
||||
$data = apply_filters( 'woocommerce_api_xml_data', $data, $root_element );
|
||||
break;
|
||||
}
|
||||
|
||||
// generate xml starting with the root element and recursively generating child elements
|
||||
$this->array_to_xml( $root_element, $data );
|
||||
|
||||
$this->xml->endDocument();
|
||||
|
||||
return $this->xml->outputMemory();
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert array into XML by recursively generating child elements
|
||||
*
|
||||
* @since 2.1
|
||||
* @param string|array $element_key - name for element, e.g. <OrderID>
|
||||
* @param string|array $element_value - value for element, e.g. 1234
|
||||
* @return string - generated XML
|
||||
*/
|
||||
private function array_to_xml( $element_key, $element_value = array() ) {
|
||||
|
||||
if ( is_array( $element_value ) ) {
|
||||
|
||||
// handle attributes
|
||||
if ( '@attributes' === $element_key ) {
|
||||
foreach ( $element_value as $attribute_key => $attribute_value ) {
|
||||
|
||||
$this->xml->startAttribute( $attribute_key );
|
||||
$this->xml->text( $attribute_value );
|
||||
$this->xml->endAttribute();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// handle multi-elements (e.g. multiple <Order> elements)
|
||||
if ( is_numeric( key( $element_value ) ) ) {
|
||||
|
||||
// recursively generate child elements
|
||||
foreach ( $element_value as $child_element_key => $child_element_value ) {
|
||||
|
||||
$this->xml->startElement( $element_key );
|
||||
|
||||
foreach ( $child_element_value as $sibling_element_key => $sibling_element_value ) {
|
||||
$this->array_to_xml( $sibling_element_key, $sibling_element_value );
|
||||
}
|
||||
|
||||
$this->xml->endElement();
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
// start root element
|
||||
$this->xml->startElement( $element_key );
|
||||
|
||||
// recursively generate child elements
|
||||
foreach ( $element_value as $child_element_key => $child_element_value ) {
|
||||
$this->array_to_xml( $child_element_key, $child_element_value );
|
||||
}
|
||||
|
||||
// end root element
|
||||
$this->xml->endElement();
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
// handle single elements
|
||||
if ( '@value' == $element_key ) {
|
||||
|
||||
$this->xml->text( $element_value );
|
||||
|
||||
} else {
|
||||
|
||||
// wrap element in CDATA tags if it contains illegal characters
|
||||
if ( false !== strpos( $element_value, '<' ) || false !== strpos( $element_value, '>' ) ) {
|
||||
|
||||
$this->xml->startElement( $element_key );
|
||||
$this->xml->writeCdata( $element_value );
|
||||
$this->xml->endElement();
|
||||
|
||||
} else {
|
||||
|
||||
$this->xml->writeElement( $element_key, $element_value );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjust the sales report array format to change totals keyed with the sales date to become an
|
||||
* attribute for the totals element instead
|
||||
*
|
||||
* @since 2.1
|
||||
* @param array $data
|
||||
* @return array
|
||||
*/
|
||||
public function format_sales_report_data( $data ) {
|
||||
|
||||
if ( ! empty( $data['totals'] ) ) {
|
||||
|
||||
foreach ( $data['totals'] as $date => $totals ) {
|
||||
|
||||
unset( $data['totals'][ $date ] );
|
||||
|
||||
$data['totals'][] = array_merge( array( '@attributes' => array( 'date' => $date ) ), $totals );
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjust the product data to handle options for attributes without a named child element and other
|
||||
* fields that have no named child elements (e.g. categories = array( 'cat1', 'cat2' ) )
|
||||
*
|
||||
* Note that the parent product data for variations is also adjusted in the same manner as needed
|
||||
*
|
||||
* @since 2.1
|
||||
* @param array $data
|
||||
* @return array
|
||||
*/
|
||||
public function format_product_data( $data ) {
|
||||
|
||||
// handle attribute values
|
||||
if ( ! empty( $data['attributes'] ) ) {
|
||||
|
||||
foreach ( $data['attributes'] as $attribute_key => $attribute ) {
|
||||
|
||||
if ( ! empty( $attribute['options'] ) && is_array( $attribute['options'] ) ) {
|
||||
|
||||
foreach ( $attribute['options'] as $option_key => $option ) {
|
||||
|
||||
unset( $data['attributes'][ $attribute_key ]['options'][ $option_key ] );
|
||||
|
||||
$data['attributes'][ $attribute_key ]['options']['option'][] = array( $option );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// simple arrays are fine for JSON, but XML requires a child element name, so this adjusts the data
|
||||
// array to define a child element name for each field
|
||||
$fields_to_fix = array(
|
||||
'related_ids' => 'related_id',
|
||||
'upsell_ids' => 'upsell_id',
|
||||
'cross_sell_ids' => 'cross_sell_id',
|
||||
'categories' => 'category',
|
||||
'tags' => 'tag'
|
||||
);
|
||||
|
||||
foreach ( $fields_to_fix as $parent_field_name => $child_field_name ) {
|
||||
|
||||
if ( ! empty( $data[ $parent_field_name ] ) ) {
|
||||
|
||||
foreach ( $data[ $parent_field_name ] as $field_key => $field ) {
|
||||
|
||||
unset( $data[ $parent_field_name ][ $field_key ] );
|
||||
|
||||
$data[ $parent_field_name ][ $child_field_name ][] = array( $field );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// handle adjusting the parent product for variations
|
||||
if ( ! empty( $data['parent'] ) ) {
|
||||
|
||||
// attributes
|
||||
if ( ! empty( $data['parent']['attributes'] ) ) {
|
||||
|
||||
foreach ( $data['parent']['attributes'] as $attribute_key => $attribute ) {
|
||||
|
||||
if ( ! empty( $attribute['options'] ) && is_array( $attribute['options'] ) ) {
|
||||
|
||||
foreach ( $attribute['options'] as $option_key => $option ) {
|
||||
|
||||
unset( $data['parent']['attributes'][ $attribute_key ]['options'][ $option_key ] );
|
||||
|
||||
$data['parent']['attributes'][ $attribute_key ]['options']['option'][] = array( $option );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// fields
|
||||
foreach ( $fields_to_fix as $parent_field_name => $child_field_name ) {
|
||||
|
||||
if ( ! empty( $data['parent'][ $parent_field_name ] ) ) {
|
||||
|
||||
foreach ( $data['parent'][ $parent_field_name ] as $field_key => $field ) {
|
||||
|
||||
unset( $data['parent'][ $parent_field_name ][ $field_key ] );
|
||||
|
||||
$data['parent'][ $parent_field_name ][ $child_field_name ][] = array( $field );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue