Completed
Pull Request — master (#2165)
by Justin
05:28
created

ajax.php ➔ _wpsc_ajax_update_log_item_qty()   B

Complexity

Conditions 5
Paths 5

Size

Total Lines 22
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 13
nc 5
nop 0
dl 0
loc 22
rs 8.6737
c 0
b 0
f 0
1
<?php
2
/**
3
 * Verify nonce of an AJAX request
4
 *
5
 * @since  3.8.9
6
 * @access private
7
 *
8
 * @uses WP_Error           WordPress Error Class
9
 * @uses wp_verify_nonce()    Verify that correct nonce was used with time limit.
10
 *
11
 * @param string $ajax_action Name of AJAX action
12
 * @return WP_Error|boolean True if nonce is valid. WP_Error if otherwise.
13
 */
14
function _wpsc_ajax_verify_nonce( $ajax_action ) {
15
	// nonce can be passed with name wpsc_nonce or _wpnonce
16
	$nonce = '';
17
18
	if ( isset( $_REQUEST['nonce'] ) )
19
		$nonce = $_REQUEST['nonce'];
20
	elseif ( isset( $_REQUEST['_wpnonce'] ) )
21
		$nonce = $_REQUEST['_wpnonce'];
22
	else
23
		return _wpsc_error_invalid_nonce();
24
25
	// validate nonce
26
	if ( ! wp_verify_nonce( $nonce, 'wpsc_ajax_' . $ajax_action ) )
27
		return _wpsc_error_invalid_nonce();
28
29
	return true;
30
}
31
32
function _wpsc_error_invalid_nonce() {
33
	return new WP_Error( 'wpsc_ajax_invalid_nonce', __( 'Your session has expired. Please refresh the page and try again.', 'wp-e-commerce' ) );
34
}
35
36
/**
37
 * Verify AJAX callback and call it if it exists.
38
 *
39
 * @since  3.8.9
40
 * @access private
41
 *
42
 * @uses WP_Error   WordPress Error object
43
 *
44
 * @param  string $ajax_action Name of AJAX action
45
 * @return WP_Error|array Array of response args if callback is valid. WP_Error if otherwise.
46
 */
47
function _wpsc_ajax_fire_callback( $ajax_action ) {
48
	// if callback exists, call it and output JSON response
49
	$callback = "_wpsc_ajax_{$ajax_action}";
50
51
	if ( is_callable( $callback ) )
52
		$result = call_user_func( $callback );
53
	else
54
		$result = new WP_Error( 'wpsc_invalid_ajax_callback', __( 'Invalid AJAX callback.', 'wp-e-commerce' ) );
55
56
	return $result;
57
}
58
59
/**
60
 * AJAX handler for all WPEC ajax requests.
61
 *
62
 * This function automates nonce checking and outputs JSON response.
63
 *
64
 * @since 3.8.9
65
 * @access private
66
 *
67
 * @uses _wpsc_ajax_fire_callback()     Verify ajax callback if it exists
68
 * @uses _wpsc_ajax_verify_nonce()      Verify nonce of an ajax request
69
 * @uses is_wp_error()                  Check whether variable is a WordPress Error.
70
 *
71
 * @return array $output    json encoded response
0 ignored issues
show
Documentation introduced by
Should the return type not be array|null? Also, consider making the array more specific, something like array<String>, or String[].

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

If the return type contains the type array, this check recommends the use of a more specific type like String[] or array<String>.

Loading history...
72
 */
73
function _wpsc_ajax_handler() {
74
	$ajax_action = str_replace( '-', '_', $_REQUEST['wpsc_action'] );
75
76
	if ( is_callable( '_wpsc_ajax_verify_' . $ajax_action ) ) {
77
		$result = call_user_func( '_wpsc_ajax_verify_' . $ajax_action );
78
	} else {
79
		$result = _wpsc_ajax_verify_nonce( $ajax_action );
80
	}
81
82
	if ( ! is_wp_error( $result ) ) {
83
		$result = _wpsc_ajax_fire_callback( $ajax_action );
84
	}
85
86
	$output = array(
87
		'is_successful' => false,
88
	);
89
90
	if ( is_wp_error( $result ) ) {
91
		$output['error'] = array(
92
			'code'     => $result->get_error_code(),
93
			'messages' => $result->get_error_messages(),
94
			'data'     => $result->get_error_data(),
95
		);
96
	} else {
97
		$output['is_successful'] = true;
98
		$output['obj'] = $result;
99
	}
100
101
	echo json_encode( $output );
102
	exit;
103
}
104
add_action( 'wp_ajax_wpsc_ajax', '_wpsc_ajax_handler' );
105
106
/**
107
 * Checks if WPSC is doing ajax
108
 *
109
 * @param   string  $action     req     The action we're checking
110
 * @return  bool    True if doing ajax
111
 */
112
function wpsc_is_doing_ajax( $action = '' ) {
113
	$ajax = defined( 'DOING_AJAX' ) && DOING_AJAX && ! empty( $_REQUEST['action'] ) && $_REQUEST['action'] == 'wpsc_ajax';
114
115
	if ( $action ) {
116
		$ajax = $ajax && ! empty( $_REQUEST['wpsc_action'] ) && $action == str_replace( '-', '_', $_REQUEST['wpsc_action'] );
117
	}
118
119
	return $ajax;
120
}
121
122
/**
123
 * Helper function that generates nonce for an AJAX action. Basically just a wrapper of
124
 * wp_create_nonce() but automatically add prefix.
125
 *
126
 * @since  3.8.9
127
 * @access private
128
 *
129
 * @uses wp_create_nonce()  Creates a random one time use token
130
 *
131
 * @param  string $action AJAX action without prefix
0 ignored issues
show
Documentation introduced by
There is no parameter named $action. Did you maybe mean $ajax_action?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. It has, however, found a similar but not annotated parameter which might be a good fit.

Consider the following example. The parameter $ireland is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $ireland
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was changed, but the annotation was not.

Loading history...
132
 * @return string         The generated nonce.
133
 */
134
function _wpsc_create_ajax_nonce( $ajax_action ) {
135
	return wp_create_nonce( "wpsc_ajax_{$ajax_action}" );
136
}
137
138
/**
139
 * Add new variation set via AJAX.
140
 *
141
 * If the variation set name is the same as an existing variation set,
142
 * the children variant terms will be added inside that existing set.
143
 *
144
 * @since 3.8.8
145
 * @access private
146
 *
147
 * @uses term_exists()                      Returns true if term exists
148
 * @uses get_term()                         Gets all term data by term_id
149
 * @uses wp_insert_term()                   Inserts a term to the WordPress database
150
 * @uses is_wp_error()                      Checks whether variable is a WordPress error
151
 * @uses WP_Error                           WordPress Error class
152
 * @uses clean_term_cache()                 Will remove all of the term ids from the cache.
153
 * @uses delete_option()                    Deletes option from the database
154
 * @uses wp_cache_set()                     Saves the data to the cache.
155
 * @uses _get_term_hierarchy()              Retrieves children of taxonomy as Term IDs.
156
 * @uses wp_terms_checklist()               Output an unordered list of checkbox <input> elements labelled
157
 * @uses WPSC_Walker_Variation_Checklist    Walker variation checklist
158
 *
159
 * @return array Response args
160
 */
161
function _wpsc_ajax_add_variation_set() {
162
	$new_variation_set = $_POST['variation_set'];
163
	$variants = preg_split( '/\s*,\s*/', $_POST['variants'] );
164
165
	$return = array();
166
167
	$parent_term_exists = term_exists( $new_variation_set, 'wpsc-variation' );
168
169
	// only use an existing parent ID if the term is not a child term
170
	if ( $parent_term_exists ) {
171
		$parent_term = get_term( $parent_term_exists['term_id'], 'wpsc-variation' );
172
		if ( $parent_term->parent == '0' )
173
			$variation_set_id = $parent_term_exists['term_id'];
174
	}
175
176
	if ( empty( $variation_set_id ) ) {
177
		$results = wp_insert_term( apply_filters( 'wpsc_new_variation_set', $new_variation_set ), 'wpsc-variation' );
178
		if ( is_wp_error( $results ) )
179
			return $results;
180
		$variation_set_id = $results['term_id'];
181
	}
182
183
	if ( empty( $variation_set_id ) )
184
		return new WP_Error( 'wpsc_invalid_variation_id', __( 'Cannot retrieve the variation set in order to proceed.', 'wp-e-commerce' ) );
185
186
	foreach ( $variants as $variant ) {
187
		$results = wp_insert_term( apply_filters( 'wpsc_new_variant', $variant, $variation_set_id ), 'wpsc-variation', array( 'parent' => $variation_set_id ) );
188
189
		if ( is_wp_error( $results ) )
190
			return $results;
191
192
		$inserted_variants[] = $results['term_id'];
0 ignored issues
show
Coding Style Comprehensibility introduced by
$inserted_variants was never initialized. Although not strictly required by PHP, it is generally a good practice to add $inserted_variants = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
193
	}
194
195
	require_once( 'includes/walker-variation-checklist.php' );
196
197
	if ( ! version_compare( $GLOBALS['wp_version'], '3.8.3', '>' ) ) {
198
199
		/* --- DIRTY HACK START --- */
200
		/*
201
		There's a bug with term cache in WordPress core. See http://core.trac.wordpress.org/ticket/14485. Fixed in 3.9.
202
		The next 3 lines will delete children term cache for wpsc-variation.
203
		Without this hack, the new child variations won't be displayed on "Variations" page and
204
		also won't be displayed in wp_terms_checklist() call below.
205
		*/
206
		clean_term_cache( $variation_set_id, 'wpsc-variation' );
207
		delete_option('wpsc-variation_children');
208
		wp_cache_set( 'last_changed', 1, 'terms' );
209
		_get_term_hierarchy('wpsc-variation');
210
		/* --- DIRTY HACK END --- */
211
212
	}
213
214
	ob_start();
215
216
	wp_terms_checklist( (int) $_POST['post_id'], array(
217
		'taxonomy'      => 'wpsc-variation',
218
		'descendants_and_self' => $variation_set_id,
219
		'walker'        => new WPSC_Walker_Variation_Checklist( $inserted_variants ),
0 ignored issues
show
Bug introduced by
The variable $inserted_variants does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
220
		'checked_ontop' => false,
221
	) );
222
223
	$content = ob_get_clean();
224
225
	$return = array(
226
		'variation_set_id'  => $variation_set_id,
227
		'inserted_variants' => $inserted_variants,
228
		'content'           => $content,
229
	);
230
231
	return $return;
232
}
233
234
/**
235
 * Display gateway settings form via AJAX
236
 *
237
 * @since  3.8.9
238
 * @access private
239
 *
240
 * @uses WPSC_Settings_Tab_Gateway
241
 * @uses WPSC_Settings_Tab_Gateway::display_payment_gateway_settings_form()     Displays payment gateway form
242
 *
243
 * @return array Response args
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use array<string,string>.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
244
 */
245
function _wpsc_ajax_payment_gateway_settings_form() {
246
247
	require_once( 'settings-page.php' );
248
	require_once( 'includes/settings-tabs/gateway.php' );
249
250
	$return = array();
251
	ob_start();
252
	$tab = new WPSC_Settings_Tab_Gateway();
253
	$tab->display_payment_gateway_settings_form();
254
	$return['content'] = ob_get_clean();
255
256
	return $return;
257
}
258
259
/**
260
 * Display shipping module settings form via AJAX
261
 *
262
 * @since  3.8.9
263
 * @access private
264
 *
265
 * @uses WPSC_Settings_Table_Shipping
266
 * @uses WPSC_Settings_Table_Shipping::display_shipping_module_settings_form()  Displays shipping module form
267
 *
268
 * @return array $return    Response args
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use array<string,string>.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
269
 */
270
function _wpsc_ajax_shipping_module_settings_form() {
271
	require_once( 'settings-page.php' );
272
	require_once( 'includes/settings-tabs/shipping.php' );
273
274
	$return = array();
275
	ob_start();
276
	$tab = new WPSC_Settings_Tab_Shipping();
277
	$tab->display_shipping_module_settings_form();
278
	$return['content'] = ob_get_clean();
279
280
	return $return;
281
}
282
283
/**
284
 * Display settings tab via AJAX
285
 *
286
 * @since 3.8.9
287
 * @access private
288
 *
289
 * @uses WPSC_Settings_Page
290
 * @uses WPSC_Settings_Page::display_current_tab()  Shows current tab of settings page
291
 *
292
 * @return array $return    Response args
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use array<string,string>.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
293
 */
294
function _wpsc_ajax_navigate_settings_tab() {
295
	require_once( 'settings-page.php' );
296
297
	$return = array();
298
	ob_start();
299
	$settings_page = new WPSC_Settings_Page( $_POST['tab'] );
300
	$settings_page->display_current_tab();
301
	$return['content'] = ob_get_clean();
302
303
	return $return;
304
}
305
306
/**
307
 * Display base region list in Store Settings -> General
308
 *
309
 * @since 3.8.9
310
 * @access private
311
 *
312
 * @uses WPSC_Settings_Tab_General
313
 * @uses WPSC_Settings_Tab_General::display_region_drop_down()  Shows region dropdown
314
 *
315
 * @return array    $return     Response args
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use array<string,string>.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
316
 */
317
function _wpsc_ajax_display_region_list() {
318
	require_once( 'settings-page.php' );
319
	require_once( 'includes/settings-tabs/general.php' );
320
321
	$return = array();
322
	ob_start();
323
	$tab = new WPSC_Settings_Tab_General();
324
	$tab->display_region_drop_down();
325
	$return['content'] = ob_get_clean();
326
327
	return $return;
328
}
329
330
/**
331
 * Save tracking ID of a sales log.
332
 *
333
 * @since 3.8.9
334
 * @access private
335
 *
336
 * @uses WP_Error   WordPress Error class
337
 *
338
 * @return array|WP_Error   $return     Response args if successful, WP_Error if otherwise.
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use WP_Error|array.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
339
 */
340
function _wpsc_ajax_purchase_log_save_tracking_id() {
341
	global $wpdb;
342
343
	$result = $wpdb->update(
344
		WPSC_TABLE_PURCHASE_LOGS,
345
		array(
346
			'track_id' => $_POST['value']
347
		),
348
		array(
349
			'id' => $_POST['log_id']
350
		),
351
		'%s',
352
		'%d'
353
	);
354
355
	if ( ! $result )
356
		return new WP_Error( 'wpsc_cannot_save_tracking_id', __( "Couldn't save tracking ID of the transaction. Please try again.", 'wp-e-commerce' ) );
357
358
	$return = array(
359
		'rows_affected' => $result,
360
		'id'            => $_POST['log_id'],
361
		'track_id'      => $_POST['value'],
362
	);
363
364
	return $return;
365
}
366
367
/**
368
 * Send sales log tracking email via AJAX
369
 *
370
 * @since 3.8.9
371
 * @access private
372
 *
373
 * @uses $wpdb              WordPress database object for queries
374
 * @uses get_option()       Gets option from DB given key
375
 * @uses add_filter()       Calls 'wp_mail_from' which can replace the from email address
376
 * @uses add_filter()       Calls 'wp_mail_from_name' allows replacement of the from name on WordPress emails
377
 * @uses wp_mail()          All the emailses in WordPress are sent through this function
378
 * @uses WP_Error           WordPress Error class
379
 *
380
 * @return array|WP_Error   $return     Response args if successful, WP_Error if otherwise
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use WP_Error|array.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
381
 */
382
function _wpsc_ajax_purchase_log_send_tracking_email() {
383
	global $wpdb;
384
385
	$id = absint( $_POST['log_id'] );
386
	$sql = $wpdb->prepare( "SELECT `track_id` FROM " . WPSC_TABLE_PURCHASE_LOGS . " WHERE `id`=%d LIMIT 1", $id );
387
	$trackingid = $wpdb->get_var( $sql );
388
389
	$message = get_option( 'wpsc_trackingid_message' );
390
	$message = str_replace( '%trackid%', $trackingid, $message );
391
	$message = str_replace( '%shop_name%', get_option( 'blogname' ), $message );
392
393
	$email = wpsc_get_buyers_email( $id );
394
395
	$subject = get_option( 'wpsc_trackingid_subject' );
396
	$subject = str_replace( '%shop_name%', get_option( 'blogname' ), $subject );
397
398
	add_filter( 'wp_mail_from', 'wpsc_replace_reply_address', 0 );
399
	add_filter( 'wp_mail_from_name', 'wpsc_replace_reply_name', 0 );
400
401
	$result = wp_mail( $email, $subject, $message);
402
403
	if ( ! $result ) {
404
		return new WP_Error( 'wpsc_cannot_send_tracking_email', __( "Couldn't send tracking email. Please try again.", 'wp-e-commerce' ) );
405
	}
406
407
	$return = array(
408
		'id'          => $id,
409
		'tracking_id' => $trackingid,
410
		'subject'     => $subject,
411
		'message'     => $message,
412
		'email'       => $email
413
	);
414
415
	return $return;
416
}
417
418
/**
419
 * Do purchase log action link via AJAX
420
 *
421
 * @since   3.9.0
422
 * @access  private
423
 *
424
 * @return  array|WP_Error  $return  Response args if successful, WP_Error if otherwise
425
 */
426
function _wpsc_ajax_purchase_log_action_link() {
427
428
	if ( isset( $_POST['log_id'] ) && isset( $_POST['purchase_log_action_link'] ) && isset( $_POST['purchase_log_action_nonce'] ) ) {
429
430
		$log_id = absint( $_POST['log_id'] );
431
		$purchase_log_action_link = sanitize_key( $_POST['purchase_log_action_link'] );
432
433
		// Verify action nonce
434
		if ( wp_verify_nonce( $_POST['purchase_log_action_nonce'], 'wpsc_purchase_log_action_ajax_' . $purchase_log_action_link ) ) {
435
436
			// Expected to receive success = true by default, or false on error.
437
			$return = apply_filters( 'wpsc_purchase_log_action_ajax-' . $purchase_log_action_link, array( 'success' => null ), $log_id );
438
439
		} else {
440
			$return = _wpsc_error_invalid_nonce();
441
		}
442
443
		if ( ! is_wp_error( $return ) ) {
444
			$return['log_id'] = $log_id;
445
			$return['purchase_log_action_link'] = $purchase_log_action_link;
446
			$return['success'] = isset( $return['success'] ) ? (bool) $return['success'] : null;
447
		}
448
449
		return $return;
450
451
	}
452
453
	return new WP_Error( 'wpsc_ajax_invalid_purchase_log_action', __( 'Purchase log action failed.', 'wp-e-commerce' ) );
454
455
}
456
457
/**
458
 * Remove purchase log item.
459
 *
460
 * @since   4.0
461
 * @access  private
462
 *
463
 * @return  array|WP_Error  $return  Response args if successful, WP_Error if otherwise
464
 */
465
function _wpsc_ajax_remove_log_item() {
466
467
	if ( isset( $_POST['item_id'], $_POST['log_id'] ) ) {
468
469
		$item_id = absint( $_POST['item_id'] );
470
		$log_id  = absint( $_POST['log_id'] );
471
		$log     = new WPSC_Purchase_Log( $log_id );
472
473
		if ( $log->remove_cart_item( $item_id ) ) {
474
			return _wpsc_init_log_items( $log );
475
		}
476
	}
477
478
	return new WP_Error( 'wpsc_ajax_invalid_remove_log_item', __( 'Removing log item failed.', 'wp-e-commerce' ) );
479
}
480
481
/**
482
 * Update purchase log item quantity.
483
 *
484
 * @since   4.0
485
 * @access  private
486
 *
487
 * @return  array|WP_Error  $return  Response args if successful, WP_Error if otherwise
488
 */
489
function _wpsc_ajax_update_log_item_qty() {
490
491
	if ( isset( $_POST['item_id'], $_POST['log_id'], $_POST['qty'] ) ) {
492
493
		if ( empty( $_POST['qty'] ) ) {
494
			return _wpsc_ajax_remove_log_item();
495
		}
496
497
		$item_id = absint( $_POST['item_id'] );
498
		$log_id  = absint( $_POST['log_id'] );
499
		$log     = new WPSC_Purchase_Log( $log_id );
500
		$result  = $log->update_cart_item( $item_id, array( 'quantity' => absint( $_POST['qty'] ) ) );
501
502
		if ( 0 === $result ) {
503
			return true;
504
		} elseif ( false !== $result ) {
505
			return _wpsc_init_log_items( $log );
506
		}
507
	}
508
509
	return new WP_Error( 'wpsc_ajax_invalid_update_log_item_qty', __( 'Updating log item quantity failed.', 'wp-e-commerce' ) );
510
}
511
512
/**
513
 * Add purchase log item.
514
 *
515
 * @since   4.0
516
 * @access  private
517
 *
518
 * @return  array|WP_Error  $return  Response args if successful, WP_Error if otherwise
519
 */
520
function _wpsc_ajax_add_log_item() {
521
	global $wpsc_cart;
522
523
	if (
524
		isset( $_POST['product_ids'], $_POST['log_id'] )
525
		&& is_array( $_POST['product_ids'] )
526
		&& ! empty( $_POST['product_ids'] )
527
	) {
528
529
		$existing = isset( $_POST['existing'] ) && is_array( $_POST['existing'] )
530
			? array_map( 'absint', $_POST['existing'] )
531
			: false;
532
533
		$item_ids = array();
534
535
		foreach ( $_POST['product_ids'] as $product_id ) {
536
			$product_id = absint( $product_id );
537
			$log_id     = absint( $_POST['log_id'] );
538
			$log        = new WPSC_Purchase_Log( $log_id );
539
540
			// Is product is already in item list?
541
			if ( $existing && in_array( $product_id, $existing, true ) ) {
542
				$item = $log->get_cart_item_from_product_id( $product_id );
543
				if ( $item ) {
544
					// Update item quantity...
545
					$log->update_cart_item( $item->id, array( 'quantity' => ++$item->quantity ) );
546
					// And move on.
547
					continue;
548
				}
549
			}
550
551
			$item = new wpsc_cart_item( $product_id, array(), $wpsc_cart );
552
			$item_id = $item->save_to_db( $log_id );
553
			$item_ids[] = absint( $item_id );
554
		}
555
556
		return _wpsc_init_log_items( $log, $item_ids );
0 ignored issues
show
Bug introduced by
The variable $log does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
557
	}
558
559
	return new WP_Error( 'wpsc_ajax_invalid_add_log_item', __( 'Adding log item failed.', 'wp-e-commerce' ) );
560
}
561
562
function _wpsc_init_log_items( WPSC_Purchase_Log $log, $item_ids = array() ) {
563
	$log->init_items();
564
565
	require_once( WPSC_FILE_PATH . '/wpsc-admin/display-sales-logs.php' );
566
567
	$html = '';
568
	$htmls[] = array();
0 ignored issues
show
Coding Style Comprehensibility introduced by
$htmls was never initialized. Although not strictly required by PHP, it is generally a good practice to add $htmls = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
569
570
	while ( wpsc_have_purchaselog_details() ) {
571
		wpsc_the_purchaselog_item();
572
573
		ob_start();
574
		WPSC_Purchase_Log_Page::purchase_log_cart_item( $log->can_edit() );
575
		$cart_item = ob_get_clean();
576
577
		$htmls[ wpsc_purchaselog_details_id() ] = $cart_item;
578
		if ( ! empty( $item_ids ) && in_array( absint( wpsc_purchaselog_details_id() ), $item_ids, true ) ) {
579
			$html .= $cart_item;
580
		}
581
	}
582
583
	return array(
584
		'quantities'     => wp_list_pluck( $log->get_items(), 'quantity', 'id' ),
585
		'html'           => $html,
586
		'htmls'          => $htmls,
587
		'discount_data'  => wpsc_purchlog_has_discount_data() ? esc_html__( 'Coupon Code', 'wp-e-commerce' ) . ': ' . wpsc_display_purchlog_discount_data() : '',
588
		'discount'       => wpsc_display_purchlog_discount(),
589
		'total_taxes'    => wpsc_display_purchlog_taxes(),
590
		'total_shipping' => wpsc_display_purchlog_shipping(),
591
		'final_total'    => wpsc_display_purchlog_totalprice(),
592
	);
593
}
594
595
/**
596
 * Search for products.
597
 *
598
 * @since   4.0
599
 * @access  private
600
 *
601
 * @return  array|WP_Error  $return  Response args if successful, WP_Error if otherwise
602
 */
603
function _wpsc_ajax_search_products() {
604
	$pt_object = get_post_type_object( 'wpsc-product' );
605
606
	$s = wp_unslash( $_POST['search'] );
607
	$args = array(
608
		'post_type' => 'wpsc-product',
609
		'post_status' => array( 'publish', 'inherit' ),
610
		'posts_per_page' => 50,
611
	);
612
	if ( '' !== $s ) {
613
		$args['s'] = $s;
614
	}
615
616
	$posts = get_posts( $args );
617
618
	if ( ! $posts ) {
619
		return new WP_Error( 'wpsc_ajax_invalid_search_products', __( 'No items found.', 'wp-e-commerce' ) );
620
	}
621
622
	$alt = '';
623
	foreach ( $posts as $post ) {
624
		$post->title = trim( $post->post_title ) ? $post->post_title : __( '(no title)' );
625
		$alt = ( 'alternate' === $alt ) ? '' : 'alternate';
626
627
		$post->status = $post->post_status;
628
629
		switch ( $post->post_status ) {
630
			case 'publish' :
631
			case 'private' :
632
				$post->status = __( 'Published' );
633
				break;
634
			case 'future' :
635
				$post->status = __( 'Scheduled' );
636
				break;
637
			case 'pending' :
638
				$post->status = __( 'Pending Review' );
639
				break;
640
			case 'draft' :
641
				$post->status = __( 'Draft' );
642
				break;
643
			default :
644
				$post->status = $post->post_status;
645
				break;
646
		}
647
648
		if ( '0000-00-00 00:00:00' === $post->post_date ) {
649
			$post->time = '';
650
		} else {
651
			/* translators: date format in table columns, see https://secure.php.net/date */
652
			$post->time = mysql2date( __( 'Y/m/d' ), $post->post_date );
653
		}
654
655
		$post->class = $alt;
656
	}
657
658
	return $posts;
659
}
660
661
/**
662
 * Handle AJAX clear downloads lock purchase log action
663
 *
664
 * The _wpsc_ajax_purchase_log_action_link() function which triggers this function is nonce
665
 * and capability checked in _wpsc_ajax_handler().
666
 *
667
 * @since   3.9.0
668
 * @access  private
669
 *
670
 * @param  array  $response  AJAX response.
671
 * @param  int    $log_id    Purchase log ID.
672
 */
673
function wpsc_purchase_log_action_ajax_downloads_lock( $response, $log_id ) {
674
675
	$response['success'] = wpsc_purchlog_clear_download_items( $log_id );
676
677
	return $response;
678
679
}
680
add_action( 'wpsc_purchase_log_action_ajax-downloads_lock', 'wpsc_purchase_log_action_ajax_downloads_lock', 10, 2 );
681
682
683
/**
684
 * Handle AJAX email receipt purchase log action
685
 *
686
 * The _wpsc_ajax_purchase_log_action_link() function which triggers this function is nonce
687
 * and capability checked in _wpsc_ajax_handler().
688
 *
689
 * @since   3.9.0
690
 * @access  private
691
 *
692
 * @param  array  $response  AJAX response.
693
 * @param  int    $log_id    Purchase log ID.
694
 */
695
function wpsc_purchase_log_action_ajax_email_receipt( $response, $log_id ) {
696
697
	$response['success'] = wpsc_purchlog_resend_email( $log_id );
698
699
	return $response;
700
701
}
702
add_action( 'wpsc_purchase_log_action_ajax-email_receipt', 'wpsc_purchase_log_action_ajax_email_receipt', 10, 2 );
703
704
/**
705
 * Delete an attached downloadable file via AJAX.
706
 *
707
 * @since 3.8.9
708
 * @access private
709
 *
710
 * @uses _wpsc_delete_file()    Deletes files associated with a product
711
 * @uses WP_Error               WordPress error class
712
 *
713
 * @return array|WP_Error   $return     Response args if successful, WP_Error if otherwise
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use WP_Error|array.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
714
 */
715
function _wpsc_ajax_delete_file() {
716
	$product_id = absint( $_REQUEST['product_id'] );
717
	$file_name = basename( $_REQUEST['file_name'] );
718
719
	$result = _wpsc_delete_file( $product_id, $file_name );
720
721
	if ( ! $result )
722
		return new WP_Error( 'wpsc_cannot_delete_file', __( "Couldn't delete the file. Please try again.", 'wp-e-commerce' ) );
723
724
	$return = array(
725
		'product_id' => $product_id,
726
		'file_name'  => $file_name,
727
	);
728
729
	return $return;
730
}
731
732
/**
733
 * Delete a product meta via AJAX
734
 *
735
 * @since 3.8.9
736
 * @access private
737
 *
738
 * @uses delete_meta()      Deletes metadata by meta id
739
 * @uses WP_Error           WordPress error class
740
 *
741
 * @return  array|WP_Error  $return     Response args if successful, WP_Error if otherwise
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use WP_Error|array<string,integer>.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
742
 */
743
function _wpsc_ajax_remove_product_meta() {
744
	$meta_id = (int) $_POST['meta_id'];
745
	if ( ! delete_meta( $meta_id ) )
746
		return new WP_Error( 'wpsc_cannot_delete_product_meta', __( "Couldn't delete product meta. Please try again.", 'wp-e-commerce' ) );
747
748
	return array( 'meta_id' => $meta_id );
749
}
750
751
/**
752
 * Modify a purchase log's status.
753
 *
754
 * @since 3.8.9
755
 * @access private
756
 *
757
 * @uses wpsc_purchlog_edit_status()                    Edits purchase log status
758
 * @uses WP_Error                                       WordPress Error class
759
 * @uses WPSC_Purchase_Log_List_Table
760
 * @uses WPSC_Purchase_Log_List_Table::prepare_items()
761
 * @uses WPSC_Purchase_Log_List_Table::views()
762
 * @uses WPSC_Purchase_Log_List_Table::display_tablenav()   @todo docs
763
 *
764
 * @return array|WP_Error   $return     Response args if successful, WP_Error if otherwise.
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use WP_Error|array.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
765
 */
766
function _wpsc_ajax_change_purchase_log_status() {
767
	$result = wpsc_purchlog_edit_status( $_POST['id'], $_POST['new_status'] );
768
	if ( ! $result )
769
		return new WP_Error( 'wpsc_cannot_edit_purchase_log_status', __( "Couldn't modify purchase log's status. Please try again.", 'wp-e-commerce' ) );
770
771
	$args = array();
772
773
	$args['screen'] = 'dashboard_page_wpsc-sales-logs';
774
775
	require_once( WPSC_FILE_PATH . '/wpsc-admin/includes/purchase-log-list-table-class.php' );
776
	$purchaselog_table = new WPSC_Purchase_Log_List_Table( $args );
777
	$purchaselog_table->prepare_items();
778
779
	ob_start();
780
	$purchaselog_table->views();
781
	$views = ob_get_clean();
782
783
	ob_start();
784
	$purchaselog_table->display_tablenav( 'top' );
785
	$tablenav_top = ob_get_clean();
786
787
	ob_start();
788
	$purchaselog_table->display_tablenav( 'bottom' );
789
	$tablenav_bottom = ob_get_clean();
790
791
	$return = array(
792
		'id'              => $_POST['id'],
793
		'new_status'      => $_POST['new_status'],
794
		'views'           => $views,
795
		'tablenav_top'    => $tablenav_top,
796
		'tablenav_bottom' => $tablenav_bottom,
797
	);
798
799
	return $return;
800
}
801
802
/**
803
 * Save product ordering after drag-and-drop sorting
804
 *
805
 * @since 3.8.9
806
 * @access private
807
 *
808
 * @uses $wpdb              WordPress database object for use in queries
809
 * @uses wp_update_post()   Updates post based on passed $args. Needs a post_id
810
 * @uses WP_Error           WordPress Error class
811
 *
812
 * @return array|WP_Error Response args if successful, WP_Error if otherwise
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use WP_Error|array<string,array>.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
813
 */
814
function _wpsc_ajax_save_product_order() {
815
816
	$products = array( );
0 ignored issues
show
introduced by
Empty array declaration must have no space between the parentheses
Loading history...
817
	foreach ( $_POST['post'] as $product ) {
818
		$products[] = (int) str_replace( 'post-', '', $product );
819
	}
820
821
	$failed = array();
822
	foreach ( $products as $order => $product_id ) {
823
		$result = wp_update_post( array(
824
			'ID' => $product_id,
825
			'menu_order' => $order,
826
		) );
827
828
		if ( ! $result )
829
			$failed[] = $product_id;
830
	}
831
832
	// Validate data before exposing to action
833
	$category = isset( $_POST['category_id'] ) ? get_term_by( 'slug', $_POST['category_id'], 'wpsc_product_category' ) : false;
834
	do_action( 'wpsc_save_product_order', $products, $category );
835
836
	if ( ! empty( $failed ) ) {
837
		$error_data = array(
838
			'failed_ids' => $failed,
839
		);
840
841
		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 );
842
	}
843
844
	return array(
845
		'ids' => $products,
846
	);
847
}
848
849
/**
850
 * Save Category Product Order
851
 *
852
 * Note that this uses the 'term_order' field in the 'term_relationships' table to store
853
 * the order. Although this column presently seems to be unused by WordPress, the intention
854
 * is it should be used to store the order of terms associates to a post, not the order
855
 * of posts as we are doing. This shouldn't be an issue for WPEC unless WordPress adds a UI
856
 * for this. More info at http://core.trac.wordpress.org/ticket/9547
857
 *
858
 * @since 3.9
859
 * @access private
860
 *
861
 * @uses $wpdb   WordPress database object used for queries
862
 */
