Issues (942)

Security Analysis    not enabled

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

includes/import/abstract-wc-product-importer.php (1 issue)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
/**
3
 * Abstract Product importer
4
 *
5
 * @package  WooCommerce/Import
6
 * @version  3.1.0
7
 */
8
9 1
if ( ! defined( 'ABSPATH' ) ) {
10
	exit;
11
}
12
13
/**
14
 * Include dependencies.
15
 */
16 1
if ( ! class_exists( 'WC_Importer_Interface', false ) ) {
17 1
	include_once WC_ABSPATH . 'includes/interfaces/class-wc-importer-interface.php';
18
}
19
20
/**
21
 * WC_Product_Importer Class.
22
 */
23
abstract class WC_Product_Importer implements WC_Importer_Interface {
24
25
	/**
26
	 * CSV file.
27
	 *
28
	 * @var string
29
	 */
30
	protected $file = '';
31
32
	/**
33
	 * The file position after the last read.
34
	 *
35
	 * @var int
36
	 */
37
	protected $file_position = 0;
38
39
	/**
40
	 * Importer parameters.
41
	 *
42
	 * @var array
43
	 */
44
	protected $params = array();
45
46
	/**
47
	 * Raw keys - CSV raw headers.
48
	 *
49
	 * @var array
50
	 */
51
	protected $raw_keys = array();
52
53
	/**
54
	 * Mapped keys - CSV headers.
55
	 *
56
	 * @var array
57
	 */
58
	protected $mapped_keys = array();
59
60
	/**
61
	 * Raw data.
62
	 *
63
	 * @var array
64
	 */
65
	protected $raw_data = array();
66
67
	/**
68
	 * Raw data.
69
	 *
70
	 * @var array
71
	 */
72
	protected $file_positions = array();
73
74
	/**
75
	 * Parsed data.
76
	 *
77
	 * @var array
78
	 */
79
	protected $parsed_data = array();
80
81
	/**
82
	 * Start time of current import.
83
	 *
84
	 * (default value: 0)
85
	 *
86
	 * @var int
87
	 */
88
	protected $start_time = 0;
89
90
	/**
91
	 * Get file raw headers.
92
	 *
93
	 * @return array
94
	 */
95 1
	public function get_raw_keys() {
96 1
		return $this->raw_keys;
97
	}
98
99
	/**
100
	 * Get file mapped headers.
101
	 *
102
	 * @return array
103
	 */
104 4
	public function get_mapped_keys() {
105 4
		return ! empty( $this->mapped_keys ) ? $this->mapped_keys : $this->raw_keys;
106
	}
107
108
	/**
109
	 * Get raw data.
110
	 *
111
	 * @return array
112
	 */
113 2
	public function get_raw_data() {
114 2
		return $this->raw_data;
115
	}
116
117
	/**
118
	 * Get parsed data.
119
	 *
120
	 * @return array
121
	 */
122 1
	public function get_parsed_data() {
123 1
		return apply_filters( 'woocommerce_product_importer_parsed_data', $this->parsed_data, $this->get_raw_data() );
124
	}
125
126
	/**
127
	 * Get importer parameters.
128
	 *
129
	 * @return array
130
	 */
131
	public function get_params() {
132
		return $this->params;
133
	}
134
135
	/**
136
	 * Get file pointer position from the last read.
137
	 *
138
	 * @return int
139
	 */
140
	public function get_file_position() {
141
		return $this->file_position;
142
	}
143
144
	/**
145
	 * Get file pointer position as a percentage of file size.
146
	 *
147
	 * @return int
148
	 */
149
	public function get_percent_complete() {
150
		$size = filesize( $this->file );
151
		if ( ! $size ) {
152
			return 0;
153
		}
154
155
		return absint( min( round( ( $this->file_position / $size ) * 100 ), 100 ) );
156
	}
157
158
	/**
159
	 * Prepare a single product for create or update.
160
	 *
161
	 * @param  array $data     Item data.
162
	 * @return WC_Product|WP_Error
163
	 */
164 2
	protected function get_product_object( $data ) {
165 2
		$id = isset( $data['id'] ) ? absint( $data['id'] ) : 0;
166
167
		// Type is the most important part here because we need to be using the correct class and methods.
168 2
		if ( isset( $data['type'] ) ) {
169 1
			$types   = array_keys( wc_get_product_types() );
170 1
			$types[] = 'variation';
171
172 1 View Code Duplication
			if ( ! in_array( $data['type'], $types, true ) ) {
173
				return new WP_Error( 'woocommerce_product_importer_invalid_type', __( 'Invalid product type.', 'woocommerce' ), array( 'status' => 401 ) );
174
			}
175
176 1
			$classname = WC_Product_Factory::get_classname_from_product_type( $data['type'] );
177
178 1
			if ( ! class_exists( $classname ) ) {
179
				$classname = 'WC_Product_Simple';
180
			}
181
182 1
			$product = new $classname( $id );
183 1
		} elseif ( ! empty( $data['id'] ) ) {
184 1
			$product = wc_get_product( $id );
185
186 1 View Code Duplication
			if ( ! $product ) {
187
				return new WP_Error(
188
					'woocommerce_product_csv_importer_invalid_id',
189
					/* translators: %d: product ID */
190
					sprintf( __( 'Invalid product ID %d.', 'woocommerce' ), $id ),
191
					array(
192
						'id'     => $id,
193 1
						'status' => 401,
194
					)
195
				);
196
			}
197
		} else {
198
			$product = new WC_Product_Simple( $id );
199
		}
200
201 2
		return apply_filters( 'woocommerce_product_import_get_product_object', $product, $data );
202
	}
203
204
	/**
205
	 * Process a single item and save.
206
	 *
207
	 * @throws Exception If item cannot be processed.
208
	 * @param  array $data Raw CSV data.
209
	 * @return array|WP_Error
210
	 */
211 2
	protected function process_item( $data ) {
212
		try {
213 2
			do_action( 'woocommerce_product_import_before_process_item', $data );
214 2
			$data = apply_filters( 'woocommerce_product_import_process_item_data', $data );
215
216
			// Get product ID from SKU if created during the importation.
217 2
			if ( empty( $data['id'] ) && ! empty( $data['sku'] ) ) {
218 2
				$product_id = wc_get_product_id_by_sku( $data['sku'] );
219
220 2
				if ( $product_id ) {
221 2
					$data['id'] = $product_id;
222
				}
223
			}
224
225 2
			$object   = $this->get_product_object( $data );
226 2
			$updating = false;
227
228 2
			if ( is_wp_error( $object ) ) {
229
				return $object;
230
			}
231
232 2
			if ( $object->get_id() && 'importing' !== $object->get_status() ) {
233 1
				$updating = true;
234
			}
235
236 2
			if ( 'external' === $object->get_type() ) {
237 1
				unset( $data['manage_stock'], $data['stock_status'], $data['backorders'], $data['low_stock_amount'] );
238
			}
239
240 2
			if ( 'variation' === $object->get_type() ) {
241 1
				if ( isset( $data['status'] ) && -1 === $data['status'] ) {
242
					$data['status'] = 0; // Variations cannot be drafts - set to private.
243
				}
244
			}
245
246 2
			if ( 'importing' === $object->get_status() ) {
247 1
				$object->set_status( 'publish' );
248 1
				$object->set_slug( '' );
249
			}
250
251 2
			$result = $object->set_props( array_diff_key( $data, array_flip( array( 'meta_data', 'raw_image_id', 'raw_gallery_image_ids', 'raw_attributes' ) ) ) );
252
253 2
			if ( is_wp_error( $result ) ) {
254
				throw new Exception( $result->get_error_message() );
255
			}
256
257 2
			if ( 'variation' === $object->get_type() ) {
258 1
				$this->set_variation_data( $object, $data );
259
			} else {
260 2
				$this->set_product_data( $object, $data );
261
			}
262
263 2
			$this->set_image_data( $object, $data );
264 2
			$this->set_meta_data( $object, $data );
265
266 2
			$object = apply_filters( 'woocommerce_product_import_pre_insert_product_object', $object, $data );
267 2
			$object->save();
268
269 2
			do_action( 'woocommerce_product_import_inserted_product_object', $object, $data );
270
271
			return array(
272 2
				'id'      => $object->get_id(),
273 2
				'updated' => $updating,
274
			);
275
		} catch ( Exception $e ) {
276
			return new WP_Error( 'woocommerce_product_importer_error', $e->getMessage(), array( 'status' => $e->getCode() ) );
277
		}
278
	}
279
280
	/**
281
	 * Convert raw image URLs to IDs and set.
282
	 *
283
	 * @param WC_Product $product Product instance.
284
	 * @param array      $data    Item data.
285
	 */
286 2
	protected function set_image_data( &$product, $data ) {
287
		// Image URLs need converting to IDs before inserting.
288 2
		if ( isset( $data['raw_image_id'] ) ) {
289 1
			$product->set_image_id( $this->get_attachment_id_from_url( $data['raw_image_id'], $product->get_id() ) );
290
		}
291
292
		// Gallery image URLs need converting to IDs before inserting.
293 2
		if ( isset( $data['raw_gallery_image_ids'] ) ) {
294 1
			$gallery_image_ids = array();
295
296 1
			foreach ( $data['raw_gallery_image_ids'] as $image_id ) {
297 1
				$gallery_image_ids[] = $this->get_attachment_id_from_url( $image_id, $product->get_id() );
298
			}
299 1
			$product->set_gallery_image_ids( $gallery_image_ids );
300
		}
301
	}
302
303
	/**
304
	 * Append meta data.
305
	 *
306
	 * @param WC_Product $product Product instance.
307
	 * @param array      $data    Item data.
308
	 */
309 2
	protected function set_meta_data( &$product, $data ) {
310 2
		if ( isset( $data['meta_data'] ) ) {
311
			foreach ( $data['meta_data'] as $meta ) {
312
				$product->update_meta_data( $meta['key'], $meta['value'] );
313
			}
314
		}
315
	}
316
317
	/**
318
	 * Set product data.
319
	 *
320
	 * @param WC_Product $product Product instance.
321
	 * @param array      $data    Item data.
322
	 * @throws Exception If data cannot be set.
323
	 */
324 2
	protected function set_product_data( &$product, $data ) {
325 2
		if ( isset( $data['raw_attributes'] ) ) {
326 1
			$attributes          = array();
327 1
			$default_attributes  = array();
328 1
			$existing_attributes = $product->get_attributes();
329
330 1
			foreach ( $data['raw_attributes'] as $position => $attribute ) {
331 1
				$attribute_id = 0;
332
333
				// Get ID if is a global attribute.
334 1
				if ( ! empty( $attribute['taxonomy'] ) ) {
335
					$attribute_id = $this->get_attribute_taxonomy_id( $attribute['name'] );
336
				}
337
338
				// Set attribute visibility.
339 1
				if ( isset( $attribute['visible'] ) ) {
340
					$is_visible = $attribute['visible'];
341
				} else {
342 1
					$is_visible = 1;
343
				}
344
345
				// Get name.
346 1
				$attribute_name = $attribute_id ? wc_attribute_taxonomy_name_by_id( $attribute_id ) : $attribute['name'];
347
348
				// Set if is a variation attribute based on existing attributes if possible so updates via CSV do not change this.
349 1
				$is_variation = 0;
350
351 1
				if ( $existing_attributes ) {
352
					foreach ( $existing_attributes as $existing_attribute ) {
353
						if ( $existing_attribute->get_name() === $attribute_name ) {
354
							$is_variation = $existing_attribute->get_variation();
355
							break;
356
						}
357
					}
358
				}
359
360 1
				if ( $attribute_id ) {
361
					if ( isset( $attribute['value'] ) ) {
362
						$options = array_map( 'wc_sanitize_term_text_based', $attribute['value'] );
363
						$options = array_filter( $options, 'strlen' );
364
					} else {
365
						$options = array();
366
					}
367
368
					// Check for default attributes and set "is_variation".
369
					if ( ! empty( $attribute['default'] ) && in_array( $attribute['default'], $options, true ) ) {
370
						$default_term = get_term_by( 'name', $attribute['default'], $attribute_name );
371
372
						if ( $default_term && ! is_wp_error( $default_term ) ) {
373
							$default = $default_term->slug;
374
						} else {
375
							$default = sanitize_title( $attribute['default'] );
376
						}
377
378
						$default_attributes[ $attribute_name ] = $default;
379
						$is_variation                          = 1;
380
					}
381
382
					if ( ! empty( $options ) ) {
383
						$attribute_object = new WC_Product_Attribute();
384
						$attribute_object->set_id( $attribute_id );
385
						$attribute_object->set_name( $attribute_name );
386
						$attribute_object->set_options( $options );
387
						$attribute_object->set_position( $position );
388
						$attribute_object->set_visible( $is_visible );
389
						$attribute_object->set_variation( $is_variation );
390
						$attributes[] = $attribute_object;
391
					}
392 1
				} elseif ( isset( $attribute['value'] ) ) {
393
					// Check for default attributes and set "is_variation".
394 1
					if ( ! empty( $attribute['default'] ) && in_array( $attribute['default'], $attribute['value'], true ) ) {
395 1
						$default_attributes[ sanitize_title( $attribute['name'] ) ] = $attribute['default'];
396 1
						$is_variation = 1;
397
					}
398
399 1
					$attribute_object = new WC_Product_Attribute();
400 1
					$attribute_object->set_name( $attribute['name'] );
401 1
					$attribute_object->set_options( $attribute['value'] );
402 1
					$attribute_object->set_position( $position );
403 1
					$attribute_object->set_visible( $is_visible );
404 1
					$attribute_object->set_variation( $is_variation );
405 1
					$attributes[] = $attribute_object;
406
				}
407
			}
408
409 1
			$product->set_attributes( $attributes );
410
411
			// Set variable default attributes.
412 1
			if ( $product->is_type( 'variable' ) ) {
413 1
				$product->set_default_attributes( $default_attributes );
414
			}
415
		}
416
	}
417
418
	/**
419
	 * Set variation data.
420
	 *
421
	 * @param WC_Product $variation Product instance.
422
	 * @param array      $data    Item data.
423
	 * @return WC_Product|WP_Error
424
	 * @throws Exception If data cannot be set.
425
	 */
426 1
	protected function set_variation_data( &$variation, $data ) {
427 1
		$parent = false;
428
429
		// Check if parent exist.
430 1
		if ( isset( $data['parent_id'] ) ) {
431 1
			$parent = wc_get_product( $data['parent_id'] );
432
433 1
			if ( $parent ) {
434 1
				$variation->set_parent_id( $parent->get_id() );
435
			}
436
		}
437
438
		// Stop if parent does not exists.
439 1
		if ( ! $parent ) {
440
			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 ) );
441
		}
