1
|
|
|
<?php |
2
|
|
|
function _wpsc_ajax_purchase_log_refund_items() { |
3
|
|
|
if ( isset( $_POST['order_id'] ) ) { |
4
|
|
|
|
5
|
|
|
_wpsc_ajax_verify_nonce( 'purchase_log_refund_items' ); |
6
|
|
|
|
7
|
|
|
if ( ! current_user_can( 'manage_options' ) ) { |
8
|
|
|
die( -1 ); |
9
|
|
|
} |
10
|
|
|
|
11
|
|
|
$order_id = absint( $_POST['order_id'] ); |
12
|
|
|
$refund_reason = isset( $_POST['refund_reason'] ) ? sanitize_text_field( $_POST['refund_reason'] ) : ''; |
13
|
|
|
$refund_amount = isset( $_POST['refund_amount'] ) ? sanitize_text_field( $_POST['refund_amount'] ) : false; |
14
|
|
|
$manual = $_POST['api_refund'] === 'true' ? false : true; |
15
|
|
|
$refund = false; |
16
|
|
|
$response_data = array(); |
17
|
|
|
$gateway_id = $log->get( 'gateway' ); |
|
|
|
|
18
|
|
|
$gateway = wpsc_get_payment_gateway( $gateway_id ); |
19
|
|
|
|
20
|
|
|
try { |
21
|
|
|
// Validate that the refund can occur |
22
|
|
|
$log = new WPSC_Purchase_Log( $order_id ); |
23
|
|
|
$order_items = $log->get_items(); |
24
|
|
|
$refund_amount = $refund_amount ? $refund_amount : $log->get( 'totalprice' ); |
25
|
|
|
|
26
|
|
|
if ( wpsc_payment_gateway_supports( $gateway_id, 'refunds' ) ) { |
27
|
|
|
// Send api request to process refund. Returns Refund transaction ID |
28
|
|
|
$result = $gateway->process_refund( $order_id, $refund_amount, $refund_reason, $manual ); |
29
|
|
|
|
30
|
|
|
do_action( 'wpsc_refund_processed', $log, $result, $refund_amount, $refund_reason ); |
31
|
|
|
|
32
|
|
|
if ( is_wp_error( $result ) ) { |
33
|
|
|
throw new Exception( $result->get_error_message() ); |
34
|
|
|
} elseif ( ! $result ) { |
35
|
|
|
throw new Exception( __( 'Refund failed', 'wp-e-commerce' ) ); |
36
|
|
|
} |
37
|
|
|
} |
38
|
|
|
|
39
|
|
|
if ( $log->get_remaining_refund() > 0 ) { |
40
|
|
|
/** |
41
|
|
|
* wpsc_order_partially_refunded. |
42
|
|
|
* |
43
|
|
|
* @since 4.0.0 |
44
|
|
|
*/ |
45
|
|
|
do_action( 'wpsc_order_partially_refunded', $log ); |
46
|
|
|
$response_data['status'] = 'partially_refunded'; |
47
|
|
|
|
48
|
|
|
} else { |
49
|
|
|
/** |
50
|
|
|
* wpsc_order_fully_refunded. |
51
|
|
|
* |
52
|
|
|
* @since 4.0.0 |
53
|
|
|
*/ |
54
|
|
|
do_action( 'wpsc_order_fully_refunded', $log ); |
55
|
|
|
$response_data['status'] = 'fully_refunded'; |
56
|
|
|
} |
57
|
|
|
|
|
|
|
|
58
|
|
|
|
59
|
|
|
wp_send_json_success( $response_data ); |
60
|
|
|
|
61
|
|
|
} catch ( Exception $e ) { |
62
|
|
|
wp_send_json_error( array( 'error' => $e->getMessage() ) ); |
63
|
|
|
} |
64
|
|
|
} |
65
|
|
|
return new WP_Error( 'wpsc_ajax_invalid_purchase_log_refund_items', __( 'Refund failed.', 'wp-e-commerce' ) ); |
66
|
|
|
} |
67
|
|
|
|
68
|
|
|
/** |
69
|
|
|
* Verify nonce of an AJAX request |
70
|
|
|
* |
71
|
|
|
* @since 3.8.9 |
72
|
|
|
* @access private |
73
|
|
|
* |
74
|
|
|
* @uses WP_Error WordPress Error Class |
75
|
|
|
* @uses wp_verify_nonce() Verify that correct nonce was used with time limit. |
76
|
|
|
* |
77
|
|
|
* @param string $ajax_action Name of AJAX action |
78
|
|
|
* @return WP_Error|boolean True if nonce is valid. WP_Error if otherwise. |
79
|
|
|
*/ |
80
|
|
|
function _wpsc_ajax_verify_nonce( $ajax_action ) { |
81
|
|
|
// nonce can be passed with name wpsc_nonce or _wpnonce |
82
|
|
|
$nonce = ''; |
83
|
|
|
|
84
|
|
|
if ( isset( $_REQUEST['nonce'] ) ) |
85
|
|
|
$nonce = $_REQUEST['nonce']; |
86
|
|
|
elseif ( isset( $_REQUEST['_wpnonce'] ) ) |
87
|
|
|
$nonce = $_REQUEST['_wpnonce']; |
88
|
|
|
else |
89
|
|
|
return _wpsc_error_invalid_nonce(); |
90
|
|
|
|
91
|
|
|
// validate nonce |
92
|
|
|
if ( ! wp_verify_nonce( $nonce, 'wpsc_ajax_' . $ajax_action ) ) |
93
|
|
|
return _wpsc_error_invalid_nonce(); |
94
|
|
|
|
95
|
|
|
return true; |
96
|
|
|
} |
97
|
|
|
|
98
|
|
|
function _wpsc_error_invalid_nonce() { |
99
|
|
|
return new WP_Error( 'wpsc_ajax_invalid_nonce', __( 'Your session has expired. Please refresh the page and try again.', 'wp-e-commerce' ) ); |
100
|
|
|
} |
101
|
|
|
|
102
|
|
|
/** |
103
|
|
|
* Verify AJAX callback and call it if it exists. |
104
|
|
|
* |
105
|
|
|
* @since 3.8.9 |
106
|
|
|
* @access private |
107
|
|
|
* |
108
|
|
|
* @uses WP_Error WordPress Error object |
109
|
|
|
* |
110
|
|
|
* @param string $ajax_action Name of AJAX action |
111
|
|
|
* @return WP_Error|array Array of response args if callback is valid. WP_Error if otherwise. |
112
|
|
|
*/ |
113
|
|
|
function _wpsc_ajax_fire_callback( $ajax_action ) { |
114
|
|
|
// if callback exists, call it and output JSON response |
115
|
|
|
$callback = "_wpsc_ajax_{$ajax_action}"; |
116
|
|
|
|
117
|
|
|
if ( is_callable( $callback ) ) |
118
|
|
|
$result = call_user_func( $callback ); |
119
|
|
|
else |
120
|
|
|
$result = new WP_Error( 'wpsc_invalid_ajax_callback', __( 'Invalid AJAX callback.', 'wp-e-commerce' ) ); |
121
|
|
|
|
122
|
|
|
return $result; |
123
|
|
|
} |
124
|
|
|
|
125
|
|
|
/** |
126
|
|
|
* AJAX handler for all WPEC ajax requests. |
127
|
|
|
* |
128
|
|
|
* This function automates nonce checking and outputs JSON response. |
129
|
|
|
* |
130
|
|
|
* @since 3.8.9 |
131
|
|
|
* @access private |
132
|
|
|
* |
133
|
|
|
* @uses _wpsc_ajax_fire_callback() Verify ajax callback if it exists |
134
|
|
|
* @uses _wpsc_ajax_verify_nonce() Verify nonce of an ajax request |
135
|
|
|
* @uses is_wp_error() Check whether variable is a WordPress Error. |
136
|
|
|
* |
137
|
|
|
* @return array $output json encoded response |
|
|
|
|
138
|
|
|
*/ |
139
|
|
|
function _wpsc_ajax_handler() { |
140
|
|
|
$ajax_action = str_replace( '-', '_', $_REQUEST['wpsc_action'] ); |
141
|
|
|
|
142
|
|
|
if ( is_callable( '_wpsc_ajax_verify_' . $ajax_action ) ) { |
143
|
|
|
$result = call_user_func( '_wpsc_ajax_verify_' . $ajax_action ); |
144
|
|
|
} else { |
145
|
|
|
$result = _wpsc_ajax_verify_nonce( $ajax_action ); |
146
|
|
|
} |
147
|
|
|
|
148
|
|
|
if ( ! is_wp_error( $result ) ) { |
149
|
|
|
$result = _wpsc_ajax_fire_callback( $ajax_action ); |
150
|
|
|
} |
151
|
|
|
|
152
|
|
|
$output = array( |
153
|
|
|
'is_successful' => false, |
154
|
|
|
); |
155
|
|
|
|
156
|
|
|
if ( is_wp_error( $result ) ) { |
157
|
|
|
$output['error'] = array( |
158
|
|
|
'code' => $result->get_error_code(), |
159
|
|
|
'messages' => $result->get_error_messages(), |
160
|
|
|
'data' => $result->get_error_data(), |
161
|
|
|
); |
162
|
|
|
} else { |
163
|
|
|
$output['is_successful'] = true; |
164
|
|
|
$output['obj'] = $result; |
165
|
|
|
} |
166
|
|
|
|
167
|
|
|
echo json_encode( $output ); |
168
|
|
|
exit; |
169
|
|
|
} |
170
|
|
|
add_action( 'wp_ajax_wpsc_ajax', '_wpsc_ajax_handler' ); |
171
|
|
|
|
172
|
|
|
/** |
173
|
|
|
* Checks if WPSC is doing ajax |
174
|
|
|
* |
175
|
|
|
* @param string $action req The action we're checking |
176
|
|
|
* @return bool True if doing ajax |
177
|
|
|
*/ |
178
|
|
|
function wpsc_is_doing_ajax( $action = '' ) { |
179
|
|
|
$ajax = defined( 'DOING_AJAX' ) && DOING_AJAX && ! empty( $_REQUEST['action'] ) && $_REQUEST['action'] == 'wpsc_ajax'; |
180
|
|
|
|
181
|
|
|
if ( $action ) { |
182
|
|
|
$ajax = $ajax && ! empty( $_REQUEST['wpsc_action'] ) && $action == str_replace( '-', '_', $_REQUEST['wpsc_action'] ); |
183
|
|
|
} |
184
|
|
|
|
185
|
|
|
return $ajax; |
186
|
|
|
} |
187
|
|
|
|
188
|
|
|
/** |
189
|
|
|
* Helper function that generates nonce for an AJAX action. Basically just a wrapper of |
190
|
|
|
* wp_create_nonce() but automatically add prefix. |
191
|
|
|
* |
192
|
|
|
* @since 3.8.9 |
193
|
|
|
* @access private |
194
|
|
|
* |
195
|
|
|
* @uses wp_create_nonce() Creates a random one time use token |
196
|
|
|
* |
197
|
|
|
* @param string $action AJAX action without prefix |
|
|
|
|
198
|
|
|
* @return string The generated nonce. |
199
|
|
|
*/ |
200
|
|
|
function _wpsc_create_ajax_nonce( $ajax_action ) { |
201
|
|
|
return wp_create_nonce( "wpsc_ajax_{$ajax_action}" ); |
202
|
|
|
} |
203
|
|
|
|
204
|
|
|
/** |
205
|
|
|
* Add new variation set via AJAX. |
206
|
|
|
* |
207
|
|
|
* If the variation set name is the same as an existing variation set, |
208
|
|
|
* the children variant terms will be added inside that existing set. |
209
|
|
|
* |
210
|
|
|
* @since 3.8.8 |
211
|
|
|
* @access private |
212
|
|
|
* |
213
|
|
|
* @uses term_exists() Returns true if term exists |
214
|
|
|
* @uses get_term() Gets all term data by term_id |
215
|
|
|
* @uses wp_insert_term() Inserts a term to the WordPress database |
216
|
|
|
* @uses is_wp_error() Checks whether variable is a WordPress error |
217
|
|
|
* @uses WP_Error WordPress Error class |
218
|
|
|
* @uses clean_term_cache() Will remove all of the term ids from the cache. |
219
|
|
|
* @uses delete_option() Deletes option from the database |
220
|
|
|
* @uses wp_cache_set() Saves the data to the cache. |
221
|
|
|
* @uses _get_term_hierarchy() Retrieves children of taxonomy as Term IDs. |
222
|
|
|
* @uses wp_terms_checklist() Output an unordered list of checkbox <input> elements labelled |
223
|
|
|
* @uses WPSC_Walker_Variation_Checklist Walker variation checklist |
224
|
|
|
* |
225
|
|
|
* @return array Response args |
226
|
|
|
*/ |
227
|
|
|
function _wpsc_ajax_add_variation_set() { |
228
|
|
|
$new_variation_set = $_POST['variation_set']; |
229
|
|
|
$variants = preg_split( '/\s*,\s*/', $_POST['variants'] ); |
230
|
|
|
|
231
|
|
|
$return = array(); |
232
|
|
|
|
233
|
|
|
$parent_term_exists = term_exists( $new_variation_set, 'wpsc-variation' ); |
234
|
|
|
|
235
|
|
|
// only use an existing parent ID if the term is not a child term |
236
|
|
|
if ( $parent_term_exists ) { |
237
|
|
|
$parent_term = get_term( $parent_term_exists['term_id'], 'wpsc-variation' ); |
238
|
|
|
if ( $parent_term->parent == '0' ) |
239
|
|
|
$variation_set_id = $parent_term_exists['term_id']; |
240
|
|
|
} |
241
|
|
|
|
242
|
|
|
if ( empty( $variation_set_id ) ) { |
243
|
|
|
$results = wp_insert_term( apply_filters( 'wpsc_new_variation_set', $new_variation_set ), 'wpsc-variation' ); |
244
|
|
|
if ( is_wp_error( $results ) ) |
245
|
|
|
return $results; |
246
|
|
|
$variation_set_id = $results['term_id']; |
247
|
|
|
} |
248
|
|
|
|
249
|
|
|
if ( empty( $variation_set_id ) ) |
250
|
|
|
return new WP_Error( 'wpsc_invalid_variation_id', __( 'Cannot retrieve the variation set in order to proceed.', 'wp-e-commerce' ) ); |
251
|
|
|
|
252
|
|
|
foreach ( $variants as $variant ) { |
253
|
|
|
$results = wp_insert_term( apply_filters( 'wpsc_new_variant', $variant, $variation_set_id ), 'wpsc-variation', array( 'parent' => $variation_set_id ) ); |
254
|
|
|
|
255
|
|
|
if ( is_wp_error( $results ) ) |
256
|
|
|
return $results; |
257
|
|
|
|
258
|
|
|
$inserted_variants[] = $results['term_id']; |
|
|
|
|
259
|
|
|
} |
260
|
|
|
|
261
|
|
|
require_once( 'includes/walker-variation-checklist.php' ); |
262
|
|
|
|
263
|
|
|
if ( ! version_compare( $GLOBALS['wp_version'], '3.8.3', '>' ) ) { |
264
|
|
|
|
265
|
|
|
/* --- DIRTY HACK START --- */ |
266
|
|
|
/* |
267
|
|
|
There's a bug with term cache in WordPress core. See http://core.trac.wordpress.org/ticket/14485. Fixed in 3.9. |
268
|
|
|
The next 3 lines will delete children term cache for wpsc-variation. |
269
|
|
|
Without this hack, the new child variations won't be displayed on "Variations" page and |
270
|
|
|
also won't be displayed in wp_terms_checklist() call below. |
271
|
|
|
*/ |
272
|
|
|
clean_term_cache( $variation_set_id, 'wpsc-variation' ); |
273
|
|
|
delete_option('wpsc-variation_children'); |
274
|
|
|
wp_cache_set( 'last_changed', 1, 'terms' ); |
275
|
|
|
_get_term_hierarchy('wpsc-variation'); |
276
|
|
|
/* --- DIRTY HACK END --- */ |
277
|
|
|
|
278
|
|
|
} |
279
|
|
|
|
280
|
|
|
ob_start(); |
281
|
|
|
|
282
|
|
|
wp_terms_checklist( (int) $_POST['post_id'], array( |
283
|
|
|
'taxonomy' => 'wpsc-variation', |
284
|
|
|
'descendants_and_self' => $variation_set_id, |
285
|
|
|
'walker' => new WPSC_Walker_Variation_Checklist( $inserted_variants ), |
|
|
|
|
286
|
|
|
'checked_ontop' => false, |
287
|
|
|
) ); |
288
|
|
|
|
289
|
|
|
$content = ob_get_clean(); |
290
|
|
|
|
291
|
|
|
$return = array( |
292
|
|
|
'variation_set_id' => $variation_set_id, |
293
|
|
|
'inserted_variants' => $inserted_variants, |
294
|
|
|
'content' => $content, |
295
|
|
|
); |
296
|
|
|
|
297
|
|
|
return $return; |
298
|
|
|
} |
299
|
|
|
|
300
|
|
|
/** |
301
|
|
|
* Display gateway settings form via AJAX |
302
|
|
|
* |
303
|
|
|
* @since 3.8.9 |
304
|
|
|
* @access private |
305
|
|
|
* |
306
|
|
|
* @uses WPSC_Settings_Tab_Gateway |
307
|
|
|
* @uses WPSC_Settings_Tab_Gateway::display_payment_gateway_settings_form() Displays payment gateway form |
308
|
|
|
* |
309
|
|
|
* @return array Response args |
|
|
|
|
310
|
|
|
*/ |
311
|
|
|
function _wpsc_ajax_payment_gateway_settings_form() { |
312
|
|
|
|
313
|
|
|
require_once( 'settings-page.php' ); |
314
|
|
|
require_once( 'includes/settings-tabs/gateway.php' ); |
315
|
|
|
|
316
|
|
|
$return = array(); |
317
|
|
|
ob_start(); |
318
|
|
|
$tab = new WPSC_Settings_Tab_Gateway(); |
319
|
|
|
$tab->display_payment_gateway_settings_form(); |
320
|
|
|
$return['content'] = ob_get_clean(); |
321
|
|
|
|
322
|
|
|
return $return; |
323
|
|
|
} |
324
|
|
|
|
325
|
|
|
/** |
326
|
|
|
* Display shipping module settings form via AJAX |
327
|
|
|
* |
328
|
|
|
* @since 3.8.9 |
329
|
|
|
* @access private |
330
|
|
|
* |
331
|
|
|
* @uses WPSC_Settings_Table_Shipping |
332
|
|
|
* @uses WPSC_Settings_Table_Shipping::display_shipping_module_settings_form() Displays shipping module form |
333
|
|
|
* |
334
|
|
|
* @return array $return Response args |
|
|
|
|
335
|
|
|
*/ |
336
|
|
|
function _wpsc_ajax_shipping_module_settings_form() { |
337
|
|
|
require_once( 'settings-page.php' ); |
338
|
|
|
require_once( 'includes/settings-tabs/shipping.php' ); |
339
|
|
|
|
340
|
|
|
$return = array(); |
341
|
|
|
ob_start(); |
342
|
|
|
$tab = new WPSC_Settings_Tab_Shipping(); |
343
|
|
|
$tab->display_shipping_module_settings_form(); |
344
|
|
|
$return['content'] = ob_get_clean(); |
345
|
|
|
|
346
|
|
|
return $return; |
347
|
|
|
} |
348
|
|
|
|
349
|
|
|
/** |
350
|
|
|
* Display settings tab via AJAX |
351
|
|
|
* |
352
|
|
|
* @since 3.8.9 |
353
|
|
|
* @access private |
354
|
|
|
* |
355
|
|
|
* @uses WPSC_Settings_Page |
356
|
|
|
* @uses WPSC_Settings_Page::display_current_tab() Shows current tab of settings page |
357
|
|
|
* |
358
|
|
|
* @return array $return Response args |
|
|
|
|
359
|
|
|
*/ |
360
|
|
|
function _wpsc_ajax_navigate_settings_tab() { |
361
|
|
|
require_once( 'settings-page.php' ); |
362
|
|
|
|
363
|
|
|
$return = array(); |
364
|
|
|
ob_start(); |
365
|
|
|
$settings_page = new WPSC_Settings_Page( $_POST['tab'] ); |
366
|
|
|
$settings_page->display_current_tab(); |
367
|
|
|
$return['content'] = ob_get_clean(); |
368
|
|
|
|
369
|
|
|
return $return; |
370
|
|
|
} |
371
|
|
|
|
372
|
|
|
/** |
373
|
|
|
* Display base region list in Store Settings -> General |
374
|
|
|
* |
375
|
|
|
* @since 3.8.9 |
376
|
|
|
* @access private |
377
|
|
|
* |
378
|
|
|
* @uses WPSC_Settings_Tab_General |
379
|
|
|
* @uses WPSC_Settings_Tab_General::display_region_drop_down() Shows region dropdown |
380
|
|
|
* |
381
|
|
|
* @return array $return Response args |
|
|
|
|
382
|
|
|
*/ |
383
|
|
|
function _wpsc_ajax_display_region_list() { |
384
|
|
|
require_once( 'settings-page.php' ); |
385
|
|
|
require_once( 'includes/settings-tabs/general.php' ); |
386
|
|
|
|
387
|
|
|
$return = array(); |
388
|
|
|
ob_start(); |
389
|
|
|
$tab = new WPSC_Settings_Tab_General(); |
390
|
|
|
$tab->display_region_drop_down(); |
391
|
|
|
$return['content'] = ob_get_clean(); |
392
|
|
|
|
393
|
|
|
return $return; |
394
|
|
|
} |
395
|
|
|
|
396
|
|
|
/** |
397
|
|
|
* Save tracking ID of a sales log. |
398
|
|
|
* |
399
|
|
|
* @since 3.8.9 |
400
|
|
|
* @access private |
401
|
|
|
* |
402
|
|
|
* @uses WP_Error WordPress Error class |
403
|
|
|
* |
404
|
|
|
* @return array|WP_Error $return Response args if successful, WP_Error if otherwise. |
|
|
|
|
405
|
|
|
*/ |
406
|
|
|
function _wpsc_ajax_purchase_log_save_tracking_id() { |
407
|
|
|
global $wpdb; |
408
|
|
|
|
409
|
|
|
$result = $wpdb->update( |
410
|
|
|
WPSC_TABLE_PURCHASE_LOGS, |
411
|
|
|
array( |
412
|
|
|
'track_id' => $_POST['value'] |
413
|
|
|
), |
414
|
|
|
array( |
415
|
|
|
'id' => $_POST['log_id'] |
416
|
|
|
), |
417
|
|
|
'%s', |
418
|
|
|
'%d' |
419
|
|
|
); |
420
|
|
|
|
421
|
|
|
if ( ! $result ) |
422
|
|
|
return new WP_Error( 'wpsc_cannot_save_tracking_id', __( "Couldn't save tracking ID of the transaction. Please try again.", 'wp-e-commerce' ) ); |
423
|
|
|
|
424
|
|
|
$return = array( |
425
|
|
|
'rows_affected' => $result, |
426
|
|
|
'id' => $_POST['log_id'], |
427
|
|
|
'track_id' => $_POST['value'], |
428
|
|
|
); |
429
|
|
|
|
430
|
|
|
return $return; |
431
|
|
|
} |
432
|
|
|
|
433
|
|
|
/** |
434
|
|
|
* Send sales log tracking email via AJAX |
435
|
|
|
* |
436
|
|
|
* @since 3.8.9 |
437
|
|
|
* @access private |
438
|
|
|
* |
439
|
|
|
* @uses $wpdb WordPress database object for queries |
440
|
|
|
* @uses get_option() Gets option from DB given key |
441
|
|
|
* @uses add_filter() Calls 'wp_mail_from' which can replace the from email address |
442
|
|
|
* @uses add_filter() Calls 'wp_mail_from_name' allows replacement of the from name on WordPress emails |
443
|
|
|
* @uses wp_mail() All the emailses in WordPress are sent through this function |
444
|
|
|
* @uses WP_Error WordPress Error class |
445
|
|
|
* |
446
|
|
|
* @return array|WP_Error $return Response args if successful, WP_Error if otherwise |
|
|
|
|
447
|
|
|
*/ |
448
|
|
|
function _wpsc_ajax_purchase_log_send_tracking_email() { |
449
|
|
|
global $wpdb; |
450
|
|
|
|
451
|
|
|
$id = absint( $_POST['log_id'] ); |
452
|
|
|
$sql = $wpdb->prepare( "SELECT `track_id` FROM " . WPSC_TABLE_PURCHASE_LOGS . " WHERE `id`=%d LIMIT 1", $id ); |
453
|
|
|
$trackingid = $wpdb->get_var( $sql ); |
454
|
|
|
|
455
|
|
|
$message = get_option( 'wpsc_trackingid_message' ); |
456
|
|
|
$message = str_replace( '%trackid%', $trackingid, $message ); |
457
|
|
|
$message = str_replace( '%shop_name%', get_option( 'blogname' ), $message ); |
458
|
|
|
|
459
|
|
|
$email = wpsc_get_buyers_email( $id ); |
460
|
|
|
|
461
|
|
|
$subject = get_option( 'wpsc_trackingid_subject' ); |
462
|
|
|
$subject = str_replace( '%shop_name%', get_option( 'blogname' ), $subject ); |
463
|
|
|
|
464
|
|
|
add_filter( 'wp_mail_from', 'wpsc_replace_reply_address', 0 ); |
465
|
|
|
add_filter( 'wp_mail_from_name', 'wpsc_replace_reply_name', 0 ); |
466
|
|
|
|
467
|
|
|
$result = wp_mail( $email, $subject, $message); |
468
|
|
|
|
469
|
|
|
if ( ! $result ) { |
470
|
|
|
return new WP_Error( 'wpsc_cannot_send_tracking_email', __( "Couldn't send tracking email. Please try again.", 'wp-e-commerce' ) ); |
471
|
|
|
} |
472
|
|
|
|
473
|
|
|
$return = array( |
474
|
|
|
'id' => $id, |
475
|
|
|
'tracking_id' => $trackingid, |
476
|
|
|
'subject' => $subject, |
477
|
|
|
'message' => $message, |
478
|
|
|
'email' => $email |
479
|
|
|
); |
480
|
|
|
|
481
|
|
|
return $return; |
482
|
|
|
} |
483
|
|
|
|
484
|
|
|
/** |
485
|
|
|
* Do purchase log action link via AJAX |
486
|
|
|
* |
487
|
|
|
* @since 3.9.0 |
488
|
|
|
* @access private |
489
|
|
|
* |
490
|
|
|
* @return array|WP_Error $return Response args if successful, WP_Error if otherwise |
491
|
|
|
*/ |
492
|
|
|
function _wpsc_ajax_purchase_log_action_link() { |
493
|
|
|
|
494
|
|
|
if ( isset( $_POST['log_id'] ) && isset( $_POST['purchase_log_action_link'] ) && isset( $_POST['purchase_log_action_nonce'] ) ) { |
495
|
|
|
|
496
|
|
|
$log_id = absint( $_POST['log_id'] ); |
497
|
|
|
$purchase_log_action_link = sanitize_key( $_POST['purchase_log_action_link'] ); |
498
|
|
|
|
499
|
|
|
// Verify action nonce |
500
|
|
|
if ( wp_verify_nonce( $_POST['purchase_log_action_nonce'], 'wpsc_purchase_log_action_ajax_' . $purchase_log_action_link ) ) { |
501
|
|
|
|
502
|
|
|
// Expected to receive success = true by default, or false on error. |
503
|
|
|
$return = apply_filters( 'wpsc_purchase_log_action_ajax-' . $purchase_log_action_link, array( 'success' => null ), $log_id ); |
504
|
|
|
|
505
|
|
|
} else { |
506
|
|
|
$return = _wpsc_error_invalid_nonce(); |
507
|
|
|
} |
508
|
|
|
|
509
|
|
|
if ( ! is_wp_error( $return ) ) { |
510
|
|
|
$return['log_id'] = $log_id; |
511
|
|
|
$return['purchase_log_action_link'] = $purchase_log_action_link; |
512
|
|
|
$return['success'] = isset( $return['success'] ) ? (bool) $return['success'] : null; |
513
|
|
|
} |
514
|
|
|
|
515
|
|
|
return $return; |
516
|
|
|
|
517
|
|
|
} |
518
|
|
|
|
519
|
|
|
return new WP_Error( 'wpsc_ajax_invalid_purchase_log_action', __( 'Purchase log action failed.', 'wp-e-commerce' ) ); |
520
|
|
|
|
521
|
|
|
} |
522
|
|
|
|
523
|
|
|
/** |
524
|
|
|
* Remove purchase log item. |
525
|
|
|
* |
526
|
|
|
* @since 4.0 |
527
|
|
|
* @access private |
528
|
|
|
* |
529
|
|
|
* @return array|WP_Error $return Response args if successful, WP_Error if otherwise |
530
|
|
|
*/ |
531
|
|
|
function _wpsc_ajax_remove_log_item() { |
532
|
|
|
|
533
|
|
|
if ( isset( $_POST['item_id'], $_POST['log_id'] ) ) { |
534
|
|
|
|
535
|
|
|
$item_id = absint( $_POST['item_id'] ); |
536
|
|
|
$log_id = absint( $_POST['log_id'] ); |
537
|
|
|
$log = new WPSC_Purchase_Log( $log_id ); |
538
|
|
|
|
539
|
|
|
if ( $log->remove_item( $item_id ) ) { |
540
|
|
|
return _wpsc_init_log_items( $log ); |
541
|
|
|
} |
542
|
|
|
} |
543
|
|
|
|
544
|
|
|
return new WP_Error( 'wpsc_ajax_invalid_remove_log_item', __( 'Removing log item failed.', 'wp-e-commerce' ) ); |
545
|
|
|
} |
546
|
|
|
|
547
|
|
|
/** |
548
|
|
|
* Update purchase log item quantity. |
549
|
|
|
* |
550
|
|
|
* @since 4.0 |
551
|
|
|
* @access private |
552
|
|
|
* |
553
|
|
|
* @return array|WP_Error $return Response args if successful, WP_Error if otherwise |
554
|
|
|
*/ |
555
|
|
|
function _wpsc_ajax_update_log_item_qty() { |
556
|
|
|
|
557
|
|
|
if ( isset( $_POST['item_id'], $_POST['log_id'], $_POST['qty'] ) ) { |
558
|
|
|
|
559
|
|
|
if ( empty( $_POST['qty'] ) ) { |
560
|
|
|
return _wpsc_ajax_remove_log_item(); |
561
|
|
|
} |
562
|
|
|
|
563
|
|
|
$item_id = absint( $_POST['item_id'] ); |
564
|
|
|
$log_id = absint( $_POST['log_id'] ); |
565
|
|
|
$log = new WPSC_Purchase_Log( $log_id ); |
566
|
|
|
$result = $log->update_item( $item_id, array( 'quantity' => absint( $_POST['qty'] ) ) ); |
567
|
|
|
|
568
|
|
|
if ( 0 === $result ) { |
569
|
|
|
return true; |
570
|
|
|
} elseif ( false !== $result ) { |
571
|
|
|
return _wpsc_init_log_items( $log ); |
572
|
|
|
} |
573
|
|
|
} |
574
|
|
|
|
575
|
|
|
return new WP_Error( 'wpsc_ajax_invalid_update_log_item_qty', __( 'Updating log item quantity failed.', 'wp-e-commerce' ) ); |
576
|
|
|
} |
577
|
|
|
|
578
|
|
|
/** |
579
|
|
|
* Add purchase log item. |
580
|
|
|
* |
581
|
|
|
* @since 4.0 |
582
|
|
|
* @access private |
583
|
|
|
* |
584
|
|
|
* @return array|WP_Error $return Response args if successful, WP_Error if otherwise |
585
|
|
|
*/ |
586
|
|
|
function _wpsc_ajax_add_log_item() { |
587
|
|
|
global $wpsc_cart; |
588
|
|
|
|
589
|
|
|
if ( |
590
|
|
|
isset( $_POST['product_ids'], $_POST['log_id'] ) |
591
|
|
|
&& is_array( $_POST['product_ids'] ) |
592
|
|
|
&& ! empty( $_POST['product_ids'] ) |
593
|
|
|
) { |
594
|
|
|
|
595
|
|
|
$existing = isset( $_POST['existing'] ) && is_array( $_POST['existing'] ) |
596
|
|
|
? array_map( 'absint', $_POST['existing'] ) |
597
|
|
|
: false; |
598
|
|
|
|
599
|
|
|
$item_ids = array(); |
600
|
|
|
$log = null; |
601
|
|
|
|
602
|
|
|
foreach ( $_POST['product_ids'] as $product_id ) { |
603
|
|
|
$product_id = absint( $product_id ); |
604
|
|
|
$log_id = absint( $_POST['log_id'] ); |
605
|
|
|
$log = new WPSC_Purchase_Log( $log_id ); |
606
|
|
|
|
607
|
|
|
// Is product is already in item list? |
608
|
|
|
if ( $existing && in_array( $product_id, $existing, true ) ) { |
609
|
|
|
$item = $log->get_item_from_product_id( $product_id ); |
610
|
|
|
if ( $item ) { |
611
|
|
|
// Update item quantity... |
612
|
|
|
$log->update_item( $item->id, array( 'quantity' => ++$item->quantity ) ); |
613
|
|
|
// And move on. |
614
|
|
|
continue; |
615
|
|
|
} |
616
|
|
|
} |
617
|
|
|
|
618
|
|
|
$item = new wpsc_cart_item( $product_id, array(), $wpsc_cart ); |
619
|
|
|
$item_id = $item->save_to_db( $log_id ); |
620
|
|
|
$item_ids[] = absint( $item_id ); |
621
|
|
|
} |
622
|
|
|
|
623
|
|
|
return _wpsc_init_log_items( $log, $item_ids ); |
|
|
|
|
624
|
|
|
} |
625
|
|
|
|
626
|
|
|
return new WP_Error( 'wpsc_ajax_invalid_add_log_item', __( 'Adding log item failed.', 'wp-e-commerce' ) ); |
627
|
|
|
} |
628
|
|
|
|
629
|
|
|
function _wpsc_init_log_items( WPSC_Purchase_Log $log, $item_ids = array() ) { |
630
|
|
|
$log->init_items(); |
631
|
|
|
|
632
|
|
|
require_once( WPSC_FILE_PATH . '/wpsc-admin/display-sales-logs.php' ); |
633
|
|
|
|
634
|
|
|
$html = ''; |
635
|
|
|
$htmls = array(); |
636
|
|
|
$htmls[] = array(); |
637
|
|
|
|
638
|
|
|
while ( wpsc_have_purchaselog_details() ) { |
639
|
|
|
wpsc_the_purchaselog_item(); |
640
|
|
|
|
641
|
|
|
ob_start(); |
642
|
|
|
WPSC_Purchase_Log_Page::purchase_log_cart_item( $log->can_edit() ); |
643
|
|
|
$cart_item = ob_get_clean(); |
644
|
|
|
|
645
|
|
|
$htmls[ wpsc_purchaselog_details_id() ] = $cart_item; |
646
|
|
|
if ( ! empty( $item_ids ) && in_array( absint( wpsc_purchaselog_details_id() ), $item_ids, true ) ) { |
647
|
|
|
$html .= $cart_item; |
648
|
|
|
} |
649
|
|
|
} |
650
|
|
|
|
651
|
|
|
return array( |
652
|
|
|
'quantities' => wp_list_pluck( $log->get_items(), 'quantity', 'id' ), |
653
|
|
|
'html' => $html, |
654
|
|
|
'htmls' => $htmls, |
655
|
|
|
'discount_data' => wpsc_purchlog_has_discount_data() ? esc_html__( 'Coupon Code', 'wp-e-commerce' ) . ': ' . wpsc_display_purchlog_discount_data() : '', |
656
|
|
|
'discount' => wpsc_display_purchlog_discount(), |
657
|
|
|
'total_taxes' => wpsc_display_purchlog_taxes(), |
658
|
|
|
'total_shipping' => wpsc_display_purchlog_shipping( false, true ), |
659
|
|
|
'final_total' => wpsc_display_purchlog_totalprice(), |
660
|
|
|
); |
661
|
|
|
} |
662
|
|
|
|
663
|
|
|
/** |
664
|
|
|
* Edit log contact details. |
665
|
|
|
* |
666
|
|
|
* @since 4.0 |
667
|
|
|
* @access private |
668
|
|
|
* |
669
|
|
|
* @return array|WP_Error $return Response args if successful, WP_Error if otherwise |
670
|
|
|
*/ |
671
|
|
|
function _wpsc_ajax_edit_contact_details() { |
672
|
|
|
|
673
|
|
|
if ( isset( $_POST['log_id'], $_POST['fields'] ) && ! empty( $_POST['fields'] ) ) { |
674
|
|
|
|
675
|
|
|
// Parse the URL query string of the fields array. |
676
|
|
|
parse_str( $_POST['fields'], $fields ); |
677
|
|
|
|
678
|
|
|
$log_id = absint( $_POST['log_id'] ); |
679
|
|
|
$log = new WPSC_Purchase_Log( $log_id ); |
680
|
|
|
|
681
|
|
|
if ( isset( $fields['wpsc_checkout_details'] ) && is_array( $fields['wpsc_checkout_details'] ) ) { |
682
|
|
|
$details = wp_unslash( $fields['wpsc_checkout_details'] ); |
683
|
|
|
|
684
|
|
|
// Save the new/updated contact details. |
685
|
|
|
WPSC_Checkout_Form_Data::save_form( |
686
|
|
|
$log, |
687
|
|
|
WPSC_Checkout_Form::get()->get_fields(), |
688
|
|
|
array_map( 'sanitize_text_field', $details ), |
689
|
|
|
false |
690
|
|
|
); |
691
|
|
|
|
692
|
|
|
require_once( WPSC_FILE_PATH . '/wpsc-admin/display-sales-logs.php' ); |
693
|
|
|
|
694
|
|
|
$log->init_items(); |
695
|
|
|
|
696
|
|
|
// Fetch the shipping/billing formatted output. |
697
|
|
|
|
698
|
|
|
ob_start(); |
699
|
|
|
WPSC_Purchase_Log_Page::shipping_address_output(); |
700
|
|
|
$shipping = ob_get_clean(); |
701
|
|
|
|
702
|
|
|
ob_start(); |
703
|
|
|
WPSC_Purchase_Log_Page::billing_address_output(); |
704
|
|
|
$billing = ob_get_clean(); |
705
|
|
|
|
706
|
|
|
ob_start(); |
707
|
|
|
WPSC_Purchase_Log_Page::payment_details_output(); |
708
|
|
|
$payment = ob_get_clean(); |
709
|
|
|
|
710
|
|
|
return compact( 'shipping', 'billing', 'payment' ); |
711
|
|
|
|
712
|
|
|
} |
|
|
|
|
713
|
|
|
|
714
|
|
|
} |
715
|
|
|
|
716
|
|
|
return new WP_Error( 'wpsc_ajax_invalid_edit_contact_details', __( 'Failed to update contact details for log.', 'wp-e-commerce' ) ); |
717
|
|
|
} |
718
|
|
|
|
719
|
|
|
/** |
720
|
|
|
* Add a note to a log. |
721
|
|
|
* |
722
|
|
|
* @since 4.0 |
723
|
|
|
* @access private |
724
|
|
|
* |
725
|
|
|
* @return array|WP_Error $return Response args if successful, WP_Error if otherwise |
726
|
|
|
*/ |
727
|
|
|
function _wpsc_ajax_add_note() { |
728
|
|
|
|
729
|
|
|
if ( isset( $_POST['log_id'], $_POST['note'] ) && ! empty( $_POST['note'] ) ) { |
730
|
|
|
|
731
|
|
|
$result = wpsc_purchlogs_update_notes( |
732
|
|
|
absint( $_POST['log_id'] ), |
733
|
|
|
wp_kses_post( wp_unslash( $_POST['note'] ) ) |
734
|
|
|
); |
735
|
|
|
|
736
|
|
|
if ( $result instanceof WPSC_Purchase_Log_Notes ) { |
737
|
|
|
require_once( WPSC_FILE_PATH . '/wpsc-admin/display-sales-logs.php' ); |
738
|
|
|
|
739
|
|
|
$data = $result->get_data(); |
740
|
|
|
$keys = array_keys( $data ); |
741
|
|
|
$note_id = end( $keys ); |
742
|
|
|
$note_args = end( $data ); |
743
|
|
|
|
744
|
|
|
ob_start(); |
745
|
|
|
WPSC_Purchase_Log_Page::note_output( $result, $note_id, $note_args ); |
746
|
|
|
$row = ob_get_clean(); |
747
|
|
|
|
748
|
|
|
return $row; |
749
|
|
|
} |
750
|
|
|
} |
751
|
|
|
|
752
|
|
|
return new WP_Error( 'wpsc_ajax_invalid_add_note', __( 'Failed adding log note.', 'wp-e-commerce' ) ); |
753
|
|
|
} |
754
|
|
|
|
755
|
|
|
/** |
756
|
|
|
* Delete a note from a log. |
757
|
|
|
* |
758
|
|
|
* @since 4.0 |
759
|
|
|
* @access private |
760
|
|
|
* |
761
|
|
|
* @return array|WP_Error $return Response args if successful, WP_Error if otherwise |
762
|
|
|
*/ |
763
|
|
|
function _wpsc_ajax_delete_note() { |
764
|
|
|
|
765
|
|
|
if ( isset( $_POST['log_id'], $_POST['note'] ) && is_numeric( $_POST['note'] ) ) { |
766
|
|
|
|
767
|
|
|
$notes = wpsc_get_order_notes( absint( $_POST['log_id'] ) ); |
768
|
|
|
$notes->remove( absint( $_POST['note'] ) )->save(); |
769
|
|
|
|
770
|
|
|
return true; |
771
|
|
|
} |
772
|
|
|
|
773
|
|
|
return new WP_Error( 'wpsc_ajax_invalid_delete_note', __( 'Failed to delete log note.', 'wp-e-commerce' ) ); |
774
|
|
|
} |
775
|
|
|
|
776
|
|
|
/** |
777
|
|
|
* Search for products. |
778
|
|
|
* |
779
|
|
|
* @since 4.0 |
780
|
|
|
* @access private |
781
|
|
|
* |
782
|
|
|
* @return array|WP_Error $return Response args if successful, WP_Error if otherwise |
783
|
|
|
*/ |
784
|
|
|
function _wpsc_ajax_search_products() { |
785
|
|
|
$pt_object = get_post_type_object( 'wpsc-product' ); |
786
|
|
|
|
787
|
|
|
$s = wp_unslash( $_POST['search'] ); |
788
|
|
|
$args = array( |
789
|
|
|
'post_type' => 'wpsc-product', |
790
|
|
|
'post_status' => array( 'publish', 'inherit' ), |
791
|
|
|
'posts_per_page' => 50, |
792
|
|
|
); |
793
|
|
|
if ( '' !== $s ) { |
794
|
|
|
$args['s'] = $s; |
795
|
|
|
} |
796
|
|
|
|
797
|
|
|
$posts = get_posts( $args ); |
798
|
|
|
|
799
|
|
|
if ( ! $posts ) { |
800
|
|
|
return new WP_Error( 'wpsc_ajax_invalid_search_products', __( 'No items found.', 'wp-e-commerce' ) ); |
801
|
|
|
} |
802
|
|
|
|
803
|
|
|
$alt = ''; |
804
|
|
|
foreach ( $posts as $post ) { |
805
|
|
|
$post->title = trim( $post->post_title ) ? $post->post_title : __( '(no title)' ); |
806
|
|
|
$alt = ( 'alternate' === $alt ) ? '' : 'alternate'; |
807
|
|
|
|
808
|
|
|
$post->status = $post->post_status; |
809
|
|
|
|
810
|
|
|
switch ( $post->post_status ) { |
811
|
|
|
case 'publish' : |
812
|
|
|
case 'private' : |
813
|
|
|
$post->status = __( 'Published' ); |
814
|
|
|
break; |
815
|
|
|
case 'future' : |
816
|
|
|
$post->status = __( 'Scheduled' ); |
817
|
|
|
break; |
818
|
|
|
case 'pending' : |
819
|
|
|
$post->status = __( 'Pending Review' ); |
820
|
|
|
break; |
821
|
|
|
case 'draft' : |
822
|
|
|
$post->status = __( 'Draft' ); |
823
|
|
|
break; |
824
|
|
|
default : |
825
|
|
|
$post->status = $post->post_status; |
826
|
|
|
break; |
827
|
|
|
} |
828
|
|
|
|
829
|
|
|
if ( '0000-00-00 00:00:00' === $post->post_date ) { |
830
|
|
|
$post->time = ''; |
831
|
|
|
} else { |
832
|
|
|
/* translators: date format in table columns, see https://secure.php.net/date */ |
833
|
|
|
$post->time = mysql2date( __( 'Y/m/d' ), $post->post_date ); |
834
|
|
|
} |
835
|
|
|
|
836
|
|
|
$post->class = $alt; |
837
|
|
|
} |
838
|
|
|
|
839
|
|
|
return $posts; |
840
|
|
|
} |
841
|
|
|
|
842
|
|
|
/** |
843
|
|
|
* Handle AJAX clear downloads lock purchase log action |
844
|
|
|
* |
845
|
|
|
* The _wpsc_ajax_purchase_log_action_link() function which triggers this function is nonce |
846
|
|
|
* and capability checked in _wpsc_ajax_handler(). |
847
|
|
|
* |
848
|
|
|
* @since 3.9.0 |
849
|
|
|
* @access private |
850
|
|
|
* |
851
|
|
|
* @param array $response AJAX response. |
852
|
|
|
* @param int $log_id Purchase log ID. |
853
|
|
|
*/ |
854
|
|
|
function wpsc_purchase_log_action_ajax_downloads_lock( $response, $log_id ) { |
855
|
|
|
|
856
|
|
|
$response['success'] = wpsc_purchlog_clear_download_items( $log_id ); |
857
|
|
|
|
858
|
|
|
return $response; |
859
|
|
|
|
860
|
|
|
} |
861
|
|
|
add_action( 'wpsc_purchase_log_action_ajax-downloads_lock', 'wpsc_purchase_log_action_ajax_downloads_lock', 10, 2 ); |
862
|
|
|
|
863
|
|
|
|
864
|
|
|
/** |
865
|
|
|
* Handle AJAX email receipt purchase log action |
866
|
|
|
* |
867
|
|
|
* The _wpsc_ajax_purchase_log_action_link() function which triggers this function is nonce |
868
|
|
|
* and capability checked in _wpsc_ajax_handler(). |
869
|
|
|
* |
870
|
|
|
* @since 3.9.0 |
871
|
|
|
* @access private |
872
|
|
|
* |
873
|
|
|
* @param array $response AJAX response. |
874
|
|
|
* @param int $log_id Purchase log ID. |
875
|
|
|
*/ |
876
|
|
|
function wpsc_purchase_log_action_ajax_email_receipt( $response, $log_id ) { |
877
|
|
|
|
878
|
|
|
$response['success'] = wpsc_purchlog_resend_email( $log_id ); |
879
|
|
|
|
880
|
|
|
return $response; |
881
|
|
|
|
882
|
|
|
} |
883
|
|
|
add_action( 'wpsc_purchase_log_action_ajax-email_receipt', 'wpsc_purchase_log_action_ajax_email_receipt', 10, 2 ); |
884
|
|
|
|
885
|
|
|
/** |
886
|
|
|
* Delete an attached downloadable file via AJAX. |
887
|
|
|
* |
888
|
|
|
* @since 3.8.9 |
889
|
|
|
* @access private |
890
|
|
|
* |
891
|
|
|
* @uses _wpsc_delete_file() Deletes files associated with a product |
892
|
|
|
* @uses WP_Error WordPress error class |
893
|
|
|
* |
894
|
|
|
* @return array|WP_Error $return Response args if successful, WP_Error if otherwise |
|
|
|
|
895
|
|
|
*/ |
896
|
|
|
function _wpsc_ajax_delete_file() { |
897
|
|
|
$product_id = absint( $_REQUEST['product_id'] ); |
898
|
|
|
$file_name = basename( $_REQUEST['file_name'] ); |
899
|
|
|
|
900
|
|
|
$result = _wpsc_delete_file( $product_id, $file_name ); |
901
|
|
|
|
902
|
|
|
if ( ! $result ) |
903
|
|
|
return new WP_Error( 'wpsc_cannot_delete_file', __( "Couldn't delete the file. Please try again.", 'wp-e-commerce' ) ); |
904
|
|
|
|
905
|
|
|
$return = array( |
906
|
|
|
'product_id' => $product_id, |
907
|
|
|
'file_name' => $file_name, |
908
|
|
|
); |
909
|
|
|
|
910
|
|
|
return $return; |
911
|
|
|
} |
912
|
|
|
|
913
|
|
|
/** |
914
|
|
|
* Delete a product meta via AJAX |
915
|
|
|
* |
916
|
|
|
* @since 3.8.9 |
917
|
|
|
* @access private |
918
|
|
|
* |
919
|
|
|
* @uses delete_meta() Deletes metadata by meta id |
920
|
|
|
* @uses WP_Error WordPress error class |
921
|
|
|
* |
922
|
|
|
* @return array|WP_Error $return Response args if successful, WP_Error if otherwise |
|
|
|
|
923
|
|
|
*/ |
924
|
|
|
function _wpsc_ajax_remove_product_meta() { |
925
|
|
|
$meta_id = (int) $_POST['meta_id']; |
926
|
|
|
if ( ! delete_meta( $meta_id ) ) |
927
|
|
|
return new WP_Error( 'wpsc_cannot_delete_product_meta', __( "Couldn't delete product meta. Please try again.", 'wp-e-commerce' ) ); |
928
|
|
|
|
929
|
|
|
return array( 'meta_id' => $meta_id ); |
930
|
|
|
} |
931
|
|
|
|
932
|
|
|
/** |
933
|
|
|
* Modify a purchase log's status. |
934
|
|
|
* |
935
|
|
|
* @since 3.8.9 |
936
|
|
|
* @access private |
937
|
|
|
* |
938
|
|
|
* @uses wpsc_purchlog_edit_status() Edits purchase log status |
939
|
|
|
* @uses WP_Error WordPress Error class |
940
|
|
|
* @uses WPSC_Purchase_Log_List_Table |
941
|
|
|
* @uses WPSC_Purchase_Log_List_Table::prepare_items() |
942
|
|
|
* @uses WPSC_Purchase_Log_List_Table::views() |
943
|
|
|
* @uses WPSC_Purchase_Log_List_Table::display_tablenav() @todo docs |
944
|
|
|
* |
945
|
|
|
* @return array|WP_Error $return Response args if successful, WP_Error if otherwise. |
|
|
|
|
946
|
|
|
*/ |
947
|
|
|
function _wpsc_ajax_change_purchase_log_status() { |
948
|
|
|
$result = wpsc_purchlog_edit_status( $_POST['id'], $_POST['new_status'] ); |
949
|
|
|
if ( ! $result ) |
950
|
|
|
return new WP_Error( 'wpsc_cannot_edit_purchase_log_status', __( "Couldn't modify purchase log's status. Please try again.", 'wp-e-commerce' ) ); |
951
|
|
|
|
952
|
|
|
$args = array(); |
953
|
|
|
|
954
|
|
|
$args['screen'] = 'dashboard_page_wpsc-sales-logs'; |
955
|
|
|
|
956
|
|
|
require_once( WPSC_FILE_PATH . '/wpsc-admin/includes/purchase-log-list-table-class.php' ); |
957
|
|
|
$purchaselog_table = new WPSC_Purchase_Log_List_Table( $args ); |
958
|
|
|
$purchaselog_table->prepare_items(); |
959
|
|
|
|
960
|
|
|
ob_start(); |
961
|
|
|
$purchaselog_table->views(); |
962
|
|
|
$views = ob_get_clean(); |
963
|
|
|
|
964
|
|
|
ob_start(); |
965
|
|
|
$purchaselog_table->display_tablenav( 'top' ); |
966
|
|
|
$tablenav_top = ob_get_clean(); |
967
|
|
|
|
968
|
|
|
ob_start(); |
969
|
|
|
$purchaselog_table->display_tablenav( 'bottom' ); |
970
|
|
|
$tablenav_bottom = ob_get_clean(); |
971
|
|
|
|
972
|
|
|
$return = array( |
973
|
|
|
'id' => $_POST['id'], |
974
|
|
|
'new_status' => $_POST['new_status'], |
975
|
|
|
'views' => $views, |
976
|
|
|
'tablenav_top' => $tablenav_top, |
977
|
|
|
'tablenav_bottom' => $tablenav_bottom, |
978
|
|
|
); |
979
|
|
|
|
980
|
|
|
return $return; |
981
|
|
|
} |
982
|
|
|
|
983
|
|
|
/** |
984
|
|
|
* Save product ordering after drag-and-drop sorting |
985
|
|
|
* |
986
|
|
|
* @since 3.8.9 |
987
|
|
|
* @access private |
988
|
|
|
* |
989
|
|
|
* @uses $wpdb WordPress database object for use in queries |
990
|
|
|
* @uses wp_update_post() Updates post based on passed $args. Needs a post_id |
991
|
|
|
* @uses WP_Error WordPress Error class |
992
|
|
|
* |
993
|
|
|
* @return array|WP_Error Response args if successful, WP_Error if otherwise |
|
|
|
|
994
|
|
|
*/ |
995
|
|
|
function _wpsc_ajax_save_product_order() { |
996
|
|
|
|
997
|
|
|
$products = array( ); |
|
|
|
|
998
|
|
|
foreach ( $_POST['post'] as $product ) { |
999
|
|
|
$products[] = (int) str_replace( 'post-', '', $product ); |
1000
|
|
|
} |
1001
|
|
|
|
1002
|
|
|
$failed = array(); |
1003
|
|
|
foreach ( $products as $order => $product_id ) { |
1004
|
|
|
$result = wp_update_post( array( |
1005
|
|
|
'ID' => $product_id, |
1006
|
|
|
'menu_order' => $order, |
1007
|
|
|
) ); |
1008
|
|
|
|
1009
|
|
|
if ( ! $result ) |
1010
|
|
|
$failed[] = $product_id; |
1011
|
|
|
} |
1012
|
|
|
|
1013
|
|
|
// Validate data before exposing to action |
1014
|
|
|
$category = isset( $_POST['category_id'] ) ? get_term_by( 'slug', $_POST['category_id'], 'wpsc_product_category' ) : false; |
1015
|
|
|
do_action( 'wpsc_save_product_order', $products, $category ); |
1016
|
|
|
|
1017
|
|
|
if ( ! empty( $failed ) ) { |
1018
|
|
|
$error_data = array( |
1019
|
|
|
'failed_ids' => $failed, |
1020
|
|
|
); |
1021
|
|
|
|
1022
|
|
|
return new WP_Error( 'wpsc_cannot_save_product_sort_order', __( "Couldn't save the products' sort order. Please try again.", 'wp-e-commerce' ), $error_data ); |
1023
|
|
|
} |
1024
|
|
|
|
1025
|
|
|
return array( |
1026
|
|
|
'ids' => $products, |
1027
|
|
|
); |
1028
|
|
|
} |
1029
|
|
|
|
1030
|
|
|
/** |
1031
|
|
|
* Save Category Product Order |
1032
|
|
|
* |
1033
|
|
|
* Note that this uses the 'term_order' field in the 'term_relationships' table to store |
1034
|
|
|
* the order. Although this column presently seems to be unused by WordPress, the intention |
1035
|
|
|
* is it should be used to store the order of terms associates to a post, not the order |
1036
|
|
|
* of posts as we are doing. This shouldn't be an issue for WPEC unless WordPress adds a UI |
1037
|
|
|
* for this. More info at http://core.trac.wordpress.org/ticket/9547 |
1038
|
|
|
* |
1039
|
|
|
* @since 3.9 |
1040
|
|
|
* @access private |
1041
|
|
|
* |
1042
|
|
|
* @uses $wpdb WordPress database object used for queries |
1043
|
|
|
*/ |
1044
|
|
|
function _wpsc_save_category_product_order( $products, $category ) { |
1045
|
|
|
global $wpdb; |
1046
|
|
|
|
1047
|
|
|
// Only save category product order if in category |
1048
|
|
|
if ( ! $category ) |
1049
|
|
|
return; |
1050
|
|
|
|
1051
|
|
|
// Save product order in term_relationships table |
1052
|
|
|
foreach ( $products as $order => $product_id ) { |
1053
|
|
|
$wpdb->update( $wpdb->term_relationships, |
1054
|
|
|
array( 'term_order' => $order ), |
1055
|
|
|
array( 'object_id' => $product_id, 'term_taxonomy_id' => $category->term_taxonomy_id ), |
1056
|
|
|
array( '%d' ), |
1057
|
|
|
array( '%d', '%d' ) |
1058
|
|
|
); |
1059
|
|
|
} |
1060
|
|
|
} |
1061
|
|
|
add_action( 'wpsc_save_product_order', '_wpsc_save_category_product_order', 10, 2 ); |
1062
|
|
|
|
1063
|
|
|
/** |
1064
|
|
|
* Update Checkout fields order |
1065
|
|
|
* |
1066
|
|
|
* @since 3.8.9 |
1067
|
|
|
* @access private |
1068
|
|
|
* |
1069
|
|
|
* @uses $wpdb WordPress database object used for queries |
1070
|
|
|
* @uses WP_Error WordPress error class |
1071
|
|
|
* |
1072
|
|
|
* @return array|WP_Error Response args or WP_Error |
|
|
|
|
1073
|
|
|
*/ |
1074
|
|
|
function _wpsc_ajax_update_checkout_fields_order() { |
1075
|
|
|
global $wpdb; |
1076
|
|
|
|
1077
|
|
|
$checkout_fields = $_REQUEST['sort_order']; |
1078
|
|
|
$order = 1; |
1079
|
|
|
$failed = array(); |
1080
|
|
|
$modified = array(); |
1081
|
|
|
foreach ( $checkout_fields as &$checkout_field ) { |
1082
|
|
|
// ignore new fields |
1083
|
|
|
if ( strpos( $checkout_field, 'new-field' ) === 0 ) |
1084
|
|
|
continue; |
1085
|
|
|
$checkout_field = absint( preg_replace('/[^0-9]+/', '', $checkout_field ) ); |
1086
|
|
|
$result = $wpdb->update( |
1087
|
|
|
WPSC_TABLE_CHECKOUT_FORMS, |
1088
|
|
|
array( |
1089
|
|
|
'checkout_order' => $order |
1090
|
|
|
), |
1091
|
|
|
array( |
1092
|
|
|
'id' => $checkout_field |
1093
|
|
|
), |
1094
|
|
|
'%d', |
1095
|
|
|
'%d' |
1096
|
|
|
); |
1097
|
|
|
$order ++; |
1098
|
|
|
if ( $result === false ) |
1099
|
|
|
$failed[] = $checkout_field; |
1100
|
|
|
elseif ( $result > 0 ) |
1101
|
|
|
$modified[] = $checkout_field; |
1102
|
|
|
} |
1103
|
|
|
|
1104
|
|
|
if ( ! empty( $failed ) ) |
1105
|
|
|
return new WP_Error( 'wpsc_cannot_save_checkout_field_sort_order', __( "Couldn't save checkout field sort order. Please try again.", 'wp-e-commerce' ), array( 'failed_ids' => $failed ) ); |
1106
|
|
|
|
1107
|
|
|
return array( |
1108
|
|
|
'modified' => $modified, |
1109
|
|
|
); |
1110
|
|
|
} |
1111
|
|
|
|
1112
|
|
|
/** |
1113
|
|
|
* Save a downloadable file to a product |
1114
|
|
|
* |
1115
|
|
|
* @since 3.8.9 |
1116
|
|
|
* @access private |
1117
|
|
|
* |
1118
|
|
|
* @uses $wpdb WordPress database object for use in queries |
1119
|
|
|
* @uses _wpsc_create_ajax_nonce() Creates nonce for an ajax action |
1120
|
|
|
* @uses wpsc_get_mimetype() Returns mimetype of file |
1121
|
|
|
* @uses wp_insert_post() Inserts post to WordPress database |
1122
|
|
|
* @uses wp_nonce_url() Retrieve URL with nonce added to URL query. |
1123
|
|
|
* @uses wpsc_convert_bytes() Formats bytes |
1124
|
|
|
* @uses wpsc_get_extension() Gets extension of file |
1125
|
|
|
* @uses esc_attr() Escapes HTML attributes |
1126
|
|
|
* @uses _x() Retrieve translated string with gettext context |
1127
|
|
|
* |
1128
|
|
|
* @return array|WP_Error Response args if successful, WP_Error if otherwise. |
1129
|
|
|
*/ |
1130
|
|
|
function _wpsc_ajax_upload_product_file() { |
1131
|
|
|
global $wpdb; |
1132
|
|
|
$product_id = absint( $_POST["product_id"] ); |
1133
|
|
|
$output = ''; |
1134
|
|
|
$delete_nonce = _wpsc_create_ajax_nonce( 'delete_file' ); |
1135
|
|
|
|
1136
|
|
|
foreach ( $_POST["select_product_file"] as $selected_file ) { |
1137
|
|
|
// if we already use this file, there is no point doing anything more. |
1138
|
|
|
$sql = $wpdb->prepare( "SELECT * FROM $wpdb->posts WHERE post_type = 'wpsc-product-file' AND post_title = %s", $selected_file ); // TODO it's safer to select by post ID, in that case we will use get_posts() |
1139
|
|
|
$file_post_data = $wpdb->get_row( $sql, ARRAY_A ); |
1140
|
|
|
$selected_file_path = WPSC_FILE_DIR . basename( $selected_file ); |
1141
|
|
|
$file_url = WPSC_FILE_URL . basename( $selected_file ); |
1142
|
|
|
$file_size = filesize( $selected_file_path ); |
1143
|
|
|
if ( empty( $file_post_data ) ) { |
1144
|
|
|
$type = wpsc_get_mimetype( $selected_file_path ); |
1145
|
|
|
$attachment = array( |
1146
|
|
|
'post_mime_type' => $type, |
1147
|
|
|
'post_parent' => $product_id, |
1148
|
|
|
'post_title' => $selected_file, |
1149
|
|
|
'post_content' => '', |
1150
|
|
|
'post_type' => "wpsc-product-file", |
1151
|
|
|
'post_status' => 'inherit' |
1152
|
|
|
); |
1153
|
|
|
$id = wp_insert_post( $attachment ); |
1154
|
|
|
} else { |
1155
|
|
|
// already attached |
1156
|
|
|
if ( $file_post_data['post_parent'] == $product_id ) |
1157
|
|
|
continue; |
1158
|
|
|
$type = $file_post_data["post_mime_type"]; |
1159
|
|
|
$url = $file_post_data["guid"]; |
1160
|
|
|
$title = $file_post_data["post_title"]; |
1161
|
|
|
$content = $file_post_data["post_content"]; |
1162
|
|
|
// Construct the attachment |
1163
|
|
|
$attachment = array( |
1164
|
|
|
'post_mime_type' => $type, |
1165
|
|
|
'guid' => $url, |
1166
|
|
|
'post_parent' => absint( $product_id ), |
1167
|
|
|
'post_title' => $title, |
1168
|
|
|
'post_content' => $content, |
1169
|
|
|
'post_type' => "wpsc-product-file", |
1170
|
|
|
'post_status' => 'inherit' |
1171
|
|
|
); |
1172
|
|
|
// Save the data |
1173
|
|
|
$id = wp_insert_post( $attachment ); |
1174
|
|
|
} |
1175
|
|
|
|
1176
|
|
|
$deletion_url = wp_nonce_url( "admin.php?wpsc_admin_action=delete_file&file_name={$attachment['post_title']}&product_id={$product_id}", 'delete_file_' . $attachment['post_title'] ); |
1177
|
|
|
|
1178
|
|
|
$output .= '<tr class="wpsc_product_download_row">'; |
1179
|
|
|
$output .= '<td style="padding-right: 30px;">' . $attachment['post_title'] . '</td>'; |
1180
|
|
|
$output .= '<td>' . wpsc_convert_byte( $file_size ) . '</td>'; |
1181
|
|
|
$output .= '<td>.' . wpsc_get_extension( $attachment['post_title'] ) . '</td>'; |
1182
|
|
|
$output .= "<td><a data-file-name='" . esc_attr( $attachment['post_title'] ) . "' data-product-id='" . esc_attr( $product_id ) . "' data-nonce='" . esc_attr( $delete_nonce ) . "' class='file_delete_button' href='{$deletion_url}' >" . _x( 'Delete', 'Digital Download UI row', 'wp-e-commerce' ) . "</a></td>"; |
1183
|
|
|
$output .= '<td><a href=' .$file_url .'>' . _x( 'Download', 'Digital Download UI row', 'wp-e-commerce' ) . '</a></td>'; |
1184
|
|
|
$output .= '</tr>'; |
1185
|
|
|
} |
1186
|
|
|
|
1187
|
|
|
return array( |
1188
|
|
|
'content' => $output, |
1189
|
|
|
); |
1190
|
|
|
} |
1191
|
|
|
|
1192
|
|
|
/** |
1193
|
|
|
* Generate variations |
1194
|
|
|
* |
1195
|
|
|
* @since 3.8.9 |
1196
|
|
|
* @access private |
1197
|
|
|
* |
1198
|
|
|
* @uses wpsc_update_variations() Updates product variations given |
1199
|
|
|
* @uses wpsc_admin_product_listing() DEPRECATED |
1200
|
|
|
* |
1201
|
|
|
* @return array|WP_Error Response args if successful, WP_Error if otherwise |
1202
|
|
|
*/ |
1203
|
|
|
function _wpsc_ajax_update_variations() { |
1204
|
|
|
$product_id = absint( $_REQUEST["product_id"] ); |
1205
|
|
|
wpsc_update_variations(); |
1206
|
|
|
|
1207
|
|
|
ob_start(); |
1208
|
|
|
wpsc_admin_product_listing( $product_id ); |
1209
|
|
|
$content = ob_get_clean(); |
1210
|
|
|
|
1211
|
|
|
return array( 'content' => $content ); |
1212
|
|
|
} |
1213
|
|
|
|
1214
|
|
|
/** |
1215
|
|
|
* Display the shortcode generator. |
1216
|
|
|
* |
1217
|
|
|
* @since 3.8.9 |
1218
|
|
|
* @access private |
1219
|
|
|
*/ |
1220
|
|
|
function _wpsc_action_tinymce_window() { |
1221
|
|
|
require_once( WPSC_CORE_JS_PATH . '/tinymce3/window.php' ); |
1222
|
|
|
exit; |
1223
|
|
|
} |
1224
|
|
|
add_action( 'wp_ajax_wpsc_tinymce_window', '_wpsc_action_tinymce_window' ); |
1225
|
|
|
|
1226
|
|
|
/** |
1227
|
|
|
* Add tax rate |
1228
|
|
|
* @since 3.8.9 |
1229
|
|
|
* @access private |
1230
|
|
|
* |
1231
|
|
|
* @uses wpec_taxes_controller Contains all the logic to communicate with the taxes system |
1232
|
|
|
* @uses wpec_taxes_controller::wpec_taxes::wpec_taxes_get_regions() Gets tax regions based on input country code |
1233
|
|
|
* @uses wpec_taxes_controller::wpec_taxes_build_select_options() Returns HTML formatted options from input array |
1234
|
|
|
* @uses wpec_taxes_controller::wpec_taxes_build_form() Builds the tax rate form |
1235
|
|
|
* @uses wpec_taxes_controller::wpec_taxes::wpec_taxes_get_band_from_index() Retrieves tax band for given name |
1236
|
|
|
* |
1237
|
|
|
* @return array|WP_Error Response args if successful, WP_Error if otherwise |
1238
|
|
|
*/ |
1239
|
|
|
function _wpsc_ajax_add_tax_rate() { |
1240
|
|
|
//include taxes controller |
1241
|
|
|
$wpec_taxes_controller = new wpec_taxes_controller; |
1242
|
|
|
|
1243
|
|
|
switch ( $_REQUEST['wpec_taxes_action'] ) { |
1244
|
|
|
case 'wpec_taxes_get_regions': |
1245
|
|
|
$regions = $wpec_taxes_controller->wpec_taxes->wpec_taxes_get_regions( $_REQUEST['country_code'] ); |
|
|
|
|
1246
|
|
|
$key = $_REQUEST['current_key']; |
1247
|
|
|
$type = $_REQUEST['taxes_type']; |
1248
|
|
|
$default_option = array( 'region_code' => 'all-markets', 'name' => 'All Markets' ); |
1249
|
|
|
$select_settings = array( |
1250
|
|
|
'id' => "{$type}-region-{$key}", |
1251
|
|
|
'name' => "wpsc_options[wpec_taxes_{$type}][{$key}][region_code]", |
1252
|
|
|
'class' => 'wpsc-taxes-region-drop-down' |
1253
|
|
|
); |
1254
|
|
|
$returnable = $wpec_taxes_controller->wpec_taxes_build_select_options( $regions, 'region_code', 'name', $default_option, $select_settings ); |
1255
|
|
|
break; |
1256
|
|
|
}// switch |
1257
|
|
|
|
1258
|
|
|
return array( |
1259
|
|
|
'content' => $returnable, |
|
|
|
|
1260
|
|
|
); |
1261
|
|
|
} |
1262
|
|
|
|
1263
|
|
|
/** |
1264
|
|
|
* Displays the WPSC product variations table |
1265
|
|
|
* |
1266
|
|
|
* @uses check_admin_referrer() Makes sure user was referred from another admin page |
1267
|
|
|
* @uses WPSC_Product_Variations_Page The WPSC Product variations class |
1268
|
|
|
* @uses WPSC_Product_Variations_Page::display() Displays the product variations page |
1269
|
|
|
*/ |
1270
|
|
|
function wpsc_product_variations_table() { |
1271
|
|
|
check_admin_referer( 'wpsc_product_variations_table' ); |
1272
|
|
|
set_current_screen( 'wpsc-product' ); |
1273
|
|
|
require_once( WPSC_FILE_PATH . '/wpsc-admin/includes/product-variations-page.class.php' ); |
1274
|
|
|
$page = new WPSC_Product_Variations_Page(); |
1275
|
|
|
$page->display(); |
1276
|
|
|
|
1277
|
|
|
exit; |
1278
|
|
|
} |
1279
|
|
|
add_action( 'wp_ajax_wpsc_product_variations_table', 'wpsc_product_variations_table' ); |
1280
|
|
|
|
1281
|
|
|
/** |
1282
|
|
|
* @access private |
1283
|
|
|
* |
1284
|
|
|
* @uses current_user_can() Checks user capabilities given string |
1285
|
|
|
* @uses delete_post_thumbnail() Deletes post thumbnail given thumbnail id |
1286
|
|
|
* @uses set_post_thumbnail() Sets post thumbnail given post_id and thumbnail_id |
1287
|
|
|
* @uses wpsc_the_product_thumbnail() Returns URL to the product thumbnail |
1288
|
|
|
* |
1289
|
|
|
* @return array $response Includes the thumbnail URL and success bool value |
|
|
|
|
1290
|
|
|
*/ |
1291
|
|
|
function _wpsc_ajax_set_variation_product_thumbnail() { |
1292
|
|
|
$response = array( |
1293
|
|
|
'success' => false |
1294
|
|
|
); |
1295
|
|
|
|
1296
|
|
|
$post_ID = intval( $_POST['post_id'] ); |
1297
|
|
|
if ( current_user_can( 'edit_post', $post_ID ) ) { |
1298
|
|
|
$thumbnail_id = intval( $_POST['thumbnail_id'] ); |
1299
|
|
|
|
1300
|
|
|
if ( $thumbnail_id == '-1' ) |
1301
|
|
|
delete_post_thumbnail( $post_ID ); |
1302
|
|
|
|
1303
|
|
|
set_post_thumbnail( $post_ID, $thumbnail_id ); |
1304
|
|
|
|
1305
|
|
|
$thumbnail = wpsc_the_product_thumbnail( 50, 50, $post_ID, '' ); |
1306
|
|
|
if ( ! $thumbnail ) |
1307
|
|
|
$thumbnail = WPSC_CORE_IMAGES_URL . '/no-image-uploaded.gif'; |
1308
|
|
|
$response['src'] = $thumbnail; |
1309
|
|
|
$response['success'] = true; |
1310
|
|
|
} |
1311
|
|
|
|
1312
|
|
|
echo json_encode( $response ); |
1313
|
|
|
exit; |
1314
|
|
|
} |
1315
|
|
|
add_action( 'wp_ajax_wpsc_set_variation_product_thumbnail', '_wpsc_ajax_set_variation_product_thumbnail' ); |
1316
|
|
|
|
1317
|
|
|
/** |
1318
|
|
|
* Delete WPSC product image from gallery |
1319
|
|
|
* |
1320
|
|
|
* @uses check_ajax_referer() Verifies the AJAX request to prevent processing external requests |
1321
|
|
|
* @uses get_post_meta() Returns meta from the specified post |
1322
|
|
|
* @uses update_post_meta() Updates meta from the specified post |
1323
|
|
|
*/ |
1324
|
|
|
function product_gallery_image_delete_action() { |
1325
|
|
|
|
1326
|
|
|
$product_gallery = array(); |
1327
|
|
|
$gallery_image_id = $gallery_post_id = ''; |
1328
|
|
|
|
1329
|
|
|
$gallery_image_id = absint($_POST['product_gallery_image_id']); |
1330
|
|
|
$gallery_post_id = absint($_POST['product_gallery_post_id']); |
1331
|
|
|
|
1332
|
|
|
check_ajax_referer( 'wpsc_gallery_nonce', 'wpsc_gallery_nonce_check' ); |
1333
|
|
|
|
1334
|
|
|
$product_gallery = get_post_meta( $gallery_post_id, '_wpsc_product_gallery', true ); |
1335
|
|
|
|
1336
|
|
|
foreach ( $product_gallery as $index => $image_id ) { |
1337
|
|
|
if ( $image_id == $gallery_image_id ) { |
1338
|
|
|
unset( $product_gallery[$index] ); |
1339
|
|
|
} |
1340
|
|
|
} |
1341
|
|
|
|
1342
|
|
|
update_post_meta( $gallery_post_id, '_wpsc_product_gallery', $product_gallery ); |
1343
|
|
|
} |
1344
|
|
|
add_action( 'wp_ajax_product_gallery_image_delete', 'product_gallery_image_delete_action' ); |
1345
|
|
|
|
This error can happen if you refactor code and forget to move the variable initialization.
Let’s take a look at a simple example:
The above code is perfectly fine. Now imagine that we re-order the statements:
In that case,
$x
would be read before it is initialized. This was a very basic example, however the principle is the same for the found issue.