863
function _wpsc_save_category_product_order( $products, $category ) {
864
	global $wpdb;
865
866
	// Only save category product order if in category
867
	if ( ! $category )
868
		return;
869
870
	// Save product order in term_relationships table
871
	foreach ( $products as $order => $product_id ) {
872
		$wpdb->update( $wpdb->term_relationships,
873
			array( 'term_order' => $order ),
874
			array( 'object_id' => $product_id, 'term_taxonomy_id' => $category->term_taxonomy_id ),
875
			array( '%d' ),
876
			array( '%d', '%d' )
877
		);
878
	}
879
}
880
add_action( 'wpsc_save_product_order', '_wpsc_save_category_product_order', 10, 2 );
881
882
/**
883
 * Update Checkout fields order
884
 *
885
 * @since 3.8.9
886
 * @access private
887
 *
888
 * @uses $wpdb      WordPress database object used for queries
889
 * @uses WP_Error   WordPress error class
890
 *
891
 * @return array|WP_Error Response args or WP_Error
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use WP_Error|array<string,array>.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
892
 */
893
function _wpsc_ajax_update_checkout_fields_order() {
894
	global $wpdb;
895
896
	$checkout_fields = $_REQUEST['sort_order'];
897
	$order = 1;
898
	$failed = array();
899
	$modified = array();
900
	foreach ( $checkout_fields as &$checkout_field ) {
901
		// ignore new fields
902
		if ( strpos( $checkout_field, 'new-field' ) === 0 )
903
			continue;
904
		$checkout_field = absint( preg_replace('/[^0-9]+/', '', $checkout_field ) );
905
		$result = $wpdb->update(
906
			WPSC_TABLE_CHECKOUT_FORMS,
907
			array(
908
				'checkout_order' => $order
909
			),
910
			array(
911
				'id' => $checkout_field
912
			),
913
			'%d',
914
			'%d'
915
		);
916
		$order ++;
917
		if ( $result === false )
918
			$failed[] = $checkout_field;
919
		elseif ( $result > 0 )
920
			$modified[] = $checkout_field;
921
	}
922
923
	if ( ! empty( $failed ) )
924
		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 ) );
