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. * @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 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; } }