442
443
		// Stop if parent is a product variation.
444 1
		if ( $parent->is_type( 'variation' ) ) {
445
			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 ) );
446
		}
447
448 1
		if ( isset( $data['raw_attributes'] ) ) {
449 1
			$attributes        = array();
450 1
			$parent_attributes = $this->get_variation_parent_attributes( $data['raw_attributes'], $parent );
451
452 1
			foreach ( $data['raw_attributes'] as $attribute ) {
453 1
				$attribute_id = 0;
454
455
				// Get ID if is a global attribute.
456 1
				if ( ! empty( $attribute['taxonomy'] ) ) {
457
					$attribute_id = $this->get_attribute_taxonomy_id( $attribute['name'] );
458
				}
459
460 1
				if ( $attribute_id ) {
461
					$attribute_name = wc_attribute_taxonomy_name_by_id( $attribute_id );
462
				} else {
463 1
					$attribute_name = sanitize_title( $attribute['name'] );
464
				}
465
466 1
				if ( ! isset( $parent_attributes[ $attribute_name ] ) || ! $parent_attributes[ $attribute_name ]->get_variation() ) {
467 1
					continue;
468
				}
469
470 1
				$attribute_key   = sanitize_title( $parent_attributes[ $attribute_name ]->get_name() );
471 1
				$attribute_value = isset( $attribute['value'] ) ? current( $attribute['value'] ) : '';
472
473 1
				if ( $parent_attributes[ $attribute_name ]->is_taxonomy() ) {
474
					// If dealing with a taxonomy, we need to get the slug from the name posted to the API.
475
					$term = get_term_by( 'name', $attribute_value, $attribute_name );
476
477
					if ( $term && ! is_wp_error( $term ) ) {
478
						$attribute_value = $term->slug;
479
					} else {
480
						$attribute_value = sanitize_title( $attribute_value );
481
					}
482
				}
483
484 1
				$attributes[ $attribute_key ] = $attribute_value;
485
			}
486
487 1
			$variation->set_attributes( $attributes );
488
		}