925
926
	return array(
927
		'modified' => $modified,
928
	);
929
}
930
931
/**
932
 * Save a downloadable file to a product
933
 *
934
 * @since 3.8.9
935
 * @access private
936
 *
937
 * @uses $wpdb                          WordPress database object for use in queries
938
 * @uses _wpsc_create_ajax_nonce()      Creates nonce for an ajax action
939
 * @uses wpsc_get_mimetype()            Returns mimetype of file
940
 * @uses wp_insert_post()               Inserts post to WordPress database
941
 * @uses wp_nonce_url()                 Retrieve URL with nonce added to URL query.
942
 * @uses wpsc_convert_bytes()           Formats bytes
943
 * @uses wpsc_get_extension()           Gets extension of file
944
 * @uses esc_attr()                     Escapes HTML attributes
945
 * @uses _x()                           Retrieve translated string with gettext context
946
 *
947
 * @return array|WP_Error Response args if successful, WP_Error if otherwise.
948
 */
949
function _wpsc_ajax_upload_product_file() {
950
	global $wpdb;
951
	$product_id = absint( $_POST["product_id"] );
952
	$output = '';
953
	$delete_nonce = _wpsc_create_ajax_nonce( 'delete_file' );
954
955
	foreach ( $_POST["select_product_file"] as $selected_file ) {
956
		// if we already use this file, there is no point doing anything more.
957
		$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()
958
		$file_post_data = $wpdb->get_row( $sql, ARRAY_A );
959
		$selected_file_path = WPSC_FILE_DIR . basename( $selected_file );
960
		$file_url = WPSC_FILE_URL . basename( $selected_file );
961
		$file_size = filesize( $selected_file_path );
962
		if ( empty( $file_post_data ) ) {
963
			$type = wpsc_get_mimetype( $selected_file_path );
964
			$attachment = array(
965
				'post_mime_type' => $type,
966
				'post_parent' => $product_id,
967
				'post_title' => $selected_file,
968
				'post_content' => '',
969
				'post_type' => "wpsc-product-file",
970
				'post_status' => 'inherit'
971
			);
972
			$id = wp_insert_post( $attachment );
973
		} else {
974
			// already attached
975
			if ( $file_post_data['post_parent'] == $product_id )
976
				continue;
977
			$type = $file_post_data["post_mime_type"];
978
			$url = $file_post_data["guid"];
979
			$title = $file_post_data["post_title"];
980
			$content = $file_post_data["post_content"];
981
			// Construct the attachment
982
			$attachment = array(
983
				'post_mime_type' => $type,
984
				'guid' => $url,
985
				'post_parent' => absint( $product_id ),
986
				'post_title' => $title,
987
				'post_content' => $content,
988
				'post_type' => "wpsc-product-file",
989
				'post_status' => 'inherit'
990
			);
991
			// Save the data
992
			$id = wp_insert_post( $attachment );
993
		}
994
995
		$deletion_url = wp_nonce_url( "admin.php?wpsc_admin_action=delete_file&amp;file_name={$attachment['post_title']}&amp;product_id={$product_id}", 'delete_file_' . $attachment['post_title'] );
996
997
		$output .= '<tr class="wpsc_product_download_row">';
998
		$output .= '<td style="padding-right: 30px;">' . $attachment['post_title'] . '</td>';
999
		$output .= '<td>' . wpsc_convert_byte( $file_size ) . '</td>';
1000
		$output .= '<td>.' . wpsc_get_extension( $attachment['post_title'] ) . '</td>';
1001
		$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>";
1002
		$output .= '<td><a href=' .$file_url .'>' . _x( 'Download', 'Digital Download UI row', 'wp-e-commerce' ) . '</a></td>';
1003
		$output .= '</tr>';
1004
	}
1005
1006
	return array(
1007
		'content' => $output,
1008
	);
1009
}
1010
1011
/**
1012
 * Generate variations
1013
 *
1014
 * @since 3.8.9
1015
 * @access private
1016
 *
1017
 * @uses wpsc_update_variations()       Updates product variations given
1018
 * @uses wpsc_admin_product_listing()   DEPRECATED
1019
 *
1020
 * @return array|WP_Error Response args if successful, WP_Error if otherwise
1021
 */
