PluginProbe ʕ •ᴥ•ʔ
WooCommerce / 10.9.4
WooCommerce v10.9.4
10.9.4 10.9.3 10.9.2 10.9.1 10.9.0 10.9.0-rc.1 10.9.0-beta.2 10.9.0-beta.1 10.8.1 10.8.0 10.8.0-rc.1 10.8.0-beta.2 10.8.0-beta.1 7.8.0-beta.1 7.8.0-beta.2 7.8.0-rc.1 7.8.0-rc.2 7.8.1 7.8.2 7.8.3 7.8.4 7.9.0 7.9.0-beta.1 7.9.0-beta.2 7.9.0-rc.2 7.9.0-rc.3 7.9.1 7.9.2 8.0.0 8.0.0-beta.1 8.0.0-beta.2 8.0.0-rc.1 8.0.0-rc.2 8.0.1 8.0.2 8.0.3 8.0.4 8.0.5 8.1.0 8.1.0-beta.1 8.1.0-rc.1 8.1.0-rc.2 8.1.1 8.1.2 8.1.3 8.1.4 8.2.0 8.2.0-beta.1 8.2.0-rc.1 8.2.0-rc.2 8.2.1 8.2.2 8.2.3 8.2.4 8.2.5 8.3.0 8.3.0-beta.1 8.3.0-rc.1 8.3.0-rc.2 8.3.1 8.3.2 8.3.3 8.3.4 8.4.0 8.4.0-beta.1 8.4.0-rc.1 8.4.1 8.4.2 8.4.3 8.5.0 8.5.0-beta.1 8.5.0-rc.1 8.5.1 8.5.2 8.5.3 8.5.4 8.5.5 8.6.0 8.6.0-beta.1 8.6.0-rc.1 8.6.1 8.6.2 8.6.3 8.6.4 8.7.0 8.7.0-beta.1 8.7.0-beta.2 8.7.0-rc.1 8.7.1 8.7.2 8.7.3 8.8.0 8.8.0-beta.1 8.8.0-rc.1 8.8.1 8.8.2 8.8.3 8.8.4 8.8.5 8.8.6 8.8.7 8.9.0 8.9.0-beta.1 8.9.0-rc.1 8.9.1 8.9.2 8.9.3 8.9.4 8.9.5 9.0.0 9.0.0-beta.1 9.0.0-beta.2 9.0.0-rc.1 9.0.1 9.0.2 9.0.3 9.0.4 9.1.0 9.1.0-beta.1 9.1.0-rc.1 9.1.1 9.1.2 9.1.3 9.1.4 9.1.5 9.1.6 9.2.0 9.2.0-beta.1 9.2.0-rc.1 9.2.1 9.2.2 9.2.3 9.2.4 9.2.5 9.3.0 9.3.0-beta.1 9.3.0-rc.1 9.3.1 9.3.2 9.3.3 9.3.4 9.3.5 9.3.6 9.4.0 9.4.0-beta.1 9.4.0-beta.2 9.4.0-rc.1 9.4.0-rc.2 9.4.0-rc.3 9.4.0-rc.4 9.4.1 9.4.2 9.4.3 9.4.4 9.4.5 9.5.0 9.5.0-beta.1 9.5.0-beta.2 9.5.0-rc.1 9.5.1 9.5.2 9.5.3 9.5.4 9.6.0 9.6.0-beta.1 9.6.0-beta.2 9.6.0-rc.1 9.6.1 9.6.2 9.6.3 9.6.4 9.7.0 9.7.0-beta.1 9.7.0-rc.1 9.7.1 9.7.2 9.7.3 9.8.0 9.8.0-beta.1 9.8.0-rc.1 9.8.1 9.8.2 9.8.3 9.8.4 9.8.5 9.8.6 9.8.7 9.9.0 9.9.0-beta.1 9.9.0-rc.1 9.9.1 9.9.2 9.9.3 9.9.4 9.9.5 9.9.6 9.9.7 3.7.3 7.1.2 3.8.0 7.2.0 3.8.0-beta.1 7.2.0-beta.1 3.8.0-rc.1 7.2.0-beta.2 3.8.0-rc.2 7.2.0-rc.1 3.8.1 7.2.0-rc.2 3.8.2 7.2.1 3.8.3 7.2.2 3.9.0 7.2.3 3.9.0-beta.1 7.2.4 3.9.0-beta.2 7.3.0 3.9.0-rc.1 7.3.0-beta.1 3.9.0-rc.2 7.3.0-beta.2 3.9.0-rc.3 7.3.0-rc.1 3.9.0-rc.4 7.3.0-rc.2 3.9.1 7.3.1 3.9.2 7.4.0 3.9.3 7.4.0-beta.1 3.9.4 7.4.0-beta.2 3.9.5 7.4.0-rc.1 4.0.0 7.4.0-rc.2 4.0.0-beta.1 7.4.1 4.0.0-rc.1 7.4.2 4.0.0-rc.2 7.5.0 4.0.1 7.5.0-beta.1 4.0.2 7.5.0-beta.2 4.0.3 7.5.0-rc.1 4.0.4 7.5.1 4.1.0 7.5.2 4.1.0-beta.1 7.6.0 4.1.0-beta.2 7.6.0-beta.1 4.1.0-rc.1 7.6.0-beta.2 4.1.0-rc.2 7.6.0-rc.1 4.1.1 7.6.0-rc.2 4.1.2 7.6.0-rc.3 4.1.3 7.6.1 4.1.4 7.6.2 4.2.0 7.7.0 4.2.0-RC.1 7.7.0-beta.1 4.2.0-RC.2 7.7.0-beta.2 4.2.0-beta.1 7.7.0-rc.1 4.2.1 7.7.1 4.2.2 7.7.2 4.2.3 7.7.3 4.2.4 7.8.0 4.2.5 4.3.0 4.3.0-beta.1 4.3.0-rc.1 4.3.0-rc.2 4.3.0-rc.3 4.3.1 4.3.2 4.3.3 4.3.4 4.3.5 4.3.6 4.4.0 4.4.0-beta.1 4.4.0-rc.1 4.4.1 4.4.2 4.4.3 4.4.4 4.5.0 4.5.0-beta.1 4.5.0-rc.1 4.5.0-rc.3 4.5.1 4.5.2 4.5.3 4.5.4 4.5.5 4.6.0 4.6.0-beta.1 4.6.0-rc.1 4.6.1 4.6.2 4.6.3 4.6.4 4.6.5 4.7.0 4.7.0-beta.1 4.7.0-beta.2 4.7.0-rc.1 4.7.1 4.7.1-beta.1 4.7.2 4.7.3 4.7.4 4.8.0 4.8.0-beta.1 4.8.0-rc.1 4.8.0-rc.2 4.8.1 4.8.2 4.8.3 4.9.0 4.9.0-beta.1 4.9.0-rc.1 4.9.0-rc.2 4.9.1 4.9.2 4.9.3 4.9.4 4.9.5 5.0.0 5.0.0-beta.1 5.0.0-beta.2 5.0.0-rc.1 5.0.0-rc.2 5.0.0-rc.3 5.0.1 5.0.2 5.0.3 5.1.0 5.1.0-beta.1 5.1.0-rc.1 trunk 5.1.1 10.0.0 5.1.2 10.0.0-rc.1 5.1.3 10.0.0-rc.2 5.2.0 10.0.1 5.2.0-beta.1 10.0.2 5.2.0-rc.1 10.0.3 5.2.0-rc.2 10.0.4 5.2.1 10.0.5 5.2.2 10.0.6 5.2.3 10.1.0 5.2.4 10.1.0-rc.1 5.2.5 10.1.0-rc.2 5.3.0 10.1.0-rc.3 5.3.0-beta.1 10.1.0-rc.4 5.3.0-rc.1 10.1.1 5.3.0-rc.2 10.1.2 5.3.1 10.1.3 5.3.2 10.1.4 5.3.3 10.2.0 5.4.0 10.2.0-beta.1 5.4.0-beta.1 10.2.0-beta.2 5.4.0-rc.1 10.2.0-rc.1 5.4.1 10.2.1 5.4.2 10.2.2 5.4.3 10.2.3 5.4.4 10.2.4 5.4.5 10.3.0 5.5.0 10.3.0-beta.1 5.5.0-beta.1 10.3.0-beta.2 5.5.0-rc.1 10.3.0-rc.1 5.5.0-rc.2 10.3.0-rc.2 5.5.1 10.3.1 5.5.2 10.3.2 5.5.3 10.3.3 5.5.4 10.3.4 5.5.5 10.3.5 5.6.0 10.3.6 5.6.0-beta.1 10.3.7 5.6.0-rc.1 10.3.8 5.6.0-rc.2 10.4.0 5.6.1 10.4.0-beta.1 5.6.2 10.4.0-beta.2 5.6.3 10.4.0-rc.1 5.7.0 10.4.1 5.7.0-beta.1 10.4.2 5.7.0-rc.1 10.4.3 5.7.1 10.4.4 5.7.2 10.5.0 5.7.3 10.5.0-beta.1 5.8.0 10.5.0-beta.2 5.8.0-beta.1 10.5.0-rc.1 5.8.0-beta.2 10.5.0-rc.2 5.8.0-rc.1 10.5.0-rc.3 5.8.1 10.5.1 5.8.2 10.5.2 5.9.0 10.5.3 5.9.0-beta.1 10.6.0 5.9.0-rc.1 10.6.0-beta.1 5.9.0-rc.2 10.6.0-beta.2 5.9.1 10.6.0-rc.1 5.9.2 10.6.1 6.0.0 10.6.2 6.0.0-beta.1 10.7.0 6.0.0-rc.1 10.7.0-beta.1 6.0.1 10.7.0-beta.2 6.0.2 10.7.0-rc.1 6.1.0 3.0.0 6.1.0-beta.1 3.0.1 6.1.0-rc.1 3.0.2 6.1.0-rc.2 3.0.3 6.1.1 3.0.4 6.1.2 3.0.5 6.1.3 3.0.6 6.2.0 3.0.7 6.2.0-beta.1 3.0.8 6.2.0-rc.1 3.0.9 6.2.0-rc.2 3.1.0 6.2.1 3.1.1 6.2.2 3.1.2 6.2.3 3.2.0 6.3.0 3.2.1 6.3.0-beta.1 3.2.2 6.3.0-rc.1 3.2.3 6.3.0-rc.2 3.2.4 6.3.1 3.2.5 6.3.2 3.2.6 6.4.0 3.3.0 6.4.0-beta.1 3.3.1 6.4.0-rc.1 3.3.2 6.4.1 3.3.2-rc.1 6.4.2 3.3.3 6.5.0 3.3.4 6.5.0-beta.1 3.3.5 6.5.0-rc.1 3.3.6 6.5.0-rc.2 3.4.0 6.5.1 3.4.0-beta.1 6.5.2 3.4.0-rc.2 6.6.0 3.4.1 6.6.0-beta.1 3.4.2 6.6.0-rc.1 3.4.3 6.6.0-rc.2 3.4.4 6.6.1 3.4.5 6.6.2 3.4.6 6.7.0 3.4.7 6.7.0-beta.1 3.4.8 6.7.0-beta.2 3.5.0 6.7.0-rc.1 3.5.0-beta.1 6.7.1 3.5.0-rc.1 6.8.0 3.5.0-rc.2 6.8.0-beta.1 3.5.1 6.8.0-beta.2 3.5.10 6.8.0-rc.1 3.5.2 6.8.1 3.5.3 6.8.2 3.5.4 6.8.3 3.5.5 6.9.0 3.5.6 6.9.0-beta.1 3.5.7 6.9.0-beta.2 3.5.8 6.9.0-rc.1 3.5.9 6.9.1 3.6.0 6.9.2 3.6.0-beta.1 6.9.3 3.6.0-rc.1 6.9.4 3.6.0-rc.2 6.9.5 3.6.0-rc.3 7.0.0 3.6.1 7.0.0-beta.1 3.6.2 7.0.0-beta.2 3.6.3 7.0.0-beta.3 3.6.4 7.0.0-rc.1 3.6.5 7.0.0-rc.2 3.6.6 7.0.1 3.6.7 7.0.2 3.7.0 7.1.0 3.7.0-beta.1 7.1.0-beta.1 3.7.0-rc.1 7.1.0-beta.2 3.7.0-rc.2 7.1.0-rc.1 3.7.1 7.1.0-rc.2 3.7.2 7.1.1
woocommerce / includes / export / class-wc-product-csv-exporter.php
woocommerce / includes / export Last commit date
abstract-wc-csv-batch-exporter.php 3 years ago abstract-wc-csv-exporter.php 1 year ago class-wc-product-csv-exporter.php 1 year ago
class-wc-product-csv-exporter.php
800 lines
1 <?php
2 /**
3 * Handles product CSV export.
4 *
5 * @package WooCommerce\Export
6 * @version 3.1.0
7 */
8
9 use Automattic\WooCommerce\Enums\ProductStatus;
10 use Automattic\WooCommerce\Enums\ProductStockStatus;
11 use Automattic\WooCommerce\Enums\ProductType;
12 use Automattic\WooCommerce\Internal\CostOfGoodsSold\CostOfGoodsSoldController;
13 use Automattic\WooCommerce\Utilities\I18nUtil;
14
15 if ( ! defined( 'ABSPATH' ) ) {
16 exit;
17 }
18
19 /**
20 * Include dependencies.
21 */
22 if ( ! class_exists( 'WC_CSV_Batch_Exporter', false ) ) {
23 include_once WC_ABSPATH . 'includes/export/abstract-wc-csv-batch-exporter.php';
24 }
25
26 /**
27 * WC_Product_CSV_Exporter Class.
28 */
29 class WC_Product_CSV_Exporter extends WC_CSV_Batch_Exporter {
30
31 /**
32 * Type of export used in filter names.
33 *
34 * @var string
35 */
36 protected $export_type = 'product';
37
38 /**
39 * Should meta be exported?
40 *
41 * @var boolean
42 */
43 protected $enable_meta_export = false;
44
45 /**
46 * Which product types are being exported.
47 *
48 * @var array
49 */
50 protected $product_types_to_export = array();
51
52 /**
53 * Products belonging to what category should be exported.
54 *
55 * @var array
56 */
57 protected $product_category_to_export = array();
58
59 /**
60 * Specific product IDs to export, overriding other filters if hook is not used.
61 *
62 * @var array
63 */
64 protected $product_ids_to_export = array();
65
66 /**
67 * Constructor.
68 */
69 public function __construct() {
70 parent::__construct();
71 $this->set_product_types_to_export( array_keys( WC_Admin_Exporters::get_product_types() ) );
72 }
73
74 /**
75 * Should meta be exported?
76 *
77 * @param bool $enable_meta_export Should meta be exported.
78 *
79 * @since 3.1.0
80 */
81 public function enable_meta_export( $enable_meta_export ) {
82 $this->enable_meta_export = (bool) $enable_meta_export;
83 }
84
85 /**
86 * Product types to export.
87 *
88 * @param array $product_types_to_export List of types to export.
89 *
90 * @since 3.1.0
91 */
92 public function set_product_types_to_export( $product_types_to_export ) {
93 $this->product_types_to_export = array_map( 'wc_clean', $product_types_to_export );
94 }
95
96 /**
97 * Product category to export
98 *
99 * @param string $product_category_to_export Product category slug to export, empty string exports all.
100 *
101 * @since 3.5.0
102 * @return void
103 */
104 public function set_product_category_to_export( $product_category_to_export ) {
105 $this->product_category_to_export = array_map( 'sanitize_title_with_dashes', $product_category_to_export );
106 }
107
108 /**
109 * Specific product IDs to export.
110 *
111 * @param array $product_ids List of product IDs to export.
112 * @since 9.9.0
113 */
114 public function set_product_ids_to_export( $product_ids ) {
115 $this->product_ids_to_export = array_filter( array_map( 'absint', (array) $product_ids ) );
116 }
117
118 /**
119 * Return an array of columns to export.
120 *
121 * @since 3.1.0
122 * @return array
123 */
124 public function get_default_column_names() {
125 $weight_unit_label = I18nUtil::get_weight_unit_label( get_option( 'woocommerce_weight_unit', 'kg' ) );
126 $dimension_unit_label = I18nUtil::get_dimensions_unit_label( get_option( 'woocommerce_dimension_unit', 'cm' ) );
127
128 $default_columns = array(
129 'id' => __( 'ID', 'woocommerce' ),
130 'type' => __( 'Type', 'woocommerce' ),
131 'sku' => __( 'SKU', 'woocommerce' ),
132 'global_unique_id' => __( 'GTIN, UPC, EAN, or ISBN', 'woocommerce' ),
133 'name' => __( 'Name', 'woocommerce' ),
134 'published' => __( 'Published', 'woocommerce' ),
135 'featured' => __( 'Is featured?', 'woocommerce' ),
136 'catalog_visibility' => __( 'Visibility in catalog', 'woocommerce' ),
137 'short_description' => __( 'Short description', 'woocommerce' ),
138 'description' => __( 'Description', 'woocommerce' ),
139 'date_on_sale_from' => __( 'Date sale price starts', 'woocommerce' ),
140 'date_on_sale_to' => __( 'Date sale price ends', 'woocommerce' ),
141 'tax_status' => __( 'Tax status', 'woocommerce' ),
142 'tax_class' => __( 'Tax class', 'woocommerce' ),
143 'stock_status' => __( 'In stock?', 'woocommerce' ),
144 'stock' => __( 'Stock', 'woocommerce' ),
145 'low_stock_amount' => __( 'Low stock amount', 'woocommerce' ),
146 'backorders' => __( 'Backorders allowed?', 'woocommerce' ),
147 'sold_individually' => __( 'Sold individually?', 'woocommerce' ),
148 /* translators: %s: weight */
149 'weight' => sprintf( __( 'Weight (%s)', 'woocommerce' ), $weight_unit_label ),
150 /* translators: %s: length */
151 'length' => sprintf( __( 'Length (%s)', 'woocommerce' ), $dimension_unit_label ),
152 /* translators: %s: width */
153 'width' => sprintf( __( 'Width (%s)', 'woocommerce' ), $dimension_unit_label ),
154 /* translators: %s: Height */
155 'height' => sprintf( __( 'Height (%s)', 'woocommerce' ), $dimension_unit_label ),
156 'reviews_allowed' => __( 'Allow customer reviews?', 'woocommerce' ),
157 'purchase_note' => __( 'Purchase note', 'woocommerce' ),
158 'sale_price' => __( 'Sale price', 'woocommerce' ),
159 'regular_price' => __( 'Regular price', 'woocommerce' ),
160 'category_ids' => __( 'Categories', 'woocommerce' ),
161 'tag_ids' => __( 'Tags', 'woocommerce' ),
162 'shipping_class_id' => __( 'Shipping class', 'woocommerce' ),
163 'images' => __( 'Images', 'woocommerce' ),
164 'download_limit' => __( 'Download limit', 'woocommerce' ),
165 'download_expiry' => __( 'Download expiry days', 'woocommerce' ),
166 'parent_id' => __( 'Parent', 'woocommerce' ),
167 'grouped_products' => __( 'Grouped products', 'woocommerce' ),
168 'upsell_ids' => __( 'Upsells', 'woocommerce' ),
169 'cross_sell_ids' => __( 'Cross-sells', 'woocommerce' ),
170 'product_url' => __( 'External URL', 'woocommerce' ),
171 'button_text' => __( 'Button text', 'woocommerce' ),
172 'menu_order' => __( 'Position', 'woocommerce' ),
173 );
174
175 if ( wc_get_container()->get( CostOfGoodsSoldController::class )->feature_is_enabled() ) {
176 $default_columns['cogs_value'] = __( 'Cost of goods', 'woocommerce' );
177 }
178
179 return apply_filters(
180 "woocommerce_product_export_{$this->export_type}_default_columns",
181 $default_columns
182 );
183 }
184
185 /**
186 * Prepare data for export.
187 *
188 * @since 3.1.0
189 */
190 public function prepare_data_to_export() {
191 $args = array(
192 'status' => array( ProductStatus::PRIVATE, ProductStatus::PUBLISH, ProductStatus::DRAFT, ProductStatus::FUTURE, ProductStatus::PENDING ),
193 'limit' => $this->get_limit(),
194 'page' => $this->get_page(),
195 'orderby' => array(
196 'ID' => 'ASC',
197 ),
198 'return' => 'objects',
199 'paginate' => true,
200 );
201
202 // Set up query args based on whether specific IDs are being exported.
203 // We ignore type/category initially when specific IDs are provided.
204 if ( ! empty( $this->product_ids_to_export ) ) {
205 $args['include'] = $this->product_ids_to_export;
206 } else {
207 // Use the type and category filters set on the instance.
208 $args['type'] = $this->product_types_to_export;
209 if ( ! empty( $this->product_category_to_export ) ) {
210 $args['category'] = $this->product_category_to_export;
211 }
212 }
213
214 /**
215 * Filter the query args for the product export.
216 *
217 * @since 3.5.0
218 * @param array $args Arguments to pass to wc_get_products().
219 */
220 $args = apply_filters( "woocommerce_product_export_{$this->export_type}_query_args", $args );
221
222 if ( ! empty( $args['include'] ) ) {
223 $args['include'] = array_map( 'absint', (array) $args['include'] );
224 }
225
226 $products = wc_get_products( $args );
227
228 $this->total_rows = $products->total;
229 $this->row_data = array();
230 $variable_products = array();
231
232 foreach ( $products->products as $product ) {
233 // Check if the product is variable and if either the include or category filter is active.
234 // This is to ensure that product variations are only included if they are being selectively exported or if they are part of a category.
235 if ( ( ! empty( $args['include'] ) || ! empty( $args['category'] ) ) &&
236 $product->is_type( ProductType::VARIABLE ) &&
237 ! in_array( $product->get_id(), $variable_products, true ) ) {
238 $variable_products[] = $product->get_id();
239 }
240
241 $this->row_data[] = $this->generate_row_data( $product );
242 }
243
244 // If variable products were identified (either through include or category filters), fetch their variations.
245 if ( ! empty( $variable_products ) ) {
246 foreach ( $variable_products as $parent_id ) {
247 $products = wc_get_products(
248 array(
249 'parent' => $parent_id,
250 'type' => array( ProductType::VARIATION ),
251 'return' => 'objects',
252 'limit' => -1,
253 )
254 );
255
256 if ( ! $products ) {
257 continue;
258 }
259
260 foreach ( $products as $product ) {
261 $this->row_data[] = $this->generate_row_data( $product );
262 }
263 }
264 }
265 }
266
267 /**
268 * Take a product and generate row data from it for export.
269 *
270 * @param WC_Product $product WC_Product object.
271 *
272 * @return array
273 */
274 protected function generate_row_data( $product ) {
275 $columns = $this->get_column_names();
276 $row = array();
277 foreach ( $columns as $column_id => $column_name ) {
278 $column_id = strstr( $column_id, ':' ) ? current( explode( ':', $column_id ) ) : $column_id;
279 $value = '';
280
281 // Skip some columns if dynamically handled later or if we're being selective.
282 if ( in_array( $column_id, array( 'downloads', 'attributes', 'meta' ), true ) || ! $this->is_column_exporting( $column_id ) ) {
283 continue;
284 }
285
286 if ( has_filter( "woocommerce_product_export_{$this->export_type}_column_{$column_id}" ) ) {
287 // Filter for 3rd parties.
288 $value = apply_filters( "woocommerce_product_export_{$this->export_type}_column_{$column_id}", '', $product, $column_id );
289
290 } elseif ( is_callable( array( $this, "get_column_value_{$column_id}" ) ) ) {
291 // Handle special columns which don't map 1:1 to product data.
292 $value = $this->{"get_column_value_{$column_id}"}( $product );
293
294 } elseif ( is_callable( array( $product, "get_{$column_id}" ) ) ) {
295 // Default and custom handling.
296 $value = $product->{"get_{$column_id}"}( 'edit' );
297 }
298
299 if ( 'description' === $column_id || 'short_description' === $column_id ) {
300 $value = $this->filter_description_field( $value );
301 }
302
303 $row[ $column_id ] = $value;
304 }
305
306 $this->prepare_downloads_for_export( $product, $row );
307 $this->prepare_attributes_for_export( $product, $row );
308 $this->prepare_meta_for_export( $product, $row );
309
310 /**
311 * Allow third-party plugins to filter the data in a single row of the exported CSV file.
312 *
313 * @since 3.1.0
314 *
315 * @param array $row An associative array with the data of a single row in the CSV file.
316 * @param WC_Product $product The product object corresponding to the current row.
317 * @param WC_Product_CSV_Exporter $exporter The instance of the CSV exporter.
318 */
319 return apply_filters( 'woocommerce_product_export_row_data', $row, $product, $this );
320 }
321
322 /**
323 * Get published value.
324 *
325 * @param WC_Product $product Product being exported.
326 *
327 * @since 3.1.0
328 * @return int
329 */
330 protected function get_column_value_published( $product ) {
331 $statuses = array(
332 ProductStatus::DRAFT => -1,
333 ProductStatus::PRIVATE => 0,
334 ProductStatus::PUBLISH => 1,
335 );
336
337 // Fix display for variations when parent product is a draft.
338 if ( ProductType::VARIATION === $product->get_type() ) {
339 $parent = $product->get_parent_data();
340 $status = ProductStatus::DRAFT === $parent['status'] ? $parent['status'] : $product->get_status( 'edit' );
341 } else {
342 $status = $product->get_status( 'edit' );
343 }
344
345 return isset( $statuses[ $status ] ) ? $statuses[ $status ] : -1;
346 }
347
348 /**
349 * Get formatted sale price.
350 *
351 * @param WC_Product $product Product being exported.
352 *
353 * @return string
354 */
355 protected function get_column_value_sale_price( $product ) {
356 return wc_format_localized_price( $product->get_sale_price( 'view' ) );
357 }
358
359 /**
360 * Get formatted regular price.
361 *
362 * @param WC_Product $product Product being exported.
363 *
364 * @return string
365 */
366 protected function get_column_value_regular_price( $product ) {
367 return wc_format_localized_price( $product->get_regular_price() );
368 }
369
370 /**
371 * Get product_cat value.
372 *
373 * @param WC_Product $product Product being exported.
374 *
375 * @since 3.1.0
376 * @return string
377 */
378 protected function get_column_value_category_ids( $product ) {
379 $term_ids = $product->get_category_ids( 'edit' );
380 return $this->format_term_ids( $term_ids, 'product_cat' );
381 }
382
383 /**
384 * Get product_tag value.
385 *
386 * @param WC_Product $product Product being exported.
387 *
388 * @since 3.1.0
389 * @return string
390 */
391 protected function get_column_value_tag_ids( $product ) {
392 $term_ids = $product->get_tag_ids( 'edit' );
393 return $this->format_term_ids( $term_ids, 'product_tag' );
394 }
395
396 /**
397 * Get product_shipping_class value.
398 *
399 * @param WC_Product $product Product being exported.
400 *
401 * @since 3.1.0
402 * @return string
403 */
404 protected function get_column_value_shipping_class_id( $product ) {
405 $term_ids = $product->get_shipping_class_id( 'edit' );
406 return $this->format_term_ids( $term_ids, 'product_shipping_class' );
407 }
408
409 /**
410 * Get images value.
411 *
412 * @param WC_Product $product Product being exported.
413 *
414 * @since 3.1.0
415 * @return string
416 */
417 protected function get_column_value_images( $product ) {
418 $image_ids = array_merge( array( $product->get_image_id( 'edit' ) ), $product->get_gallery_image_ids( 'edit' ) );
419 $images = array();
420
421 foreach ( $image_ids as $image_id ) {
422 $image = wp_get_attachment_image_src( $image_id, 'full' );
423
424 if ( $image ) {
425 $images[] = $image[0];
426 }
427 }
428
429 return $this->implode_values( $images );
430 }
431
432 /**
433 * Prepare linked products for export.
434 *
435 * @param int[] $linked_products Array of linked product ids.
436 *
437 * @since 3.1.0
438 * @return string
439 */
440 protected function prepare_linked_products_for_export( $linked_products ) {
441 $product_list = array();
442
443 foreach ( $linked_products as $linked_product ) {
444 if ( $linked_product->get_sku() ) {
445 $product_list[] = $linked_product->get_sku();
446 } else {
447 $product_list[] = 'id:' . $linked_product->get_id();
448 }
449 }
450
451 return $this->implode_values( $product_list );
452 }
453
454 /**
455 * Get cross_sell_ids value.
456 *
457 * @param WC_Product $product Product being exported.
458 *
459 * @since 3.1.0
460 * @return string
461 */
462 protected function get_column_value_cross_sell_ids( $product ) {
463 return $this->prepare_linked_products_for_export( array_filter( array_map( 'wc_get_product', (array) $product->get_cross_sell_ids( 'edit' ) ) ) );
464 }
465
466 /**
467 * Get upsell_ids value.
468 *
469 * @param WC_Product $product Product being exported.
470 *
471 * @since 3.1.0
472 * @return string
473 */
474 protected function get_column_value_upsell_ids( $product ) {
475 return $this->prepare_linked_products_for_export( array_filter( array_map( 'wc_get_product', (array) $product->get_upsell_ids( 'edit' ) ) ) );
476 }
477
478 /**
479 * Get parent_id value.
480 *
481 * @param WC_Product $product Product being exported.
482 *
483 * @since 3.1.0
484 * @return string
485 */
486 protected function get_column_value_parent_id( $product ) {
487 if ( $product->get_parent_id( 'edit' ) ) {
488 $parent = wc_get_product( $product->get_parent_id( 'edit' ) );
489 if ( ! $parent ) {
490 return '';
491 }
492
493 return $parent->get_sku( 'edit' ) ? $parent->get_sku( 'edit' ) : 'id:' . $parent->get_id();
494 }
495 return '';
496 }
497
498 /**
499 * Get grouped_products value.
500 *
501 * @param WC_Product $product Product being exported.
502 *
503 * @since 3.1.0
504 * @return string
505 */
506 protected function get_column_value_grouped_products( $product ) {
507 if ( ProductType::GROUPED !== $product->get_type() ) {
508 return '';
509 }
510
511 $grouped_products = array();
512 $child_ids = $product->get_children( 'edit' );
513 foreach ( $child_ids as $child_id ) {
514 $child = wc_get_product( $child_id );
515 if ( ! $child ) {
516 continue;
517 }
518
519 $grouped_products[] = $child->get_sku( 'edit' ) ? $child->get_sku( 'edit' ) : 'id:' . $child_id;
520 }
521 return $this->implode_values( $grouped_products );
522 }
523
524 /**
525 * Get download_limit value.
526 *
527 * @param WC_Product $product Product being exported.
528 *
529 * @since 3.1.0
530 * @return string
531 */
532 protected function get_column_value_download_limit( $product ) {
533 return $product->is_downloadable() && $product->get_download_limit( 'edit' ) ? $product->get_download_limit( 'edit' ) : '';
534 }
535
536 /**
537 * Get download_expiry value.
538 *
539 * @param WC_Product $product Product being exported.
540 *
541 * @since 3.1.0
542 * @return string
543 */
544 protected function get_column_value_download_expiry( $product ) {
545 return $product->is_downloadable() && $product->get_download_expiry( 'edit' ) ? $product->get_download_expiry( 'edit' ) : '';
546 }
547
548 /**
549 * Get stock value.
550 *
551 * @param WC_Product $product Product being exported.
552 *
553 * @since 3.1.0
554 * @return string
555 */
556 protected function get_column_value_stock( $product ) {
557 $manage_stock = $product->get_manage_stock( 'edit' );
558 $stock_quantity = $product->get_stock_quantity( 'edit' );
559
560 if ( $product->is_type( ProductType::VARIATION ) && 'parent' === $manage_stock ) {
561 return 'parent';
562 } elseif ( $manage_stock ) {
563 return $stock_quantity;
564 } else {
565 return '';
566 }
567 }
568
569 /**
570 * Get stock status value.
571 *
572 * @param WC_Product $product Product being exported.
573 *
574 * @since 3.1.0
575 * @return string
576 */
577 protected function get_column_value_stock_status( $product ) {
578 $status = $product->get_stock_status( 'edit' );
579
580 if ( ProductStockStatus::ON_BACKORDER === $status ) {
581 return 'backorder';
582 }
583
584 return ProductStockStatus::IN_STOCK === $status ? 1 : 0;
585 }
586
587 /**
588 * Get backorders.
589 *
590 * @param WC_Product $product Product being exported.
591 *
592 * @since 3.1.0
593 * @return string
594 */
595 protected function get_column_value_backorders( $product ) {
596 $backorders = $product->get_backorders( 'edit' );
597
598 switch ( $backorders ) {
599 case 'notify':
600 return 'notify';
601 default:
602 return wc_string_to_bool( $backorders ) ? 1 : 0;
603 }
604 }
605
606 /**
607 * Get low stock amount value.
608 *
609 * @param WC_Product $product Product being exported.
610 *
611 * @since 3.5.0
612 * @return int|string Empty string if value not set
613 */
614 protected function get_column_value_low_stock_amount( $product ) {
615 return $product->managing_stock() && $product->get_low_stock_amount( 'edit' ) ? $product->get_low_stock_amount( 'edit' ) : '';
616 }
617
618 /**
619 * Get type value.
620 *
621 * @param WC_Product $product Product being exported.
622 *
623 * @since 3.1.0
624 * @return string
625 */
626 protected function get_column_value_type( $product ) {
627 $types = array();
628 $types[] = $product->get_type();
629
630 if ( $product->is_downloadable() ) {
631 $types[] = 'downloadable';
632 }
633
634 if ( $product->is_virtual() ) {
635 $types[] = 'virtual';
636 }
637
638 return $this->implode_values( $types );
639 }
640
641 /**
642 * Filter description field for export.
643 * Convert newlines to '\n'.
644 *
645 * @param string $description Product description text to filter.
646 *
647 * @since 3.5.4
648 * @return string
649 */
650 protected function filter_description_field( $description ) {
651 $description = str_replace( '\n', "\\\\n", $description );
652 $description = str_replace( "\n", '\n', $description );
653 return $description;
654 }
655 /**
656 * Export downloads.
657 *
658 * @param WC_Product $product Product being exported.
659 * @param array $row Row being exported.
660 *
661 * @since 3.1.0
662 */
663 protected function prepare_downloads_for_export( $product, &$row ) {
664 if ( $product->is_downloadable() && $this->is_column_exporting( 'downloads' ) ) {
665 $downloads = $product->get_downloads( 'edit' );
666
667 if ( $downloads ) {
668 $i = 1;
669 foreach ( $downloads as $download ) {
670 /* translators: %s: download number */
671 $this->column_names[ 'downloads:id' . $i ] = sprintf( __( 'Download %d ID', 'woocommerce' ), $i );
672 /* translators: %s: download number */
673 $this->column_names[ 'downloads:name' . $i ] = sprintf( __( 'Download %d name', 'woocommerce' ), $i );
674 /* translators: %s: download number */
675 $this->column_names[ 'downloads:url' . $i ] = sprintf( __( 'Download %d URL', 'woocommerce' ), $i );
676 $row[ 'downloads:id' . $i ] = $download->get_id();
677 $row[ 'downloads:name' . $i ] = $download->get_name();
678 $row[ 'downloads:url' . $i ] = $download->get_file();
679 ++$i;
680 }
681 }
682 }
683 }
684
685 /**
686 * Export attributes data.
687 *
688 * @param WC_Product $product Product being exported.
689 * @param array $row Row being exported.
690 *
691 * @since 3.1.0
692 */
693 protected function prepare_attributes_for_export( $product, &$row ) {
694 if ( $this->is_column_exporting( 'attributes' ) ) {
695 $attributes = $product->get_attributes();
696 $default_attributes = $product->get_default_attributes();
697
698 if ( count( $attributes ) ) {
699 $i = 1;
700 foreach ( $attributes as $attribute_name => $attribute ) {
701 /* translators: %s: attribute number */
702 $this->column_names[ 'attributes:name' . $i ] = sprintf( __( 'Attribute %d name', 'woocommerce' ), $i );
703 /* translators: %s: attribute number */
704 $this->column_names[ 'attributes:value' . $i ] = sprintf( __( 'Attribute %d value(s)', 'woocommerce' ), $i );
705 /* translators: %s: attribute number */
706 $this->column_names[ 'attributes:visible' . $i ] = sprintf( __( 'Attribute %d visible', 'woocommerce' ), $i );
707 /* translators: %s: attribute number */
708 $this->column_names[ 'attributes:taxonomy' . $i ] = sprintf( __( 'Attribute %d global', 'woocommerce' ), $i );
709
710 if ( is_a( $attribute, 'WC_Product_Attribute' ) ) {
711 $row[ 'attributes:name' . $i ] = html_entity_decode( wc_attribute_label( $attribute->get_name(), $product ), ENT_QUOTES );
712
713 if ( $attribute->is_taxonomy() ) {
714 $terms = $attribute->get_terms();
715 $values = array();
716
717 foreach ( $terms as $term ) {
718 $values[] = $term->name;
719 }
720
721 $row[ 'attributes:value' . $i ] = $this->implode_values( $values );
722 $row[ 'attributes:taxonomy' . $i ] = 1;
723 } else {
724 $row[ 'attributes:value' . $i ] = $this->implode_values( $attribute->get_options() );
725 $row[ 'attributes:taxonomy' . $i ] = 0;
726 }
727
728 $row[ 'attributes:visible' . $i ] = $attribute->get_visible();
729 } else {
730 $row[ 'attributes:name' . $i ] = html_entity_decode( wc_attribute_label( $attribute_name, $product ), ENT_QUOTES );
731
732 if ( 0 === strpos( $attribute_name, 'pa_' ) ) {
733 $option_term = get_term_by( 'slug', $attribute, $attribute_name ); // @codingStandardsIgnoreLine.
734 $row[ 'attributes:value' . $i ] = $option_term && ! is_wp_error( $option_term ) ? html_entity_decode( str_replace( ',', '\\,', $option_term->name ), ENT_QUOTES ) : html_entity_decode( str_replace( ',', '\\,', $attribute ), ENT_QUOTES );
735 $row[ 'attributes:taxonomy' . $i ] = 1;
736 } else {
737 $row[ 'attributes:value' . $i ] = html_entity_decode( str_replace( ',', '\\,', $attribute ), ENT_QUOTES );
738 $row[ 'attributes:taxonomy' . $i ] = 0;
739 }
740
741 $row[ 'attributes:visible' . $i ] = '';
742 }
743
744 if ( $product->is_type( ProductType::VARIABLE ) && isset( $default_attributes[ sanitize_title( $attribute_name ) ] ) ) {
745 /* translators: %s: attribute number */
746 $this->column_names[ 'attributes:default' . $i ] = sprintf( __( 'Attribute %d default', 'woocommerce' ), $i );
747 $default_value = $default_attributes[ sanitize_title( $attribute_name ) ];
748
749 if ( 0 === strpos( $attribute_name, 'pa_' ) ) {
750 $option_term = get_term_by( 'slug', $default_value, $attribute_name ); // @codingStandardsIgnoreLine.
751 $row[ 'attributes:default' . $i ] = $option_term && ! is_wp_error( $option_term ) ? $option_term->name : $default_value;
752 } else {
753 $row[ 'attributes:default' . $i ] = $default_value;
754 }
755 }
756 ++$i;
757 }
758 }
759 }
760 }
761
762 /**
763 * Export meta data.
764 *
765 * @param WC_Product $product Product being exported.
766 * @param array $row Row data.
767 *
768 * @since 3.1.0
769 */
770 protected function prepare_meta_for_export( $product, &$row ) {
771 if ( $this->enable_meta_export ) {
772 $meta_data = $product->get_meta_data();
773
774 if ( count( $meta_data ) ) {
775 $meta_keys_to_skip = apply_filters( 'woocommerce_product_export_skip_meta_keys', array(), $product );
776
777 $i = 1;
778 foreach ( $meta_data as $meta ) {
779 if ( in_array( $meta->key, $meta_keys_to_skip, true ) ) {
780 continue;
781 }
782
783 // Allow 3rd parties to process the meta, e.g. to transform non-scalar values to scalar.
784 $meta_value = apply_filters( 'woocommerce_product_export_meta_value', $meta->value, $meta, $product, $row );
785
786 if ( ! is_scalar( $meta_value ) ) {
787 continue;
788 }
789
790 $column_key = 'meta:' . esc_attr( $meta->key );
791 /* translators: %s: meta data name */
792 $this->column_names[ $column_key ] = sprintf( __( 'Meta: %s', 'woocommerce' ), $meta->key );
793 $row[ $column_key ] = $meta_value;
794 ++$i;
795 }
796 }
797 }
798 }
799 }
800