489
	}
490
491
	/**
492
	 * Get variation parent attributes and set "is_variation".
493
	 *
494
	 * @param  array      $attributes Attributes list.
495
	 * @param  WC_Product $parent     Parent product data.
496
	 * @return array
497
	 */
498 1
	protected function get_variation_parent_attributes( $attributes, $parent ) {
499 1
		$parent_attributes = $parent->get_attributes();
500 1
		$require_save      = false;
501
502 1
		foreach ( $attributes as $attribute ) {
503 1
			$attribute_id = 0;
504
505
			// Get ID if is a global attribute.
506 1
			if ( ! empty( $attribute['taxonomy'] ) ) {
507
				$attribute_id = $this->get_attribute_taxonomy_id( $attribute['name'] );
508
			}
509
510 1
			if ( $attribute_id ) {
511
				$attribute_name = wc_attribute_taxonomy_name_by_id( $attribute_id );
512
			} else {
513 1
				$attribute_name = sanitize_title( $attribute['name'] );
514
			}
515
516
			// Check if attribute handle variations.
517 1
			if ( isset( $parent_attributes[ $attribute_name ] ) && ! $parent_attributes[ $attribute_name ]->get_variation() ) {
518
				// Re-create the attribute to CRUD save and generate again.
519
				$parent_attributes[ $attribute_name ] = clone $parent_attributes[ $attribute_name ];
520
				$parent_attributes[ $attribute_name ]->set_variation( 1 );
521
522
				$require_save = true;
523
			}
524
		}
525
526
		// Save variation attributes.
527 1
		if ( $require_save ) {
528
			$parent->set_attributes( array_values( $parent_attributes ) );
529
			$parent->save();
530
		}
531
532 1
		return $parent_attributes;
533
	}