1022
function _wpsc_ajax_update_variations() {
1023
	$product_id = absint( $_REQUEST["product_id"] );
1024
	wpsc_update_variations();
1025
1026
	ob_start();
1027
	wpsc_admin_product_listing( $product_id );
1028
	$content = ob_get_clean();
1029
1030
	return array( 'content' => $content );
1031
}
1032
1033
/**
1034
 * Display the shortcode generator.
1035
 *
1036
 * @since  3.8.9
1037
 * @access private
1038
 */
1039
function _wpsc_action_tinymce_window() {
1040
	require_once( WPSC_CORE_JS_PATH . '/tinymce3/window.php' );
1041
	exit;
1042
}
1043
add_action( 'wp_ajax_wpsc_tinymce_window', '_wpsc_action_tinymce_window' );
1044
1045
/**
1046
 * Add tax rate
1047
 * @since  3.8.9
1048
 * @access private
1049
 *
1050
 * @uses wpec_taxes_controller                                                  Contains all the logic to communicate with the taxes system
1051
 * @uses wpec_taxes_controller::wpec_taxes::wpec_taxes_get_regions()            Gets tax regions based on input country code
1052
 * @uses wpec_taxes_controller::wpec_taxes_build_select_options()               Returns HTML formatted options from input array
1053
 * @uses wpec_taxes_controller::wpec_taxes_build_form()                         Builds the tax rate form
1054
 * @uses wpec_taxes_controller::wpec_taxes::wpec_taxes_get_band_from_index()    Retrieves tax band for given name
1055
 *
1056
 * @return array|WP_Error Response args if successful, WP_Error if otherwise
1057
 */
