Файловый менеджер - Редактировать - /home/tuudkjt/globeasy/wp-includes/ID3/import.tar
Назад
abstract-wc-product-importer.php 0000777 00000054773 15252741661 0013044 0 ustar 00 <?php /** * Abstract Product importer * * @package WooCommerce\Import * @version 3.1.0 */ use Automattic\WooCommerce\Enums\ProductStatus; use Automattic\WooCommerce\Enums\ProductType; use Automattic\WooCommerce\Utilities\NumberUtil; if ( ! defined( 'ABSPATH' ) ) { exit; } /** * Include dependencies. */ if ( ! class_exists( 'WC_Importer_Interface', false ) ) { include_once WC_ABSPATH . 'includes/interfaces/class-wc-importer-interface.php'; } /** * WC_Product_Importer Class. */ abstract class WC_Product_Importer implements WC_Importer_Interface { /** * CSV file. * * @var string */ protected $file = ''; /** * The file position after the last read. * * @var int */ protected $file_position = 0; /** * Importer parameters. * * @var array */ protected $params = array(); /** * Raw keys - CSV raw headers. * * @var array */ protected $raw_keys = array(); /** * Mapped keys - CSV headers. * * @var array */ protected $mapped_keys = array(); /** * Raw data. * * @var array */ protected $raw_data = array(); /** * Raw data. * * @var array */ protected $file_positions = array(); /** * Parsed data. * * @var array */ protected $parsed_data = array(); /** * Start time of current import. * * (default value: 0) * * @var int */ protected $start_time = 0; /** * Get file raw headers. * * @return array */ public function get_raw_keys() { return $this->raw_keys; } /** * Get file mapped headers. * * @return array */ public function get_mapped_keys() { return ! empty( $this->mapped_keys ) ? $this->mapped_keys : $this->raw_keys; } /** * Get raw data. * * @return array */ public function get_raw_data() { return $this->raw_data; } /** * Get parsed data. * * @return array */ public function get_parsed_data() { /** * Filter product importer parsed data. * * @param array $parsed_data Parsed data. * @param WC_Product_Importer $importer Importer instance. */ return apply_filters( 'woocommerce_product_importer_parsed_data', $this->parsed_data, $this ); } /** * Get importer parameters. * * @return array */ public function get_params() { return $this->params; } /** * Get file pointer position from the last read. * * @return int */ public function get_file_position() { return $this->file_position; } /** * Get file pointer position as a percentage of file size. * * @return int */ public function get_percent_complete() { $size = filesize( $this->file ); if ( ! $size ) { return 0; } return absint( min( floor( ( $this->file_position / $size ) * 100 ), 100 ) ); } /** * Prepare a single product for create or update. * * @param array $data Item data. * @return WC_Product|WP_Error */ protected function get_product_object( $data ) { $id = isset( $data['id'] ) ? absint( $data['id'] ) : 0; // Type is the most important part here because we need to be using the correct class and methods. if ( isset( $data['type'] ) ) { if ( ! array_key_exists( $data['type'], WC_Admin_Exporters::get_product_types() ) ) { return new WP_Error( 'woocommerce_product_importer_invalid_type', __( 'Invalid product type.', 'woocommerce' ), array( 'status' => 401 ) ); } try { // Prevent getting "variation_invalid_id" error message from Variation Data Store. if ( ProductType::VARIATION === $data['type'] ) { $id = wp_update_post( array( 'ID' => $id, 'post_type' => 'product_variation', ) ); } $product = wc_get_product_object( $data['type'], $id ); } catch ( WC_Data_Exception $e ) { return new WP_Error( 'woocommerce_product_csv_importer_' . $e->getErrorCode(), $e->getMessage(), array( 'status' => 401 ) ); } } elseif ( ! empty( $data['id'] ) ) { $product = wc_get_product( $id ); if ( ! $product ) { return new WP_Error( 'woocommerce_product_csv_importer_invalid_id', /* translators: %d: product ID */ sprintf( __( 'Invalid product ID %d.', 'woocommerce' ), $id ), array( 'id' => $id, 'status' => 401, ) ); } } else { $product = wc_get_product_object( ProductType::SIMPLE, $id ); } return apply_filters( 'woocommerce_product_import_get_product_object', $product, $data ); } /** * Process a single item and save. * * @throws Exception If item cannot be processed. * @param array $data Raw CSV data. * @return array|WP_Error */ protected function process_item( $data ) { try { do_action( 'woocommerce_product_import_before_process_item', $data ); $data = apply_filters( 'woocommerce_product_import_process_item_data', $data ); // Get product ID from SKU if created during the importation. if ( empty( $data['id'] ) && ! empty( $data['sku'] ) ) { $product_id = wc_get_product_id_by_sku( $data['sku'] ); if ( $product_id ) { $data['id'] = $product_id; } } $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 ( ProductType::EXTERNAL === $object->get_type() ) { unset( $data['manage_stock'], $data['stock_status'], $data['backorders'], $data['low_stock_amount'] ); } $is_variation = false; if ( ProductType::VARIATION === $object->get_type() ) { if ( isset( $data['status'] ) && -1 === $data['status'] ) { $data['status'] = 0; // Variations cannot be drafts - set to private. } $is_variation = true; } if ( 'importing' === $object->get_status() ) { $object->set_status( ProductStatus::PUBLISH ); $object->set_slug( '' ); } // Cost needs to be set explicitly because null is a legal value // but set_props doesn't support nulls. if ( array_key_exists( 'cogs_value', $data ) ) { $object->set_cogs_value( $data['cogs_value'] ); unset( $data['cogs_value'] ); } $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 ( ProductType::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 ); $object = apply_filters( 'woocommerce_product_import_pre_insert_product_object', $object, $data ); $object->save(); do_action( 'woocommerce_product_import_inserted_product_object', $object, $data ); return array( 'id' => $object->get_id(), 'updated' => $updating, 'is_variation' => $is_variation, ); } 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 Product instance. * @param array $data Item data. */ protected function set_image_data( &$product, $data ) { // Image URLs need converting to IDs before inserting. if ( isset( $data['raw_image_id'] ) ) { $attachment_id = $this->get_attachment_id_from_url( $data['raw_image_id'], $product->get_id() ); $product->set_image_id( $attachment_id ); wc_product_attach_featured_image( $attachment_id, $product ); } // Gallery image URLs need converting to IDs before inserting. if ( isset( $data['raw_gallery_image_ids'] ) ) { $gallery_image_ids = array(); foreach ( $data['raw_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 Product instance. * @param array $data Item 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 Item data. * @throws Exception If data cannot be set. */ protected function set_product_data( &$product, $data ) { if ( isset( $data['raw_attributes'] ) ) { $attributes = array(); $default_attributes = array(); $existing_attributes = $product->get_attributes(); foreach ( $data['raw_attributes'] as $position => $attribute ) { $attribute_id = 0; // Get ID if is a global attribute. if ( ! empty( $attribute['taxonomy'] ) ) { $attribute_id = $this->get_attribute_taxonomy_id( $attribute['name'] ); } // Set attribute visibility. if ( isset( $attribute['visible'] ) ) { $is_visible = $attribute['visible']; } else { $is_visible = 1; } // Get name. $attribute_name = $attribute_id ? wc_attribute_taxonomy_name_by_id( $attribute_id ) : $attribute['name']; // Set if is a variation attribute based on existing attributes if possible so updates via CSV do not change this. $is_variation = 0; if ( $existing_attributes ) { foreach ( $existing_attributes as $existing_attribute ) { if ( $existing_attribute->get_name() === $attribute_name ) { $is_variation = $existing_attribute->get_variation(); break; } } } if ( $attribute_id ) { if ( isset( $attribute['value'] ) ) { $options = array_map( 'wc_sanitize_term_text_based', $attribute['value'] ); $options = array_filter( $options, 'strlen' ); } else { $options = array(); } // Check for default attributes and set "is_variation". if ( ! empty( $attribute['default'] ) && in_array( $attribute['default'], $options, true ) ) { $default_term = get_term_by( 'name', $attribute['default'], $attribute_name ); if ( $default_term && ! is_wp_error( $default_term ) ) { $default = $default_term->slug; } else { $default = sanitize_title( $attribute['default'] ); } $default_attributes[ $attribute_name ] = $default; $is_variation = 1; } if ( ! empty( $options ) ) { $attribute_object = new WC_Product_Attribute(); $attribute_object->set_id( $attribute_id ); $attribute_object->set_name( $attribute_name ); $attribute_object->set_options( $options ); $attribute_object->set_position( $position ); $attribute_object->set_visible( $is_visible ); $attribute_object->set_variation( $is_variation ); $attributes[] = $attribute_object; } } elseif ( isset( $attribute['value'] ) ) { // Check for default attributes and set "is_variation". if ( ! empty( $attribute['default'] ) && in_array( $attribute['default'], $attribute['value'], true ) ) { $default_attributes[ sanitize_title( $attribute['name'] ) ] = $attribute['default']; $is_variation = 1; } $attribute_object = new WC_Product_Attribute(); $attribute_object->set_name( $attribute['name'] ); $attribute_object->set_options( $attribute['value'] ); $attribute_object->set_position( $position ); $attribute_object->set_visible( $is_visible ); $attribute_object->set_variation( $is_variation ); $attributes[] = $attribute_object; } } $product->set_attributes( $attributes ); // Set variable default attributes. if ( $product->is_type( ProductType::VARIABLE ) ) { $product->set_default_attributes( $default_attributes ); } } } /** * Set variation data. * * @param WC_Product $variation Product instance. * @param array $data Item data. * @return WC_Product|WP_Error * @throws Exception If data cannot be set. */ protected function set_variation_data( &$variation, $data ) { $parent = false; // Check if parent exist. if ( isset( $data['parent_id'] ) ) { $parent = wc_get_product( $data['parent_id'] ); if ( $parent ) { $variation->set_parent_id( $parent->get_id() ); } } // Stop if parent does not exists. if ( ! $parent ) { 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 ) ); } // Stop if parent is a product variation. if ( $parent->is_type( ProductType::VARIATION ) ) { return new WP_Error( 'woocommerce_product_importer_parent_set_as_variation', __( 'Variation cannot be imported: Parent product cannot be a product variation', 'woocommerce' ), array( 'status' => 401 ) ); } if ( isset( $data['raw_attributes'] ) ) { $attributes = array(); $parent_attributes = $this->get_variation_parent_attributes( $data['raw_attributes'], $parent ); foreach ( $data['raw_attributes'] as $attribute ) { $attribute_id = 0; // Get ID if is a global attribute. if ( ! empty( $attribute['taxonomy'] ) ) { $attribute_id = $this->get_attribute_taxonomy_id( $attribute['name'] ); } if ( $attribute_id ) { $attribute_name = wc_attribute_taxonomy_name_by_id( $attribute_id ); } else { $attribute_name = sanitize_title( $attribute['name'] ); } if ( ! isset( $parent_attributes[ $attribute_name ] ) || ! $parent_attributes[ $attribute_name ]->get_variation() ) { continue; } $attribute_key = sanitize_title( $parent_attributes[ $attribute_name ]->get_name() ); $attribute_value = isset( $attribute['value'] ) ? current( $attribute['value'] ) : ''; if ( $parent_attributes[ $attribute_name ]->is_taxonomy() ) { // If dealing with a taxonomy, we need to get the slug from the name posted to the API. $term = get_term_by( 'name', $attribute_value, $attribute_name ); if ( $term && ! is_wp_error( $term ) ) { $attribute_value = $term->slug; } else { $attribute_value = sanitize_title( $attribute_value ); } } $attributes[ $attribute_key ] = $attribute_value; } $variation->set_attributes( $attributes ); } } /** * Get variation parent attributes and set "is_variation". * * @param array $attributes Attributes list. * @param WC_Product $parent Parent product data. * @return array */ protected function get_variation_parent_attributes( $attributes, $parent ) { $parent_attributes = $parent->get_attributes(); $require_save = false; foreach ( $attributes as $attribute ) { $attribute_id = 0; // Get ID if is a global attribute. if ( ! empty( $attribute['taxonomy'] ) ) { $attribute_id = $this->get_attribute_taxonomy_id( $attribute['name'] ); } if ( $attribute_id ) { $attribute_name = wc_attribute_taxonomy_name_by_id( $attribute_id ); } else { $attribute_name = sanitize_title( $attribute['name'] ); } // Check if attribute handle variations. if ( isset( $parent_attributes[ $attribute_name ] ) && ! $parent_attributes[ $attribute_name ]->get_variation() ) { // Re-create the attribute to CRUD save and generate again. $parent_attributes[ $attribute_name ] = clone $parent_attributes[ $attribute_name ]; $parent_attributes[ $attribute_name ]->set_variation( 1 ); $require_save = true; } } // Save variation attributes. if ( $require_save ) { $parent->set_attributes( array_values( $parent_attributes ) ); $parent->save(); } return $parent_attributes; } /** * Get attachment ID. * * @param string $url Attachment URL. * @param int $product_id Product ID. * @return int * @throws Exception If attachment cannot be loaded. */ public function get_attachment_id_from_url( $url, $product_id ) { if ( empty( $url ) ) { return 0; } $id = 0; $upload_dir = wp_upload_dir( null, false ); $base_url = $upload_dir['baseurl'] . '/'; // Check first if attachment is inside the WordPress uploads directory, or we're given a filename only. if ( false !== strpos( $url, $base_url ) || false === strpos( $url, '://' ) ) { // Search for yyyy/mm/slug.extension or slug.extension - remove the base URL. $file = str_replace( $base_url, '', $url ); $args = array( 'post_type' => 'attachment', 'post_status' => 'any', 'fields' => 'ids', 'meta_query' => array( // @codingStandardsIgnoreLine. 'relation' => 'OR', array( 'key' => '_wp_attached_file', 'value' => '^' . $file, 'compare' => 'REGEXP', ), array( 'key' => '_wp_attached_file', 'value' => '/' . $file, 'compare' => 'LIKE', ), array( 'key' => '_wc_attachment_source', 'value' => '/' . $file, 'compare' => 'LIKE', ), ), ); } else { // This is an external URL, so compare to source. $args = array( 'post_type' => 'attachment', 'post_status' => 'any', 'fields' => 'ids', 'meta_query' => array( // @codingStandardsIgnoreLine. array( 'value' => $url, 'key' => '_wc_attachment_source', ), ), ); } $ids = get_posts( $args ); // @codingStandardsIgnoreLine. if ( $ids ) { $id = current( $ids ); } // Upload if attachment does not exists. if ( ! $id && stristr( $url, '://' ) ) { $upload = wc_rest_upload_image_from_url( $url ); if ( is_wp_error( $upload ) ) { throw new Exception( $upload->get_error_message(), 400 ); } $id = wc_rest_set_uploaded_image_as_attachment( $upload, $product_id ); if ( ! wp_attachment_is_image( $id ) ) { /* translators: %s: image URL */ throw new Exception( sprintf( __( 'Not able to attach "%s".', 'woocommerce' ), $url ), 400 ); } // Save attachment source for future reference. update_post_meta( $id, '_wc_attachment_source', $url ); } if ( ! $id ) { /* translators: %s: image URL */ throw new Exception( sprintf( __( 'Unable to use image "%s".', 'woocommerce' ), $url ), 400 ); } return $id; } /** * Get attribute taxonomy ID from the imported data. * If does not exists register a new attribute. * * @param string $raw_name Attribute name. * @return int * @throws Exception If taxonomy cannot be loaded. */ public function get_attribute_taxonomy_id( $raw_name ) { global $wpdb, $wc_product_attributes; // These are exported as labels, so convert the label to a name if possible first. $attribute_labels = wp_list_pluck( wc_get_attribute_taxonomies(), 'attribute_label', 'attribute_name' ); $attribute_name = array_search( $raw_name, $attribute_labels, true ); if ( ! $attribute_name ) { $attribute_name = wc_sanitize_taxonomy_name( $raw_name ); } $attribute_id = wc_attribute_taxonomy_id_by_name( $attribute_name ); // Get the ID from the name. if ( $attribute_id ) { return $attribute_id; } // If the attribute does not exist, create it. $attribute_id = wc_create_attribute( array( 'name' => $raw_name, 'slug' => $attribute_name, 'type' => 'select', 'order_by' => 'menu_order', 'has_archives' => false, ) ); if ( is_wp_error( $attribute_id ) ) { throw new Exception( $attribute_id->get_error_message(), 400 ); } // Register as taxonomy while importing. $taxonomy_name = wc_attribute_taxonomy_name( $attribute_name ); register_taxonomy( $taxonomy_name, apply_filters( 'woocommerce_taxonomy_objects_' . $taxonomy_name, array( 'product' ) ), apply_filters( 'woocommerce_taxonomy_args_' . $taxonomy_name, array( 'labels' => array( 'name' => $raw_name, ), 'hierarchical' => true, 'show_ui' => false, 'query_var' => true, 'rewrite' => false, ) ) ); // Set product attributes global. $wc_product_attributes = array(); foreach ( wc_get_attribute_taxonomies() as $taxonomy ) { $wc_product_attributes[ wc_attribute_taxonomy_name( $taxonomy->attribute_name ) ] = $taxonomy; } return $attribute_id; } /** * Memory exceeded * * Ensures the batch process never exceeds 90% * of the maximum WordPress memory. * * @return bool */ protected function memory_exceeded() { $memory_limit = $this->get_memory_limit() * 0.9; // 90% of max memory $current_memory = memory_get_usage( true ); $return = false; if ( $current_memory >= $memory_limit ) { $return = true; } return apply_filters( 'woocommerce_product_importer_memory_exceeded', $return ); } /** * Get memory limit * * @return int */ protected function get_memory_limit() { if ( function_exists( 'ini_get' ) ) { $memory_limit = ini_get( 'memory_limit' ); } else { // Sensible default. $memory_limit = '128M'; } if ( ! $memory_limit || -1 === intval( $memory_limit ) ) { // Unlimited, set to 32GB. $memory_limit = '32000M'; } return wp_convert_hr_to_bytes( $memory_limit ); } /** * Time exceeded. * * Ensures the batch never exceeds a sensible time limit. * A timeout limit of 30s is common on shared hosting. * * @return bool */ protected function time_exceeded() { $finish = $this->start_time + apply_filters( 'woocommerce_product_importer_default_time_limit', 20 ); // 20 seconds $return = false; if ( time() >= $finish ) { $return = true; } return apply_filters( 'woocommerce_product_importer_time_exceeded', $return ); } /** * Explode CSV cell values using commas by default, and handling escaped * separators. * * @since 3.2.0 * @param string $value Value to explode. * @param string $separator Separator separating each value. Defaults to comma. * @return array */ protected function explode_values( $value, $separator = ',' ) { $value = str_replace( '\\,', '::separator::', $value ); $values = explode( $separator, $value ); $values = array_map( array( $this, 'explode_values_formatter' ), $values ); return $values; } /** * Remove formatting and trim each value. * * @since 3.2.0 * @param string $value Value to format. * @return string */ protected function explode_values_formatter( $value ) { return trim( str_replace( '::separator::', ',', $value ) ); } /** * The exporter prepends a ' to escape fields that start with =, +, - or @. * Remove the prepended ' character preceding those characters. * * @since 3.5.2 * @param string $value A string that may or may not have been escaped with '. * @return string */ protected function unescape_data( $value ) { $active_content_triggers = array( "'=", "'+", "'-", "'@" ); if ( in_array( mb_substr( $value, 0, 2 ), $active_content_triggers, true ) ) { $value = mb_substr( $value, 1 ); } return $value; } } class-wc-product-csv-importer.php 0000777 00000104011 15252741661 0013114 0 ustar 00 <?php /** * WooCommerce Product CSV importer * * @package WooCommerce\Import * @version 10.0.0 */ use Automattic\WooCommerce\Enums\ProductStatus; use Automattic\WooCommerce\Enums\ProductStockStatus; use Automattic\WooCommerce\Enums\ProductTaxStatus; use Automattic\WooCommerce\Enums\ProductType; use Automattic\WooCommerce\Internal\CostOfGoodsSold\CostOfGoodsSoldController; use Automattic\WooCommerce\Utilities\ArrayUtil; if ( ! defined( 'ABSPATH' ) ) { exit; } /** * Include dependencies. */ if ( ! class_exists( 'WC_Product_Importer', false ) ) { include_once __DIR__ . '/abstract-wc-product-importer.php'; } if ( ! class_exists( 'WC_Product_CSV_Importer_Controller', false ) ) { include_once WC_ABSPATH . 'includes/admin/importers/class-wc-product-csv-importer-controller.php'; } /** * WC_Product_CSV_Importer Class. */ class WC_Product_CSV_Importer extends WC_Product_Importer { /** * Tracks current row being parsed. * * @var integer */ protected $parsing_raw_data_index = 0; /** * Is the Cost of Goods Sold feature enabled? * * @var bool */ private $cogs_is_enabled = false; /** * Initialize importer. * * @param string $file File to read. * @param array $params Arguments for the parser. */ public function __construct( $file, $params = array() ) { $this->cogs_is_enabled = wc_get_container()->get( CostOfGoodsSoldController::class )->feature_is_enabled(); $default_args = array( 'start_pos' => 0, // File pointer start. 'end_pos' => -1, // File pointer end. 'lines' => -1, // Max lines to read. 'mapping' => array(), // Column mapping. csv_heading => schema_heading. 'parse' => false, // Whether to sanitize and format data. 'update_existing' => false, // Whether to update existing items. 'delimiter' => ',', // CSV delimiter. 'prevent_timeouts' => true, // Check memory and time usage and abort if reaching limit. 'enclosure' => '"', // The character used to wrap text in the CSV. 'escape' => "\0", // PHP uses '\' as the default escape character. This is not RFC-4180 compliant. This disables the escape character. ); $this->params = wp_parse_args( $params, $default_args ); $this->file = $file; if ( isset( $this->params['mapping']['from'], $this->params['mapping']['to'] ) ) { $this->params['mapping'] = array_combine( $this->params['mapping']['from'], $this->params['mapping']['to'] ); } // Import mappings for CSV data. include_once dirname( __DIR__ ) . '/admin/importers/mappings/mappings.php'; $this->read_file(); } /** * Convert a string from the input encoding to UTF-8. * * @param string $value The string to convert. * @return string The converted string. */ private function adjust_character_encoding( $value ) { $encoding = $this->params['character_encoding']; return 'UTF-8' === $encoding ? $value : mb_convert_encoding( $value, 'UTF-8', $encoding ); } /** * Read file. */ protected function read_file() { if ( ! WC_Product_CSV_Importer_Controller::is_file_valid_csv( $this->file ) ) { wp_die( esc_html__( 'Invalid file type. The importer supports CSV and TXT file formats.', 'woocommerce' ) ); } $handle = fopen( $this->file, 'r' ); // @codingStandardsIgnoreLine. if ( false !== $handle ) { $this->raw_keys = array_map( 'trim', fgetcsv( $handle, 0, $this->params['delimiter'], $this->params['enclosure'], $this->params['escape'] ) ); // @codingStandardsIgnoreLine if ( ArrayUtil::is_truthy( $this->params, 'character_encoding' ) ) { $this->raw_keys = array_map( array( $this, 'adjust_character_encoding' ), $this->raw_keys ); } // Remove line breaks in keys, to avoid mismatch mapping of keys. $this->raw_keys = wc_clean( wp_unslash( $this->raw_keys ) ); // Remove BOM signature from the first item. if ( isset( $this->raw_keys[0] ) ) { $this->raw_keys[0] = $this->remove_utf8_bom( $this->raw_keys[0] ); } if ( 0 !== $this->params['start_pos'] ) { fseek( $handle, (int) $this->params['start_pos'] ); } while ( 1 ) { $row = fgetcsv( $handle, 0, $this->params['delimiter'], $this->params['enclosure'], $this->params['escape'] ); // @codingStandardsIgnoreLine if ( false !== $row ) { if ( ArrayUtil::is_truthy( $this->params, 'character_encoding' ) ) { $row = array_map( array( $this, 'adjust_character_encoding' ), $row ); } $this->raw_data[] = $row; $this->file_positions[ count( $this->raw_data ) ] = ftell( $handle ); if ( ( $this->params['end_pos'] > 0 && ftell( $handle ) >= $this->params['end_pos'] ) || 0 === --$this->params['lines'] ) { break; } } else { break; } } $this->file_position = ftell( $handle ); } if ( ! empty( $this->params['mapping'] ) ) { $this->set_mapped_keys(); } if ( $this->params['parse'] ) { $this->set_parsed_data(); } } /** * Remove UTF-8 BOM signature. * * @param string $string String to handle. * * @return string */ protected function remove_utf8_bom( $string ) { if ( 'efbbbf' === substr( bin2hex( $string ), 0, 6 ) ) { $string = substr( $string, 3 ); } return $string; } /** * Set file mapped keys. */ protected function set_mapped_keys() { $mapping = $this->params['mapping']; foreach ( $this->raw_keys as $key ) { $this->mapped_keys[] = isset( $mapping[ $key ] ) ? $mapping[ $key ] : $key; } } /** * Parse relative field and return product ID. * * Handles `id:xx` and SKUs. * * If mapping to an id: and the product ID does not exist, this link is not * valid. * * If mapping to a SKU and the product ID does not exist, a temporary object * will be created so it can be updated later. * * @param string $value Field value. * * @return int|string */ public function parse_relative_field( $value ) { global $wpdb; if ( empty( $value ) ) { return ''; } // IDs are prefixed with id:. if ( preg_match( '/^id:(\d+)$/', $value, $matches ) ) { $id = intval( $matches[1] ); // If original_id is found, use that instead of the given ID since a new placeholder must have been created already. $original_id = $wpdb->get_var( $wpdb->prepare( "SELECT post_id FROM {$wpdb->postmeta} WHERE meta_key = '_original_id' AND meta_value = %s;", $id ) ); // WPCS: db call ok, cache ok. if ( $original_id ) { return absint( $original_id ); } // See if the given ID maps to a valid product already. $existing_id = $wpdb->get_var( $wpdb->prepare( "SELECT ID FROM {$wpdb->posts} WHERE post_type IN ( 'product', 'product_variation' ) AND ID = %d;", $id ) ); // WPCS: db call ok, cache ok. if ( $existing_id ) { return absint( $existing_id ); } // If we're not updating existing posts, we may need a placeholder product to map to. if ( ! $this->params['update_existing'] ) { $product = wc_get_product_object( ProductType::SIMPLE ); $product->set_name( 'Import placeholder for ' . $id ); $product->set_status( 'importing' ); $product->add_meta_data( '_original_id', $id, true ); $id = $product->save(); } return $id; } $id = wc_get_product_id_by_sku( $value ); if ( $id ) { return $id; } try { $product = wc_get_product_object( ProductType::SIMPLE ); $product->set_name( 'Import placeholder for ' . $value ); $product->set_status( 'importing' ); $product->set_sku( $value ); $id = $product->save(); if ( $id && ! is_wp_error( $id ) ) { return $id; } } catch ( Exception $e ) { return ''; } return ''; } /** * Parse the ID field. * * If we're not doing an update, create a placeholder product so mapping works * for rows following this one. * * @param string $value Field value. * * @return int */ public function parse_id_field( $value ) { global $wpdb; $id = absint( $value ); if ( ! $id ) { return 0; } // See if this maps to an ID placeholder already. $original_id = $wpdb->get_var( $wpdb->prepare( "SELECT post_id FROM {$wpdb->postmeta} WHERE meta_key = '_original_id' AND meta_value = %s;", $id ) ); // WPCS: db call ok, cache ok. if ( $original_id ) { return absint( $original_id ); } // Not updating? Make sure we have a new placeholder for this ID. if ( ! $this->params['update_existing'] ) { $mapped_keys = $this->get_mapped_keys(); $sku_column_index = absint( array_search( 'sku', $mapped_keys, true ) ); $row_sku = isset( $this->raw_data[ $this->parsing_raw_data_index ][ $sku_column_index ] ) ? $this->raw_data[ $this->parsing_raw_data_index ][ $sku_column_index ] : ''; $id_from_sku = $row_sku ? wc_get_product_id_by_sku( $row_sku ) : ''; // If row has a SKU, make sure placeholder was not made already. if ( $id_from_sku ) { return $id_from_sku; } $product = wc_get_product_object( ProductType::SIMPLE ); $product->set_name( 'Import placeholder for ' . $id ); $product->set_status( 'importing' ); $product->add_meta_data( '_original_id', $id, true ); // If row has a SKU, make sure placeholder has it too. if ( $row_sku ) { $product->set_sku( $row_sku ); } $id = $product->save(); } return $id && ! is_wp_error( $id ) ? $id : 0; } /** * Parse relative comma-delineated field and return product ID. * * @param string $value Field value. * * @return array */ public function parse_relative_comma_field( $value ) { if ( empty( $value ) ) { return array(); } return array_filter( array_map( array( $this, 'parse_relative_field' ), $this->explode_values( $value ) ) ); } /** * Parse a comma-delineated field from a CSV. * * @param string $value Field value. * * @return array */ public function parse_comma_field( $value ) { if ( empty( $value ) && '0' !== $value ) { return array(); } $value = $this->unescape_data( $value ); return array_map( 'wc_clean', $this->explode_values( $value ) ); } /** * Parse a field that is generally '1' or '0' but can be something else. * * @param string $value Field value. * * @return bool|string */ public function parse_bool_field( $value ) { if ( '0' === $value ) { return false; } if ( '1' === $value ) { return true; } // Don't return explicit true or false for empty fields or values like 'notify'. return wc_clean( $value ); } /** * Parse a float value field. * * @param string $value Field value. * * @return float|string */ public function parse_float_field( $value ) { if ( '' === $value ) { return $value; } // Remove the ' prepended to fields that start with - if needed. $value = $this->unescape_data( $value ); return floatval( $value ); } /** * Parse the stock qty field. * * @param string $value Field value. * * @return float|string */ public function parse_stock_quantity_field( $value ) { if ( '' === $value ) { return $value; } // Remove the ' prepended to fields that start with - if needed. $value = $this->unescape_data( $value ); return wc_stock_amount( $value ); } /** * Parse the tax status field. * * @param string $value Field value. * * @return string */ public function parse_tax_status_field( $value ) { if ( '' === $value ) { return $value; } // Remove the ' prepended to fields that start with - if needed. $value = $this->unescape_data( $value ); if ( 'true' === strtolower( $value ) || 'false' === strtolower( $value ) ) { $value = wc_string_to_bool( $value ) ? ProductTaxStatus::TAXABLE : ProductTaxStatus::NONE; } return wc_clean( $value ); } /** * Parse a category field from a CSV. * Categories are separated by commas and subcategories are "parent > subcategory". * * @param string $value Field value. * * @return array of arrays with "parent" and "name" keys. */ public function parse_categories_field( $value ) { if ( empty( $value ) ) { return array(); } $row_terms = $this->explode_values( $value ); $categories = array(); foreach ( $row_terms as $row_term ) { $parent = null; $_terms = array_map( 'trim', explode( '>', $row_term ) ); $total = count( $_terms ); foreach ( $_terms as $index => $_term ) { // Don't allow users without capabilities to create new categories. if ( ! current_user_can( 'manage_product_terms' ) ) { break; } $term = wp_insert_term( $_term, 'product_cat', array( 'parent' => intval( $parent ) ) ); if ( is_wp_error( $term ) ) { if ( $term->get_error_code() === 'term_exists' ) { // When term exists, error data should contain existing term id. $term_id = $term->get_error_data(); } else { break; // We cannot continue on any other error. } } else { // New term. $term_id = $term['term_id']; } // Only requires assign the last category. if ( ( 1 + $index ) === $total ) { $categories[] = $term_id; } else { // Store parent to be able to insert or query categories based in parent ID. $parent = $term_id; } } } return $categories; } /** * Parse a tag field from a CSV. * * @param string $value Field value. * * @return array */ public function parse_tags_field( $value ) { if ( empty( $value ) ) { return array(); } $value = $this->unescape_data( $value ); $names = $this->explode_values( $value ); $tags = array(); foreach ( $names as $name ) { $term = get_term_by( 'name', $name, 'product_tag' ); if ( ! $term || is_wp_error( $term ) ) { $term = (object) wp_insert_term( $name, 'product_tag' ); } if ( ! is_wp_error( $term ) ) { $tags[] = $term->term_id; } } return $tags; } /** * Parse a tag field from a CSV with space separators. * * @param string $value Field value. * * @return array */ public function parse_tags_spaces_field( $value ) { if ( empty( $value ) ) { return array(); } $value = $this->unescape_data( $value ); $names = $this->explode_values( $value, ' ' ); $tags = array(); foreach ( $names as $name ) { $term = get_term_by( 'name', $name, 'product_tag' ); if ( ! $term || is_wp_error( $term ) ) { $term = (object) wp_insert_term( $name, 'product_tag' ); } if ( ! is_wp_error( $term ) ) { $tags[] = $term->term_id; } } return $tags; } /** * Parse a shipping class field from a CSV. * * @param string $value Field value. * * @return int */ public function parse_shipping_class_field( $value ) { if ( empty( $value ) ) { return 0; } $term = get_term_by( 'name', $value, 'product_shipping_class' ); if ( ! $term || is_wp_error( $term ) ) { $term = (object) wp_insert_term( $value, 'product_shipping_class' ); } if ( is_wp_error( $term ) ) { return 0; } return $term->term_id; } /** * Parse images list from a CSV. Images can be filenames or URLs. * * @param string $value Field value. * * @return array */ public function parse_images_field( $value ) { if ( empty( $value ) ) { return array(); } $images = array(); $separator = apply_filters( 'woocommerce_product_import_image_separator', ',' ); foreach ( $this->explode_values( $value, $separator ) as $image ) { if ( stristr( $image, '://' ) ) { $images[] = esc_url_raw( $image ); } else { $images[] = sanitize_file_name( $image ); } } return $images; } /** * Parse dates from a CSV. * Dates requires the format YYYY-MM-DD and time is optional. * * @param string $value Field value. * * @return string|null */ public function parse_date_field( $value ) { if ( empty( $value ) ) { return null; } if ( preg_match( '/^[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])([ 01-9:]*)$/', $value ) ) { // Don't include the time if the field had time in it. return current( explode( ' ', $value ) ); } return null; } /** * Parse dates from a CSV. * Dates can be Unix timestamps or in any format supported by strtotime(). * * @param string $value Field value. * * @return string|null */ public function parse_datetime_field( $value ) { try { // If value is a Unix timestamp, convert it to a datetime string. if ( is_numeric( $value ) ) { $datetime = new DateTime( "@{$value}" ); // Return datetime string in ISO8601 format (eg. 2018-01-01T00:00:00Z) to preserve UTC timezone since Unix timestamps are always UTC. return $datetime->format( 'Y-m-d\TH:i:s\Z' ); } // Check whether the value is a valid date string. if ( false !== strtotime( $value ) ) { // If the value is a valid date string, return as is. return $value; } } catch ( Exception $e ) { // DateTime constructor throws an exception if the value is not a valid Unix timestamp. return null; } // If value is not valid Unix timestamp or date string, return null. return null; } /** * Parse backorders from a CSV. * * @param string $value Field value. * * @return string */ public function parse_backorders_field( $value ) { if ( empty( $value ) ) { return 'no'; } $value = $this->parse_bool_field( $value ); if ( 'notify' === $value ) { return 'notify'; } elseif ( is_bool( $value ) ) { return $value ? 'yes' : 'no'; } return 'no'; } /** * Just skip current field. * * By default is applied wc_clean() to all not listed fields * in self::get_formatting_callback(), use this method to skip any formatting. * * @param string $value Field value. * * @return string */ public function parse_skip_field( $value ) { return $value; } /** * Parse download file urls, we should allow shortcodes here. * * Allow shortcodes if present, otherwise esc_url the value. * * @param string $value Field value. * * @return string */ public function parse_download_file_field( $value ) { // Absolute file paths. if ( 0 === strpos( $value, 'http' ) ) { return esc_url_raw( $value ); } // Relative and shortcode paths. return wc_clean( $value ); } /** * Parse an int value field * * @param int $value field value. * * @return int|string */ public function parse_int_field( $value ) { // Similar to WC_Meta_Box_Product_Data::save, do not cast the empty value to int. // An empty value indicates that the field should be cleared. if ( '' === $value ) { return $value; } // Remove the ' prepended to fields that start with - if needed. $value = $this->unescape_data( $value ); return intval( $value ); } /** * Parse a description value field * * @param string $description field value. * * @return string */ public function parse_description_field( $description ) { $parts = explode( "\\\\n", $description ); foreach ( $parts as $key => $part ) { $parts[ $key ] = str_replace( '\n', "\n", $part ); } return implode( '\\\n', $parts ); } /** * Parse the published field. 1 is published, 0 is private, -1 is draft. * Alternatively, 'true' can be used for published and 'false' for draft. * * @param string $value Field value. * * @return float|string */ public function parse_published_field( $value ) { if ( '' === $value ) { return $value; } // Remove the ' prepended to fields that start with - if needed. $value = $this->unescape_data( $value ); if ( 'true' === strtolower( $value ) || 'false' === strtolower( $value ) ) { return wc_string_to_bool( $value ) ? 1 : -1; } return floatval( $value ); } /** * Parse the Cost of Goods Sold field. * * @param string $value Field value. * * @return float|null */ public function parse_cogs_field( $value ) { return '' === $value ? null : (float) wc_format_decimal( $value ); } /** * Deprecated get formatting callback method. * * @deprecated 4.3.0 * @return array */ protected function get_formating_callback() { return $this->get_formatting_callback(); } /** * Get formatting callback. * * @since 4.3.0 * @return array */ protected function get_formatting_callback() { /** * Columns not mentioned here will get parsed with 'wc_clean'. * column_name => callback. */ $data_formatting = array( 'id' => array( $this, 'parse_id_field' ), 'type' => array( $this, 'parse_comma_field' ), 'published' => array( $this, 'parse_published_field' ), 'featured' => array( $this, 'parse_bool_field' ), 'date_on_sale_from' => array( $this, 'parse_datetime_field' ), 'date_on_sale_to' => array( $this, 'parse_datetime_field' ), 'name' => array( $this, 'parse_skip_field' ), 'short_description' => array( $this, 'parse_description_field' ), 'description' => array( $this, 'parse_description_field' ), 'manage_stock' => array( $this, 'parse_bool_field' ), 'low_stock_amount' => array( $this, 'parse_stock_quantity_field' ), 'backorders' => array( $this, 'parse_backorders_field' ), 'stock_status' => array( $this, 'parse_bool_field' ), 'sold_individually' => array( $this, 'parse_bool_field' ), 'width' => array( $this, 'parse_float_field' ), 'length' => array( $this, 'parse_float_field' ), 'height' => array( $this, 'parse_float_field' ), 'weight' => array( $this, 'parse_float_field' ), 'reviews_allowed' => array( $this, 'parse_bool_field' ), 'purchase_note' => 'wp_filter_post_kses', 'price' => 'wc_format_decimal', 'regular_price' => 'wc_format_decimal', 'stock_quantity' => array( $this, 'parse_stock_quantity_field' ), 'category_ids' => array( $this, 'parse_categories_field' ), 'tag_ids' => array( $this, 'parse_tags_field' ), 'tag_ids_spaces' => array( $this, 'parse_tags_spaces_field' ), 'shipping_class_id' => array( $this, 'parse_shipping_class_field' ), 'images' => array( $this, 'parse_images_field' ), 'parent_id' => array( $this, 'parse_relative_field' ), 'grouped_products' => array( $this, 'parse_relative_comma_field' ), 'upsell_ids' => array( $this, 'parse_relative_comma_field' ), 'cross_sell_ids' => array( $this, 'parse_relative_comma_field' ), 'download_limit' => array( $this, 'parse_int_field' ), 'download_expiry' => array( $this, 'parse_int_field' ), 'product_url' => 'esc_url_raw', 'menu_order' => 'intval', 'tax_status' => array( $this, 'parse_tax_status_field' ), 'cogs_value' => array( $this, 'parse_cogs_field' ), ); /** * Match special column names. */ $regex_match_data_formatting = array( '/attributes:value*/' => array( $this, 'parse_comma_field' ), '/attributes:visible*/' => array( $this, 'parse_bool_field' ), '/attributes:taxonomy*/' => array( $this, 'parse_bool_field' ), '/downloads:url*/' => array( $this, 'parse_download_file_field' ), '/meta:*/' => 'wp_kses_post', // Allow some HTML in meta fields. ); $callbacks = array(); // Figure out the parse function for each column. foreach ( $this->get_mapped_keys() as $index => $heading ) { $callback = 'wc_clean'; if ( isset( $data_formatting[ $heading ] ) ) { $callback = $data_formatting[ $heading ]; } else { foreach ( $regex_match_data_formatting as $regex => $callback ) { if ( preg_match( $regex, $heading ) ) { $callback = $callback; break; } } } $callbacks[] = $callback; } return apply_filters( 'woocommerce_product_importer_formatting_callbacks', $callbacks, $this ); } /** * Check if strings starts with determined word. * * @param string $haystack Complete sentence. * @param string $needle Excerpt. * * @return bool */ protected function starts_with( $haystack, $needle ) { return substr( $haystack, 0, strlen( $needle ) ) === $needle; } /** * Expand special and internal data into the correct formats for the product CRUD. * * @param array $data Data to import. * * @return array */ protected function expand_data( $data ) { $data = apply_filters( 'woocommerce_product_importer_pre_expand_data', $data ); // 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 ); $data['downloadable'] = in_array( 'downloadable', $data['type'], true ); // Convert type to string. $data['type'] = current( array_diff( $data['type'], array( 'virtual', 'downloadable' ) ) ); if ( ! $data['type'] ) { $data['type'] = ProductType::SIMPLE; } } // Status is mapped from a special published field. if ( isset( $data['published'] ) ) { $published = $data['published']; if ( is_float( $published ) ) { $published = (int) $published; } $statuses = array( -1 => ProductStatus::DRAFT, 0 => ProductStatus::PRIVATE, 1 => ProductStatus::PUBLISH, ); $data['status'] = $statuses[ $published ] ?? ProductStatus::DRAFT; // Fix draft status of variations. if ( ProductType::VARIATION === ( $data['type'] ?? null ) && -1 === $published ) { $data['status'] = ProductStatus::PUBLISH; } unset( $data['published'] ); } if ( isset( $data['stock_quantity'] ) ) { if ( '' === $data['stock_quantity'] ) { $data['manage_stock'] = false; $data['stock_status'] = isset( $data['stock_status'] ) ? $data['stock_status'] : true; } else { $data['manage_stock'] = true; } } // Stock is bool or 'backorder'. if ( isset( $data['stock_status'] ) ) { if ( 'backorder' === $data['stock_status'] ) { $data['stock_status'] = ProductStockStatus::ON_BACKORDER; } else { $data['stock_status'] = $data['stock_status'] ? ProductStockStatus::IN_STOCK : ProductStockStatus::OUT_OF_STOCK; } } // Prepare grouped products. if ( isset( $data['grouped_products'] ) ) { $data['children'] = $data['grouped_products']; unset( $data['grouped_products'] ); } // Tag ids. if ( isset( $data['tag_ids_spaces'] ) ) { $data['tag_ids'] = $data['tag_ids_spaces']; unset( $data['tag_ids_spaces'] ); } if ( ! $this->cogs_is_enabled ) { unset( $data['cogs_value'] ); } // Handle special column names which span multiple columns. $attributes = array(); $downloads = array(); $meta_data = array(); foreach ( $data as $key => $value ) { if ( $this->starts_with( $key, 'attributes:name' ) ) { if ( ! empty( $value ) ) { $attributes[ str_replace( 'attributes:name', '', $key ) ]['name'] = $value; } unset( $data[ $key ] ); } elseif ( $this->starts_with( $key, 'attributes:value' ) ) { $attributes[ str_replace( 'attributes:value', '', $key ) ]['value'] = $value; unset( $data[ $key ] ); } elseif ( $this->starts_with( $key, 'attributes:taxonomy' ) ) { $attributes[ str_replace( 'attributes:taxonomy', '', $key ) ]['taxonomy'] = wc_string_to_bool( $value ); unset( $data[ $key ] ); } elseif ( $this->starts_with( $key, 'attributes:visible' ) ) { $attributes[ str_replace( 'attributes:visible', '', $key ) ]['visible'] = wc_string_to_bool( $value ); unset( $data[ $key ] ); } elseif ( $this->starts_with( $key, 'attributes:default' ) ) { if ( ! empty( $value ) ) { $attributes[ str_replace( 'attributes:default', '', $key ) ]['default'] = $value; } unset( $data[ $key ] ); } elseif ( $this->starts_with( $key, 'downloads:id' ) ) { if ( ! empty( $value ) ) { $downloads[ str_replace( 'downloads:id', '', $key ) ]['id'] = $value; } unset( $data[ $key ] ); } elseif ( $this->starts_with( $key, 'downloads:name' ) ) { if ( ! empty( $value ) ) { $downloads[ str_replace( 'downloads:name', '', $key ) ]['name'] = $value; } unset( $data[ $key ] ); } elseif ( $this->starts_with( $key, 'downloads:url' ) ) { if ( ! empty( $value ) ) { $downloads[ str_replace( 'downloads:url', '', $key ) ]['url'] = $value; } unset( $data[ $key ] ); } elseif ( $this->starts_with( $key, 'meta:' ) ) { $meta_data[] = array( 'key' => str_replace( 'meta:', '', $key ), 'value' => $value, ); unset( $data[ $key ] ); } } if ( ! empty( $attributes ) ) { // Remove empty attributes and clear indexes. foreach ( $attributes as $attribute ) { if ( empty( $attribute['name'] ) ) { continue; } $data['raw_attributes'][] = $attribute; } } if ( ! empty( $downloads ) ) { $data['downloads'] = array(); foreach ( $downloads as $key => $file ) { if ( empty( $file['url'] ) ) { continue; } $data['downloads'][] = array( 'download_id' => isset( $file['id'] ) ? $file['id'] : null, 'name' => $file['name'] ? $file['name'] : wc_get_filename_from_url( $file['url'] ), 'file' => $file['url'], ); } } if ( ! empty( $meta_data ) ) { $data['meta_data'] = $meta_data; } return $data; } /** * Map and format raw data to known fields. */ protected function set_parsed_data() { $parse_functions = $this->get_formatting_callback(); $mapped_keys = $this->get_mapped_keys(); $use_mb = function_exists( 'mb_convert_encoding' ); // Parse the data. foreach ( $this->raw_data as $row_index => $row ) { // Skip empty rows. if ( ! count( array_filter( $row ) ) ) { continue; } $this->parsing_raw_data_index = $row_index; $data = array(); do_action( 'woocommerce_product_importer_before_set_parsed_data', $row, $mapped_keys ); foreach ( $row as $id => $value ) { // Skip ignored columns. if ( empty( $mapped_keys[ $id ] ) ) { continue; } // Convert UTF8. if ( $use_mb ) { $encoding = mb_detect_encoding( $value, mb_detect_order(), true ); if ( $encoding ) { $value = mb_convert_encoding( $value, 'UTF-8', $encoding ); } else { $value = mb_convert_encoding( $value, 'UTF-8', 'UTF-8' ); } } else { $value = wp_check_invalid_utf8( $value, true ); } $data[ $mapped_keys[ $id ] ] = call_user_func( $parse_functions[ $id ], $value ); } /** * Filter product importer parsed data. * * @param array $parsed_data Parsed data. * @param WC_Product_Importer $importer Importer instance. * * @since */ $this->parsed_data[] = apply_filters( 'woocommerce_product_importer_parsed_data', $this->expand_data( $data ), $this ); } } /** * Get a string to identify the row from parsed data. * * @param array $parsed_data Parsed data. * * @return string */ protected function get_row_id( $parsed_data ) { $id = isset( $parsed_data['id'] ) ? absint( $parsed_data['id'] ) : 0; $sku = isset( $parsed_data['sku'] ) ? esc_attr( $parsed_data['sku'] ) : ''; $name = isset( $parsed_data['name'] ) ? esc_attr( $parsed_data['name'] ) : ''; $row_data = array(); if ( $name ) { $row_data[] = $name; } if ( $id ) { /* translators: %d: product ID */ $row_data[] = sprintf( __( 'ID %d', 'woocommerce' ), $id ); } if ( $sku ) { /* translators: %s: product SKU */ $row_data[] = sprintf( __( 'SKU %s', 'woocommerce' ), $sku ); } return implode( ', ', $row_data ); } /** * Process importer. * * Do not import products with IDs or SKUs that already exist if option * update existing is false, and likewise, if updating products, do not * process rows which do not exist if an ID/SKU is provided. * * @return array */ public function import() { $this->start_time = time(); $index = 0; $update_existing = $this->params['update_existing']; $data = array( 'imported' => array(), 'imported_variations' => array(), 'failed' => array(), 'updated' => array(), 'skipped' => array(), ); foreach ( $this->parsed_data as $parsed_data_key => $parsed_data ) { do_action( 'woocommerce_product_import_before_import', $parsed_data ); $id = isset( $parsed_data['id'] ) ? absint( $parsed_data['id'] ) : 0; $sku = isset( $parsed_data['sku'] ) ? $parsed_data['sku'] : ''; $id_exists = false; $sku_exists = false; if ( $id ) { $product = wc_get_product( $id ); $id_exists = $product && 'importing' !== $product->get_status(); } if ( $sku ) { $id_from_sku = wc_get_product_id_by_sku( $sku ); $product = $id_from_sku ? wc_get_product( $id_from_sku ) : false; $sku_exists = $product && 'importing' !== $product->get_status(); } if ( $sku_exists && ! $update_existing ) { $data['skipped'][] = new WP_Error( 'woocommerce_product_importer_error', esc_html__( 'A product with this SKU already exists.', 'woocommerce' ), array( 'sku' => esc_attr( $sku ), 'row' => $this->get_row_id( $parsed_data ), ) ); continue; } if ( $id_exists && ! $update_existing ) { $data['skipped'][] = new WP_Error( 'woocommerce_product_importer_error', esc_html__( 'A product with this ID already exists.', 'woocommerce' ), array( 'id' => $id, 'row' => $this->get_row_id( $parsed_data ), ) ); continue; } if ( $update_existing && ( isset( $parsed_data['id'] ) || isset( $parsed_data['sku'] ) ) && ! $id_exists && ! $sku_exists ) { $data['skipped'][] = new WP_Error( 'woocommerce_product_importer_error', esc_html__( 'No matching product exists to update.', 'woocommerce' ), array( 'id' => $id, 'sku' => esc_attr( $sku ), 'row' => $this->get_row_id( $parsed_data ), ) ); continue; } $result = $this->process_item( $parsed_data ); if ( is_wp_error( $result ) ) { $result->add_data( array( 'row' => $this->get_row_id( $parsed_data ) ) ); $data['failed'][] = $result; } elseif ( $result['updated'] ) { $data['updated'][] = $result['id']; } elseif ( $result['is_variation'] ) { $data['imported_variations'][] = $result['id']; } else { $data['imported'][] = $result['id']; } ++$index; if ( $this->params['prevent_timeouts'] && ( $this->time_exceeded() || $this->memory_exceeded() ) ) { $this->file_position = $this->file_positions[ $index ]; break; } } return $data; } }
| ver. 1.6 |
Github
|
.
| PHP 8.1.34 | Генерация страницы: 0 |
proxy
|
phpinfo
|
Настройка