534
535
	/**
536
	 * Get attachment ID.
537
	 *
538
	 * @param  string $url        Attachment URL.
539
	 * @param  int    $product_id Product ID.
540
	 * @return int
541
	 * @throws Exception If attachment cannot be loaded.
542
	 */
543 1
	public function get_attachment_id_from_url( $url, $product_id ) {
544 1
		if ( empty( $url ) ) {
545
			return 0;
546
		}
547
548 1
		$id         = 0;
549 1
		$upload_dir = wp_upload_dir( null, false );
550 1
		$base_url   = $upload_dir['baseurl'] . '/';
551
552
		// Check first if attachment is inside the WordPress uploads directory, or we're given a filename only.
553 1
		if ( false !== strpos( $url, $base_url ) || false === strpos( $url, '://' ) ) {
554
			// Search for yyyy/mm/slug.extension or slug.extension - remove the base URL.
555
			$file = str_replace( $base_url, '', $url );
556
			$args = array(
557
				'post_type'   => 'attachment',
558
				'post_status' => 'any',
559
				'fields'      => 'ids',
560
				'meta_query'  => array( // @codingStandardsIgnoreLine.
561
					'relation' => 'OR',
562
					array(
563
						'key'     => '_wp_attached_file',
564
						'value'   => '^' . $file,
565
						'compare' => 'REGEXP',
566
					),
567
					array(
568
						'key'     => '_wp_attached_file',
569
						'value'   => '/' . $file,
570
						'compare' => 'LIKE',
571
					),
572
					array(
573
						'key'     => '_wc_attachment_source',
574
						'value'   => '/' . $file,
575
						'compare' => 'LIKE',
576
					),
577
				),
578
			);
579
		} else {
580
			// This is an external URL, so compare to source.
581
			$args = array(
582 1
				'post_type'   => 'attachment',
583 1
				'post_status' => 'any',
584 1
				'fields'      => 'ids',
585
				'meta_query'  => array( // @codingStandardsIgnoreLine.
586
					array(
587 1
						'value' => $url,
588 1
						'key'   => '_wc_attachment_source',
589
					),
590
				),
591
			);
592
		}
593
594 1
		$ids = get_posts( $args ); // @codingStandardsIgnoreLine.
595
596 1
		if ( $ids ) {
597 1
			$id = current( $ids );
598
		}
599
600
		// Upload if attachment does not exists.
601 1
		if ( ! $id && stristr( $url, '://' ) ) {
602 1
			$upload = wc_rest_upload_image_from_url( $url );
603
604 1
			if ( is_wp_error( $upload ) ) {
605
				throw new Exception( $upload->get_error_message(), 400 );
606
			}
607
608 1
			$id = wc_rest_set_uploaded_image_as_attachment( $upload, $product_id );
609
610 1
			if ( ! wp_attachment_is_image( $id ) ) {
611
				/* translators: %s: image URL */
612
				throw new Exception( sprintf( __( 'Not able to attach "%s".', 'woocommerce' ), $url ), 400 );
613
			}
614
615
			// Save attachment source for future reference.
616 1
			update_post_meta( $id, '_wc_attachment_source', $url );
617
		}
618
619 1
		if ( ! $id ) {
620
			/* translators: %s: image URL */
621
			throw new Exception( sprintf( __( 'Unable to use image "%s".', 'woocommerce' ), $url ), 400 );
622
		}
623
624 1
		return $id;
625
	}