1058
function _wpsc_ajax_add_tax_rate() {
1059
	//include taxes controller
1060
	$wpec_taxes_controller = new wpec_taxes_controller;
1061
1062
	switch ( $_REQUEST['wpec_taxes_action'] ) {
1063
		case 'wpec_taxes_get_regions':
1064
			$regions = $wpec_taxes_controller->wpec_taxes->wpec_taxes_get_regions( $_REQUEST['country_code'] );
0 ignored issues
show
Bug introduced by
The property wpec_taxes does not seem to exist in wpec_taxes_controller.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
1065
			$key = $_REQUEST['current_key'];
1066
			$type = $_REQUEST['taxes_type'];
1067
			$default_option = array( 'region_code' => 'all-markets', 'name' => 'All Markets' );
1068
			$select_settings = array(
1069
				'id' => "{$type}-region-{$key}",
1070
				'name' => "wpsc_options[wpec_taxes_{$type}][{$key}][region_code]",
1071
				'class' => 'wpsc-taxes-region-drop-down'
1072
			);
1073
			$returnable = $wpec_taxes_controller->wpec_taxes_build_select_options( $regions, 'region_code', 'name', $default_option, $select_settings );
1074
			break;
1075
	}// switch
1076
1077
	return array(
1078
		'content' => $returnable,
0 ignored issues
show
Bug introduced by
The variable $returnable does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
1079
	);
1080
}
1081
1082
/**
1083
 * Displays the WPSC product variations table
1084
 *
1085
 * @uses check_admin_referrer()                     Makes sure user was referred from another admin page
1086
 * @uses WPSC_Product_Variations_Page               The WPSC Product variations class
1087
 * @uses WPSC_Product_Variations_Page::display()    Displays the product variations page
1088
 */
