From 3a7f4884d813892640de07e25b1f8f6e170d6cde Mon Sep 17 00:00:00 2001 From: Mike Jolley Date: Fri, 26 May 2017 15:57:17 +0100 Subject: [PATCH 1/5] Moved logic around and organised --- .../import/abstract-wc-product-importer.php | 575 +++--------------- .../import/class-wc-product-csv-importer.php | 110 ++-- 2 files changed, 164 insertions(+), 521 deletions(-) diff --git a/includes/import/abstract-wc-product-importer.php b/includes/import/abstract-wc-product-importer.php index 75abf245630..744273a3241 100644 --- a/includes/import/abstract-wc-product-importer.php +++ b/includes/import/abstract-wc-product-importer.php @@ -131,45 +131,6 @@ abstract class WC_Product_Importer implements WC_Importer_Interface { return absint( min( round( ( $this->file_position / $size ) * 100 ), 100 ) ); } - /** - * Process a single item and save. - * - * @param array $data Raw CSV data. - * @return array|WC_Error - */ - protected function process_item( $data ) { - try { - $object = $this->get_product_object( $data ); - $updating = false; - - if ( is_wp_error( $object ) ) { - return $object; - } - - if ( $object->get_id() && 'importing' !== $object->get_status() ) { - $updating = true; - } - - if ( 'variation' === $object->get_type() ) { - $object = $this->save_variation_data( $object, $data ); - } else { - $object = $this->save_product_data( $object, $data ); - } - - $object = apply_filters( 'woocommerce_product_import_pre_insert_product_object', $object, $data ); - $object->save(); - - return array( - 'id' => $object->get_id(), - 'updated' => $updating, - ); - } catch ( WC_Data_Exception $e ) { - return new WP_Error( $e->getErrorCode(), $e->getMessage(), $e->getErrorData() ); - } catch ( Exception $e ) { - return new WP_Error( 'woocommerce_product_importer_error', $e->getMessage(), array( 'status' => $e->getCode() ) ); - } - } - /** * Prepare a single product for create or update. * @@ -208,92 +169,108 @@ abstract class WC_Product_Importer implements WC_Importer_Interface { return apply_filters( 'woocommerce_product_import_get_product_object', $product, $data ); } + /** + * Process a single item and save. + * + * @param array $data Raw CSV data. + * @return array|WC_Error + */ + protected function process_item( $data ) { + try { + $object = $this->get_product_object( $data ); + $updating = false; + + if ( is_wp_error( $object ) ) { + return $object; + } + + if ( $object->get_id() && 'importing' !== $object->get_status() ) { + $updating = true; + } + + $result = $object->set_props( array_diff_key( $data, array_flip( array( 'meta_data', 'raw_image_id', 'raw_gallery_image_ids', 'raw_attributes' ) ) ) ); + + if ( is_wp_error( $result ) ) { + throw new Exception( $result->get_error_message() ); + } + + if ( 'variation' === $object->get_type() ) { + $this->set_variation_data( $object, $data ); + } else { + $this->set_product_data( $object, $data ); + } + + $this->set_image_data( $object, $data ); + $this->set_meta_data( $object, $data ); + + if ( 'importing' === $object->get_status() ) { + $object->set_status( 'publish' ); + } + + $object = apply_filters( 'woocommerce_product_import_pre_insert_product_object', $object, $data ); + $object->save(); + + return array( + 'id' => $object->get_id(), + 'updated' => $updating, + ); + } catch ( Exception $e ) { + return new WP_Error( 'woocommerce_product_importer_error', $e->getMessage(), array( 'status' => $e->getCode() ) ); + } + } + + /** + * Convert raw image URLs to IDs and set. + * + * @param WC_Product $product + * @param array $data + */ + protected function set_image_data( &$product, $data ) { + // Image URLs need converting to IDs before inserting. + if ( isset( $data['image_id'] ) ) { + $product->set_image_id( $this->get_attachment_id_from_url( $data['image_id'], $product->get_id() ) ); + } + + // Gallery image URLs need converting to IDs before inserting. + if ( isset( $data['gallery_image_ids'] ) ) { + $gallery_image_ids = array(); + + foreach ( $data['gallery_image_ids'] as $image_id ) { + $gallery_image_ids[] = $this->get_attachment_id_from_url( $image_id, $product->get_id() ); + } + $product->set_gallery_image_ids( $gallery_image_ids ); + } + } + + /** + * Append meta data. + * + * @param WC_Product $product + * @param array $data + */ + protected function set_meta_data( &$product, $data ) { + if ( isset( $data['meta_data'] ) ) { + foreach ( $data['meta_data'] as $meta ) { + $product->update_meta_data( $meta['key'], $meta['value'] ); + } + } + } + /** * Set product data. * * @param WC_Product $product Product instance. * @param array $data Row data. * - * @return WC_Product + * @return WC_Product|WP_Error + * @throws Exception */ - protected function save_product_data( $product, $data ) { - - // Name. - if ( isset( $data['name'] ) ) { - $product->set_name( wp_filter_post_kses( $data['name'] ) ); - } - - // Description. - if ( isset( $data['description'] ) ) { - $product->set_description( wp_filter_post_kses( $data['description'] ) ); - } - - // Short description. - if ( isset( $data['short_description'] ) ) { - $product->set_short_description( wp_filter_post_kses( $data['short_description'] ) ); - } - - // Status. - if ( isset( $data['published'] ) ) { - $product->set_status( $data['published'] ? 'publish' : 'draft' ); - } elseif ( 'importing' === $product->get_status() ) { - $product->set_status( 'publish' ); - } - - // Slug. - if ( isset( $data['slug'] ) ) { - $product->set_slug( $data['slug'] ); - } - - // Comment status. - if ( isset( $data['reviews_allowed'] ) ) { - $product->set_reviews_allowed( $data['reviews_allowed'] ); - } - - // Virtual. - if ( isset( $data['virtual'] ) ) { - $product->set_virtual( $data['virtual'] ); - } - - // Tax status. - if ( isset( $data['tax_status'] ) ) { - $product->set_tax_status( $data['tax_status'] ); - } - - // Tax Class. - if ( isset( $data['tax_class'] ) ) { - $product->set_tax_class( $data['tax_class'] ); - } - - // Catalog Visibility. - if ( isset( $data['catalog_visibility'] ) ) { - $product->set_catalog_visibility( $data['catalog_visibility'] ); - } - - // Purchase Note. - if ( isset( $data['purchase_note'] ) ) { - $product->set_purchase_note( $data['purchase_note'] ); - } - - // Featured Product. - if ( isset( $data['featured'] ) ) { - $product->set_featured( $data['featured'] ); - } - - // Shipping data. - $product = $this->save_product_shipping_data( $product, $data ); - - // SKU. - if ( isset( $data['sku'] ) ) { - $product->set_sku( $data['sku'] ); - } - - // Attributes. - if ( isset( $data['attributes'] ) ) { + protected function set_product_data( &$product, $data ) { + if ( isset( $data['raw_attributes'] ) ) { $attributes = array(); $default_attributes = array(); - foreach ( $data['attributes'] as $position => $attribute ) { + foreach ( $data['raw_attributes'] as $position => $attribute ) { // Get ID if is a global attribute. $attribute_id = wc_attribute_taxonomy_id_by_name( $attribute['name'] ); @@ -365,177 +342,6 @@ abstract class WC_Product_Importer implements WC_Importer_Interface { $product->set_default_attributes( $default_attributes ); } } - - // Sales and prices. - if ( in_array( $product->get_type(), array( 'variable', 'grouped' ), true ) ) { - $product->set_regular_price( '' ); - $product->set_sale_price( '' ); - $product->set_date_on_sale_to( '' ); - $product->set_date_on_sale_from( '' ); - $product->set_price( '' ); - } else { - // Regular Price. - if ( isset( $data['regular_price'] ) ) { - $product->set_regular_price( $data['regular_price'] ); - } - - // Sale Price. - if ( isset( $data['sale_price'] ) ) { - $product->set_sale_price( $data['sale_price'] ); - } - - if ( isset( $data['date_on_sale_from'] ) ) { - $product->set_date_on_sale_from( $data['date_on_sale_from'] ); - } - - if ( isset( $data['date_on_sale_to'] ) ) { - $product->set_date_on_sale_to( $data['date_on_sale_to'] ); - } - } - - // Product parent ID for groups. - if ( isset( $data['parent_id'] ) ) { - $product->set_parent_id( $data['parent_id'] ); - } - - // Sold individually. - if ( isset( $data['sold_individually'] ) ) { - $product->set_sold_individually( $data['sold_individually'] ); - } - - // Stock status. - if ( isset( $data['stock_status'] ) ) { - $stock_status = $data['stock_status'] ? 'instock' : 'outofstock'; - } else { - $stock_status = $product->get_stock_status(); - } - - // Stock data. - if ( 'yes' === get_option( 'woocommerce_manage_stock' ) ) { - // Manage stock. - if ( isset( $data['manage_stock'] ) ) { - $product->set_manage_stock( $data['manage_stock'] ); - } - - // Backorders. - if ( isset( $data['backorders'] ) ) { - $product->set_backorders( $data['backorders'] ); - } - - if ( $product->is_type( 'grouped' ) ) { - $product->set_manage_stock( false ); - $product->set_backorders( false ); - $product->set_stock_quantity( '' ); - $product->set_stock_status( $stock_status ); - } elseif ( $product->is_type( 'external' ) ) { - $product->set_manage_stock( false ); - $product->set_backorders( false ); - $product->set_stock_quantity( '' ); - $product->set_stock_status( 'instock' ); - } elseif ( $product->get_manage_stock() ) { - // Stock status is always determined by children so sync later. - if ( ! $product->is_type( 'variable' ) ) { - $product->set_stock_status( $stock_status ); - } - - // Stock quantity. - if ( isset( $data['stock_quantity'] ) ) { - $product->set_stock_quantity( wc_stock_amount( $data['stock_quantity'] ) ); - } - } else { - // Don't manage stock. - $product->set_manage_stock( false ); - $product->set_stock_quantity( '' ); - $product->set_stock_status( $stock_status ); - } - } elseif ( ! $product->is_type( 'variable' ) ) { - $product->set_stock_status( $stock_status ); - } - - // Upsells. - if ( isset( $data['upsell_ids'] ) ) { - $product->set_upsell_ids( $data['upsell_ids'] ); - } - - // Cross sells. - if ( isset( $data['cross_sell_ids'] ) ) { - $product->set_cross_sell_ids( $data['cross_sell_ids'] ); - } - - // Product categories. - if ( isset( $data['category_ids'] ) ) { - $product->set_category_ids( $data['category_ids'] ); - } - - // Product tags. - if ( isset( $data['tag_ids'] ) ) { - $product->set_tag_ids( $data['tag_ids'] ); - } - - // Downloadable. - if ( isset( $data['downloadable'] ) ) { - $product->set_downloadable( $data['downloadable'] ); - } - - // Downloadable options. - if ( $product->get_downloadable() ) { - - // Downloadable files. - if ( isset( $data['downloads'] ) ) { - $product = $this->save_downloadable_files( $product, $data['downloads'] ); - } - - // Download limit. - if ( isset( $data['download_limit'] ) ) { - $product->set_download_limit( $data['download_limit'] ); - } - - // Download expiry. - if ( isset( $data['download_expiry'] ) ) { - $product->set_download_expiry( $data['download_expiry'] ); - } - } - - // Product url and button text for external products. - if ( $product->is_type( 'external' ) ) { - if ( isset( $data['external_url'] ) ) { - $product->set_product_url( $data['external_url'] ); - } - - if ( isset( $data['button_text'] ) ) { - $product->set_button_text( $data['button_text'] ); - } - } - - // Featured image. - if ( isset( $data['image_id'] ) ) { - $image_id = $data['image_id'] ? $this->get_attachment_id( $data['image_id'], $product->get_id() ) : ''; - $product->set_image_id( $image_id ); - } - - // Gallery. - if ( isset( $data['gallery_image_ids'] ) ) { - $gallery_image_ids = array(); - - foreach ( $data['gallery_image_ids'] as $url ) { - if ( empty( $url ) ) { - continue; - } - - $gallery_image_ids[] = $this->get_attachment_id( $url, $product->get_id() ); - } - - $product->set_gallery_image_ids( array_filter( $gallery_image_ids ) ); - } - - // Allow set meta_data. - if ( isset( $data['meta_data'] ) ) { - foreach ( $data['meta_data'] as $meta ) { - $product->update_meta_data( $meta['key'], $meta['value'] ); - } - } - - return $product; } /** @@ -545,8 +351,9 @@ abstract class WC_Product_Importer implements WC_Importer_Interface { * @param array $data Row data. * * @return WC_Product|WP_Error + * @throws Exception */ - protected function save_variation_data( $variation, $data ) { + protected function set_variation_data( &$variation, $data ) { $parent = false; // Check if parent exist. @@ -563,121 +370,11 @@ abstract class WC_Product_Importer implements WC_Importer_Interface { return new WP_Error( 'woocommerce_product_importer_missing_variation_parent_id', __( 'Missing parent ID or parent does not exist.', 'woocommerce' ), array( 'status' => 401 ) ); } - // Status. - if ( isset( $data['published'] ) ) { - $variation->set_status( $data['published'] ? 'publish' : 'draft' ); - } elseif ( 'importing' === $variation->get_status() ) { - $variation->set_status( 'publish' ); - } - - // SKU. - if ( isset( $data['sku'] ) ) { - $variation->set_sku( wc_clean( $data['sku'] ) ); - } - - // Featured image. - if ( isset( $data['image_id'] ) ) { - $image_id = $data['image_id'] ? $this->get_attachment_id( $data['image_id'], $variation->get_id() ) : ''; - $variation->set_image_id( $image_id ); - } - - // Virtual variation. - if ( isset( $data['virtual'] ) ) { - $variation->set_virtual( $data['virtual'] ); - } - - // Downloadable variation. - if ( isset( $data['downloadable'] ) ) { - $variation->set_downloadable( $data['downloadable'] ); - } - - // Downloads. - if ( $variation->get_downloadable() ) { - // Downloadable files. - if ( isset( $data['downloads'] ) ) { - $variation = $this->save_downloadable_files( $variation, $data['downloads'] ); - } - - // Download limit. - if ( isset( $data['download_limit'] ) ) { - $variation->set_download_limit( $data['download_limit'] ); - } - - // Download expiry. - if ( isset( $data['download_expiry'] ) ) { - $variation->set_download_expiry( $data['download_expiry'] ); - } - } - - // Shipping data. - $variation = $this->save_product_shipping_data( $variation, $data ); - - // Stock handling. - if ( isset( $data['stock_status'] ) ) { - $variation->set_stock_status( $data['stock_status'] ? 'instock' : 'outofstock' ); - } - - if ( 'yes' === get_option( 'woocommerce_manage_stock' ) ) { - if ( isset( $data['manage_stock'] ) ) { - $variation->set_manage_stock( $data['manage_stock'] ); - } - - if ( isset( $data['backorders'] ) ) { - $variation->set_backorders( $data['backorders'] ); - } - - if ( $variation->get_manage_stock() ) { - if ( isset( $data['stock_quantity'] ) ) { - $variation->set_stock_quantity( $data['stock_quantity'] ); - } - } else { - $variation->set_backorders( 'no' ); - $variation->set_stock_quantity( '' ); - } - } - - // Regular Price. - if ( isset( $data['regular_price'] ) ) { - $variation->set_regular_price( $data['regular_price'] ); - } - - // Sale Price. - if ( isset( $data['sale_price'] ) ) { - $variation->set_sale_price( $data['sale_price'] ); - } - - if ( isset( $data['date_on_sale_from'] ) ) { - $variation->set_date_on_sale_from( $data['date_on_sale_from'] ); - } - - if ( isset( $data['date_on_sale_from_gmt'] ) ) { - $variation->set_date_on_sale_from( $data['date_on_sale_from_gmt'] ? strtotime( $data['date_on_sale_from_gmt'] ) : null ); - } - - if ( isset( $data['date_on_sale_to'] ) ) { - $variation->set_date_on_sale_to( $data['date_on_sale_to'] ); - } - - if ( isset( $data['date_on_sale_to_gmt'] ) ) { - $variation->set_date_on_sale_to( $data['date_on_sale_to_gmt'] ? strtotime( $data['date_on_sale_to_gmt'] ) : null ); - } - - // Tax class. - if ( isset( $data['tax_class'] ) ) { - $variation->set_tax_class( $data['tax_class'] ); - } - - // Description. - if ( isset( $data['description'] ) ) { - $variation->set_description( wp_kses_post( $data['description'] ) ); - } - - // Update taxonomies. - if ( isset( $data['attributes'] ) ) { + if ( isset( $data['raw_attributes'] ) ) { $attributes = array(); - $parent_attributes = $this->get_variation_parent_attributes( $data['attributes'], $parent ); + $parent_attributes = $this->get_variation_parent_attributes( $data['raw_attributes'], $parent ); - foreach ( $data['attributes'] as $attribute ) { + foreach ( $data['raw_attributes'] as $attribute ) { // Get ID if is a global attribute. $attribute_id = wc_attribute_taxonomy_id_by_name( $attribute['name'] ); @@ -710,15 +407,6 @@ abstract class WC_Product_Importer implements WC_Importer_Interface { $variation->set_attributes( $attributes ); } - - // Meta data. - if ( isset( $data['meta_data'] ) ) { - foreach ( $data['meta_data'] as $meta ) { - $variation->update_meta_data( $meta['key'], $meta['value'] ); - } - } - - return $variation; } /** @@ -768,7 +456,7 @@ abstract class WC_Product_Importer implements WC_Importer_Interface { * @param int $product_id Product ID. * @return int */ - protected function get_attachment_id( $url, $product_id ) { + protected function get_attachment_id_from_url( $url, $product_id ) { if ( empty( $url ) ) { return 0; } @@ -835,71 +523,4 @@ abstract class WC_Product_Importer implements WC_Importer_Interface { return $id; } - - /** - * Save product shipping data. - * - * @param WC_Product $product Product instance. - * @param array $data Shipping data. - * @return WC_Product - */ - protected function save_product_shipping_data( $product, $data ) { - // Virtual. - if ( $product->is_virtual() ) { - $product->set_weight( '' ); - $product->set_height( '' ); - $product->set_length( '' ); - $product->set_width( '' ); - } else { - if ( isset( $data['weight'] ) ) { - $product->set_weight( $data['weight'] ); - } - - // Height. - if ( isset( $data['height'] ) ) { - $product->set_height( $data['height'] ); - } - - // Width. - if ( isset( $data['width'] ) ) { - $product->set_width( $data['width'] ); - } - - // Length. - if ( isset( $data['length'] ) ) { - $product->set_length( $data['length'] ); - } - } - - // Shipping class. - if ( isset( $data['shipping_class_id'] ) ) { - $product->set_shipping_class_id( $data['shipping_class_id'] ); - } - - return $product; - } - - /** - * Save downloadable files. - * - * @param WC_Product $product Product instance. - * @param array $downloads Downloads data. - * @return WC_Product - */ - protected function save_downloadable_files( $product, $data ) { - $downloads = array(); - foreach ( $data as $key => $file ) { - if ( empty( $file['url'] ) ) { - continue; - } - - $downloads[] = array( - 'name' => $file['name'] ? $file['name'] : wc_get_filename_from_url( $file['url'] ), - 'file' => apply_filters( 'woocommerce_file_download_path', $file['url'], $product, $key ), - ); - } - $product->set_downloads( $downloads ); - - return $product; - } } diff --git a/includes/import/class-wc-product-csv-importer.php b/includes/import/class-wc-product-csv-importer.php index 60c2043f0de..da1d0b0551e 100644 --- a/includes/import/class-wc-product-csv-importer.php +++ b/includes/import/class-wc-product-csv-importer.php @@ -322,8 +322,9 @@ class WC_Product_CSV_Importer extends WC_Product_Importer { 'featured' => array( $this, 'parse_bool_field' ), 'date_on_sale_from' => 'strtotime', 'date_on_sale_to' => 'strtotime', - 'short_description' => 'wp_kses_post', - 'description' => 'wp_kses_post', + 'name' => 'wp_filter_post_kses', + 'short_description' => 'wp_filter_post_kses', + 'description' => 'wp_filter_post_kses', 'manage_stock' => array( $this, 'parse_bool_field' ), 'backorders' => array( $this, 'parse_bool_field' ), 'stock_status' => array( $this, 'parse_bool_field' ), @@ -333,20 +334,20 @@ class WC_Product_CSV_Importer extends WC_Product_Importer { 'height' => array( $this, 'parse_float_field' ), 'weight' => array( $this, 'parse_float_field' ), 'reviews_allowed' => array( $this, 'parse_bool_field' ), - 'purchase_note' => 'wp_kses_post', + 'purchase_note' => 'wp_filter_post_kses', 'price' => 'wc_format_decimal', 'regular_price' => 'wc_format_decimal', 'stock_quantity' => 'absint', 'category_ids' => array( $this, 'parse_categories_field' ), 'tag_ids' => array( $this, 'parse_tags_field' ), 'shipping_class_id' => array( $this, 'parse_shipping_class_field' ), - 'image_id' => array( $this, 'parse_images_field' ), + 'images' => array( $this, 'parse_images_field' ), 'parent_id' => array( $this, 'parse_relative_field' ), 'upsell_ids' => array( $this, 'parse_relative_comma_field' ), 'cross_sell_ids' => array( $this, 'parse_relative_comma_field' ), 'download_limit' => 'absint', 'download_expiry' => 'absint', - 'external_url' => 'esc_url', + 'external_url' => 'esc_url_raw', ); /** @@ -394,7 +395,7 @@ class WC_Product_CSV_Importer extends WC_Product_Importer { } /** - * Expand special and internal data. + * Expand special and internal data into the correct formats for the product CRUD. * * @param array $data Data to import. * @return array @@ -403,33 +404,33 @@ class WC_Product_CSV_Importer extends WC_Product_Importer { $data = apply_filters( 'woocommerce_product_importer_pre_expand_data', $data ); // Product ID and SKU mapping. - if ( empty( $data['id'] ) && ! empty( $data['sku'] ) && ( $id = wc_get_product_id_by_sku( $data['sku'] ) ) ) { - $data['id'] = $id; + if ( empty( $data['id'] ) && ! empty( $data['sku'] ) && ( $product_id = wc_get_product_id_by_sku( $data['sku'] ) ) ) { + $data['id'] = $product_id; } - // Meta data. - $data['meta_data'] = array(); - $data['attributes'] = array(); - $data['default_attributes'] = array(); - $data['downloads'] = array(); - $data['gallery_image_ids'] = array(); - - // Manage stock. + // Manage stock is mapped from the stock_quantity field. if ( isset( $data['stock_quantity'] ) ) { $data['manage_stock'] = 0 < $data['stock_quantity']; } - // Images. - if ( isset( $data['image_id'] ) ) { - $images = $data['image_id']; - $data['image_id'] = array_shift( $images ); - - if ( ! empty( $images ) ) { - $data['gallery_image_ids'] = $images; - } + // Status is mapped from a special published field. + if ( isset( $data['published'] ) ) { + $data['status'] = ( $data['published'] ? 'publish' : 'draft' ); + unset( $data['published'] ); } - // Type, virtual and downlodable. + // Images field maps to image and gallery id fields. + if ( isset( $data['images'] ) ) { + $images = $data['images']; + $data['raw_image_id'] = array_shift( $images ); + + if ( ! empty( $images ) ) { + $data['raw_gallery_image_ids'] = $images; + } + unset( $data['images'] ); + } + + // Type, virtual and downloadable are all stored in the same column. if ( isset( $data['type'] ) ) { $data['type'] = array_map( 'strtolower', $data['type'] ); $data['virtual'] = in_array( 'virtual', $data['type'], true ); @@ -439,67 +440,88 @@ class WC_Product_CSV_Importer extends WC_Product_Importer { $data['type'] = current( array_diff( $data['type'], array( 'virtual', 'downloadable' ) ) ); } - // Handle special column names. + // Stock is bool. + if ( isset( $data['stock_status'] ) ) { + $stock_status = $data['stock_status'] ? 'instock' : 'outofstock'; + } + + // Handle special column names which span multiple columns. + $attributes = array(); + $downloads = array(); + $meta_data = array(); + foreach ( $data as $key => $value ) { // Attributes. if ( $this->starts_with( $key, 'attributes:name' ) ) { if ( ! empty( $value ) ) { - $data['attributes'][ str_replace( 'attributes:name', '', $key ) ]['name'] = $value; + $attributes[ str_replace( 'attributes:name', '', $key ) ]['name'] = $value; } - unset( $data[ $key ] ); } if ( $this->starts_with( $key, 'attributes:value' ) ) { if ( ! empty( $value ) ) { - $data['attributes'][ str_replace( 'attributes:value', '', $key ) ]['value'] = $value; + $attributes[ str_replace( 'attributes:value', '', $key ) ]['value'] = $value; } - unset( $data[ $key ] ); } if ( $this->starts_with( $key, 'attributes:visible' ) ) { if ( '' !== $value ) { - $data['attributes'][ str_replace( 'attributes:visible', '', $key ) ]['visible'] = $value; + $attributes[ str_replace( 'attributes:visible', '', $key ) ]['visible'] = $value; } - unset( $data[ $key ] ); } - - // Default attributes. if ( $this->starts_with( $key, 'attributes:default' ) ) { if ( ! empty( $value ) ) { - $data['attributes'][ str_replace( 'attributes:default', '', $key ) ]['default'] = $value; + $attributes[ str_replace( 'attributes:default', '', $key ) ]['default'] = $value; } - unset( $data[ $key ] ); } // Downloads. if ( $this->starts_with( $key, 'downloads:name' ) ) { if ( ! empty( $value ) ) { - $data['downloads'][ str_replace( 'downloads:name', '', $key ) ]['name'] = $value; + $downloads[ str_replace( 'downloads:name', '', $key ) ]['name'] = $value; } - unset( $data[ $key ] ); } if ( $this->starts_with( $key, 'downloads:url' ) ) { if ( ! empty( $value ) ) { - $data['downloads'][ str_replace( 'downloads:url', '', $key ) ]['url'] = $value; + $downloads[ str_replace( 'downloads:url', '', $key ) ]['url'] = $value; } - unset( $data[ $key ] ); } // Meta data. if ( $this->starts_with( $key, 'meta:' ) ) { - $data['meta_data'][] = array( + $meta_data[] = array( 'key' => str_replace( 'meta:', '', $key ), 'value' => $value, ); - unset( $data[ $key ] ); } } + if ( ! empty( $attributes ) ) { + $data['raw_attributes'] = $attributes; + } + if ( ! empty( $downloads ) ) { + $data['downloads'] = array(); + + foreach ( $downloads as $key => $file ) { + if ( empty( $file['url'] ) ) { + continue; + } + + $data['downloads'][] = array( + 'name' => $file['name'] ? $file['name'] : wc_get_filename_from_url( $file['url'] ), + 'file' => apply_filters( 'woocommerce_file_download_path', $file['url'], $product, $key ), + ); + } + } + if ( ! empty( $meta_data ) ) { + $data['meta_data'] = $meta_data; + } + return $data; } @@ -582,14 +604,14 @@ class WC_Product_CSV_Importer extends WC_Product_Importer { $product = wc_get_product( $id ); if ( $product && 'importing' !== $product->get_status() ) { - $data['skipped'][] = new WP_Error( 'woocommerce_product_csv_importer_error', __( 'A product with this ID already exists.', 'woocommerce' ), array( 'id' => $id, 'row' => $this->get_row_id( $parsed_data ) ) ); + $data['skipped'][] = new WP_Error( 'woocommerce_product_importer_error', __( 'A product with this ID already exists.', 'woocommerce' ), array( 'id' => $id, 'row' => $this->get_row_id( $parsed_data ) ) ); continue; } } elseif ( $sku && ( $id_from_sku = wc_get_product_id_by_sku( $sku ) ) ) { $product = wc_get_product( $id_from_sku ); if ( $product && 'importing' !== $product->get_status() ) { - $data['skipped'][] = new WP_Error( 'woocommerce_product_csv_importer_error', __( 'A product with this SKU already exists.', 'woocommerce' ), array( 'sku' => $sku, 'row' => $this->get_row_id( $parsed_data ) ) ); + $data['skipped'][] = new WP_Error( 'woocommerce_product_importer_error', __( 'A product with this SKU already exists.', 'woocommerce' ), array( 'sku' => $sku, 'row' => $this->get_row_id( $parsed_data ) ) ); continue; } } From f51d434d10a8731da0bff52a2314c9d93c8a8ea8 Mon Sep 17 00:00:00 2001 From: Mike Jolley Date: Fri, 26 May 2017 15:57:29 +0100 Subject: [PATCH 2/5] Added todo item in exporter --- includes/export/class-wc-product-csv-exporter.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/includes/export/class-wc-product-csv-exporter.php b/includes/export/class-wc-product-csv-exporter.php index bb151bc98ee..86daa9ca0e2 100644 --- a/includes/export/class-wc-product-csv-exporter.php +++ b/includes/export/class-wc-product-csv-exporter.php @@ -104,12 +104,13 @@ class WC_Product_CSV_Exporter extends WC_CSV_Batch_Exporter { 'category_ids' => __( 'Categories', 'woocommerce' ), 'tag_ids' => __( 'Tags', 'woocommerce' ), 'shipping_class_id' => __( 'Shipping Class', 'woocommerce' ), - 'image_id' => __( 'Images', 'woocommerce' ), + 'images' => __( 'Images', 'woocommerce' ), 'download_limit' => __( 'Download Limit', 'woocommerce' ), 'download_expiry' => __( 'Download Expiry Days', 'woocommerce' ), 'parent_id' => __( 'Parent', 'woocommerce' ), 'upsell_ids' => __( 'Upsells', 'woocommerce' ), 'cross_sell_ids' => __( 'Cross-sells', 'woocommerce' ), + // @todo product_url button_text ); } @@ -218,13 +219,13 @@ class WC_Product_CSV_Exporter extends WC_CSV_Batch_Exporter { } /** - * Get image_id value. + * Get images value. * * @since 3.1.0 * @param WC_Product $product * @return string */ - protected function get_column_value_image_id( $product ) { + protected function get_column_value_images( $product ) { $image_ids = array_merge( array( $product->get_image_id( 'edit' ) ), $product->get_gallery_image_ids( 'edit' ) ); $images = array(); From 67dde58d83a0ff8a0fb09337f567ed86d3ee16d4 Mon Sep 17 00:00:00 2001 From: Mike Jolley Date: Fri, 26 May 2017 16:00:32 +0100 Subject: [PATCH 3/5] Tests --- tests/unit-tests/importer/product.php | 57 ++++++++++----------------- 1 file changed, 21 insertions(+), 36 deletions(-) diff --git a/tests/unit-tests/importer/product.php b/tests/unit-tests/importer/product.php index ecda0ebf362..60f4f0fb171 100644 --- a/tests/unit-tests/importer/product.php +++ b/tests/unit-tests/importer/product.php @@ -147,46 +147,31 @@ class WC_Tests_Product_CSV_Importer extends WC_Unit_Test_Case { $importer = new WC_Product_CSV_Importer( $this->csv_file, $args ); $items = array( array( - 'type' => 'simple', - 'sku' => 'PRODUCT-01', - 'name' => 'Imported Product 1', - 'published' => true, - 'regular_price' => '40', - 'meta_data' => array(), - 'attributes' => array(), - 'default_attributes' => array(), - 'downloads' => array(), - 'virtual' => false, - 'downloadable' => false, - 'gallery_image_ids' => array(), + 'type' => 'simple', + 'sku' => 'PRODUCT-01', + 'name' => 'Imported Product 1', + 'regular_price' => '40', + 'virtual' => false, + 'downloadable' => false, + 'status' => 'publish', ), array( - 'type' => 'simple', - 'sku' => 'PRODUCT-02', - 'name' => 'Imported Product 2', - 'published' => true, - 'regular_price' => '41', - 'meta_data' => array(), - 'attributes' => array(), - 'default_attributes' => array(), - 'downloads' => array(), - 'virtual' => false, - 'downloadable' => false, - 'gallery_image_ids' => array(), + 'type' => 'simple', + 'sku' => 'PRODUCT-02', + 'name' => 'Imported Product 2', + 'regular_price' => '41', + 'virtual' => false, + 'downloadable' => false, + 'status' => 'publish', ), array( - 'type' => 'simple', - 'sku' => 'PRODUCT-03', - 'name' => 'Imported Product 3', - 'published' => true, - 'regular_price' => '42', - 'meta_data' => array(), - 'attributes' => array(), - 'default_attributes' => array(), - 'downloads' => array(), - 'virtual' => false, - 'downloadable' => false, - 'gallery_image_ids' => array(), + 'type' => 'simple', + 'sku' => 'PRODUCT-03', + 'name' => 'Imported Product 3', + 'regular_price' => '42', + 'virtual' => false, + 'downloadable' => false, + 'status' => 'publish', ), ); From d9217b1d592d5b247d369efedb5c955a6c9a4c2f Mon Sep 17 00:00:00 2001 From: Mike Jolley Date: Fri, 26 May 2017 16:54:43 +0100 Subject: [PATCH 4/5] More tidyup --- .../import/class-wc-product-csv-importer.php | 40 ++++++++----------- 1 file changed, 17 insertions(+), 23 deletions(-) diff --git a/includes/import/class-wc-product-csv-importer.php b/includes/import/class-wc-product-csv-importer.php index da1d0b0551e..2ccf29d06f4 100644 --- a/includes/import/class-wc-product-csv-importer.php +++ b/includes/import/class-wc-product-csv-importer.php @@ -457,42 +457,34 @@ class WC_Product_CSV_Importer extends WC_Product_Importer { $attributes[ str_replace( 'attributes:name', '', $key ) ]['name'] = $value; } unset( $data[ $key ] ); - } - if ( $this->starts_with( $key, 'attributes:value' ) ) { - if ( ! empty( $value ) ) { - $attributes[ str_replace( 'attributes:value', '', $key ) ]['value'] = $value; - } + + } elseif ( $this->starts_with( $key, 'attributes:value' ) ) { + $attributes[ str_replace( 'attributes:value', '', $key ) ]['value'] = $value; unset( $data[ $key ] ); - } - if ( $this->starts_with( $key, 'attributes:visible' ) ) { - if ( '' !== $value ) { - $attributes[ str_replace( 'attributes:visible', '', $key ) ]['visible'] = $value; - } + + } elseif ( $this->starts_with( $key, 'attributes:visible' ) ) { + $attributes[ str_replace( 'attributes:visible', '', $key ) ]['visible'] = wc_string_to_bool( $value ); unset( $data[ $key ] ); - } - if ( $this->starts_with( $key, 'attributes:default' ) ) { - if ( ! empty( $value ) ) { - $attributes[ str_replace( 'attributes:default', '', $key ) ]['default'] = $value; - } + + } elseif ( $this->starts_with( $key, 'attributes:default' ) ) { + $attributes[ str_replace( 'attributes:default', '', $key ) ]['default'] = $value; unset( $data[ $key ] ); - } // Downloads. - if ( $this->starts_with( $key, 'downloads:name' ) ) { + } elseif ( $this->starts_with( $key, 'downloads:name' ) ) { if ( ! empty( $value ) ) { $downloads[ str_replace( 'downloads:name', '', $key ) ]['name'] = $value; } unset( $data[ $key ] ); - } - if ( $this->starts_with( $key, 'downloads:url' ) ) { + + } elseif ( $this->starts_with( $key, 'downloads:url' ) ) { if ( ! empty( $value ) ) { $downloads[ str_replace( 'downloads:url', '', $key ) ]['url'] = $value; } unset( $data[ $key ] ); - } // Meta data. - if ( $this->starts_with( $key, 'meta:' ) ) { + } elseif ( $this->starts_with( $key, 'meta:' ) ) { $meta_data[] = array( 'key' => str_replace( 'meta:', '', $key ), 'value' => $value, @@ -504,6 +496,7 @@ class WC_Product_CSV_Importer extends WC_Product_Importer { if ( ! empty( $attributes ) ) { $data['raw_attributes'] = $attributes; } + if ( ! empty( $downloads ) ) { $data['downloads'] = array(); @@ -518,6 +511,7 @@ class WC_Product_CSV_Importer extends WC_Product_Importer { ); } } + if ( ! empty( $meta_data ) ) { $data['meta_data'] = $meta_data; } @@ -571,10 +565,10 @@ class WC_Product_CSV_Importer extends WC_Product_Importer { $row_data[] = $name; } if ( $id ) { - $row_data[] = __( 'ID: ', 'woocommerce' ) . $id; + $row_data[] = sprintf( __( 'ID %d', 'woocommerce' ), $id ); } if ( $sku ) { - $row_data[] = __( 'SKU: ', 'woocommerce' ) . $sku; + $row_data[] = sprintf( __( 'SKU %s', 'woocommerce' ), $sku ); } return implode( ', ', $row_data ); From dbd0f3dce0c956b0bf36cbb4a81fa2cae4516d2d Mon Sep 17 00:00:00 2001 From: Mike Jolley Date: Fri, 26 May 2017 16:56:37 +0100 Subject: [PATCH 5/5] error message --- includes/import/abstract-wc-product-importer.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/includes/import/abstract-wc-product-importer.php b/includes/import/abstract-wc-product-importer.php index 744273a3241..0d705bfd21d 100644 --- a/includes/import/abstract-wc-product-importer.php +++ b/includes/import/abstract-wc-product-importer.php @@ -367,7 +367,7 @@ abstract class WC_Product_Importer implements WC_Importer_Interface { // Stop if parent does not exists. if ( ! $parent ) { - return new WP_Error( 'woocommerce_product_importer_missing_variation_parent_id', __( 'Missing parent ID or parent does not exist.', 'woocommerce' ), array( 'status' => 401 ) ); + return new WP_Error( 'woocommerce_product_importer_missing_variation_parent_id', __( 'Variation cannot be imported: Missing parent ID or parent does not exist yet.', 'woocommerce' ), array( 'status' => 401 ) ); } if ( isset( $data['raw_attributes'] ) ) {