626
627
	/**
628
	 * Get attribute taxonomy ID from the imported data.
629
	 * If does not exists register a new attribute.
630
	 *
631
	 * @param  string $raw_name Attribute name.
632
	 * @return int
633
	 * @throws Exception If taxonomy cannot be loaded.
634
	 */
635
	public function get_attribute_taxonomy_id( $raw_name ) {
636
		global $wpdb, $wc_product_attributes;
637
638
		// These are exported as labels, so convert the label to a name if possible first.
639
		$attribute_labels = wp_list_pluck( wc_get_attribute_taxonomies(), 'attribute_label', 'attribute_name' );
640
		$attribute_name   = array_search( $raw_name, $attribute_labels, true );
641
642
		if ( ! $attribute_name ) {
643
			$attribute_name = wc_sanitize_taxonomy_name( $raw_name );
644
		}
645
646
		$attribute_id = wc_attribute_taxonomy_id_by_name( $attribute_name );
647
648
		// Get the ID from the name.
649
		if ( $attribute_id ) {
650
			return $attribute_id;
651
		}
652
653
		// If the attribute does not exist, create it.
654
		$attribute_id = wc_create_attribute(
655
			array(
656
				'name'         => $raw_name,
657
				'slug'         => $attribute_name,
658
				'type'         => 'select',
659
				'order_by'     => 'menu_order',
660
				'has_archives' => false,
661
			)
662
		);
663
664
		if ( is_wp_error( $attribute_id ) ) {
665
			throw new Exception( $attribute_id->get_error_message(), 400 );
666
		}
667
668
		// Register as taxonomy while importing.
669
		$taxonomy_name = wc_attribute_taxonomy_name( $attribute_name );
670
		register_taxonomy(
671
			$taxonomy_name,
672
			apply_filters( 'woocommerce_taxonomy_objects_' . $taxonomy_name, array( 'product' ) ),
673
			apply_filters(
674
				'woocommerce_taxonomy_args_' . $taxonomy_name,
675
				array(
676
					'labels'       => array(
677
						'name' => $raw_name,
678
					),
679
					'hierarchical' => true,
680
					'show_ui'      => false,
681
					'query_var'    => true,
682
					'rewrite'      => false,
683
				)
684
			)
685
		);
686
687
		// Set product attributes global.
688
		$wc_product_attributes = array();
689
690
		foreach ( wc_get_attribute_taxonomies() as $taxonomy ) {
691
			$wc_product_attributes[ wc_attribute_taxonomy_name( $taxonomy->attribute_name ) ] = $taxonomy;
692
		}
693
694
		return $attribute_id;
695
	}
