WC_API_XML_Handler

The WooCommerce WC API XML Handler class.

Defined (1)

The class is defined in the following location(s).

/includes/api/legacy/v1/class-wc-api-xml-handler.php  
  1. class WC_API_XML_Handler implements WC_API_Handler { 
  2.  
  3. /** @var XMLWriter instance */ 
  4. private $xml; 
  5.  
  6. /** 
  7. * Add some response filters 
  8. * @since 2.1 
  9. */ 
  10. public function __construct() { 
  11.  
  12. // tweak sales report response data 
  13. add_filter( 'woocommerce_api_report_response', array( $this, 'format_sales_report_data' ), 100 ); 
  14.  
  15. // tweak product response data 
  16. add_filter( 'woocommerce_api_product_response', array( $this, 'format_product_data' ), 100 ); 
  17.  
  18. /** 
  19. * Get the content type for the response 
  20. * @since 2.1 
  21. * @return string 
  22. */ 
  23. public function get_content_type() { 
  24.  
  25. return 'application/xml; charset=' . get_option( 'blog_charset' ); 
  26.  
  27. /** 
  28. * Parse the raw request body entity 
  29. * @since 2.1 
  30. * @param string $data the raw request body 
  31. * @return array 
  32. */ 
  33. public function parse_body( $data ) { 
  34.  
  35. // TODO: implement simpleXML parsing 
  36.  
  37. /** 
  38. * Generate an XML response given an array of data 
  39. * @since 2.1 
  40. * @param array $data the response data 
  41. * @return string 
  42. */ 
  43. public function generate_response( $data ) { 
  44.  
  45. $this->xml = new XMLWriter(); 
  46.  
  47. $this->xml->openMemory(); 
  48.  
  49. $this->xml->setIndent( true ); 
  50.  
  51. $this->xml->startDocument( '1.0', 'UTF-8' ); 
  52.  
  53. $root_element = key( $data ); 
  54.  
  55. $data = $data[ $root_element ]; 
  56.  
  57. switch ( $root_element ) { 
  58.  
  59. case 'orders': 
  60. $data = array( 'order' => $data ); 
  61. break; 
  62.  
  63. case 'order_notes': 
  64. $data = array( 'order_note' => $data ); 
  65. break; 
  66.  
  67. case 'customers': 
  68. $data = array( 'customer' => $data ); 
  69. break; 
  70.  
  71. case 'coupons': 
  72. $data = array( 'coupon' => $data ); 
  73. break; 
  74.  
  75. case 'products': 
  76. $data = array( 'product' => $data ); 
  77. break; 
  78.  
  79. case 'product_reviews': 
  80. $data = array( 'product_review' => $data ); 
  81. break; 
  82.  
  83. default: 
  84. $data = apply_filters( 'woocommerce_api_xml_data', $data, $root_element ); 
  85. break; 
  86.  
  87. // generate xml starting with the root element and recursively generating child elements 
  88. $this->array_to_xml( $root_element, $data ); 
  89.  
  90. $this->xml->endDocument(); 
  91.  
  92. return $this->xml->outputMemory(); 
  93.  
  94. /** 
  95. * Convert array into XML by recursively generating child elements 
  96. * @since 2.1 
  97. * @param string|array $element_key - name for element, e.g. <OrderID> 
  98. * @param string|array $element_value - value for element, e.g. 1234 
  99. * @return string - generated XML 
  100. */ 
  101. private function array_to_xml( $element_key, $element_value = array() ) { 
  102.  
  103. if ( is_array( $element_value ) ) { 
  104.  
  105. // handle attributes 
  106. if ( '@attributes' === $element_key ) { 
  107. foreach ( $element_value as $attribute_key => $attribute_value ) { 
  108.  
  109. $this->xml->startAttribute( $attribute_key ); 
  110. $this->xml->text( $attribute_value ); 
  111. $this->xml->endAttribute(); 
  112. return; 
  113.  
  114. // handle multi-elements (e.g. multiple <Order> elements) 
  115. if ( is_numeric( key( $element_value ) ) ) { 
  116.  
  117. // recursively generate child elements 
  118. foreach ( $element_value as $child_element_key => $child_element_value ) { 
  119.  
  120. $this->xml->startElement( $element_key ); 
  121.  
  122. foreach ( $child_element_value as $sibling_element_key => $sibling_element_value ) { 
  123. $this->array_to_xml( $sibling_element_key, $sibling_element_value ); 
  124.  
  125. $this->xml->endElement(); 
  126. } else { 
  127.  
  128. // start root element 
  129. $this->xml->startElement( $element_key ); 
  130.  
  131. // recursively generate child elements 
  132. foreach ( $element_value as $child_element_key => $child_element_value ) { 
  133. $this->array_to_xml( $child_element_key, $child_element_value ); 
  134.  
  135. // end root element 
  136. $this->xml->endElement(); 
  137. } else { 
  138.  
  139. // handle single elements 
  140. if ( '@value' == $element_key ) { 
  141.  
  142. $this->xml->text( $element_value ); 
  143.  
  144. } else { 
  145.  
  146. // wrap element in CDATA tags if it contains illegal characters 
  147. if ( false !== strpos( $element_value, '<' ) || false !== strpos( $element_value, '>' ) ) { 
  148.  
  149. $this->xml->startElement( $element_key ); 
  150. $this->xml->writeCdata( $element_value ); 
  151. $this->xml->endElement(); 
  152.  
  153. } else { 
  154.  
  155. $this->xml->writeElement( $element_key, $element_value ); 
  156.  
  157. return; 
  158.  
  159. /** 
  160. * Adjust the sales report array format to change totals keyed with the sales date to become an 
  161. * attribute for the totals element instead 
  162. * @since 2.1 
  163. * @param array $data 
  164. * @return array 
  165. */ 
  166. public function format_sales_report_data( $data ) { 
  167.  
  168. if ( ! empty( $data['totals'] ) ) { 
  169.  
  170. foreach ( $data['totals'] as $date => $totals ) { 
  171.  
  172. unset( $data['totals'][ $date ] ); 
  173.  
  174. $data['totals'][] = array_merge( array( '@attributes' => array( 'date' => $date ) ), $totals ); 
  175.  
  176. return $data; 
  177.  
  178. /** 
  179. * Adjust the product data to handle options for attributes without a named child element and other 
  180. * fields that have no named child elements (e.g. categories = array( 'cat1', 'cat2' ) ) 
  181. * Note that the parent product data for variations is also adjusted in the same manner as needed 
  182. * @since 2.1 
  183. * @param array $data 
  184. * @return array 
  185. */ 
  186. public function format_product_data( $data ) { 
  187.  
  188. // handle attribute values 
  189. if ( ! empty( $data['attributes'] ) ) { 
  190.  
  191. foreach ( $data['attributes'] as $attribute_key => $attribute ) { 
  192.  
  193. if ( ! empty( $attribute['options'] ) && is_array( $attribute['options'] ) ) { 
  194.  
  195. foreach ( $attribute['options'] as $option_key => $option ) { 
  196.  
  197. unset( $data['attributes'][ $attribute_key ]['options'][ $option_key ] ); 
  198.  
  199. $data['attributes'][ $attribute_key ]['options']['option'][] = array( $option ); 
  200.  
  201. // simple arrays are fine for JSON, but XML requires a child element name, so this adjusts the data 
  202. // array to define a child element name for each field 
  203. $fields_to_fix = array( 
  204. 'related_ids' => 'related_id',  
  205. 'upsell_ids' => 'upsell_id',  
  206. 'cross_sell_ids' => 'cross_sell_id',  
  207. 'categories' => 'category',  
  208. 'tags' => 'tag',  
  209. ); 
  210.  
  211. foreach ( $fields_to_fix as $parent_field_name => $child_field_name ) { 
  212.  
  213. if ( ! empty( $data[ $parent_field_name ] ) ) { 
  214.  
  215. foreach ( $data[ $parent_field_name ] as $field_key => $field ) { 
  216.  
  217. unset( $data[ $parent_field_name ][ $field_key ] ); 
  218.  
  219. $data[ $parent_field_name ][ $child_field_name ][] = array( $field ); 
  220.  
  221. // handle adjusting the parent product for variations 
  222. if ( ! empty( $data['parent'] ) ) { 
  223.  
  224. // attributes 
  225. if ( ! empty( $data['parent']['attributes'] ) ) { 
  226.  
  227. foreach ( $data['parent']['attributes'] as $attribute_key => $attribute ) { 
  228.  
  229. if ( ! empty( $attribute['options'] ) && is_array( $attribute['options'] ) ) { 
  230.  
  231. foreach ( $attribute['options'] as $option_key => $option ) { 
  232.  
  233. unset( $data['parent']['attributes'][ $attribute_key ]['options'][ $option_key ] ); 
  234.  
  235. $data['parent']['attributes'][ $attribute_key ]['options']['option'][] = array( $option ); 
  236.  
  237. // fields 
  238. foreach ( $fields_to_fix as $parent_field_name => $child_field_name ) { 
  239.  
  240. if ( ! empty( $data['parent'][ $parent_field_name ] ) ) { 
  241.  
  242. foreach ( $data['parent'][ $parent_field_name ] as $field_key => $field ) { 
  243.  
  244. unset( $data['parent'][ $parent_field_name ][ $field_key ] ); 
  245.  
  246. $data['parent'][ $parent_field_name ][ $child_field_name ][] = array( $field ); 
  247.  
  248. return $data;