1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* Product Data |
4
|
|
|
* |
5
|
|
|
* Displays the product data box, tabbed, with several panels covering price, stock etc. |
6
|
|
|
* |
7
|
|
|
* @author WooThemes |
8
|
|
|
* @category Admin |
9
|
|
|
* @package WooCommerce/Admin/Meta Boxes |
10
|
|
|
* @version 2.4.0 |
11
|
|
|
*/ |
12
|
|
|
|
13
|
|
|
if ( ! defined( 'ABSPATH' ) ) { |
14
|
|
|
exit; // Exit if accessed directly |
15
|
|
|
} |
16
|
|
|
|
17
|
|
|
/** |
18
|
|
|
* WC_Meta_Box_Product_Data Class. |
19
|
|
|
*/ |
20
|
|
|
class WC_Meta_Box_Product_Data { |
21
|
|
|
|
22
|
|
|
/** |
23
|
|
|
* Output the metabox. |
24
|
|
|
* |
25
|
|
|
* @param WP_Post $post |
26
|
|
|
*/ |
27
|
|
|
public static function output( $post ) { |
28
|
|
|
global $post, $thepostid; |
29
|
|
|
|
30
|
|
|
wp_nonce_field( 'woocommerce_save_data', 'woocommerce_meta_nonce' ); |
31
|
|
|
|
32
|
|
|
$thepostid = $post->ID; |
33
|
|
|
|
34
|
|
|
if ( $terms = wp_get_object_terms( $post->ID, 'product_type' ) ) { |
35
|
|
|
$product_type = sanitize_title( current( $terms )->name ); |
36
|
|
|
} else { |
37
|
|
|
$product_type = apply_filters( 'default_product_type', 'simple' ); |
38
|
|
|
} |
39
|
|
|
|
40
|
|
|
$product_type_selector = apply_filters( 'product_type_selector', array( |
41
|
|
|
'simple' => __( 'Simple product', 'woocommerce' ), |
42
|
|
|
'grouped' => __( 'Grouped product', 'woocommerce' ), |
43
|
|
|
'external' => __( 'External/Affiliate product', 'woocommerce' ), |
44
|
|
|
'variable' => __( 'Variable product', 'woocommerce' ) |
45
|
|
|
), $product_type ); |
46
|
|
|
|
47
|
|
|
$type_box = '<label for="product-type"><select id="product-type" name="product-type"><optgroup label="' . esc_attr__( 'Product Type', 'woocommerce' ) . '">'; |
48
|
|
|
|
49
|
|
|
foreach ( $product_type_selector as $value => $label ) { |
50
|
|
|
$type_box .= '<option value="' . esc_attr( $value ) . '" ' . selected( $product_type, $value, false ) .'>' . esc_html( $label ) . '</option>'; |
51
|
|
|
} |
52
|
|
|
|
53
|
|
|
$type_box .= '</optgroup></select></label>'; |
54
|
|
|
|
55
|
|
|
$product_type_options = apply_filters( 'product_type_options', array( |
56
|
|
|
'virtual' => array( |
57
|
|
|
'id' => '_virtual', |
58
|
|
|
'wrapper_class' => 'show_if_simple', |
59
|
|
|
'label' => __( 'Virtual', 'woocommerce' ), |
60
|
|
|
'description' => __( 'Virtual products are intangible and aren\'t shipped.', 'woocommerce' ), |
61
|
|
|
'default' => 'no' |
62
|
|
|
), |
63
|
|
|
'downloadable' => array( |
64
|
|
|
'id' => '_downloadable', |
65
|
|
|
'wrapper_class' => 'show_if_simple', |
66
|
|
|
'label' => __( 'Downloadable', 'woocommerce' ), |
67
|
|
|
'description' => __( 'Downloadable products give access to a file upon purchase.', 'woocommerce' ), |
68
|
|
|
'default' => 'no' |
69
|
|
|
) |
70
|
|
|
) ); |
71
|
|
|
|
72
|
|
|
foreach ( $product_type_options as $key => $option ) { |
73
|
|
|
$selected_value = get_post_meta( $post->ID, '_' . $key, true ); |
74
|
|
|
|
75
|
|
|
if ( '' == $selected_value && isset( $option['default'] ) ) { |
76
|
|
|
$selected_value = $option['default']; |
77
|
|
|
} |
78
|
|
|
|
79
|
|
|
$type_box .= '<label for="' . esc_attr( $option['id'] ) . '" class="'. esc_attr( $option['wrapper_class'] ) . ' tips" data-tip="' . esc_attr( $option['description'] ) . '">' . esc_html( $option['label'] ) . ': <input type="checkbox" name="' . esc_attr( $option['id'] ) . '" id="' . esc_attr( $option['id'] ) . '" ' . checked( $selected_value, 'yes', false ) .' /></label>'; |
80
|
|
|
} |
81
|
|
|
|
82
|
|
|
?> |
83
|
|
|
<div class="panel-wrap product_data"> |
84
|
|
|
|
85
|
|
|
<span class="type_box hidden"> — <?php echo $type_box; ?></span> |
86
|
|
|
|
87
|
|
|
<ul class="product_data_tabs wc-tabs"> |
88
|
|
|
<?php |
89
|
|
|
$product_data_tabs = apply_filters( 'woocommerce_product_data_tabs', array( |
90
|
|
|
'general' => array( |
91
|
|
|
'label' => __( 'General', 'woocommerce' ), |
92
|
|
|
'target' => 'general_product_data', |
93
|
|
|
'class' => array( 'hide_if_grouped' ), |
94
|
|
|
), |
95
|
|
|
'inventory' => array( |
96
|
|
|
'label' => __( 'Inventory', 'woocommerce' ), |
97
|
|
|
'target' => 'inventory_product_data', |
98
|
|
|
'class' => array( 'show_if_simple', 'show_if_variable', 'show_if_grouped' ), |
99
|
|
|
), |
100
|
|
|
'shipping' => array( |
101
|
|
|
'label' => __( 'Shipping', 'woocommerce' ), |
102
|
|
|
'target' => 'shipping_product_data', |
103
|
|
|
'class' => array( 'hide_if_virtual', 'hide_if_grouped', 'hide_if_external' ), |
104
|
|
|
), |
105
|
|
|
'linked_product' => array( |
106
|
|
|
'label' => __( 'Linked Products', 'woocommerce' ), |
107
|
|
|
'target' => 'linked_product_data', |
108
|
|
|
'class' => array(), |
109
|
|
|
), |
110
|
|
|
'attribute' => array( |
111
|
|
|
'label' => __( 'Attributes', 'woocommerce' ), |
112
|
|
|
'target' => 'product_attributes', |
113
|
|
|
'class' => array(), |
114
|
|
|
), |
115
|
|
|
'variations' => array( |
116
|
|
|
'label' => __( 'Variations', 'woocommerce' ), |
117
|
|
|
'target' => 'variable_product_options', |
118
|
|
|
'class' => array( 'variations_tab', 'show_if_variable' ), |
119
|
|
|
), |
120
|
|
|
'advanced' => array( |
121
|
|
|
'label' => __( 'Advanced', 'woocommerce' ), |
122
|
|
|
'target' => 'advanced_product_data', |
123
|
|
|
'class' => array(), |
124
|
|
|
) |
125
|
|
|
) ); |
126
|
|
|
|
127
|
|
View Code Duplication |
foreach ( $product_data_tabs as $key => $tab ) { |
|
|
|
|
128
|
|
|
?><li class="<?php echo $key; ?>_options <?php echo $key; ?>_tab <?php echo implode( ' ' , $tab['class'] ); ?>"> |
129
|
|
|
<a href="#<?php echo $tab['target']; ?>"><?php echo esc_html( $tab['label'] ); ?></a> |
130
|
|
|
</li><?php |
131
|
|
|
} |
132
|
|
|
|
133
|
|
|
do_action( 'woocommerce_product_write_panel_tabs' ); |
134
|
|
|
?> |
135
|
|
|
</ul> |
136
|
|
|
<div id="general_product_data" class="panel woocommerce_options_panel"><?php |
137
|
|
|
|
138
|
|
|
echo '<div class="options_group show_if_external">'; |
139
|
|
|
|
140
|
|
|
// External URL |
141
|
|
|
woocommerce_wp_text_input( array( 'id' => '_product_url', 'label' => __( 'Product URL', 'woocommerce' ), 'placeholder' => 'http://', 'description' => __( 'Enter the external URL to the product.', 'woocommerce' ) ) ); |
142
|
|
|
|
143
|
|
|
// Button text |
144
|
|
|
woocommerce_wp_text_input( array( 'id' => '_button_text', 'label' => __( 'Button text', 'woocommerce' ), 'placeholder' => _x('Buy product', 'placeholder', 'woocommerce'), 'description' => __( 'This text will be shown on the button linking to the external product.', 'woocommerce' ) ) ); |
145
|
|
|
|
146
|
|
|
echo '</div>'; |
147
|
|
|
|
148
|
|
|
echo '<div class="options_group pricing show_if_simple show_if_external hidden">'; |
149
|
|
|
|
150
|
|
|
// Price |
151
|
|
|
woocommerce_wp_text_input( array( 'id' => '_regular_price', 'label' => __( 'Regular price', 'woocommerce' ) . ' (' . get_woocommerce_currency_symbol() . ')', 'data_type' => 'price' ) ); |
152
|
|
|
|
153
|
|
|
// Special Price |
154
|
|
|
woocommerce_wp_text_input( array( 'id' => '_sale_price', 'data_type' => 'price', 'label' => __( 'Sale price', 'woocommerce' ) . ' ('.get_woocommerce_currency_symbol().')', 'description' => '<a href="#" class="sale_schedule">' . __( 'Schedule', 'woocommerce' ) . '</a>' ) ); |
155
|
|
|
|
156
|
|
|
// Special Price date range |
157
|
|
|
$sale_price_dates_from = ( $date = get_post_meta( $thepostid, '_sale_price_dates_from', true ) ) ? date_i18n( 'Y-m-d', $date ) : ''; |
158
|
|
|
$sale_price_dates_to = ( $date = get_post_meta( $thepostid, '_sale_price_dates_to', true ) ) ? date_i18n( 'Y-m-d', $date ) : ''; |
159
|
|
|
|
160
|
|
|
echo '<p class="form-field sale_price_dates_fields"> |
161
|
|
|
<label for="_sale_price_dates_from">' . __( 'Sale price dates', 'woocommerce' ) . '</label> |
162
|
|
|
<input type="text" class="short" name="_sale_price_dates_from" id="_sale_price_dates_from" value="' . esc_attr( $sale_price_dates_from ) . '" placeholder="' . _x( 'From…', 'placeholder', 'woocommerce' ) . ' YYYY-MM-DD" maxlength="10" pattern="[0-9]{4}-(0[1-9]|1[012])-(0[1-9]|1[0-9]|2[0-9]|3[01])" /> |
163
|
|
|
<input type="text" class="short" name="_sale_price_dates_to" id="_sale_price_dates_to" value="' . esc_attr( $sale_price_dates_to ) . '" placeholder="' . _x( 'To…', 'placeholder', 'woocommerce' ) . ' YYYY-MM-DD" maxlength="10" pattern="[0-9]{4}-(0[1-9]|1[012])-(0[1-9]|1[0-9]|2[0-9]|3[01])" /> |
164
|
|
|
<a href="#" class="cancel_sale_schedule">'. __( 'Cancel', 'woocommerce' ) . '</a>' . wc_help_tip( __( 'The sale will end at the beginning of the set date.', 'woocommerce' ) ) . ' |
165
|
|
|
</p>'; |
166
|
|
|
|
167
|
|
|
do_action( 'woocommerce_product_options_pricing' ); |
168
|
|
|
|
169
|
|
|
echo '</div>'; |
170
|
|
|
|
171
|
|
|
echo '<div class="options_group show_if_downloadable hidden">'; |
172
|
|
|
|
173
|
|
|
?> |
174
|
|
|
<div class="form-field downloadable_files"> |
175
|
|
|
<label><?php _e( 'Downloadable files', 'woocommerce' ); ?></label> |
176
|
|
|
<table class="widefat"> |
177
|
|
|
<thead> |
178
|
|
|
<tr> |
179
|
|
|
<th class="sort"> </th> |
180
|
|
|
<th><?php _e( 'Name', 'woocommerce' ); ?> <?php echo wc_help_tip( __( 'This is the name of the download shown to the customer.', 'woocommerce' ) ); ?></th> |
181
|
|
|
<th colspan="2"><?php _e( 'File URL', 'woocommerce' ); ?> <?php echo wc_help_tip( __( 'This is the URL or absolute path to the file which customers will get access to. URLs entered here should already be encoded.', 'woocommerce' ) ); ?></th> |
182
|
|
|
<th> </th> |
183
|
|
|
</tr> |
184
|
|
|
</thead> |
185
|
|
|
<tbody> |
186
|
|
|
<?php |
187
|
|
|
$downloadable_files = get_post_meta( $post->ID, '_downloadable_files', true ); |
188
|
|
|
|
189
|
|
|
if ( $downloadable_files ) { |
190
|
|
|
foreach ( $downloadable_files as $key => $file ) { |
191
|
|
|
include( 'views/html-product-download.php' ); |
192
|
|
|
} |
193
|
|
|
} |
194
|
|
|
?> |
195
|
|
|
</tbody> |
196
|
|
|
<tfoot> |
197
|
|
|
<tr> |
198
|
|
|
<th colspan="5"> |
199
|
|
|
<a href="#" class="button insert" data-row="<?php |
200
|
|
|
$file = array( |
201
|
|
|
'file' => '', |
202
|
|
|
'name' => '' |
203
|
|
|
); |
204
|
|
|
ob_start(); |
205
|
|
|
include( 'views/html-product-download.php' ); |
206
|
|
|
echo esc_attr( ob_get_clean() ); |
207
|
|
|
?>"><?php _e( 'Add File', 'woocommerce' ); ?></a> |
208
|
|
|
</th> |
209
|
|
|
</tr> |
210
|
|
|
</tfoot> |
211
|
|
|
</table> |
212
|
|
|
</div> |
213
|
|
|
<?php |
214
|
|
|
|
215
|
|
|
// Download Limit |
216
|
|
|
woocommerce_wp_text_input( array( 'id' => '_download_limit', 'label' => __( 'Download limit', 'woocommerce' ), 'placeholder' => __( 'Unlimited', 'woocommerce' ), 'description' => __( 'Leave blank for unlimited re-downloads.', 'woocommerce' ), 'type' => 'number', 'custom_attributes' => array( |
217
|
|
|
'step' => '1', |
218
|
|
|
'min' => '0' |
219
|
|
|
) ) ); |
220
|
|
|
|
221
|
|
|
// Expirey |
222
|
|
|
woocommerce_wp_text_input( array( 'id' => '_download_expiry', 'label' => __( 'Download expiry', 'woocommerce' ), 'placeholder' => __( 'Never', 'woocommerce' ), 'description' => __( 'Enter the number of days before a download link expires, or leave blank.', 'woocommerce' ), 'type' => 'number', 'custom_attributes' => array( |
223
|
|
|
'step' => '1', |
224
|
|
|
'min' => '0' |
225
|
|
|
) ) ); |
226
|
|
|
|
227
|
|
|
// Download Type |
228
|
|
|
woocommerce_wp_select( array( 'id' => '_download_type', 'label' => __( 'Download type', 'woocommerce' ), 'description' => sprintf( __( 'Choose a download type - this controls the <a href="%s">schema</a>.', 'woocommerce' ), 'http://schema.org/' ), 'options' => array( |
229
|
|
|
'' => __( 'Standard Product', 'woocommerce' ), |
230
|
|
|
'application' => __( 'Application/Software', 'woocommerce' ), |
231
|
|
|
'music' => __( 'Music', 'woocommerce' ), |
232
|
|
|
) ) ); |
233
|
|
|
|
234
|
|
|
do_action( 'woocommerce_product_options_downloads' ); |
235
|
|
|
|
236
|
|
|
echo '</div>'; |
237
|
|
|
|
238
|
|
|
if ( wc_tax_enabled() ) { |
239
|
|
|
|
240
|
|
|
echo '<div class="options_group show_if_simple show_if_external show_if_variable">'; |
241
|
|
|
|
242
|
|
|
// Tax |
243
|
|
|
woocommerce_wp_select( array( |
244
|
|
|
'id' => '_tax_status', |
245
|
|
|
'label' => __( 'Tax status', 'woocommerce' ), |
246
|
|
|
'options' => array( |
247
|
|
|
'taxable' => __( 'Taxable', 'woocommerce' ), |
248
|
|
|
'shipping' => __( 'Shipping only', 'woocommerce' ), |
249
|
|
|
'none' => _x( 'None', 'Tax status', 'woocommerce' ) |
250
|
|
|
), |
251
|
|
|
'desc_tip' => 'true', |
252
|
|
|
'description' => __( 'Define whether or not the entire product is taxable, or just the cost of shipping it.', 'woocommerce' ) |
253
|
|
|
) ); |
254
|
|
|
|
255
|
|
|
$tax_classes = WC_Tax::get_tax_classes(); |
256
|
|
|
$classes_options = array(); |
257
|
|
|
$classes_options[''] = __( 'Standard', 'woocommerce' ); |
258
|
|
|
|
259
|
|
|
if ( ! empty( $tax_classes ) ) { |
260
|
|
|
foreach ( $tax_classes as $class ) { |
261
|
|
|
$classes_options[ sanitize_title( $class ) ] = esc_html( $class ); |
262
|
|
|
} |
263
|
|
|
} |
264
|
|
|
|
265
|
|
|
woocommerce_wp_select( array( |
266
|
|
|
'id' => '_tax_class', |
267
|
|
|
'label' => __( 'Tax class', 'woocommerce' ), |
268
|
|
|
'options' => $classes_options, |
269
|
|
|
'desc_tip' => 'true', |
270
|
|
|
'description' => __( 'Choose a tax class for this product. Tax classes are used to apply different tax rates specific to certain types of product.', 'woocommerce' ) |
271
|
|
|
) ); |
272
|
|
|
|
273
|
|
|
do_action( 'woocommerce_product_options_tax' ); |
274
|
|
|
|
275
|
|
|
echo '</div>'; |
276
|
|
|
|
277
|
|
|
} |
278
|
|
|
|
279
|
|
|
do_action( 'woocommerce_product_options_general_product_data' ); |
280
|
|
|
?> |
281
|
|
|
</div> |
282
|
|
|
|
283
|
|
|
<div id="inventory_product_data" class="panel woocommerce_options_panel hidden"> |
284
|
|
|
|
285
|
|
|
<?php |
286
|
|
|
|
287
|
|
|
echo '<div class="options_group">'; |
288
|
|
|
|
289
|
|
|
// SKU |
290
|
|
|
if ( wc_product_sku_enabled() ) { |
291
|
|
|
woocommerce_wp_text_input( array( 'id' => '_sku', 'label' => '<abbr title="'. __( 'Stock Keeping Unit', 'woocommerce' ) .'">' . __( 'SKU', 'woocommerce' ) . '</abbr>', 'desc_tip' => 'true', 'description' => __( 'SKU refers to a Stock-keeping unit, a unique identifier for each distinct product and service that can be purchased.', 'woocommerce' ) ) ); |
292
|
|
|
} else { |
293
|
|
|
echo '<input type="hidden" name="_sku" value="' . esc_attr( get_post_meta( $thepostid, '_sku', true ) ) . '" />'; |
294
|
|
|
} |
295
|
|
|
|
296
|
|
|
do_action( 'woocommerce_product_options_sku' ); |
297
|
|
|
|
298
|
|
|
if ( 'yes' === get_option( 'woocommerce_manage_stock' ) ) { |
299
|
|
|
|
300
|
|
|
// manage stock |
301
|
|
|
woocommerce_wp_checkbox( array( 'id' => '_manage_stock', 'wrapper_class' => 'show_if_simple show_if_variable', 'label' => __( 'Manage stock?', 'woocommerce' ), 'description' => __( 'Enable stock management at product level', 'woocommerce' ) ) ); |
302
|
|
|
|
303
|
|
|
do_action( 'woocommerce_product_options_stock' ); |
304
|
|
|
|
305
|
|
|
echo '<div class="stock_fields show_if_simple show_if_variable">'; |
306
|
|
|
|
307
|
|
|
// Stock |
308
|
|
|
woocommerce_wp_text_input( array( |
309
|
|
|
'id' => '_stock', |
310
|
|
|
'label' => __( 'Stock quantity', 'woocommerce' ), |
311
|
|
|
'desc_tip' => true, |
312
|
|
|
'description' => __( 'Stock quantity. If this is a variable product this value will be used to control stock for all variations, unless you define stock at variation level.', 'woocommerce' ), |
313
|
|
|
'type' => 'number', |
314
|
|
|
'custom_attributes' => array( |
315
|
|
|
'step' => 'any' |
316
|
|
|
), |
317
|
|
|
'data_type' => 'stock' |
318
|
|
|
) ); |
319
|
|
|
|
320
|
|
|
// Backorders? |
321
|
|
|
woocommerce_wp_select( array( 'id' => '_backorders', 'label' => __( 'Allow backorders?', 'woocommerce' ), 'options' => array( |
322
|
|
|
'no' => __( 'Do not allow', 'woocommerce' ), |
323
|
|
|
'notify' => __( 'Allow, but notify customer', 'woocommerce' ), |
324
|
|
|
'yes' => __( 'Allow', 'woocommerce' ) |
325
|
|
|
), 'desc_tip' => true, 'description' => __( 'If managing stock, this controls whether or not backorders are allowed. If enabled, stock quantity can go below 0.', 'woocommerce' ) ) ); |
326
|
|
|
|
327
|
|
|
do_action( 'woocommerce_product_options_stock_fields' ); |
328
|
|
|
|
329
|
|
|
echo '</div>'; |
330
|
|
|
|
331
|
|
|
} |
332
|
|
|
|
333
|
|
|
// Stock status |
334
|
|
|
woocommerce_wp_select( array( 'id' => '_stock_status', 'wrapper_class' => 'hide_if_variable', 'label' => __( 'Stock status', 'woocommerce' ), 'options' => array( |
335
|
|
|
'instock' => __( 'In stock', 'woocommerce' ), |
336
|
|
|
'outofstock' => __( 'Out of stock', 'woocommerce' ) |
337
|
|
|
), 'desc_tip' => true, 'description' => __( 'Controls whether or not the product is listed as "in stock" or "out of stock" on the frontend.', 'woocommerce' ) ) ); |
338
|
|
|
|
339
|
|
|
do_action( 'woocommerce_product_options_stock_status' ); |
340
|
|
|
|
341
|
|
|
echo '</div>'; |
342
|
|
|
|
343
|
|
|
echo '<div class="options_group show_if_simple show_if_variable">'; |
344
|
|
|
|
345
|
|
|
// Individual product |
346
|
|
|
woocommerce_wp_checkbox( array( 'id' => '_sold_individually', 'wrapper_class' => 'show_if_simple show_if_variable', 'label' => __( 'Sold individually', 'woocommerce' ), 'description' => __( 'Enable this to only allow one of this item to be bought in a single order', 'woocommerce' ) ) ); |
347
|
|
|
|
348
|
|
|
do_action( 'woocommerce_product_options_sold_individually' ); |
349
|
|
|
|
350
|
|
|
echo '</div>'; |
351
|
|
|
|
352
|
|
|
do_action( 'woocommerce_product_options_inventory_product_data' ); |
353
|
|
|
?> |
354
|
|
|
|
355
|
|
|
</div> |
356
|
|
|
|
357
|
|
|
<div id="shipping_product_data" class="panel woocommerce_options_panel hidden"> |
358
|
|
|
|
359
|
|
|
<?php |
360
|
|
|
|
361
|
|
|
echo '<div class="options_group">'; |
362
|
|
|
|
363
|
|
|
// Weight |
364
|
|
|
if ( wc_product_weight_enabled() ) { |
365
|
|
|
woocommerce_wp_text_input( array( 'id' => '_weight', 'label' => __( 'Weight', 'woocommerce' ) . ' (' . get_option( 'woocommerce_weight_unit' ) . ')', 'placeholder' => wc_format_localized_decimal( 0 ), 'desc_tip' => 'true', 'description' => __( 'Weight in decimal form', 'woocommerce' ), 'type' => 'text', 'data_type' => 'decimal' ) ); |
366
|
|
|
} |
367
|
|
|
|
368
|
|
|
// Size fields |
369
|
|
|
if ( wc_product_dimensions_enabled() ) { |
370
|
|
|
?><p class="form-field dimensions_field"> |
371
|
|
|
<label for="product_length"><?php echo __( 'Dimensions', 'woocommerce' ) . ' (' . get_option( 'woocommerce_dimension_unit' ) . ')'; ?></label> |
372
|
|
|
<span class="wrap"> |
373
|
|
|
<input id="product_length" placeholder="<?php esc_attr_e( 'Length', 'woocommerce' ); ?>" class="input-text wc_input_decimal" size="6" type="text" name="_length" value="<?php echo esc_attr( wc_format_localized_decimal( get_post_meta( $thepostid, '_length', true ) ) ); ?>" /> |
374
|
|
|
<input placeholder="<?php esc_attr_e( 'Width', 'woocommerce' ); ?>" class="input-text wc_input_decimal" size="6" type="text" name="_width" value="<?php echo esc_attr( wc_format_localized_decimal( get_post_meta( $thepostid, '_width', true ) ) ); ?>" /> |
375
|
|
|
<input placeholder="<?php esc_attr_e( 'Height', 'woocommerce' ); ?>" class="input-text wc_input_decimal last" size="6" type="text" name="_height" value="<?php echo esc_attr( wc_format_localized_decimal( get_post_meta( $thepostid, '_height', true ) ) ); ?>" /> |
376
|
|
|
</span> |
377
|
|
|
<?php echo wc_help_tip( __( 'LxWxH in decimal form', 'woocommerce' ) ); ?> |
378
|
|
|
</p><?php |
379
|
|
|
} |
380
|
|
|
|
381
|
|
|
do_action( 'woocommerce_product_options_dimensions' ); |
382
|
|
|
|
383
|
|
|
echo '</div>'; |
384
|
|
|
|
385
|
|
|
echo '<div class="options_group">'; |
386
|
|
|
|
387
|
|
|
// Shipping Class |
388
|
|
|
$classes = get_the_terms( $thepostid, 'product_shipping_class' ); |
389
|
|
|
if ( $classes && ! is_wp_error( $classes ) ) { |
390
|
|
|
$current_shipping_class = current( $classes )->term_id; |
391
|
|
|
} else { |
392
|
|
|
$current_shipping_class = ''; |
393
|
|
|
} |
394
|
|
|
|
395
|
|
|
$args = array( |
396
|
|
|
'taxonomy' => 'product_shipping_class', |
397
|
|
|
'hide_empty' => 0, |
398
|
|
|
'show_option_none' => __( 'No shipping class', 'woocommerce' ), |
399
|
|
|
'name' => 'product_shipping_class', |
400
|
|
|
'id' => 'product_shipping_class', |
401
|
|
|
'selected' => $current_shipping_class, |
402
|
|
|
'class' => 'select short' |
403
|
|
|
); |
404
|
|
|
?><p class="form-field dimensions_field"><label for="product_shipping_class"><?php _e( 'Shipping class', 'woocommerce' ); ?></label> <?php wp_dropdown_categories( $args ); ?> <?php echo wc_help_tip( __( 'Shipping classes are used by certain shipping methods to group similar products.', 'woocommerce' ) ); ?></p><?php |
405
|
|
|
|
406
|
|
|
do_action( 'woocommerce_product_options_shipping' ); |
407
|
|
|
|
408
|
|
|
echo '</div>'; |
409
|
|
|
?> |
410
|
|
|
|
411
|
|
|
</div> |
412
|
|
|
|
413
|
|
|
<div id="product_attributes" class="panel wc-metaboxes-wrapper hidden"> |
414
|
|
|
<div class="toolbar toolbar-top"> |
415
|
|
|
<span class="expand-close"> |
416
|
|
|
<a href="#" class="expand_all"><?php _e( 'Expand', 'woocommerce' ); ?></a> / <a href="#" class="close_all"><?php _e( 'Close', 'woocommerce' ); ?></a> |
417
|
|
|
</span> |
418
|
|
|
<select name="attribute_taxonomy" class="attribute_taxonomy"> |
419
|
|
|
<option value=""><?php _e( 'Custom product attribute', 'woocommerce' ); ?></option> |
420
|
|
|
<?php |
421
|
|
|
global $wc_product_attributes; |
422
|
|
|
|
423
|
|
|
// Array of defined attribute taxonomies |
424
|
|
|
$attribute_taxonomies = wc_get_attribute_taxonomies(); |
425
|
|
|
|
426
|
|
|
if ( ! empty( $attribute_taxonomies ) ) { |
427
|
|
|
foreach ( $attribute_taxonomies as $tax ) { |
428
|
|
|
$attribute_taxonomy_name = wc_attribute_taxonomy_name( $tax->attribute_name ); |
429
|
|
|
$label = $tax->attribute_label ? $tax->attribute_label : $tax->attribute_name; |
430
|
|
|
echo '<option value="' . esc_attr( $attribute_taxonomy_name ) . '">' . esc_html( $label ) . '</option>'; |
431
|
|
|
} |
432
|
|
|
} |
433
|
|
|
?> |
434
|
|
|
</select> |
435
|
|
|
<button type="button" class="button add_attribute"><?php _e( 'Add', 'woocommerce' ); ?></button> |
436
|
|
|
</div> |
437
|
|
|
<div class="product_attributes wc-metaboxes"> |
438
|
|
|
<?php |
439
|
|
|
// Product attributes - taxonomies and custom, ordered, with visibility and variation attributes set |
440
|
|
|
$attributes = maybe_unserialize( get_post_meta( $thepostid, '_product_attributes', true ) ); |
441
|
|
|
|
442
|
|
|
// Output All Set Attributes |
443
|
|
|
if ( ! empty( $attributes ) ) { |
444
|
|
|
$attribute_keys = array_keys( $attributes ); |
445
|
|
|
$attribute_total = sizeof( $attribute_keys ); |
446
|
|
|
|
447
|
|
|
for ( $i = 0; $i < $attribute_total; $i ++ ) { |
448
|
|
|
$attribute = $attributes[ $attribute_keys[ $i ] ]; |
449
|
|
|
$position = empty( $attribute['position'] ) ? 0 : absint( $attribute['position'] ); |
450
|
|
|
$taxonomy = ''; |
451
|
|
|
$metabox_class = array(); |
452
|
|
|
|
453
|
|
|
if ( $attribute['is_taxonomy'] ) { |
454
|
|
|
$taxonomy = $attribute['name']; |
455
|
|
|
|
456
|
|
|
if ( ! taxonomy_exists( $taxonomy ) ) { |
457
|
|
|
continue; |
458
|
|
|
} |
459
|
|
|
|
460
|
|
|
$attribute_taxonomy = $wc_product_attributes[ $taxonomy ]; |
461
|
|
|
$metabox_class[] = 'taxonomy'; |
462
|
|
|
$metabox_class[] = $taxonomy; |
463
|
|
|
$attribute_label = wc_attribute_label( $taxonomy ); |
464
|
|
|
} else { |
465
|
|
|
$attribute_label = apply_filters( 'woocommerce_attribute_label', $attribute['name'], $attribute['name'], false ); |
466
|
|
|
} |
467
|
|
|
|
468
|
|
|
include( 'views/html-product-attribute.php' ); |
469
|
|
|
} |
470
|
|
|
} |
471
|
|
|
?> |
472
|
|
|
</div> |
473
|
|
|
<div class="toolbar"> |
474
|
|
|
<span class="expand-close"> |
475
|
|
|
<a href="#" class="expand_all"><?php _e( 'Expand', 'woocommerce' ); ?></a> / <a href="#" class="close_all"><?php _e( 'Close', 'woocommerce' ); ?></a> |
476
|
|
|
</span> |
477
|
|
|
<button type="button" class="button save_attributes button-primary"><?php _e( 'Save attributes', 'woocommerce' ); ?></button> |
478
|
|
|
</div> |
479
|
|
|
<?php do_action( 'woocommerce_product_options_attributes' ); ?> |
480
|
|
|
</div> |
481
|
|
|
<div id="linked_product_data" class="panel woocommerce_options_panel hidden"> |
482
|
|
|
|
483
|
|
|
<div class="options_group"> |
484
|
|
|
|
485
|
|
|
<p class="form-field"> |
486
|
|
|
<label for="upsell_ids"><?php _e( 'Up-sells', 'woocommerce' ); ?></label> |
487
|
|
|
<input type="hidden" class="wc-product-search" style="width: 50%;" id="upsell_ids" name="upsell_ids" data-placeholder="<?php esc_attr_e( 'Search for a product…', 'woocommerce' ); ?>" data-action="woocommerce_json_search_products" data-multiple="true" data-exclude="<?php echo intval( $post->ID ); ?>" data-selected="<?php |
488
|
|
|
$product_ids = array_filter( array_map( 'absint', (array) get_post_meta( $post->ID, '_upsell_ids', true ) ) ); |
489
|
|
|
$json_ids = array(); |
490
|
|
|
|
491
|
|
View Code Duplication |
foreach ( $product_ids as $product_id ) { |
|
|
|
|
492
|
|
|
$product = wc_get_product( $product_id ); |
493
|
|
|
if ( is_object( $product ) ) { |
494
|
|
|
$json_ids[ $product_id ] = wp_kses_post( html_entity_decode( $product->get_formatted_name(), ENT_QUOTES, get_bloginfo( 'charset' ) ) ); |
495
|
|
|
} |
496
|
|
|
} |
497
|
|
|
|
498
|
|
|
echo esc_attr( json_encode( $json_ids ) ); |
499
|
|
|
?>" value="<?php echo implode( ',', array_keys( $json_ids ) ); ?>" /> <?php echo wc_help_tip( __( 'Up-sells are products which you recommend instead of the currently viewed product, for example, products that are more profitable or better quality or more expensive.', 'woocommerce' ) ); ?> |
500
|
|
|
</p> |
501
|
|
|
|
502
|
|
|
<p class="form-field"> |
503
|
|
|
<label for="crosssell_ids"><?php _e( 'Cross-sells', 'woocommerce' ); ?></label> |
504
|
|
|
<input type="hidden" class="wc-product-search" style="width: 50%;" id="crosssell_ids" name="crosssell_ids" data-placeholder="<?php esc_attr_e( 'Search for a product…', 'woocommerce' ); ?>" data-action="woocommerce_json_search_products" data-multiple="true" data-exclude="<?php echo intval( $post->ID ); ?>" data-selected="<?php |
505
|
|
|
$product_ids = array_filter( array_map( 'absint', (array) get_post_meta( $post->ID, '_crosssell_ids', true ) ) ); |
506
|
|
|
$json_ids = array(); |
507
|
|
|
|
508
|
|
View Code Duplication |
foreach ( $product_ids as $product_id ) { |
|
|
|
|
509
|
|
|
$product = wc_get_product( $product_id ); |
510
|
|
|
if ( is_object( $product ) ) { |
511
|
|
|
$json_ids[ $product_id ] = wp_kses_post( html_entity_decode( $product->get_formatted_name(), ENT_QUOTES, get_bloginfo( 'charset' ) ) ); |
512
|
|
|
} |
513
|
|
|
} |
514
|
|
|
|
515
|
|
|
echo esc_attr( json_encode( $json_ids ) ); |
516
|
|
|
?>" value="<?php echo implode( ',', array_keys( $json_ids ) ); ?>" /> <?php echo wc_help_tip( __( 'Cross-sells are products which you promote in the cart, based on the current product.', 'woocommerce' ) ); ?> |
517
|
|
|
</p> |
518
|
|
|
</div> |
519
|
|
|
|
520
|
|
|
<div class="options_group grouping show_if_simple show_if_external"> |
521
|
|
|
|
522
|
|
|
<p class="form-field"> |
523
|
|
|
<label for="parent_id"><?php _e( 'Grouping', 'woocommerce' ); ?></label> |
524
|
|
|
<input type="hidden" class="wc-product-search" style="width: 50%;" id="parent_id" name="parent_id" data-placeholder="<?php esc_attr_e( 'Search for a product…', 'woocommerce' ); ?>" data-action="woocommerce_json_search_grouped_products" data-allow_clear="true" data-multiple="false" data-exclude="<?php echo intval( $post->ID ); ?>" data-selected="<?php |
525
|
|
|
$parent_id = absint( $post->post_parent ); |
526
|
|
|
|
527
|
|
|
if ( $parent_id ) { |
528
|
|
|
$parent = wc_get_product( $parent_id ); |
529
|
|
|
if ( is_object( $parent ) ) { |
530
|
|
|
$parent_title = wp_kses_post( html_entity_decode( $parent->get_formatted_name(), ENT_QUOTES, get_bloginfo( 'charset' ) ) ); |
531
|
|
|
} |
532
|
|
|
|
533
|
|
|
echo esc_attr( $parent_title ); |
534
|
|
|
} |
535
|
|
|
?>" value="<?php echo $parent_id ? $parent_id : ''; ?>" /> <?php echo wc_help_tip( __( 'Set this option to make this product part of a grouped product.', 'woocommerce' ) ); ?> |
536
|
|
|
</p> |
537
|
|
|
|
538
|
|
|
<?php |
539
|
|
|
woocommerce_wp_hidden_input( array( 'id' => 'previous_parent_id', 'value' => absint( $post->post_parent ) ) ); |
540
|
|
|
|
541
|
|
|
do_action( 'woocommerce_product_options_grouping' ); |
542
|
|
|
?> |
543
|
|
|
</div> |
544
|
|
|
|
545
|
|
|
<?php do_action( 'woocommerce_product_options_related' ); ?> |
546
|
|
|
</div> |
547
|
|
|
|
548
|
|
|
<div id="advanced_product_data" class="panel woocommerce_options_panel hidden"> |
549
|
|
|
|
550
|
|
|
<div class="options_group hide_if_external"> |
551
|
|
|
<?php |
552
|
|
|
// Purchase note |
553
|
|
|
woocommerce_wp_textarea_input( array( 'id' => '_purchase_note', 'label' => __( 'Purchase note', 'woocommerce' ), 'desc_tip' => 'true', 'description' => __( 'Enter an optional note to send the customer after purchase.', 'woocommerce' ) ) ); |
554
|
|
|
?> |
555
|
|
|
</div> |
556
|
|
|
|
557
|
|
|
<div class="options_group"> |
558
|
|
|
<?php |
559
|
|
|
// menu_order |
560
|
|
|
woocommerce_wp_text_input( array( 'id' => 'menu_order', 'label' => __( 'Menu order', 'woocommerce' ), 'desc_tip' => 'true', 'description' => __( 'Custom ordering position.', 'woocommerce' ), 'value' => intval( $post->menu_order ), 'type' => 'number', 'custom_attributes' => array( |
561
|
|
|
'step' => '1' |
562
|
|
|
) ) ); |
563
|
|
|
?> |
564
|
|
|
</div> |
565
|
|
|
|
566
|
|
|
<div class="options_group reviews"> |
567
|
|
|
<?php |
568
|
|
|
woocommerce_wp_checkbox( array( 'id' => 'comment_status', 'label' => __( 'Enable reviews', 'woocommerce' ), 'cbvalue' => 'open', 'value' => esc_attr( $post->comment_status ) ) ); |
569
|
|
|
|
570
|
|
|
do_action( 'woocommerce_product_options_reviews' ); |
571
|
|
|
?> |
572
|
|
|
</div> |
573
|
|
|
|
574
|
|
|
<?php do_action( 'woocommerce_product_options_advanced' ); ?> |
575
|
|
|
|
576
|
|
|
</div> |
577
|
|
|
|
578
|
|
|
<?php |
579
|
|
|
self::output_variations(); |
580
|
|
|
|
581
|
|
|
do_action( 'woocommerce_product_data_panels' ); |
582
|
|
|
do_action( 'woocommerce_product_write_panels' ); // _deprecated |
583
|
|
|
?> |
584
|
|
|
|
585
|
|
|
<div class="clear"></div> |
586
|
|
|
|
587
|
|
|
</div> |
588
|
|
|
<?php |
589
|
|
|
} |
590
|
|
|
|
591
|
|
|
/** |
592
|
|
|
* Show options for the variable product type. |
593
|
|
|
*/ |
594
|
|
|
public static function output_variations() { |
595
|
|
|
global $post, $wpdb; |
596
|
|
|
|
597
|
|
|
// Get attributes |
598
|
|
|
$attributes = maybe_unserialize( get_post_meta( $post->ID, '_product_attributes', true ) ); |
599
|
|
|
|
600
|
|
|
// See if any are set |
601
|
|
|
$variation_attribute_found = false; |
602
|
|
|
|
603
|
|
|
if ( $attributes ) { |
604
|
|
|
foreach ( $attributes as $attribute ) { |
605
|
|
|
if ( ! empty( $attribute['is_variation'] ) ) { |
606
|
|
|
$variation_attribute_found = true; |
607
|
|
|
break; |
608
|
|
|
} |
609
|
|
|
} |
610
|
|
|
} |
611
|
|
|
|
612
|
|
|
$variations_count = absint( $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(ID) FROM $wpdb->posts WHERE post_parent = %d AND post_type = 'product_variation' AND post_status IN ('publish', 'private')", $post->ID ) ) ); |
613
|
|
|
$variations_per_page = absint( apply_filters( 'woocommerce_admin_meta_boxes_variations_per_page', 15 ) ); |
614
|
|
|
$variations_total_pages = ceil( $variations_count / $variations_per_page ); |
615
|
|
|
?> |
616
|
|
|
<div id="variable_product_options" class="panel wc-metaboxes-wrapper hidden"><div id="variable_product_options_inner"> |
617
|
|
|
|
618
|
|
|
<?php if ( ! $variation_attribute_found ) : ?> |
619
|
|
|
|
620
|
|
|
<div id="message" class="inline notice woocommerce-message"> |
621
|
|
|
<p><?php _e( 'Before you can add a variation you need to add some variation attributes on the <strong>Attributes</strong> tab.', 'woocommerce' ); ?></p> |
622
|
|
|
<p> |
623
|
|
|
<a class="button-primary" href="<?php echo esc_url( apply_filters( 'woocommerce_docs_url', 'https://docs.woothemes.com/document/variable-product/', 'product-variations' ) ); ?>" target="_blank"><?php _e( 'Learn more', 'woocommerce' ); ?></a> |
624
|
|
|
</p> |
625
|
|
|
</div> |
626
|
|
|
|
627
|
|
|
<?php else : ?> |
628
|
|
|
|
629
|
|
|
<div class="toolbar toolbar-variations-defaults"> |
630
|
|
|
<div class="variations-defaults"> |
631
|
|
|
<strong><?php _e( 'Default Form Values', 'woocommerce' ); ?>: <?php echo wc_help_tip( __( 'These are the attributes that will be pre-selected on the frontend.', 'woocommerce' ) ); ?></strong> |
632
|
|
|
<?php |
633
|
|
|
$default_attributes = maybe_unserialize( get_post_meta( $post->ID, '_default_attributes', true ) ); |
634
|
|
|
|
635
|
|
|
foreach ( $attributes as $attribute ) { |
636
|
|
|
|
637
|
|
|
// Only deal with attributes that are variations |
638
|
|
|
if ( ! $attribute['is_variation'] ) { |
639
|
|
|
continue; |
640
|
|
|
} |
641
|
|
|
|
642
|
|
|
// Get current value for variation (if set) |
643
|
|
|
$variation_selected_value = isset( $default_attributes[ sanitize_title( $attribute['name'] ) ] ) ? $default_attributes[ sanitize_title( $attribute['name'] ) ] : ''; |
644
|
|
|
|
645
|
|
|
// Name will be something like attribute_pa_color |
646
|
|
|
echo '<select name="default_attribute_' . sanitize_title( $attribute['name'] ) . '" data-current="' . esc_attr( $variation_selected_value ) . '"><option value="">' . __( 'No default', 'woocommerce' ) . ' ' . esc_html( wc_attribute_label( $attribute['name'] ) ) . '…</option>'; |
647
|
|
|
|
648
|
|
|
// Get terms for attribute taxonomy or value if its a custom attribute |
649
|
|
View Code Duplication |
if ( $attribute['is_taxonomy'] ) { |
|
|
|
|
650
|
|
|
$post_terms = wp_get_post_terms( $post->ID, $attribute['name'] ); |
651
|
|
|
|
652
|
|
|
foreach ( $post_terms as $term ) { |
653
|
|
|
echo '<option ' . selected( $variation_selected_value, $term->slug, false ) . ' value="' . esc_attr( $term->slug ) . '">' . esc_html( apply_filters( 'woocommerce_variation_option_name', $term->name ) ) . '</option>'; |
654
|
|
|
} |
655
|
|
|
|
656
|
|
|
} else { |
657
|
|
|
$options = wc_get_text_attributes( $attribute['value'] ); |
658
|
|
|
|
659
|
|
|
foreach ( $options as $option ) { |
660
|
|
|
$selected = sanitize_title( $variation_selected_value ) === $variation_selected_value ? selected( $variation_selected_value, sanitize_title( $option ), false ) : selected( $variation_selected_value, $option, false ); |
661
|
|
|
echo '<option ' . $selected . ' value="' . esc_attr( $option ) . '">' . esc_html( apply_filters( 'woocommerce_variation_option_name', $option ) ) . '</option>'; |
662
|
|
|
} |
663
|
|
|
|
664
|
|
|
} |
665
|
|
|
|
666
|
|
|
echo '</select>'; |
667
|
|
|
} |
668
|
|
|
?> |
669
|
|
|
</div> |
670
|
|
|
<div class="clear"></div> |
671
|
|
|
</div> |
672
|
|
|
|
673
|
|
|
<div class="toolbar toolbar-top"> |
674
|
|
|
<select id="field_to_edit" class="variation_actions"> |
675
|
|
|
<option data-global="true" value="add_variation"><?php _e( 'Add variation', 'woocommerce' ); ?></option> |
676
|
|
|
<option data-global="true" value="link_all_variations"><?php _e( 'Create variations from all attributes', 'woocommerce' ); ?></option> |
677
|
|
|
<option value="delete_all"><?php _e( 'Delete all variations', 'woocommerce' ); ?></option> |
678
|
|
|
<optgroup label="<?php esc_attr_e( 'Status', 'woocommerce' ); ?>"> |
679
|
|
|
<option value="toggle_enabled"><?php _e( 'Toggle "Enabled"', 'woocommerce' ); ?></option> |
680
|
|
|
<option value="toggle_downloadable"><?php _e( 'Toggle "Downloadable"', 'woocommerce' ); ?></option> |
681
|
|
|
<option value="toggle_virtual"><?php _e( 'Toggle "Virtual"', 'woocommerce' ); ?></option> |
682
|
|
|
</optgroup> |
683
|
|
|
<optgroup label="<?php esc_attr_e( 'Pricing', 'woocommerce' ); ?>"> |
684
|
|
|
<option value="variable_regular_price"><?php _e( 'Set regular prices', 'woocommerce' ); ?></option> |
685
|
|
|
<option value="variable_regular_price_increase"><?php _e( 'Increase regular prices (fixed amount or percentage)', 'woocommerce' ); ?></option> |
686
|
|
|
<option value="variable_regular_price_decrease"><?php _e( 'Decrease regular prices (fixed amount or percentage)', 'woocommerce' ); ?></option> |
687
|
|
|
<option value="variable_sale_price"><?php _e( 'Set sale prices', 'woocommerce' ); ?></option> |
688
|
|
|
<option value="variable_sale_price_increase"><?php _e( 'Increase sale prices (fixed amount or percentage)', 'woocommerce' ); ?></option> |
689
|
|
|
<option value="variable_sale_price_decrease"><?php _e( 'Decrease sale prices (fixed amount or percentage)', 'woocommerce' ); ?></option> |
690
|
|
|
<option value="variable_sale_schedule"><?php _e( 'Set scheduled sale dates', 'woocommerce' ); ?></option> |
691
|
|
|
</optgroup> |
692
|
|
|
<optgroup label="<?php esc_attr_e( 'Inventory', 'woocommerce' ); ?>"> |
693
|
|
|
<option value="toggle_manage_stock"><?php _e( 'Toggle "Manage stock"', 'woocommerce' ); ?></option> |
694
|
|
|
<option value="variable_stock"><?php _e( 'Stock', 'woocommerce' ); ?></option> |
695
|
|
|
</optgroup> |
696
|
|
|
<optgroup label="<?php esc_attr_e( 'Shipping', 'woocommerce' ); ?>"> |
697
|
|
|
<option value="variable_length"><?php _e( 'Length', 'woocommerce' ); ?></option> |
698
|
|
|
<option value="variable_width"><?php _e( 'Width', 'woocommerce' ); ?></option> |
699
|
|
|
<option value="variable_height"><?php _e( 'Height', 'woocommerce' ); ?></option> |
700
|
|
|
<option value="variable_weight"><?php _e( 'Weight', 'woocommerce' ); ?></option> |
701
|
|
|
</optgroup> |
702
|
|
|
<optgroup label="<?php esc_attr_e( 'Downloadable products', 'woocommerce' ); ?>"> |
703
|
|
|
<option value="variable_download_limit"><?php _e( 'Download limit', 'woocommerce' ); ?></option> |
704
|
|
|
<option value="variable_download_expiry"><?php _e( 'Download expiry', 'woocommerce' ); ?></option> |
705
|
|
|
</optgroup> |
706
|
|
|
<?php do_action( 'woocommerce_variable_product_bulk_edit_actions' ); ?> |
707
|
|
|
</select> |
708
|
|
|
<a class="button bulk_edit do_variation_action"><?php _e( 'Go', 'woocommerce' ); ?></a> |
709
|
|
|
|
710
|
|
|
<div class="variations-pagenav"> |
711
|
|
|
<span class="displaying-num"><?php printf( _n( '%s item', '%s items', $variations_count, 'woocommerce' ), $variations_count ); ?></span> |
712
|
|
|
<span class="expand-close"> |
713
|
|
|
(<a href="#" class="expand_all"><?php _e( 'Expand', 'woocommerce' ); ?></a> / <a href="#" class="close_all"><?php _e( 'Close', 'woocommerce' ); ?></a>) |
714
|
|
|
</span> |
715
|
|
|
<span class="pagination-links"> |
716
|
|
|
<a class="first-page disabled" title="<?php esc_attr_e( 'Go to the first page', 'woocommerce' ); ?>" href="#">«</a> |
717
|
|
|
<a class="prev-page disabled" title="<?php esc_attr_e( 'Go to the previous page', 'woocommerce' ); ?>" href="#">‹</a> |
718
|
|
|
<span class="paging-select"> |
719
|
|
|
<label for="current-page-selector-1" class="screen-reader-text"><?php _e( 'Select Page', 'woocommerce' ); ?></label> |
720
|
|
|
<select class="page-selector" id="current-page-selector-1" title="<?php esc_attr_e( 'Current page', 'woocommerce' ); ?>"> |
721
|
|
View Code Duplication |
<?php for ( $i = 1; $i <= $variations_total_pages; $i++ ) : ?> |
|
|
|
|
722
|
|
|
<option value="<?php echo $i; ?>"><?php echo $i; ?></option> |
723
|
|
|
<?php endfor; ?> |
724
|
|
|
</select> |
725
|
|
|
<?php _ex( 'of', 'number of pages', 'woocommerce' ); ?> <span class="total-pages"><?php echo $variations_total_pages; ?></span> |
726
|
|
|
</span> |
727
|
|
|
<a class="next-page" title="<?php esc_attr_e( 'Go to the next page', 'woocommerce' ); ?>" href="#">›</a> |
728
|
|
|
<a class="last-page" title="<?php esc_attr_e( 'Go to the last page', 'woocommerce' ); ?>" href="#">»</a> |
729
|
|
|
</span> |
730
|
|
|
</div> |
731
|
|
|
<div class="clear"></div> |
732
|
|
|
</div> |
733
|
|
|
|
734
|
|
|
<div class="woocommerce_variations wc-metaboxes" data-attributes="<?php |
735
|
|
|
// esc_attr does not double encode - htmlspecialchars does |
736
|
|
|
echo htmlspecialchars( json_encode( $attributes ) ); |
737
|
|
|
?>" data-total="<?php echo $variations_count; ?>" data-total_pages="<?php echo $variations_total_pages; ?>" data-page="1" data-edited="false"> |
738
|
|
|
</div> |
739
|
|
|
|
740
|
|
|
<div class="toolbar"> |
741
|
|
|
<button type="button" class="button-primary save-variation-changes" disabled="disabled"><?php _e( 'Save changes', 'woocommerce' ); ?></button> |
742
|
|
|
<button type="button" class="button cancel-variation-changes" disabled="disabled"><?php _e( 'Cancel', 'woocommerce' ); ?></button> |
743
|
|
|
|
744
|
|
|
<div class="variations-pagenav"> |
745
|
|
|
<span class="displaying-num"><?php printf( _n( '%s item', '%s items', $variations_count, 'woocommerce' ), $variations_count ); ?></span> |
746
|
|
|
<span class="expand-close"> |
747
|
|
|
(<a href="#" class="expand_all"><?php _e( 'Expand', 'woocommerce' ); ?></a> / <a href="#" class="close_all"><?php _e( 'Close', 'woocommerce' ); ?></a>) |
748
|
|
|
</span> |
749
|
|
|
<span class="pagination-links"> |
750
|
|
|
<a class="first-page disabled" title="<?php esc_attr_e( 'Go to the first page', 'woocommerce' ); ?>" href="#">«</a> |
751
|
|
|
<a class="prev-page disabled" title="<?php esc_attr_e( 'Go to the previous page', 'woocommerce' ); ?>" href="#">‹</a> |
752
|
|
|
<span class="paging-select"> |
753
|
|
|
<label for="current-page-selector-1" class="screen-reader-text"><?php _e( 'Select Page', 'woocommerce' ); ?></label> |
754
|
|
|
<select class="page-selector" id="current-page-selector-1" title="<?php esc_attr_e( 'Current page', 'woocommerce' ); ?>"> |
755
|
|
View Code Duplication |
<?php for ( $i = 1; $i <= $variations_total_pages; $i++ ) : ?> |
|
|
|
|
756
|
|
|
<option value="<?php echo $i; ?>"><?php echo $i; ?></option> |
757
|
|
|
<?php endfor; ?> |
758
|
|
|
</select> |
759
|
|
|
<?php _ex( 'of', 'number of pages', 'woocommerce' ); ?> <span class="total-pages"><?php echo $variations_total_pages; ?></span> |
760
|
|
|
</span> |
761
|
|
|
<a class="next-page" title="<?php esc_attr_e( 'Go to the next page', 'woocommerce' ); ?>" href="#">›</a> |
762
|
|
|
<a class="last-page" title="<?php esc_attr_e( 'Go to the last page', 'woocommerce' ); ?>" href="#">»</a> |
763
|
|
|
</span> |
764
|
|
|
</div> |
765
|
|
|
|
766
|
|
|
<div class="clear"></div> |
767
|
|
|
</div> |
768
|
|
|
|
769
|
|
|
<?php endif; ?> |
770
|
|
|
</div></div> |
771
|
|
|
<?php |
772
|
|
|
} |
773
|
|
|
|
774
|
|
|
/** |
775
|
|
|
* Save meta box data. |
776
|
|
|
*/ |
777
|
|
|
public static function save( $post_id, $post ) { |
778
|
|
|
global $wpdb; |
779
|
|
|
|
780
|
|
|
// Add any default post meta |
781
|
|
|
add_post_meta( $post_id, 'total_sales', '0', true ); |
782
|
|
|
|
783
|
|
|
// Get types |
784
|
|
|
$product_type = empty( $_POST['product-type'] ) ? 'simple' : sanitize_title( stripslashes( $_POST['product-type'] ) ); |
785
|
|
|
$is_downloadable = isset( $_POST['_downloadable'] ) ? 'yes' : 'no'; |
786
|
|
|
$is_virtual = isset( $_POST['_virtual'] ) ? 'yes' : 'no'; |
787
|
|
|
|
788
|
|
|
// Product type + Downloadable/Virtual |
789
|
|
|
wp_set_object_terms( $post_id, $product_type, 'product_type' ); |
790
|
|
|
update_post_meta( $post_id, '_downloadable', $is_downloadable ); |
791
|
|
|
update_post_meta( $post_id, '_virtual', $is_virtual ); |
792
|
|
|
|
793
|
|
|
// Update post meta |
794
|
|
|
if ( isset( $_POST['_tax_status'] ) ) { |
795
|
|
|
update_post_meta( $post_id, '_tax_status', wc_clean( $_POST['_tax_status'] ) ); |
796
|
|
|
} |
797
|
|
|
|
798
|
|
|
if ( isset( $_POST['_tax_class'] ) ) { |
799
|
|
|
update_post_meta( $post_id, '_tax_class', wc_clean( $_POST['_tax_class'] ) ); |
800
|
|
|
} |
801
|
|
|
|
802
|
|
|
if ( isset( $_POST['_purchase_note'] ) ) { |
803
|
|
|
update_post_meta( $post_id, '_purchase_note', wp_kses_post( stripslashes( $_POST['_purchase_note'] ) ) ); |
804
|
|
|
} |
805
|
|
|
|
806
|
|
|
// Featured |
807
|
|
|
if ( update_post_meta( $post_id, '_featured', isset( $_POST['_featured'] ) ? 'yes' : 'no' ) ) { |
808
|
|
|
delete_transient( 'wc_featured_products' ); |
809
|
|
|
} |
810
|
|
|
|
811
|
|
|
// Dimensions |
812
|
|
|
if ( 'no' == $is_virtual ) { |
813
|
|
|
|
814
|
|
View Code Duplication |
if ( isset( $_POST['_weight'] ) ) { |
|
|
|
|
815
|
|
|
update_post_meta( $post_id, '_weight', ( '' === $_POST['_weight'] ) ? '' : wc_format_decimal( $_POST['_weight'] ) ); |
816
|
|
|
} |
817
|
|
|
|
818
|
|
View Code Duplication |
if ( isset( $_POST['_length'] ) ) { |
|
|
|
|
819
|
|
|
update_post_meta( $post_id, '_length', ( '' === $_POST['_length'] ) ? '' : wc_format_decimal( $_POST['_length'] ) ); |
820
|
|
|
} |
821
|
|
|
|
822
|
|
View Code Duplication |
if ( isset( $_POST['_width'] ) ) { |
|
|
|
|
823
|
|
|
update_post_meta( $post_id, '_width', ( '' === $_POST['_width'] ) ? '' : wc_format_decimal( $_POST['_width'] ) ); |
824
|
|
|
} |
825
|
|
|
|
826
|
|
View Code Duplication |
if ( isset( $_POST['_height'] ) ) { |
|
|
|
|
827
|
|
|
update_post_meta( $post_id, '_height', ( '' === $_POST['_height'] ) ? '' : wc_format_decimal( $_POST['_height'] ) ); |
828
|
|
|
} |
829
|
|
|
|
830
|
|
|
} else { |
831
|
|
|
update_post_meta( $post_id, '_weight', '' ); |
832
|
|
|
update_post_meta( $post_id, '_length', '' ); |
833
|
|
|
update_post_meta( $post_id, '_width', '' ); |
834
|
|
|
update_post_meta( $post_id, '_height', '' ); |
835
|
|
|
} |
836
|
|
|
|
837
|
|
|
// Save shipping class |
838
|
|
|
$product_shipping_class = $_POST['product_shipping_class'] > 0 && $product_type != 'external' ? absint( $_POST['product_shipping_class'] ) : ''; |
839
|
|
|
wp_set_object_terms( $post_id, $product_shipping_class, 'product_shipping_class'); |
840
|
|
|
|
841
|
|
|
// Unique SKU |
842
|
|
|
$sku = get_post_meta( $post_id, '_sku', true ); |
843
|
|
|
$new_sku = wc_clean( $_POST['_sku'] ); |
844
|
|
|
|
845
|
|
|
if ( '' == $new_sku ) { |
846
|
|
|
update_post_meta( $post_id, '_sku', '' ); |
847
|
|
|
} elseif ( $new_sku !== $sku ) { |
848
|
|
|
if ( ! empty( $new_sku ) ) { |
849
|
|
|
$unique_sku = wc_product_has_unique_sku( $post_id, $new_sku ); |
850
|
|
|
|
851
|
|
|
if ( ! $unique_sku ) { |
852
|
|
|
WC_Admin_Meta_Boxes::add_error( __( 'Product SKU must be unique.', 'woocommerce' ) ); |
853
|
|
|
} else { |
854
|
|
|
update_post_meta( $post_id, '_sku', $new_sku ); |
855
|
|
|
} |
856
|
|
|
} else { |
857
|
|
|
update_post_meta( $post_id, '_sku', '' ); |
858
|
|
|
} |
859
|
|
|
} |
860
|
|
|
|
861
|
|
|
// Save Attributes |
862
|
|
|
$attributes = array(); |
863
|
|
|
|
864
|
|
|
if ( isset( $_POST['attribute_names'] ) && isset( $_POST['attribute_values'] ) ) { |
865
|
|
|
|
866
|
|
|
$attribute_names = $_POST['attribute_names']; |
867
|
|
|
$attribute_values = $_POST['attribute_values']; |
868
|
|
|
|
869
|
|
|
if ( isset( $_POST['attribute_visibility'] ) ) { |
870
|
|
|
$attribute_visibility = $_POST['attribute_visibility']; |
871
|
|
|
} |
872
|
|
|
|
873
|
|
|
if ( isset( $_POST['attribute_variation'] ) ) { |
874
|
|
|
$attribute_variation = $_POST['attribute_variation']; |
875
|
|
|
} |
876
|
|
|
|
877
|
|
|
$attribute_is_taxonomy = $_POST['attribute_is_taxonomy']; |
878
|
|
|
$attribute_position = $_POST['attribute_position']; |
879
|
|
|
$attribute_names_max_key = max( array_keys( $attribute_names ) ); |
880
|
|
|
|
881
|
|
|
for ( $i = 0; $i <= $attribute_names_max_key; $i++ ) { |
882
|
|
|
if ( empty( $attribute_names[ $i ] ) ) { |
883
|
|
|
continue; |
884
|
|
|
} |
885
|
|
|
|
886
|
|
|
$is_visible = isset( $attribute_visibility[ $i ] ) ? 1 : 0; |
887
|
|
|
$is_variation = isset( $attribute_variation[ $i ] ) ? 1 : 0; |
888
|
|
|
$is_taxonomy = $attribute_is_taxonomy[ $i ] ? 1 : 0; |
889
|
|
|
|
890
|
|
|
if ( $is_taxonomy ) { |
891
|
|
|
|
892
|
|
|
$values_are_slugs = false; |
893
|
|
|
|
894
|
|
|
if ( isset( $attribute_values[ $i ] ) ) { |
895
|
|
|
|
896
|
|
|
// Select based attributes - Format values (posted values are slugs) |
897
|
|
|
if ( is_array( $attribute_values[ $i ] ) ) { |
898
|
|
|
$values = array_map( 'sanitize_title', $attribute_values[ $i ] ); |
899
|
|
|
$values_are_slugs = true; |
900
|
|
|
|
901
|
|
|
// Text based attributes - Posted values are term names - don't change to slugs |
902
|
|
|
} else { |
903
|
|
|
$values = array_map( 'stripslashes', array_map( 'strip_tags', explode( WC_DELIMITER, $attribute_values[ $i ] ) ) ); |
904
|
|
|
} |
905
|
|
|
|
906
|
|
|
// Remove empty items in the array |
907
|
|
|
$values = array_filter( $values, 'strlen' ); |
908
|
|
|
|
909
|
|
|
} else { |
910
|
|
|
$values = array(); |
911
|
|
|
} |
912
|
|
|
|
913
|
|
|
// Update post terms |
914
|
|
|
if ( taxonomy_exists( $attribute_names[ $i ] ) ) { |
915
|
|
|
|
916
|
|
|
foreach( $values as $key => $value ) { |
917
|
|
|
$term = get_term_by( $values_are_slugs ? 'slug' : 'name', trim( $value ), $attribute_names[ $i ] ); |
918
|
|
|
|
919
|
|
|
if ( $term ) { |
920
|
|
|
$values[ $key ] = intval( $term->term_id ); |
921
|
|
|
} else { |
922
|
|
|
$term = wp_insert_term( trim( $value ), $attribute_names[ $i ] ); |
923
|
|
|
if ( isset( $term->term_id ) ) { |
924
|
|
|
$values[ $key ] = intval($term->term_id); |
925
|
|
|
} |
926
|
|
|
} |
927
|
|
|
} |
928
|
|
|
|
929
|
|
|
wp_set_object_terms( $post_id, $values, $attribute_names[ $i ] ); |
930
|
|
|
} |
931
|
|
|
|
932
|
|
View Code Duplication |
if ( ! empty( $values ) ) { |
|
|
|
|
933
|
|
|
// Add attribute to array, but don't set values |
934
|
|
|
$attributes[ sanitize_title( $attribute_names[ $i ] ) ] = array( |
935
|
|
|
'name' => wc_clean( $attribute_names[ $i ] ), |
936
|
|
|
'value' => '', |
937
|
|
|
'position' => $attribute_position[ $i ], |
938
|
|
|
'is_visible' => $is_visible, |
939
|
|
|
'is_variation' => $is_variation, |
940
|
|
|
'is_taxonomy' => $is_taxonomy |
941
|
|
|
); |
942
|
|
|
} |
943
|
|
|
|
944
|
|
View Code Duplication |
} elseif ( isset( $attribute_values[ $i ] ) ) { |
|
|
|
|
945
|
|
|
|
946
|
|
|
// Text based, possibly separated by pipes (WC_DELIMITER). Preserve line breaks in non-variation attributes. |
947
|
|
|
$values = $is_variation ? wc_clean( $attribute_values[ $i ] ) : implode( "\n", array_map( 'wc_clean', explode( "\n", $attribute_values[ $i ] ) ) ); |
948
|
|
|
$values = implode( ' ' . WC_DELIMITER . ' ', wc_get_text_attributes( $values ) ); |
949
|
|
|
|
950
|
|
|
// Custom attribute - Add attribute to array and set the values |
951
|
|
|
$attributes[ sanitize_title( $attribute_names[ $i ] ) ] = array( |
952
|
|
|
'name' => wc_clean( $attribute_names[ $i ] ), |
953
|
|
|
'value' => $values, |
954
|
|
|
'position' => $attribute_position[ $i ], |
955
|
|
|
'is_visible' => $is_visible, |
956
|
|
|
'is_variation' => $is_variation, |
957
|
|
|
'is_taxonomy' => $is_taxonomy |
958
|
|
|
); |
959
|
|
|
} |
960
|
|
|
} |
961
|
|
|
} |
962
|
|
|
|
963
|
|
|
uasort( $attributes, 'wc_product_attribute_uasort_comparison' ); |
964
|
|
|
|
965
|
|
|
/** |
966
|
|
|
* Unset removed attributes by looping over previous values and |
967
|
|
|
* unsetting the terms. |
968
|
|
|
*/ |
969
|
|
|
$old_attributes = array_filter( (array) maybe_unserialize( get_post_meta( $post_id, '_product_attributes', true ) ) ); |
970
|
|
|
|
971
|
|
|
if ( $old_attributes ) { |
|
|
|
|
972
|
|
|
foreach ( $old_attributes as $key => $value ) { |
973
|
|
|
if ( empty( $attributes[ $key ] ) && ! empty( $value['is_taxonomy'] ) && taxonomy_exists( $key ) ) { |
974
|
|
|
wp_set_object_terms( $post_id, array(), $key ); |
975
|
|
|
} |
976
|
|
|
} |
977
|
|
|
} |
978
|
|
|
|
979
|
|
|
/** |
980
|
|
|
* After removed attributes are unset, we can set the new attribute data. |
981
|
|
|
*/ |
982
|
|
|
update_post_meta( $post_id, '_product_attributes', $attributes ); |
983
|
|
|
|
984
|
|
|
// Sales and prices |
985
|
|
|
if ( in_array( $product_type, array( 'variable', 'grouped' ) ) ) { |
986
|
|
|
|
987
|
|
|
// Variable and grouped products have no prices |
988
|
|
|
update_post_meta( $post_id, '_regular_price', '' ); |
989
|
|
|
update_post_meta( $post_id, '_sale_price', '' ); |
990
|
|
|
update_post_meta( $post_id, '_sale_price_dates_from', '' ); |
991
|
|
|
update_post_meta( $post_id, '_sale_price_dates_to', '' ); |
992
|
|
|
|
993
|
|
|
} else { |
994
|
|
|
$date_from = isset( $_POST['_sale_price_dates_from'] ) ? wc_clean( $_POST['_sale_price_dates_from'] ) : ''; |
995
|
|
|
$date_to = isset( $_POST['_sale_price_dates_to'] ) ? wc_clean( $_POST['_sale_price_dates_to'] ) : ''; |
996
|
|
|
$regular_price = isset( $_POST['_regular_price'] ) ? wc_clean( $_POST['_regular_price'] ) : ''; |
997
|
|
|
$sale_price = isset( $_POST['_sale_price'] ) ? wc_clean( $_POST['_sale_price'] ) : ''; |
998
|
|
|
|
999
|
|
|
update_post_meta( $post_id, '_regular_price', '' === $regular_price ? '' : wc_format_decimal( $regular_price ) ); |
1000
|
|
|
update_post_meta( $post_id, '_sale_price', '' === $sale_price ? '' : wc_format_decimal( $sale_price ) ); |
1001
|
|
|
|
1002
|
|
|
// Dates |
1003
|
|
|
update_post_meta( $post_id, '_sale_price_dates_from', $date_from ? strtotime( $date_from ) : '' ); |
1004
|
|
|
update_post_meta( $post_id, '_sale_price_dates_to', $date_to ? strtotime( $date_to ) : '' ); |
1005
|
|
|
|
1006
|
|
|
if ( $date_to && ! $date_from ) { |
1007
|
|
|
$date_from = date( 'Y-m-d' ); |
1008
|
|
|
update_post_meta( $post_id, '_sale_price_dates_from', strtotime( $date_from ) ); |
1009
|
|
|
} |
1010
|
|
|
|
1011
|
|
|
// Update price if on sale |
1012
|
|
|
if ( '' !== $sale_price && '' === $date_to && '' === $date_from ) { |
1013
|
|
|
update_post_meta( $post_id, '_price', wc_format_decimal( $sale_price ) ); |
1014
|
|
View Code Duplication |
} elseif ( '' !== $sale_price && $date_from && strtotime( $date_from ) <= strtotime( 'NOW', current_time( 'timestamp' ) ) ) { |
|
|
|
|
1015
|
|
|
update_post_meta( $post_id, '_price', wc_format_decimal( $sale_price ) ); |
1016
|
|
|
} else { |
1017
|
|
|
update_post_meta( $post_id, '_price', '' === $regular_price ? '' : wc_format_decimal( $regular_price ) ); |
1018
|
|
|
} |
1019
|
|
|
|
1020
|
|
|
if ( $date_to && strtotime( $date_to ) < strtotime( 'NOW', current_time( 'timestamp' ) ) ) { |
1021
|
|
|
update_post_meta( $post_id, '_price', '' === $regular_price ? '' : wc_format_decimal( $regular_price ) ); |
1022
|
|
|
update_post_meta( $post_id, '_sale_price', '' ); |
1023
|
|
|
update_post_meta( $post_id, '_sale_price_dates_from', '' ); |
1024
|
|
|
update_post_meta( $post_id, '_sale_price_dates_to', '' ); |
1025
|
|
|
} |
1026
|
|
|
} |
1027
|
|
|
|
1028
|
|
|
// Update parent if grouped so price sorting works and stays in sync with the cheapest child |
1029
|
|
|
if ( $post->post_parent > 0 || 'grouped' === $product_type || $_POST['previous_parent_id'] > 0 ) { |
1030
|
|
|
|
1031
|
|
|
$clear_parent_ids = array(); |
1032
|
|
|
|
1033
|
|
|
if ( $post->post_parent > 0 ) { |
1034
|
|
|
$clear_parent_ids[] = $post->post_parent; |
1035
|
|
|
} |
1036
|
|
|
|
1037
|
|
|
if ( 'grouped' === $product_type ) { |
1038
|
|
|
$clear_parent_ids[] = $post_id; |
1039
|
|
|
} |
1040
|
|
|
|
1041
|
|
|
if ( $_POST['previous_parent_id'] > 0 ) { |
1042
|
|
|
$clear_parent_ids[] = absint( $_POST['previous_parent_id'] ); |
1043
|
|
|
} |
1044
|
|
|
|
1045
|
|
|
if ( ! empty( $clear_parent_ids ) ) { |
1046
|
|
|
foreach ( $clear_parent_ids as $clear_id ) { |
1047
|
|
|
$children_by_price = get_posts( array( |
1048
|
|
|
'post_parent' => $clear_id, |
1049
|
|
|
'orderby' => 'meta_value_num', |
1050
|
|
|
'order' => 'asc', |
1051
|
|
|
'meta_key' => '_price', |
1052
|
|
|
'posts_per_page' => 1, |
1053
|
|
|
'post_type' => 'product', |
1054
|
|
|
'fields' => 'ids' |
1055
|
|
|
) ); |
1056
|
|
|
|
1057
|
|
|
if ( $children_by_price ) { |
1058
|
|
|
foreach ( $children_by_price as $child ) { |
1059
|
|
|
$child_price = get_post_meta( $child, '_price', true ); |
1060
|
|
|
update_post_meta( $clear_id, '_price', $child_price ); |
1061
|
|
|
} |
1062
|
|
|
} |
1063
|
|
|
|
1064
|
|
|
wc_delete_product_transients( $clear_id ); |
1065
|
|
|
} |
1066
|
|
|
} |
1067
|
|
|
} |
1068
|
|
|
|
1069
|
|
|
// Sold Individually |
1070
|
|
|
if ( ! empty( $_POST['_sold_individually'] ) ) { |
1071
|
|
|
update_post_meta( $post_id, '_sold_individually', 'yes' ); |
1072
|
|
|
} else { |
1073
|
|
|
update_post_meta( $post_id, '_sold_individually', '' ); |
1074
|
|
|
} |
1075
|
|
|
|
1076
|
|
|
// Stock Data |
1077
|
|
|
if ( 'yes' === get_option( 'woocommerce_manage_stock' ) ) { |
1078
|
|
|
|
1079
|
|
|
$manage_stock = 'no'; |
1080
|
|
|
$backorders = 'no'; |
1081
|
|
|
$stock_status = wc_clean( $_POST['_stock_status'] ); |
1082
|
|
|
|
1083
|
|
|
if ( 'external' === $product_type ) { |
1084
|
|
|
|
1085
|
|
|
$stock_status = 'instock'; |
1086
|
|
|
|
1087
|
|
|
} elseif ( 'variable' === $product_type ) { |
1088
|
|
|
|
1089
|
|
|
// Stock status is always determined by children so sync later |
1090
|
|
|
$stock_status = ''; |
1091
|
|
|
|
1092
|
|
|
if ( ! empty( $_POST['_manage_stock'] ) ) { |
1093
|
|
|
$manage_stock = 'yes'; |
1094
|
|
|
$backorders = wc_clean( $_POST['_backorders'] ); |
1095
|
|
|
} |
1096
|
|
|
|
1097
|
|
|
} elseif ( 'grouped' !== $product_type && ! empty( $_POST['_manage_stock'] ) ) { |
1098
|
|
|
$manage_stock = 'yes'; |
1099
|
|
|
$backorders = wc_clean( $_POST['_backorders'] ); |
1100
|
|
|
} |
1101
|
|
|
|
1102
|
|
|
update_post_meta( $post_id, '_manage_stock', $manage_stock ); |
1103
|
|
|
update_post_meta( $post_id, '_backorders', $backorders ); |
1104
|
|
|
|
1105
|
|
|
if ( $stock_status ) { |
1106
|
|
|
wc_update_product_stock_status( $post_id, $stock_status ); |
|
|
|
|
1107
|
|
|
} |
1108
|
|
|
|
1109
|
|
View Code Duplication |
if ( ! empty( $_POST['_manage_stock'] ) ) { |
|
|
|
|
1110
|
|
|
wc_update_product_stock( $post_id, wc_stock_amount( $_POST['_stock'] ) ); |
1111
|
|
|
} else { |
1112
|
|
|
update_post_meta( $post_id, '_stock', '' ); |
1113
|
|
|
} |
1114
|
|
|
|
1115
|
|
|
} elseif ( 'variable' !== $product_type ) { |
1116
|
|
|
wc_update_product_stock_status( $post_id, wc_clean( $_POST['_stock_status'] ) ); |
|
|
|
|
1117
|
|
|
} |
1118
|
|
|
|
1119
|
|
|
// Cross sells and upsells |
1120
|
|
|
$upsells = isset( $_POST['upsell_ids'] ) ? array_filter( array_map( 'intval', explode( ',', $_POST['upsell_ids'] ) ) ) : array(); |
1121
|
|
|
$crosssells = isset( $_POST['crosssell_ids'] ) ? array_filter( array_map( 'intval', explode( ',', $_POST['crosssell_ids'] ) ) ) : array(); |
1122
|
|
|
|
1123
|
|
|
update_post_meta( $post_id, '_upsell_ids', $upsells ); |
1124
|
|
|
update_post_meta( $post_id, '_crosssell_ids', $crosssells ); |
1125
|
|
|
|
1126
|
|
|
// Downloadable options |
1127
|
|
|
if ( 'yes' == $is_downloadable ) { |
1128
|
|
|
|
1129
|
|
|
$_download_limit = absint( $_POST['_download_limit'] ); |
1130
|
|
|
if ( ! $_download_limit ) { |
1131
|
|
|
$_download_limit = ''; // 0 or blank = unlimited |
1132
|
|
|
} |
1133
|
|
|
|
1134
|
|
|
$_download_expiry = absint( $_POST['_download_expiry'] ); |
1135
|
|
|
if ( ! $_download_expiry ) { |
1136
|
|
|
$_download_expiry = ''; // 0 or blank = unlimited |
1137
|
|
|
} |
1138
|
|
|
|
1139
|
|
|
// file paths will be stored in an array keyed off md5(file path) |
1140
|
|
|
$files = array(); |
1141
|
|
|
|
1142
|
|
|
if ( isset( $_POST['_wc_file_urls'] ) ) { |
1143
|
|
|
$file_names = isset( $_POST['_wc_file_names'] ) ? $_POST['_wc_file_names'] : array(); |
1144
|
|
|
$file_urls = isset( $_POST['_wc_file_urls'] ) ? wp_unslash( array_map( 'trim', $_POST['_wc_file_urls'] ) ) : array(); |
1145
|
|
|
$file_url_size = sizeof( $file_urls ); |
1146
|
|
|
$allowed_file_types = apply_filters( 'woocommerce_downloadable_file_allowed_mime_types', get_allowed_mime_types() ); |
1147
|
|
|
|
1148
|
|
|
for ( $i = 0; $i < $file_url_size; $i ++ ) { |
1149
|
|
|
if ( ! empty( $file_urls[ $i ] ) ) { |
1150
|
|
|
// Find type and file URL |
1151
|
|
View Code Duplication |
if ( 0 === strpos( $file_urls[ $i ], 'http' ) ) { |
|
|
|
|
1152
|
|
|
$file_is = 'absolute'; |
1153
|
|
|
$file_url = esc_url_raw( $file_urls[ $i ] ); |
1154
|
|
|
} elseif ( '[' === substr( $file_urls[ $i ], 0, 1 ) && ']' === substr( $file_urls[ $i ], -1 ) ) { |
1155
|
|
|
$file_is = 'shortcode'; |
1156
|
|
|
$file_url = wc_clean( $file_urls[ $i ] ); |
1157
|
|
|
} else { |
1158
|
|
|
$file_is = 'relative'; |
1159
|
|
|
$file_url = wc_clean( $file_urls[ $i ] ); |
1160
|
|
|
} |
1161
|
|
|
|
1162
|
|
|
$file_name = wc_clean( $file_names[ $i ] ); |
1163
|
|
|
$file_hash = md5( $file_url ); |
1164
|
|
|
|
1165
|
|
|
// Validate the file extension |
1166
|
|
View Code Duplication |
if ( in_array( $file_is, array( 'absolute', 'relative' ) ) ) { |
|
|
|
|
1167
|
|
|
$file_type = wp_check_filetype( strtok( $file_url, '?' ), $allowed_file_types ); |
1168
|
|
|
$parsed_url = parse_url( $file_url, PHP_URL_PATH ); |
1169
|
|
|
$extension = pathinfo( $parsed_url, PATHINFO_EXTENSION ); |
1170
|
|
|
|
1171
|
|
|
if ( ! empty( $extension ) && ! in_array( $file_type['type'], $allowed_file_types ) ) { |
1172
|
|
|
WC_Admin_Meta_Boxes::add_error( sprintf( __( 'The downloadable file %s cannot be used as it does not have an allowed file type. Allowed types include: %s', 'woocommerce' ), '<code>' . basename( $file_url ) . '</code>', '<code>' . implode( ', ', array_keys( $allowed_file_types ) ) . '</code>' ) ); |
1173
|
|
|
continue; |
1174
|
|
|
} |
1175
|
|
|
} |
1176
|
|
|
|
1177
|
|
|
// Validate the file exists |
1178
|
|
|
if ( 'relative' === $file_is ) { |
1179
|
|
|
$_file_url = $file_url; |
1180
|
|
|
if ( '..' === substr( $file_url, 0, 2 ) || '/' !== substr( $file_url, 0, 1 ) ) { |
1181
|
|
|
$_file_url = realpath( ABSPATH . $file_url ); |
1182
|
|
|
} |
1183
|
|
|
|
1184
|
|
View Code Duplication |
if ( ! apply_filters( 'woocommerce_downloadable_file_exists', file_exists( $_file_url ), $file_url ) ) { |
|
|
|
|
1185
|
|
|
WC_Admin_Meta_Boxes::add_error( sprintf( __( 'The downloadable file %s cannot be used as it does not exist on the server.', 'woocommerce' ), '<code>' . $file_url . '</code>' ) ); |
1186
|
|
|
continue; |
1187
|
|
|
} |
1188
|
|
|
} |
1189
|
|
|
|
1190
|
|
|
$files[ $file_hash ] = array( |
1191
|
|
|
'name' => $file_name, |
1192
|
|
|
'file' => $file_url |
1193
|
|
|
); |
1194
|
|
|
} |
1195
|
|
|
} |
1196
|
|
|
} |
1197
|
|
|
|
1198
|
|
|
// grant permission to any newly added files on any existing orders for this product prior to saving |
1199
|
|
|
do_action( 'woocommerce_process_product_file_download_paths', $post_id, 0, $files ); |
1200
|
|
|
|
1201
|
|
|
update_post_meta( $post_id, '_downloadable_files', $files ); |
1202
|
|
|
update_post_meta( $post_id, '_download_limit', $_download_limit ); |
1203
|
|
|
update_post_meta( $post_id, '_download_expiry', $_download_expiry ); |
1204
|
|
|
|
1205
|
|
|
if ( isset( $_POST['_download_type'] ) ) { |
1206
|
|
|
update_post_meta( $post_id, '_download_type', wc_clean( $_POST['_download_type'] ) ); |
1207
|
|
|
} |
1208
|
|
|
} |
1209
|
|
|
|
1210
|
|
|
// Product url |
1211
|
|
View Code Duplication |
if ( 'external' == $product_type ) { |
|
|
|
|
1212
|
|
|
|
1213
|
|
|
if ( isset( $_POST['_product_url'] ) ) { |
1214
|
|
|
update_post_meta( $post_id, '_product_url', esc_url_raw( $_POST['_product_url'] ) ); |
1215
|
|
|
} |
1216
|
|
|
|
1217
|
|
|
if ( isset( $_POST['_button_text'] ) ) { |
1218
|
|
|
update_post_meta( $post_id, '_button_text', wc_clean( $_POST['_button_text'] ) ); |
1219
|
|
|
} |
1220
|
|
|
} |
1221
|
|
|
|
1222
|
|
|
// Save variations |
1223
|
|
|
if ( 'variable' == $product_type ) { |
1224
|
|
|
// Update parent if variable so price sorting works and stays in sync with the cheapest child |
1225
|
|
|
WC_Product_Variable::sync( $post_id ); |
1226
|
|
|
WC_Product_Variable::sync_stock_status( $post_id ); |
1227
|
|
|
} |
1228
|
|
|
|
1229
|
|
|
// Update version after saving |
1230
|
|
|
update_post_meta( $post_id, '_product_version', WC_VERSION ); |
1231
|
|
|
|
1232
|
|
|
// Do action for product type |
1233
|
|
|
do_action( 'woocommerce_process_product_meta_' . $product_type, $post_id ); |
1234
|
|
|
|
1235
|
|
|
// Clear cache/transients |
1236
|
|
|
wc_delete_product_transients( $post_id ); |
1237
|
|
|
} |
1238
|
|
|
|
1239
|
|
|
/** |
1240
|
|
|
* Save meta box data. |
1241
|
|
|
* |
1242
|
|
|
* @param int $post_id |
1243
|
|
|
* @param WP_Post $post |
1244
|
|
|
*/ |
1245
|
|
|
public static function save_variations( $post_id, $post ) { |
|
|
|
|
1246
|
|
|
global $wpdb; |
1247
|
|
|
|
1248
|
|
|
$attributes = (array) maybe_unserialize( get_post_meta( $post_id, '_product_attributes', true ) ); |
1249
|
|
|
|
1250
|
|
|
if ( isset( $_POST['variable_sku'] ) ) { |
1251
|
|
|
$variable_post_id = $_POST['variable_post_id']; |
1252
|
|
|
$variable_sku = $_POST['variable_sku']; |
1253
|
|
|
$variable_regular_price = $_POST['variable_regular_price']; |
1254
|
|
|
$variable_sale_price = $_POST['variable_sale_price']; |
1255
|
|
|
$upload_image_id = $_POST['upload_image_id']; |
1256
|
|
|
$variable_download_limit = $_POST['variable_download_limit']; |
1257
|
|
|
$variable_download_expiry = $_POST['variable_download_expiry']; |
1258
|
|
|
$variable_shipping_class = $_POST['variable_shipping_class']; |
1259
|
|
|
$variable_tax_class = isset( $_POST['variable_tax_class'] ) ? $_POST['variable_tax_class'] : array(); |
1260
|
|
|
$variable_menu_order = $_POST['variation_menu_order']; |
1261
|
|
|
$variable_sale_price_dates_from = $_POST['variable_sale_price_dates_from']; |
1262
|
|
|
$variable_sale_price_dates_to = $_POST['variable_sale_price_dates_to']; |
1263
|
|
|
|
1264
|
|
|
$variable_weight = isset( $_POST['variable_weight'] ) ? $_POST['variable_weight'] : array(); |
1265
|
|
|
$variable_length = isset( $_POST['variable_length'] ) ? $_POST['variable_length'] : array(); |
1266
|
|
|
$variable_width = isset( $_POST['variable_width'] ) ? $_POST['variable_width'] : array(); |
1267
|
|
|
$variable_height = isset( $_POST['variable_height'] ) ? $_POST['variable_height'] : array(); |
1268
|
|
|
$variable_enabled = isset( $_POST['variable_enabled'] ) ? $_POST['variable_enabled'] : array(); |
1269
|
|
|
$variable_is_virtual = isset( $_POST['variable_is_virtual'] ) ? $_POST['variable_is_virtual'] : array(); |
1270
|
|
|
$variable_is_downloadable = isset( $_POST['variable_is_downloadable'] ) ? $_POST['variable_is_downloadable'] : array(); |
1271
|
|
|
|
1272
|
|
|
$variable_manage_stock = isset( $_POST['variable_manage_stock'] ) ? $_POST['variable_manage_stock'] : array(); |
1273
|
|
|
$variable_stock = isset( $_POST['variable_stock'] ) ? $_POST['variable_stock'] : array(); |
1274
|
|
|
$variable_backorders = isset( $_POST['variable_backorders'] ) ? $_POST['variable_backorders'] : array(); |
1275
|
|
|
$variable_stock_status = isset( $_POST['variable_stock_status'] ) ? $_POST['variable_stock_status'] : array(); |
1276
|
|
|
|
1277
|
|
|
$variable_description = isset( $_POST['variable_description'] ) ? $_POST['variable_description'] : array(); |
1278
|
|
|
|
1279
|
|
|
$max_loop = max( array_keys( $_POST['variable_post_id'] ) ); |
1280
|
|
|
|
1281
|
|
|
for ( $i = 0; $i <= $max_loop; $i ++ ) { |
1282
|
|
|
|
1283
|
|
|
if ( ! isset( $variable_post_id[ $i ] ) ) { |
1284
|
|
|
continue; |
1285
|
|
|
} |
1286
|
|
|
|
1287
|
|
|
$variation_id = absint( $variable_post_id[ $i ] ); |
1288
|
|
|
|
1289
|
|
|
// Checkboxes |
1290
|
|
|
$is_virtual = isset( $variable_is_virtual[ $i ] ) ? 'yes' : 'no'; |
1291
|
|
|
$is_downloadable = isset( $variable_is_downloadable[ $i ] ) ? 'yes' : 'no'; |
1292
|
|
|
$post_status = isset( $variable_enabled[ $i ] ) ? 'publish' : 'private'; |
1293
|
|
|
$manage_stock = isset( $variable_manage_stock[ $i ] ) ? 'yes' : 'no'; |
1294
|
|
|
|
1295
|
|
|
// Generate a useful post title |
1296
|
|
|
$variation_post_title = sprintf( __( 'Variation #%s of %s', 'woocommerce' ), absint( $variation_id ), esc_html( get_the_title( $post_id ) ) ); |
1297
|
|
|
|
1298
|
|
|
// Update or Add post |
1299
|
|
|
if ( ! $variation_id ) { |
1300
|
|
|
|
1301
|
|
|
$variation = array( |
1302
|
|
|
'post_title' => $variation_post_title, |
1303
|
|
|
'post_content' => '', |
1304
|
|
|
'post_status' => $post_status, |
1305
|
|
|
'post_author' => get_current_user_id(), |
1306
|
|
|
'post_parent' => $post_id, |
1307
|
|
|
'post_type' => 'product_variation', |
1308
|
|
|
'menu_order' => $variable_menu_order[ $i ] |
1309
|
|
|
); |
1310
|
|
|
|
1311
|
|
|
$variation_id = wp_insert_post( $variation ); |
1312
|
|
|
|
1313
|
|
|
do_action( 'woocommerce_create_product_variation', $variation_id ); |
1314
|
|
|
|
1315
|
|
|
} else { |
1316
|
|
|
|
1317
|
|
|
$modified_date = date_i18n( 'Y-m-d H:i:s', current_time( 'timestamp' ) ); |
1318
|
|
|
|
1319
|
|
|
$wpdb->update( $wpdb->posts, array( |
1320
|
|
|
'post_status' => $post_status, |
1321
|
|
|
'post_title' => $variation_post_title, |
1322
|
|
|
'menu_order' => $variable_menu_order[ $i ], |
1323
|
|
|
'post_modified' => $modified_date, |
1324
|
|
|
'post_modified_gmt' => get_gmt_from_date( $modified_date ) |
1325
|
|
|
), array( 'ID' => $variation_id ) ); |
1326
|
|
|
|
1327
|
|
|
clean_post_cache( $variation_id ); |
1328
|
|
|
|
1329
|
|
|
do_action( 'woocommerce_update_product_variation', $variation_id ); |
1330
|
|
|
|
1331
|
|
|
} |
1332
|
|
|
|
1333
|
|
|
// Only continue if we have a variation ID |
1334
|
|
|
if ( ! $variation_id ) { |
1335
|
|
|
continue; |
1336
|
|
|
} |
1337
|
|
|
|
1338
|
|
|
// Unique SKU |
1339
|
|
|
$sku = get_post_meta( $variation_id, '_sku', true ); |
1340
|
|
|
$new_sku = wc_clean( $variable_sku[ $i ] ); |
1341
|
|
|
|
1342
|
|
|
if ( '' == $new_sku ) { |
1343
|
|
|
update_post_meta( $variation_id, '_sku', '' ); |
1344
|
|
|
} elseif ( $new_sku !== $sku ) { |
1345
|
|
|
if ( ! empty( $new_sku ) ) { |
1346
|
|
|
$unique_sku = wc_product_has_unique_sku( $variation_id, $new_sku ); |
1347
|
|
|
|
1348
|
|
|
if ( ! $unique_sku ) { |
1349
|
|
|
WC_Admin_Meta_Boxes::add_error( sprintf( __( '#%s – Variation SKU must be unique.', 'woocommerce' ), $variation_id ) ); |
1350
|
|
|
} else { |
1351
|
|
|
update_post_meta( $variation_id, '_sku', $new_sku ); |
1352
|
|
|
} |
1353
|
|
|
} else { |
1354
|
|
|
update_post_meta( $variation_id, '_sku', '' ); |
1355
|
|
|
} |
1356
|
|
|
} |
1357
|
|
|
|
1358
|
|
|
// Update post meta |
1359
|
|
|
update_post_meta( $variation_id, '_thumbnail_id', absint( $upload_image_id[ $i ] ) ); |
1360
|
|
|
update_post_meta( $variation_id, '_virtual', wc_clean( $is_virtual ) ); |
1361
|
|
|
update_post_meta( $variation_id, '_downloadable', wc_clean( $is_downloadable ) ); |
1362
|
|
|
|
1363
|
|
View Code Duplication |
if ( isset( $variable_weight[ $i ] ) ) { |
|
|
|
|
1364
|
|
|
update_post_meta( $variation_id, '_weight', ( '' === $variable_weight[ $i ] ) ? '' : wc_format_decimal( $variable_weight[ $i ] ) ); |
1365
|
|
|
} |
1366
|
|
|
|
1367
|
|
View Code Duplication |
if ( isset( $variable_length[ $i ] ) ) { |
|
|
|
|
1368
|
|
|
update_post_meta( $variation_id, '_length', ( '' === $variable_length[ $i ] ) ? '' : wc_format_decimal( $variable_length[ $i ] ) ); |
1369
|
|
|
} |
1370
|
|
|
|
1371
|
|
View Code Duplication |
if ( isset( $variable_width[ $i ] ) ) { |
|
|
|
|
1372
|
|
|
update_post_meta( $variation_id, '_width', ( '' === $variable_width[ $i ] ) ? '' : wc_format_decimal( $variable_width[ $i ] ) ); |
1373
|
|
|
} |
1374
|
|
|
|
1375
|
|
View Code Duplication |
if ( isset( $variable_height[ $i ] ) ) { |
|
|
|
|
1376
|
|
|
update_post_meta( $variation_id, '_height', ( '' === $variable_height[ $i ] ) ? '' : wc_format_decimal( $variable_height[ $i ] ) ); |
1377
|
|
|
} |
1378
|
|
|
|
1379
|
|
|
// Stock handling |
1380
|
|
|
update_post_meta( $variation_id, '_manage_stock', $manage_stock ); |
1381
|
|
|
|
1382
|
|
|
if ( 'yes' === $manage_stock ) { |
1383
|
|
|
update_post_meta( $variation_id, '_backorders', wc_clean( $variable_backorders[ $i ] ) ); |
1384
|
|
|
wc_update_product_stock( $variation_id, wc_stock_amount( $variable_stock[ $i ] ) ); |
1385
|
|
|
} else { |
1386
|
|
|
delete_post_meta( $variation_id, '_backorders' ); |
1387
|
|
|
delete_post_meta( $variation_id, '_stock' ); |
1388
|
|
|
} |
1389
|
|
|
|
1390
|
|
|
// Only update stock status to user setting if changed by the user, but do so before looking at stock levels at variation level |
1391
|
|
|
if ( ! empty( $variable_stock_status[ $i ] ) ) { |
1392
|
|
|
wc_update_product_stock_status( $variation_id, $variable_stock_status[ $i ] ); |
1393
|
|
|
} |
1394
|
|
|
|
1395
|
|
|
// Price handling |
1396
|
|
|
$regular_price = wc_format_decimal( $variable_regular_price[ $i ] ); |
1397
|
|
|
$sale_price = $variable_sale_price[ $i ] === '' ? '' : wc_format_decimal( $variable_sale_price[ $i ] ); |
1398
|
|
|
$date_from = wc_clean( $variable_sale_price_dates_from[ $i ] ); |
1399
|
|
|
$date_to = wc_clean( $variable_sale_price_dates_to[ $i ] ); |
1400
|
|
|
|
1401
|
|
|
update_post_meta( $variation_id, '_regular_price', $regular_price ); |
1402
|
|
|
update_post_meta( $variation_id, '_sale_price', $sale_price ); |
1403
|
|
|
|
1404
|
|
|
// Save Dates |
1405
|
|
|
update_post_meta( $variation_id, '_sale_price_dates_from', $date_from ? strtotime( $date_from ) : '' ); |
1406
|
|
|
update_post_meta( $variation_id, '_sale_price_dates_to', $date_to ? strtotime( $date_to ) : '' ); |
1407
|
|
|
|
1408
|
|
|
if ( $date_to && ! $date_from ) { |
1409
|
|
|
update_post_meta( $variation_id, '_sale_price_dates_from', strtotime( 'NOW', current_time( 'timestamp' ) ) ); |
1410
|
|
|
} |
1411
|
|
|
|
1412
|
|
|
// Update price if on sale |
1413
|
|
View Code Duplication |
if ( '' !== $sale_price && '' === $date_to && '' === $date_from ) { |
|
|
|
|
1414
|
|
|
update_post_meta( $variation_id, '_price', $sale_price ); |
1415
|
|
|
} else { |
1416
|
|
|
update_post_meta( $variation_id, '_price', $regular_price ); |
1417
|
|
|
} |
1418
|
|
|
|
1419
|
|
View Code Duplication |
if ( '' !== $sale_price && $date_from && strtotime( $date_from ) < strtotime( 'NOW', current_time( 'timestamp' ) ) ) { |
|
|
|
|
1420
|
|
|
update_post_meta( $variation_id, '_price', $sale_price ); |
1421
|
|
|
} |
1422
|
|
|
|
1423
|
|
View Code Duplication |
if ( $date_to && strtotime( $date_to ) < strtotime( 'NOW', current_time( 'timestamp' ) ) ) { |
|
|
|
|
1424
|
|
|
update_post_meta( $variation_id, '_price', $regular_price ); |
1425
|
|
|
update_post_meta( $variation_id, '_sale_price_dates_from', '' ); |
1426
|
|
|
update_post_meta( $variation_id, '_sale_price_dates_to', '' ); |
1427
|
|
|
} |
1428
|
|
|
|
1429
|
|
|
if ( isset( $variable_tax_class[ $i ] ) && $variable_tax_class[ $i ] !== 'parent' ) { |
1430
|
|
|
update_post_meta( $variation_id, '_tax_class', wc_clean( $variable_tax_class[ $i ] ) ); |
1431
|
|
|
} else { |
1432
|
|
|
delete_post_meta( $variation_id, '_tax_class' ); |
1433
|
|
|
} |
1434
|
|
|
|
1435
|
|
|
if ( 'yes' == $is_downloadable ) { |
1436
|
|
|
update_post_meta( $variation_id, '_download_limit', wc_clean( $variable_download_limit[ $i ] ) ); |
1437
|
|
|
update_post_meta( $variation_id, '_download_expiry', wc_clean( $variable_download_expiry[ $i ] ) ); |
1438
|
|
|
|
1439
|
|
|
$files = array(); |
1440
|
|
|
$file_names = isset( $_POST['_wc_variation_file_names'][ $variation_id ] ) ? array_map( 'wc_clean', $_POST['_wc_variation_file_names'][ $variation_id ] ) : array(); |
1441
|
|
|
$file_urls = isset( $_POST['_wc_variation_file_urls'][ $variation_id ] ) ? array_map( 'wc_clean', $_POST['_wc_variation_file_urls'][ $variation_id ] ) : array(); |
1442
|
|
|
$file_url_size = sizeof( $file_urls ); |
1443
|
|
|
$allowed_file_types = get_allowed_mime_types(); |
1444
|
|
|
|
1445
|
|
|
for ( $ii = 0; $ii < $file_url_size; $ii ++ ) { |
1446
|
|
|
if ( ! empty( $file_urls[ $ii ] ) ) { |
1447
|
|
|
// Find type and file URL |
1448
|
|
View Code Duplication |
if ( 0 === strpos( $file_urls[ $ii ], 'http' ) ) { |
|
|
|
|
1449
|
|
|
$file_is = 'absolute'; |
1450
|
|
|
$file_url = esc_url_raw( $file_urls[ $ii ] ); |
1451
|
|
|
} elseif ( '[' === substr( $file_urls[ $ii ], 0, 1 ) && ']' === substr( $file_urls[ $ii ], -1 ) ) { |
1452
|
|
|
$file_is = 'shortcode'; |
1453
|
|
|
$file_url = wc_clean( $file_urls[ $ii ] ); |
1454
|
|
|
} else { |
1455
|
|
|
$file_is = 'relative'; |
1456
|
|
|
$file_url = wc_clean( $file_urls[ $ii ] ); |
1457
|
|
|
} |
1458
|
|
|
|
1459
|
|
|
$file_name = wc_clean( $file_names[ $ii ] ); |
1460
|
|
|
$file_hash = md5( $file_url ); |
1461
|
|
|
|
1462
|
|
|
// Validate the file extension |
1463
|
|
View Code Duplication |
if ( in_array( $file_is, array( 'absolute', 'relative' ) ) ) { |
|
|
|
|
1464
|
|
|
$file_type = wp_check_filetype( strtok( $file_url, '?' ), $allowed_file_types ); |
1465
|
|
|
$parsed_url = parse_url( $file_url, PHP_URL_PATH ); |
1466
|
|
|
$extension = pathinfo( $parsed_url, PATHINFO_EXTENSION ); |
1467
|
|
|
|
1468
|
|
|
if ( ! empty( $extension ) && ! in_array( $file_type['type'], $allowed_file_types ) ) { |
1469
|
|
|
WC_Admin_Meta_Boxes::add_error( sprintf( __( '#%s – The downloadable file %s cannot be used as it does not have an allowed file type. Allowed types include: %s', 'woocommerce' ), $variation_id, '<code>' . basename( $file_url ) . '</code>', '<code>' . implode( ', ', array_keys( $allowed_file_types ) ) . '</code>' ) ); |
1470
|
|
|
continue; |
1471
|
|
|
} |
1472
|
|
|
} |
1473
|
|
|
|
1474
|
|
|
// Validate the file exists |
1475
|
|
View Code Duplication |
if ( 'relative' === $file_is && ! apply_filters( 'woocommerce_downloadable_file_exists', file_exists( $file_url ), $file_url ) ) { |
|
|
|
|
1476
|
|
|
WC_Admin_Meta_Boxes::add_error( sprintf( __( '#%s – The downloadable file %s cannot be used as it does not exist on the server.', 'woocommerce' ), $variation_id, '<code>' . $file_url . '</code>' ) ); |
1477
|
|
|
continue; |
1478
|
|
|
} |
1479
|
|
|
|
1480
|
|
|
$files[ $file_hash ] = array( |
1481
|
|
|
'name' => $file_name, |
1482
|
|
|
'file' => $file_url |
1483
|
|
|
); |
1484
|
|
|
} |
1485
|
|
|
} |
1486
|
|
|
|
1487
|
|
|
// grant permission to any newly added files on any existing orders for this product prior to saving |
1488
|
|
|
do_action( 'woocommerce_process_product_file_download_paths', $post_id, $variation_id, $files ); |
1489
|
|
|
|
1490
|
|
|
update_post_meta( $variation_id, '_downloadable_files', $files ); |
1491
|
|
|
} else { |
1492
|
|
|
update_post_meta( $variation_id, '_download_limit', '' ); |
1493
|
|
|
update_post_meta( $variation_id, '_download_expiry', '' ); |
1494
|
|
|
update_post_meta( $variation_id, '_downloadable_files', '' ); |
1495
|
|
|
} |
1496
|
|
|
|
1497
|
|
|
update_post_meta( $variation_id, '_variation_description', wp_kses_post( $variable_description[ $i ] ) ); |
1498
|
|
|
|
1499
|
|
|
// Save shipping class |
1500
|
|
|
$variable_shipping_class[ $i ] = ! empty( $variable_shipping_class[ $i ] ) ? (int) $variable_shipping_class[ $i ] : ''; |
1501
|
|
|
wp_set_object_terms( $variation_id, $variable_shipping_class[ $i ], 'product_shipping_class'); |
1502
|
|
|
|
1503
|
|
|
// Update Attributes |
1504
|
|
|
$updated_attribute_keys = array(); |
1505
|
|
|
foreach ( $attributes as $attribute ) { |
1506
|
|
|
if ( $attribute['is_variation'] ) { |
1507
|
|
|
$attribute_key = 'attribute_' . sanitize_title( $attribute['name'] ); |
1508
|
|
|
$updated_attribute_keys[] = $attribute_key; |
1509
|
|
|
|
1510
|
|
|
if ( $attribute['is_taxonomy'] ) { |
1511
|
|
|
// Don't use wc_clean as it destroys sanitized characters |
1512
|
|
|
$value = isset( $_POST[ $attribute_key ][ $i ] ) ? sanitize_title( stripslashes( $_POST[ $attribute_key ][ $i ] ) ) : ''; |
1513
|
|
|
} else { |
1514
|
|
|
$value = isset( $_POST[ $attribute_key ][ $i ] ) ? wc_clean( stripslashes( $_POST[ $attribute_key ][ $i ] ) ) : ''; |
1515
|
|
|
} |
1516
|
|
|
|
1517
|
|
|
update_post_meta( $variation_id, $attribute_key, $value ); |
1518
|
|
|
} |
1519
|
|
|
} |
1520
|
|
|
|
1521
|
|
|
// Remove old taxonomies attributes so data is kept up to date - first get attribute key names |
1522
|
|
|
$delete_attribute_keys = $wpdb->get_col( $wpdb->prepare( "SELECT meta_key FROM {$wpdb->postmeta} WHERE meta_key LIKE 'attribute_%%' AND meta_key NOT IN ( '" . implode( "','", $updated_attribute_keys ) . "' ) AND post_id = %d;", $variation_id ) ); |
1523
|
|
|
|
1524
|
|
|
foreach ( $delete_attribute_keys as $key ) { |
1525
|
|
|
delete_post_meta( $variation_id, $key ); |
1526
|
|
|
} |
1527
|
|
|
|
1528
|
|
|
do_action( 'woocommerce_save_product_variation', $variation_id, $i ); |
1529
|
|
|
} |
1530
|
|
|
} |
1531
|
|
|
|
1532
|
|
|
// Update parent if variable so price sorting works and stays in sync with the cheapest child |
1533
|
|
|
WC_Product_Variable::sync( $post_id ); |
1534
|
|
|
|
1535
|
|
|
// Update default attribute options setting |
1536
|
|
|
$default_attributes = array(); |
1537
|
|
|
|
1538
|
|
|
foreach ( $attributes as $attribute ) { |
1539
|
|
|
|
1540
|
|
|
if ( $attribute['is_variation'] ) { |
1541
|
|
|
$value = ''; |
1542
|
|
|
|
1543
|
|
|
if ( isset( $_POST[ 'default_attribute_' . sanitize_title( $attribute['name'] ) ] ) ) { |
1544
|
|
|
if ( $attribute['is_taxonomy'] ) { |
1545
|
|
|
// Don't use wc_clean as it destroys sanitized characters |
1546
|
|
|
$value = sanitize_title( trim( stripslashes( $_POST[ 'default_attribute_' . sanitize_title( $attribute['name'] ) ] ) ) ); |
1547
|
|
|
} else { |
1548
|
|
|
$value = wc_clean( trim( stripslashes( $_POST[ 'default_attribute_' . sanitize_title( $attribute['name'] ) ] ) ) ); |
1549
|
|
|
} |
1550
|
|
|
} |
1551
|
|
|
|
1552
|
|
|
if ( $value ) { |
1553
|
|
|
$default_attributes[ sanitize_title( $attribute['name'] ) ] = $value; |
1554
|
|
|
} |
1555
|
|
|
} |
1556
|
|
|
} |
1557
|
|
|
|
1558
|
|
|
update_post_meta( $post_id, '_default_attributes', $default_attributes ); |
1559
|
|
|
} |
1560
|
|
|
} |
1561
|
|
|
|
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.