696
697
	/**
698
	 * Memory exceeded
699
	 *
700
	 * Ensures the batch process never exceeds 90%
701
	 * of the maximum WordPress memory.
702
	 *
703
	 * @return bool
704
	 */
705 1
	protected function memory_exceeded() {
706 1
		$memory_limit   = $this->get_memory_limit() * 0.9; // 90% of max memory
707 1
		$current_memory = memory_get_usage( true );
708 1
		$return         = false;
709 1
		if ( $current_memory >= $memory_limit ) {
710
			$return = true;
711
		}
712 1
		return apply_filters( 'woocommerce_product_importer_memory_exceeded', $return );
713
	}
714
715
	/**
716
	 * Get memory limit
717
	 *
718
	 * @return int
719
	 */
720 1 View Code Duplication
	protected function get_memory_limit() {
721 1
		if ( function_exists( 'ini_get' ) ) {
722 1
			$memory_limit = ini_get( 'memory_limit' );
723
		} else {
724
			// Sensible default.
725
			$memory_limit = '128M';
726
		}
727
728 1
		if ( ! $memory_limit || -1 === intval( $memory_limit ) ) {
729
			// Unlimited, set to 32GB.
730 1
			$memory_limit = '32000M';
731
		}
732 1
		return intval( $memory_limit ) * 1024 * 1024;
733
	}
