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/export/class-wc-product-csv-exporter.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
 * Handles product CSV export.
4
 *
5
 * @package WooCommerce/Export
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_CSV_Batch_Exporter', false ) ) {
17 1
	include_once WC_ABSPATH . 'includes/export/abstract-wc-csv-batch-exporter.php';
18
}
19
20
/**
21
 * WC_Product_CSV_Exporter Class.
22
 */
23
class WC_Product_CSV_Exporter extends WC_CSV_Batch_Exporter {
24
25
	/**
26
	 * Type of export used in filter names.
27
	 *
28
	 * @var string
29
	 */
30
	protected $export_type = 'product';
31
32
	/**
33
	 * Should meta be exported?
34
	 *
35
	 * @var boolean
36
	 */
37
	protected $enable_meta_export = false;
38
39
	/**
40
	 * Which product types are being exported.
41
	 *
42
	 * @var array
43
	 */
44
	protected $product_types_to_export = array();
45
46
	/**
47
	 * Products belonging to what category should be exported.
48
	 *
49
	 * @var string
50
	 */
51
	protected $product_category_to_export = array();
52
53
	/**
54
	 * Constructor.
55
	 */
56 4
	public function __construct() {
57 4
		parent::__construct();
58 4
		$this->set_product_types_to_export( array_merge( array_keys( wc_get_product_types() ), array( 'variation' ) ) );
59
	}
60
61
	/**
62
	 * Should meta be exported?
63
	 *
64
	 * @param bool $enable_meta_export Should meta be exported.
65
	 *
66
	 * @since 3.1.0
67
	 */
68
	public function enable_meta_export( $enable_meta_export ) {
69
		$this->enable_meta_export = (bool) $enable_meta_export;
70
	}
71
72
	/**
73
	 * Product types to export.
74
	 *
75
	 * @param array $product_types_to_export List of types to export.
76
	 *
77
	 * @since 3.1.0
78
	 */
79 4
	public function set_product_types_to_export( $product_types_to_export ) {
80 4
		$this->product_types_to_export = array_map( 'wc_clean', $product_types_to_export );
81
	}
82
83
	/**
84
	 * Product category to export
85
	 *
86
	 * @param string $product_category_to_export Product category slug to export, empty string exports all.
87
	 *
88
	 * @since  3.5.0
89
	 * @return void
90
	 */
91 1
	public function set_product_category_to_export( $product_category_to_export ) {
92 1
		$this->product_category_to_export = array_map( 'sanitize_title_with_dashes', $product_category_to_export );
0 ignored issues
show
Documentation Bug introduced by
It seems like array_map('sanitize_titl...uct_category_to_export) of type array is incompatible with the declared type string of property $product_category_to_export.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
93
	}
94
95
	/**
96
	 * Return an array of columns to export.
97
	 *
98
	 * @since  3.1.0
99
	 * @return array
100
	 */
101 4
	public function get_default_column_names() {
102 4
		return apply_filters(
103 4
			"woocommerce_product_export_{$this->export_type}_default_columns",
104
			array(
105 4
				'id'                 => __( 'ID', 'woocommerce' ),
106 4
				'type'               => __( 'Type', 'woocommerce' ),
107 4
				'sku'                => __( 'SKU', 'woocommerce' ),
108 4
				'name'               => __( 'Name', 'woocommerce' ),
109 4
				'published'          => __( 'Published', 'woocommerce' ),
110 4
				'featured'           => __( 'Is featured?', 'woocommerce' ),
111 4
				'catalog_visibility' => __( 'Visibility in catalog', 'woocommerce' ),
112 4
				'short_description'  => __( 'Short description', 'woocommerce' ),
113 4
				'description'        => __( 'Description', 'woocommerce' ),
114 4
				'date_on_sale_from'  => __( 'Date sale price starts', 'woocommerce' ),
115 4
				'date_on_sale_to'    => __( 'Date sale price ends', 'woocommerce' ),
116 4
				'tax_status'         => __( 'Tax status', 'woocommerce' ),
117 4
				'tax_class'          => __( 'Tax class', 'woocommerce' ),
118 4
				'stock_status'       => __( 'In stock?', 'woocommerce' ),
119 4
				'stock'              => __( 'Stock', 'woocommerce' ),
120 4
				'low_stock_amount'   => __( 'Low stock amount', 'woocommerce' ),
121 4
				'backorders'         => __( 'Backorders allowed?', 'woocommerce' ),
122 4
				'sold_individually'  => __( 'Sold individually?', 'woocommerce' ),
123
				/* translators: %s: weight */
124 4
				'weight'             => sprintf( __( 'Weight (%s)', 'woocommerce' ), get_option( 'woocommerce_weight_unit' ) ),
125
				/* translators: %s: length */
126 4
				'length'             => sprintf( __( 'Length (%s)', 'woocommerce' ), get_option( 'woocommerce_dimension_unit' ) ),
127
				/* translators: %s: width */
128 4
				'width'              => sprintf( __( 'Width (%s)', 'woocommerce' ), get_option( 'woocommerce_dimension_unit' ) ),
129
				/* translators: %s: Height */
130 4
				'height'             => sprintf( __( 'Height (%s)', 'woocommerce' ), get_option( 'woocommerce_dimension_unit' ) ),
131 4
				'reviews_allowed'    => __( 'Allow customer reviews?', 'woocommerce' ),
132 4
				'purchase_note'      => __( 'Purchase note', 'woocommerce' ),
133 4
				'sale_price'         => __( 'Sale price', 'woocommerce' ),
134 4
				'regular_price'      => __( 'Regular price', 'woocommerce' ),
135 4
				'category_ids'       => __( 'Categories', 'woocommerce' ),
136 4
				'tag_ids'            => __( 'Tags', 'woocommerce' ),
137 4
				'shipping_class_id'  => __( 'Shipping class', 'woocommerce' ),
138 4
				'images'             => __( 'Images', 'woocommerce' ),
139 4
				'download_limit'     => __( 'Download limit', 'woocommerce' ),
140 4
				'download_expiry'    => __( 'Download expiry days', 'woocommerce' ),
141 4
				'parent_id'          => __( 'Parent', 'woocommerce' ),
142 4
				'grouped_products'   => __( 'Grouped products', 'woocommerce' ),
143 4
				'upsell_ids'         => __( 'Upsells', 'woocommerce' ),
144 4
				'cross_sell_ids'     => __( 'Cross-sells', 'woocommerce' ),
145 4
				'product_url'        => __( 'External URL', 'woocommerce' ),
146 4
				'button_text'        => __( 'Button text', 'woocommerce' ),
147 4
				'menu_order'         => __( 'Position', 'woocommerce' ),
148
			)
149
		);
150
	}
151
152
	/**
153
	 * Prepare data for export.
154
	 *
155
	 * @since 3.1.0
156
	 */
157 1
	public function prepare_data_to_export() {
158
		$args = array(
159 1
			'status'   => array( 'private', 'publish', 'draft', 'future', 'pending' ),
160 1
			'type'     => $this->product_types_to_export,
161 1
			'limit'    => $this->get_limit(),
162 1
			'page'     => $this->get_page(),
163
			'orderby'  => array(
164
				'ID' => 'ASC',
165
			),
166 1
			'return'   => 'objects',
167
			'paginate' => true,
168
		);
169
170 1
		if ( ! empty( $this->product_category_to_export ) ) {
171
			$args['category'] = $this->product_category_to_export;
172
		}
173 1
		$products = wc_get_products( apply_filters( "woocommerce_product_export_{$this->export_type}_query_args", $args ) );
174
175 1
		$this->total_rows  = $products->total;
176 1
		$this->row_data    = array();
177 1
		$variable_products = array();
178
179 1
		foreach ( $products->products as $product ) {
180
			// Check if the category is set, this means we need to fetch variations seperately as they are not tied to a category.
181 1
			if ( ! empty( $args['category'] ) && $product->is_type( 'variable' ) ) {
182
				$variable_products[] = $product->get_id();
183
			}
184
185 1
			$this->row_data[] = $this->generate_row_data( $product );
186
		}
187
188
		// If a category was selected we loop through the variations as they are not tied to a category so will be excluded by default.
189 1
		if ( ! empty( $variable_products ) ) {
190
			foreach ( $variable_products as $parent_id ) {
191
				$products = wc_get_products(
192
					array(
193
						'parent' => $parent_id,
194
						'type'   => array( 'variation' ),
195
						'return' => 'objects',
196
						'limit'  => -1,
197
					)
198
				);
199
200
				if ( ! $products ) {
201
					continue;
202
				}
203
204
				foreach ( $products as $product ) {
205
					$this->row_data[] = $this->generate_row_data( $product );
206
				}
207
			}
208
		}
209
	}
210
211
	/**
212
	 * Take a product and generate row data from it for export.
213
	 *
214
	 * @param WC_Product $product WC_Product object.
215
	 *
216
	 * @return array
217
	 */
218 1
	protected function generate_row_data( $product ) {
219 1
		$columns = $this->get_column_names();
220 1
		$row     = array();
221 1
		foreach ( $columns as $column_id => $column_name ) {
222 1
			$column_id = strstr( $column_id, ':' ) ? current( explode( ':', $column_id ) ) : $column_id;
223 1
			$value     = '';
224
225
			// Skip some columns if dynamically handled later or if we're being selective.
226 1
			if ( in_array( $column_id, array( 'downloads', 'attributes', 'meta' ), true ) || ! $this->is_column_exporting( $column_id ) ) {
227 1
				continue;
228
			}
229
230 1
			if ( has_filter( "woocommerce_product_export_{$this->export_type}_column_{$column_id}" ) ) {
231
				// Filter for 3rd parties.
232
				$value = apply_filters( "woocommerce_product_export_{$this->export_type}_column_{$column_id}", '', $product, $column_id );
233
234 1
			} elseif ( is_callable( array( $this, "get_column_value_{$column_id}" ) ) ) {
235
				// Handle special columns which don't map 1:1 to product data.
236 1
				$value = $this->{"get_column_value_{$column_id}"}( $product );
237
238 1
			} elseif ( is_callable( array( $product, "get_{$column_id}" ) ) ) {
239
				// Default and custom handling.
240 1
				$value = $product->{"get_{$column_id}"}( 'edit' );
241
			}
242
243 1
			if ( 'description' === $column_id || 'short_description' === $column_id ) {
244 1
				$value = $this->filter_description_field( $value );
245
			}
246
247 1
			$row[ $column_id ] = $value;
248
		}
249
250 1
		$this->prepare_downloads_for_export( $product, $row );
251 1
		$this->prepare_attributes_for_export( $product, $row );
252 1
		$this->prepare_meta_for_export( $product, $row );
253 1
		return apply_filters( 'woocommerce_product_export_row_data', $row, $product );
254
	}
255
256
	/**
257
	 * Get published value.
258
	 *
259
	 * @param WC_Product $product Product being exported.
260
	 *
261
	 * @since  3.1.0
262
	 * @return int
263
	 */
264 1
	protected function get_column_value_published( $product ) {
265
		$statuses = array(
266 1
			'draft'   => -1,
267
			'private' => 0,
268
			'publish' => 1,
269
		);
270
271 1
		$status = $product->get_status( 'edit' );
272
273 1
		return isset( $statuses[ $status ] ) ? $statuses[ $status ] : -1;
274
	}
275
276
	/**
277
	 * Get formatted sale price.
278
	 *
279
	 * @param WC_Product $product Product being exported.
280
	 *
281
	 * @return string
282
	 */
283 1
	protected function get_column_value_sale_price( $product ) {
284 1
		return wc_format_localized_price( $product->get_sale_price( 'view' ) );
285
	}
286
287
	/**
288
	 * Get formatted regular price.
289
	 *
290
	 * @param WC_Product $product Product being exported.
291
	 *
292
	 * @return string
293
	 */
294 1
	protected function get_column_value_regular_price( $product ) {
295 1
		return wc_format_localized_price( $product->get_regular_price() );
296
	}
297
298
	/**
299
	 * Get product_cat value.
300
	 *
301
	 * @param WC_Product $product Product being exported.
302
	 *
303
	 * @since  3.1.0
304
	 * @return string
305
	 */
306 1
	protected function get_column_value_category_ids( $product ) {
307 1
		$term_ids = $product->get_category_ids( 'edit' );
308 1
		return $this->format_term_ids( $term_ids, 'product_cat' );
309
	}
310
311
	/**
312
	 * Get product_tag value.
313
	 *
314
	 * @param WC_Product $product Product being exported.
315
	 *
316
	 * @since  3.1.0
317
	 * @return string
318
	 */
319 1
	protected function get_column_value_tag_ids( $product ) {
320 1
		$term_ids = $product->get_tag_ids( 'edit' );
321 1
		return $this->format_term_ids( $term_ids, 'product_tag' );
322
	}
323
324
	/**
325
	 * Get product_shipping_class value.
326
	 *
327
	 * @param WC_Product $product Product being exported.
328
	 *
329
	 * @since  3.1.0
330
	 * @return string
331
	 */
332 1
	protected function get_column_value_shipping_class_id( $product ) {
333 1
		$term_ids = $product->get_shipping_class_id( 'edit' );
334 1
		return $this->format_term_ids( $term_ids, 'product_shipping_class' );
335
	}
336
337
	/**
338
	 * Get images value.
339
	 *
340
	 * @param WC_Product $product Product being exported.
341
	 *
342
	 * @since  3.1.0
343
	 * @return string
344
	 */
345 1
	protected function get_column_value_images( $product ) {
346 1
		$image_ids = array_merge( array( $product->get_image_id( 'edit' ) ), $product->get_gallery_image_ids( 'edit' ) );
347 1
		$images    = array();
348
349 1
		foreach ( $image_ids as $image_id ) {
350 1
			$image = wp_get_attachment_image_src( $image_id, 'full' );
351
352 1
			if ( $image ) {
353
				$images[] = $image[0];
354
			}
355
		}
356
357 1
		return $this->implode_values( $images );
358
	}
359
360
	/**
361
	 * Prepare linked products for export.
362
	 *
363
	 * @param int[] $linked_products Array of linked product ids.
364
	 *
365
	 * @since  3.1.0
366
	 * @return string
367
	 */
368 1
	protected function prepare_linked_products_for_export( $linked_products ) {
369 1
		$product_list = array();
370
371 1
		foreach ( $linked_products as $linked_product ) {
372
			if ( $linked_product->get_sku() ) {
373
				$product_list[] = $linked_product->get_sku();
374
			} else {
375
				$product_list[] = 'id:' . $linked_product->get_id();
376
			}
377
		}
378
379 1
		return $this->implode_values( $product_list );
380
	}
381
382
	/**
383
	 * Get cross_sell_ids value.
384
	 *
385
	 * @param WC_Product $product Product being exported.
386
	 *
387
	 * @since  3.1.0
388
	 * @return string
389
	 */
390 1
	protected function get_column_value_cross_sell_ids( $product ) {
391 1
		return $this->prepare_linked_products_for_export( array_filter( array_map( 'wc_get_product', (array) $product->get_cross_sell_ids( 'edit' ) ) ) );
392
	}
393
394
	/**
395
	 * Get upsell_ids value.
396
	 *
397
	 * @param WC_Product $product Product being exported.
398
	 *
399
	 * @since  3.1.0
400
	 * @return string
401
	 */
402 1
	protected function get_column_value_upsell_ids( $product ) {
403 1
		return $this->prepare_linked_products_for_export( array_filter( array_map( 'wc_get_product', (array) $product->get_upsell_ids( 'edit' ) ) ) );
404
	}
405
406
	/**
407
	 * Get parent_id value.
408
	 *
409
	 * @param WC_Product $product Product being exported.
410
	 *
411
	 * @since  3.1.0
412
	 * @return string
413
	 */
414 1
	protected function get_column_value_parent_id( $product ) {
415 1
		if ( $product->get_parent_id( 'edit' ) ) {
416 1
			$parent = wc_get_product( $product->get_parent_id( 'edit' ) );
417 1
			if ( ! $parent ) {
418
				return '';
419
			}
420
421 1
			return $parent->get_sku( 'edit' ) ? $parent->get_sku( 'edit' ) : 'id:' . $parent->get_id();
422
		}
423 1
		return '';
424
	}
425
426
	/**
427
	 * Get grouped_products value.
428
	 *
429
	 * @param WC_Product $product Product being exported.
430
	 *
431
	 * @since  3.1.0
432
	 * @return string
433
	 */
434 1
	protected function get_column_value_grouped_products( $product ) {
435 1
		if ( 'grouped' !== $product->get_type() ) {
436 1
			return '';
437
		}
438
439 1
		$grouped_products = array();
440 1
		$child_ids        = $product->get_children( 'edit' );
441 1
		foreach ( $child_ids as $child_id ) {
442 1
			$child = wc_get_product( $child_id );
443 1
			if ( ! $child ) {
444
				continue;
445
			}
446
447 1
			$grouped_products[] = $child->get_sku( 'edit' ) ? $child->get_sku( 'edit' ) : 'id:' . $child_id;
448
		}
449 1
		return $this->implode_values( $grouped_products );
450
	}
451
452
	/**
453
	 * Get download_limit value.
454
	 *
455
	 * @param WC_Product $product Product being exported.
456
	 *
457
	 * @since  3.1.0
458
	 * @return string
459
	 */
460 1
	protected function get_column_value_download_limit( $product ) {
461 1
		return $product->is_downloadable() && $product->get_download_limit( 'edit' ) ? $product->get_download_limit( 'edit' ) : '';
462
	}
463
464
	/**
465
	 * Get download_expiry value.
466
	 *
467
	 * @param WC_Product $product Product being exported.
468
	 *
469
	 * @since  3.1.0
470
	 * @return string
471
	 */
472 1
	protected function get_column_value_download_expiry( $product ) {
473 1
		return $product->is_downloadable() && $product->get_download_expiry( 'edit' ) ? $product->get_download_expiry( 'edit' ) : '';
474
	}
475
476
	/**
477
	 * Get stock value.
478
	 *
479
	 * @param WC_Product $product Product being exported.
480
	 *
481
	 * @since  3.1.0
482
	 * @return string
483
	 */
484 1
	protected function get_column_value_stock( $product ) {
485 1
		$manage_stock   = $product->get_manage_stock( 'edit' );
486 1
		$stock_quantity = $product->get_stock_quantity( 'edit' );
487
488 1
		if ( $product->is_type( 'variation' ) && 'parent' === $manage_stock ) {
489
			return 'parent';
490 1
		} elseif ( $manage_stock ) {
491
			return $stock_quantity;
492
		} else {
493 1
			return '';
494
		}
495
	}
496
497
	/**
498
	 * Get stock status value.
499
	 *
500
	 * @param WC_Product $product Product being exported.
501
	 *
502
	 * @since  3.1.0
503
	 * @return string
504
	 */
505 1
	protected function get_column_value_stock_status( $product ) {
506 1
		$status = $product->get_stock_status( 'edit' );
507
508 1
		if ( 'onbackorder' === $status ) {
509
			return 'backorder';
510
		}
511
512 1
		return 'instock' === $status ? 1 : 0;
513
	}
514
515
	/**
516
	 * Get backorders.
517
	 *
518
	 * @param WC_Product $product Product being exported.
519
	 *
520
	 * @since  3.1.0
521
	 * @return string
522
	 */
523 1
	protected function get_column_value_backorders( $product ) {
524 1
		$backorders = $product->get_backorders( 'edit' );
525
526 1
		switch ( $backorders ) {
527
			case 'notify':
528
				return 'notify';
529
			default:
530 1
				return wc_string_to_bool( $backorders ) ? 1 : 0;
531
		}
532
	}
533
534
	/**
535
	 * Get low stock amount value.
536
	 *
537
	 * @param WC_Product $product Product being exported.
538
	 *
539
	 * @since  3.5.0
540
	 * @return int|string Empty string if value not set
541
	 */
542 1
	protected function get_column_value_low_stock_amount( $product ) {
543 1
		return $product->managing_stock() && $product->get_low_stock_amount( 'edit' ) ? $product->get_low_stock_amount( 'edit' ) : '';
544
	}
545
546
	/**
547
	 * Get type value.
548
	 *
549
	 * @param WC_Product $product Product being exported.
550
	 *
551
	 * @since  3.1.0
552
	 * @return string
553
	 */
554 1
	protected function get_column_value_type( $product ) {
555 1
		$types   = array();
556 1
		$types[] = $product->get_type();
557
558 1
		if ( $product->is_downloadable() ) {
559
			$types[] = 'downloadable';
560
		}
561
562 1
		if ( $product->is_virtual() ) {
563
			$types[] = 'virtual';
564
		}
565
566 1
		return $this->implode_values( $types );
567
	}
568
569
	/**
570
	 * Filter description field for export.
571
	 * Convert newlines to '\n'.
572
	 *
573
	 * @param string $description Product description text to filter.
574
	 *
575
	 * @since  3.5.4
576
	 * @return string
577
	 */
578 1
	protected function filter_description_field( $description ) {
579 1
		$description = str_replace( '\n', "\\\\n", $description );
580 1
		$description = str_replace( "\n", '\n', $description );
581 1
		return $description;
582
	}
583
	/**
584
	 * Export downloads.
585
	 *
586
	 * @param WC_Product $product Product being exported.
587
	 * @param array      $row     Row being exported.
588
	 *
589
	 * @since 3.1.0
590
	 */
591 1
	protected function prepare_downloads_for_export( $product, &$row ) {
592 1
		if ( $product->is_downloadable() && $this->is_column_exporting( 'downloads' ) ) {
593
			$downloads = $product->get_downloads( 'edit' );
594
595
			if ( $downloads ) {
596
				$i = 1;
597
				foreach ( $downloads as $download ) {
598
					/* translators: %s: download number */
599
					$this->column_names[ 'downloads:name' . $i ] = sprintf( __( 'Download %d name', 'woocommerce' ), $i );
600
					/* translators: %s: download number */
601
					$this->column_names[ 'downloads:url' . $i ] = sprintf( __( 'Download %d URL', 'woocommerce' ), $i );
602
					$row[ 'downloads:name' . $i ]               = $download->get_name();
603
					$row[ 'downloads:url' . $i ]                = $download->get_file();
604
					$i++;
605
				}
606
			}
607
		}
608
	}
609
610
	/**
611
	 * Export attributes data.
612
	 *
613
	 * @param WC_Product $product Product being exported.
614
	 * @param array      $row     Row being exported.
615
	 *
616
	 * @since 3.1.0
617
	 */
618 1
	protected function prepare_attributes_for_export( $product, &$row ) {
619 1
		if ( $this->is_column_exporting( 'attributes' ) ) {
620 1
			$attributes         = $product->get_attributes();
621 1
			$default_attributes = $product->get_default_attributes();
622
623 1
			if ( count( $attributes ) ) {
624 1
				$i = 1;
625 1
				foreach ( $attributes as $attribute_name => $attribute ) {
626
					/* translators: %s: attribute number */
627 1
					$this->column_names[ 'attributes:name' . $i ] = sprintf( __( 'Attribute %d name', 'woocommerce' ), $i );
628
					/* translators: %s: attribute number */
629 1
					$this->column_names[ 'attributes:value' . $i ] = sprintf( __( 'Attribute %d value(s)', 'woocommerce' ), $i );
630
					/* translators: %s: attribute number */
631 1
					$this->column_names[ 'attributes:visible' . $i ] = sprintf( __( 'Attribute %d visible', 'woocommerce' ), $i );
632
					/* translators: %s: attribute number */
633 1
					$this->column_names[ 'attributes:taxonomy' . $i ] = sprintf( __( 'Attribute %d global', 'woocommerce' ), $i );
634
635 1
					if ( is_a( $attribute, 'WC_Product_Attribute' ) ) {
636 1
						$row[ 'attributes:name' . $i ] = wc_attribute_label( $attribute->get_name(), $product );
637
638 1
						if ( $attribute->is_taxonomy() ) {
639 1
							$terms  = $attribute->get_terms();
640 1
							$values = array();
641
642 1
							foreach ( $terms as $term ) {
643 1
								$values[] = $term->name;
644
							}
645
646 1
							$row[ 'attributes:value' . $i ]    = $this->implode_values( $values );
647 1
							$row[ 'attributes:taxonomy' . $i ] = 1;
648
						} else {
649
							$row[ 'attributes:value' . $i ]    = $this->implode_values( $attribute->get_options() );
650
							$row[ 'attributes:taxonomy' . $i ] = 0;
651
						}
652
653 1
						$row[ 'attributes:visible' . $i ] = $attribute->get_visible();
654
					} else {
655 1
						$row[ 'attributes:name' . $i ] = wc_attribute_label( $attribute_name, $product );
656
657 1
						if ( 0 === strpos( $attribute_name, 'pa_' ) ) {
658 1
							$option_term = get_term_by( 'slug', $attribute, $attribute_name ); // @codingStandardsIgnoreLine.
659 1
							$row[ 'attributes:value' . $i ]    = $option_term && ! is_wp_error( $option_term ) ? str_replace( ',', '\\,', $option_term->name ) : $attribute;
660 1
							$row[ 'attributes:taxonomy' . $i ] = 1;
661
						} else {
662
							$row[ 'attributes:value' . $i ]    = $attribute;
663
							$row[ 'attributes:taxonomy' . $i ] = 0;
664
						}
665
666 1
						$row[ 'attributes:visible' . $i ] = '';
667
					}
668
669 1
					if ( $product->is_type( 'variable' ) && isset( $default_attributes[ sanitize_title( $attribute_name ) ] ) ) {
670
						/* translators: %s: attribute number */
671
						$this->column_names[ 'attributes:default' . $i ] = sprintf( __( 'Attribute %d default', 'woocommerce' ), $i );
672
						$default_value                                   = $default_attributes[ sanitize_title( $attribute_name ) ];
673
674
						if ( 0 === strpos( $attribute_name, 'pa_' ) ) {
675
							$option_term = get_term_by( 'slug', $default_value, $attribute_name ); // @codingStandardsIgnoreLine.
676
							$row[ 'attributes:default' . $i ] = $option_term && ! is_wp_error( $option_term ) ? $option_term->name : $default_value;
677
						} else {
678
							$row[ 'attributes:default' . $i ] = $default_value;
679
						}
680
					}
681 1
					$i++;
682
				}
683
			}
684
		}
685
	}
686
687
	/**
688
	 * Export meta data.
689
	 *
690
	 * @param WC_Product $product Product being exported.
691
	 * @param array      $row Row data.
692
	 *
693
	 * @since 3.1.0
694
	 */
695 1
	protected function prepare_meta_for_export( $product, &$row ) {
696 1
		if ( $this->enable_meta_export ) {
697
			$meta_data = $product->get_meta_data();
698
699
			if ( count( $meta_data ) ) {
700
				$meta_keys_to_skip = apply_filters( 'woocommerce_product_export_skip_meta_keys', array(), $product );
701
702
				$i = 1;
703
				foreach ( $meta_data as $meta ) {
704
					if ( in_array( $meta->key, $meta_keys_to_skip, true ) ) {
705
						continue;
706
					}
707
708
					// Allow 3rd parties to process the meta, e.g. to transform non-scalar values to scalar.
709
					$meta_value = apply_filters( 'woocommerce_product_export_meta_value', $meta->value, $meta, $product, $row );
710
711
					if ( ! is_scalar( $meta_value ) ) {
712
						continue;
713
					}
714
715
					$column_key = 'meta:' . esc_attr( $meta->key );
716
					/* translators: %s: meta data name */
717
					$this->column_names[ $column_key ] = sprintf( __( 'Meta: %s', 'woocommerce' ), $meta->key );
718
					$row[ $column_key ]                = $meta_value;
719
					$i ++;
720
				}
721
			}
722
		}
723
	}
724
}
725