1089
function wpsc_product_variations_table() {
1090
	check_admin_referer( 'wpsc_product_variations_table' );
1091
	set_current_screen( 'wpsc-product' );
1092
	require_once( WPSC_FILE_PATH . '/wpsc-admin/includes/product-variations-page.class.php' );
1093
	$page = new WPSC_Product_Variations_Page();
1094
	$page->display();
1095
1096
	exit;
1097
}
1098
add_action( 'wp_ajax_wpsc_product_variations_table', 'wpsc_product_variations_table' );
1099
1100
/**
1101
 * @access private
1102
 *
1103
 * @uses current_user_can()             Checks user capabilities given string
1104
 * @uses delete_post_thumbnail()        Deletes post thumbnail given thumbnail id
1105
 * @uses set_post_thumbnail()           Sets post thumbnail given post_id and thumbnail_id
1106
 * @uses wpsc_the_product_thumbnail()   Returns URL to the product thumbnail
1107
 *
1108
 * @return array    $response           Includes the thumbnail URL and success bool value
0 ignored issues
show
Documentation introduced by
Should the return type not be array|null? Also, consider making the array more specific, something like array<String>, or String[].

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

If the return type contains the type array, this check recommends the use of a more specific type like String[] or array<String>.

Loading history...
1109
 */