734
735
	/**
736
	 * Time exceeded.
737
	 *
738
	 * Ensures the batch never exceeds a sensible time limit.
739
	 * A timeout limit of 30s is common on shared hosting.
740
	 *
741
	 * @return bool
742
	 */
743 1
	protected function time_exceeded() {
744 1
		$finish = $this->start_time + apply_filters( 'woocommerce_product_importer_default_time_limit', 20 ); // 20 seconds
745 1
		$return = false;
746 1
		if ( time() >= $finish ) {
747
			$return = true;
748
		}
749 1
		return apply_filters( 'woocommerce_product_importer_time_exceeded', $return );
750
	}
751
752
	/**
753
	 * Explode CSV cell values using commas by default, and handling escaped
754
	 * separators.
755
	 *
756
	 * @since  3.2.0
757
	 * @param  string $value     Value to explode.
758
	 * @param  string $separator Separator separating each value. Defaults to comma.
759
	 * @return array
760
	 */
761 2
	protected function explode_values( $value, $separator = ',' ) {
762 2
		$value  = str_replace( '\\,', '::separator::', $value );
763 2
		$values = explode( $separator, $value );
764 2
		$values = array_map( array( $this, 'explode_values_formatter' ), $values );
765
766 2
		return $values;
767
	}
768
769
	/**
770
	 * Remove formatting and trim each value.
771
	 *
772
	 * @since  3.2.0
773
	 * @param  string $value Value to format.
774
	 * @return string
775
	 */
776 2
	protected function explode_values_formatter( $value ) {
777 2
		return trim( str_replace( '::separator::', ',', $value ) );
778
	}
779
780
	/**
781
	 * The exporter prepends a ' to escape fields that start with =, +, - or @.
782
	 * Remove the prepended ' character preceding those characters.
783
	 *
784
	 * @since 3.5.2
785
	 * @param  string $value A string that may or may not have been escaped with '.
786
	 * @return string
787
	 */
788 2 View Code Duplication
	protected function unescape_data( $value ) {
0 ignored issues
show
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
789 2
		$active_content_triggers = array( "'=", "'+", "'-", "'@" );
790
791 2
		if ( in_array( mb_substr( $value, 0, 2 ), $active_content_triggers, true ) ) {
792
			$value = mb_substr( $value, 1 );
793
		}
794
795 2
		return $value;
796
	}
797
798
}
799