1110
function _wpsc_ajax_set_variation_product_thumbnail() {
1111
	$response = array(
1112
		'success' => false
1113
	);
1114
1115
	$post_ID = intval( $_POST['post_id'] );
1116
	if ( current_user_can( 'edit_post', $post_ID ) ) {
1117
		$thumbnail_id = intval( $_POST['thumbnail_id'] );
1118
1119
		if ( $thumbnail_id == '-1' )
1120
			delete_post_thumbnail( $post_ID );
1121
1122
		set_post_thumbnail( $post_ID, $thumbnail_id );
1123
1124
		$thumbnail = wpsc_the_product_thumbnail( 50, 50, $post_ID, '' );
1125
		if ( ! $thumbnail )
1126
			$thumbnail = WPSC_CORE_IMAGES_URL . '/no-image-uploaded.gif';
1127
		$response['src'] = $thumbnail;
1128
		$response['success'] = true;
1129
	}
1130
1131
	echo json_encode( $response );
1132
	exit;
1133
}
1134
add_action( 'wp_ajax_wpsc_set_variation_product_thumbnail', '_wpsc_ajax_set_variation_product_thumbnail' );
1135
1136
/**
1137
 * Delete WPSC product image from gallery
1138
 *
1139
 * @uses check_ajax_referer()		Verifies the AJAX request to prevent processing external requests
1140
 * @uses get_post_meta()		Returns meta from the specified post
1141
 * @uses update_post_meta()		Updates meta from the specified post
1142
 */
1143
function product_gallery_image_delete_action() {
1144
1145
	$product_gallery = array();
1146
	$gallery_image_id = $gallery_post_id = '';
1147
1148
	$gallery_image_id = absint($_POST['product_gallery_image_id']);
1149
	$gallery_post_id = absint($_POST['product_gallery_post_id']);
1150
1151
	check_ajax_referer( 'wpsc_gallery_nonce', 'wpsc_gallery_nonce_check' );
1152
1153
	$product_gallery = get_post_meta( $gallery_post_id, '_wpsc_product_gallery', true );
1154
1155
	foreach ( $product_gallery as $index => $image_id ) {
1156
		if ( $image_id == $gallery_image_id ) {
1157
			unset( $product_gallery[$index] );
1158
		}
1159
	}
1160
1161
	update_post_meta( $gallery_post_id, '_wpsc_product_gallery', $product_gallery );
1162
}
1163
add_action( 'wp_ajax_product_gallery_image_delete', 'product_gallery_image_delete_action' );
1164