Completed
Pull Request — master (#2165)
by Justin
06:55
created

ajax.php ➔ _wpsc_ajax_add_log_item()   B

Complexity

Conditions 5
Paths 3

Size

Total Lines 26
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 16
nc 3
nop 0
dl 0
loc 26
rs 8.439
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
		$item_ids = array();
530
531
		foreach ( $_POST['product_ids'] as $product_id ) {
532
			$product_id = absint( $product_id );
533
			$log_id  = absint( $_POST['log_id'] );
534
			$log     = new WPSC_Purchase_Log( $log_id );
535
536
			$item = new wpsc_cart_item( $product_id, array(), $wpsc_cart );
537
			$item_id = $item->save_to_db( $log_id );
538
			$item_ids[] = absint( $item_id );
539
		}
540
541
		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...
542
	}
543
544
	return new WP_Error( 'wpsc_ajax_invalid_add_log_item', __( 'Adding log item failed.', 'wp-e-commerce' ) );
545
}
546
547
function _wpsc_init_log_items( WPSC_Purchase_Log $log, $item_ids = array() ) {
548
	$log->init_items();
549
550
	require_once( WPSC_FILE_PATH . '/wpsc-admin/display-sales-logs.php' );
551
552
	$html = '';
553
554
	while ( wpsc_have_purchaselog_details() ) {
555
		wpsc_the_purchaselog_item();
556
557
		ob_start();
558
		WPSC_Purchase_Log_Page::purchase_log_cart_item( $log->can_edit() );
559
		$cart_item = ob_get_clean();
560
561
		if ( ! empty( $item_ids ) && in_array( absint( wpsc_purchaselog_details_id() ), $item_ids, true ) ) {
562
			$html .= $cart_item;
563
		}
564
	}
565
566
	return array(
567
		'html'           => $html,
568
		'discount_data'  => wpsc_purchlog_has_discount_data() ? esc_html__( 'Coupon Code', 'wp-e-commerce' ) . ': ' . wpsc_display_purchlog_discount_data() : '',
569
		'discount'       => wpsc_display_purchlog_discount(),
570
		'total_taxes'    => wpsc_display_purchlog_taxes(),
571
		'total_shipping' => wpsc_display_purchlog_shipping(),
572
		'final_total'    => wpsc_display_purchlog_totalprice(),
573
	);
574
}
575
576
/**
577
 * Search for products.
578
 *
579
 * @since   4.0
580
 * @access  private
581
 *
582
 * @return  array|WP_Error  $return  Response args if successful, WP_Error if otherwise
583
 */
584
function _wpsc_ajax_search_products() {
585
	$pt_object = get_post_type_object( 'wpsc-product' );
586
587
	$s = wp_unslash( $_POST['search'] );
588
	$args = array(
589
		'post_type' => 'wpsc-product',
590
		'post_status' => array( 'publish', 'inherit' ),
591
		'posts_per_page' => 50,
592
	);
593
	if ( '' !== $s ) {
594
		$args['s'] = $s;
595
	}
596
597
	$posts = get_posts( $args );
598
599
	if ( ! $posts ) {
600
		return new WP_Error( 'wpsc_ajax_invalid_search_products', __( 'No items found.', 'wp-e-commerce' ) );
601
	}
602
603
	$alt = '';
604
	foreach ( $posts as $post ) {
605
		$post->title = trim( $post->post_title ) ? $post->post_title : __( '(no title)' );
606
		$alt = ( 'alternate' === $alt ) ? '' : 'alternate';
607
608
		$post->status = $post->post_status;
609
610
		switch ( $post->post_status ) {
611
			case 'publish' :
612
			case 'private' :
613
				$post->status = __( 'Published' );
614
				break;
615
			case 'future' :
616
				$post->status = __( 'Scheduled' );
617
				break;
618
			case 'pending' :
619
				$post->status = __( 'Pending Review' );
620
				break;
621
			case 'draft' :
622
				$post->status = __( 'Draft' );
623
				break;
624
			default :
625
				$post->status = $post->post_status;
626
				break;
627
		}
628
629
		if ( '0000-00-00 00:00:00' === $post->post_date ) {
630
			$post->time = '';
631
		} else {
632
			/* translators: date format in table columns, see https://secure.php.net/date */
633
			$post->time = mysql2date( __( 'Y/m/d' ), $post->post_date );
634
		}
635
636
		$post->class = $alt;
637
	}
638
639
	return $posts;
640
}
641
642
/**
643
 * Handle AJAX clear downloads lock purchase log action
644
 *
645
 * The _wpsc_ajax_purchase_log_action_link() function which triggers this function is nonce
646
 * and capability checked in _wpsc_ajax_handler().
647
 *
648
 * @since   3.9.0
649
 * @access  private
650
 *
651
 * @param  array  $response  AJAX response.
652
 * @param  int    $log_id    Purchase log ID.
653
 */
654
function wpsc_purchase_log_action_ajax_downloads_lock( $response, $log_id ) {
655
656
	$response['success'] = wpsc_purchlog_clear_download_items( $log_id );
657
658
	return $response;
659
660
}
661
add_action( 'wpsc_purchase_log_action_ajax-downloads_lock', 'wpsc_purchase_log_action_ajax_downloads_lock', 10, 2 );
662
663
664
/**
665
 * Handle AJAX email receipt purchase log action
666
 *
667
 * The _wpsc_ajax_purchase_log_action_link() function which triggers this function is nonce
668
 * and capability checked in _wpsc_ajax_handler().
669
 *
670
 * @since   3.9.0
671
 * @access  private
672
 *
673
 * @param  array  $response  AJAX response.
674
 * @param  int    $log_id    Purchase log ID.
675
 */
676
function wpsc_purchase_log_action_ajax_email_receipt( $response, $log_id ) {
677
678
	$response['success'] = wpsc_purchlog_resend_email( $log_id );
679
680
	return $response;
681
682
}
683
add_action( 'wpsc_purchase_log_action_ajax-email_receipt', 'wpsc_purchase_log_action_ajax_email_receipt', 10, 2 );
684
685
/**
686
 * Delete an attached downloadable file via AJAX.
687
 *
688
 * @since 3.8.9
689
 * @access private
690
 *
691
 * @uses _wpsc_delete_file()    Deletes files associated with a product
692
 * @uses WP_Error               WordPress error class
693
 *
694
 * @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...
695
 */
696
function _wpsc_ajax_delete_file() {
697
	$product_id = absint( $_REQUEST['product_id'] );
698
	$file_name = basename( $_REQUEST['file_name'] );
699
700
	$result = _wpsc_delete_file( $product_id, $file_name );
701
702
	if ( ! $result )
703
		return new WP_Error( 'wpsc_cannot_delete_file', __( "Couldn't delete the file. Please try again.", 'wp-e-commerce' ) );
704
705
	$return = array(
706
		'product_id' => $product_id,
707
		'file_name'  => $file_name,
708
	);
709
710
	return $return;
711
}
712
713
/**
714
 * Delete a product meta via AJAX
715
 *
716
 * @since 3.8.9
717
 * @access private
718
 *
719
 * @uses delete_meta()      Deletes metadata by meta id
720
 * @uses WP_Error           WordPress error class
721
 *
722
 * @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...
723
 */
724
function _wpsc_ajax_remove_product_meta() {
725
	$meta_id = (int) $_POST['meta_id'];
726
	if ( ! delete_meta( $meta_id ) )
727
		return new WP_Error( 'wpsc_cannot_delete_product_meta', __( "Couldn't delete product meta. Please try again.", 'wp-e-commerce' ) );
728
729
	return array( 'meta_id' => $meta_id );
730
}
731
732
/**
733
 * Modify a purchase log's status.
734
 *
735
 * @since 3.8.9
736
 * @access private
737
 *
738
 * @uses wpsc_purchlog_edit_status()                    Edits purchase log status
739
 * @uses WP_Error                                       WordPress Error class
740
 * @uses WPSC_Purchase_Log_List_Table
741
 * @uses WPSC_Purchase_Log_List_Table::prepare_items()
742
 * @uses WPSC_Purchase_Log_List_Table::views()
743
 * @uses WPSC_Purchase_Log_List_Table::display_tablenav()   @todo docs
744
 *
745
 * @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...
746
 */
747
function _wpsc_ajax_change_purchase_log_status() {
748
	$result = wpsc_purchlog_edit_status( $_POST['id'], $_POST['new_status'] );
749
	if ( ! $result )
750
		return new WP_Error( 'wpsc_cannot_edit_purchase_log_status', __( "Couldn't modify purchase log's status. Please try again.", 'wp-e-commerce' ) );
751
752
	$args = array();
753
754
	$args['screen'] = 'dashboard_page_wpsc-sales-logs';
755
756
	require_once( WPSC_FILE_PATH . '/wpsc-admin/includes/purchase-log-list-table-class.php' );
757
	$purchaselog_table = new WPSC_Purchase_Log_List_Table( $args );
758
	$purchaselog_table->prepare_items();
759
760
	ob_start();
761
	$purchaselog_table->views();
762
	$views = ob_get_clean();
763
764
	ob_start();
765
	$purchaselog_table->display_tablenav( 'top' );
766
	$tablenav_top = ob_get_clean();
767
768
	ob_start();
769
	$purchaselog_table->display_tablenav( 'bottom' );
770
	$tablenav_bottom = ob_get_clean();
771
772
	$return = array(
773
		'id'              => $_POST['id'],
774
		'new_status'      => $_POST['new_status'],
775
		'views'           => $views,
776
		'tablenav_top'    => $tablenav_top,
777
		'tablenav_bottom' => $tablenav_bottom,
778
	);
779
780
	return $return;
781
}
782
783
/**
784
 * Save product ordering after drag-and-drop sorting
785
 *
786
 * @since 3.8.9
787
 * @access private
788
 *
789
 * @uses $wpdb              WordPress database object for use in queries
790
 * @uses wp_update_post()   Updates post based on passed $args. Needs a post_id
791
 * @uses WP_Error           WordPress Error class
792
 *
793
 * @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...
794
 */
795
function _wpsc_ajax_save_product_order() {
796
797
	$products = array( );
0 ignored issues
show
introduced by
Empty array declaration must have no space between the parentheses
Loading history...
798
	foreach ( $_POST['post'] as $product ) {
799
		$products[] = (int) str_replace( 'post-', '', $product );
800
	}
801
802
	$failed = array();
803
	foreach ( $products as $order => $product_id ) {
804
		$result = wp_update_post( array(
805
			'ID' => $product_id,
806
			'menu_order' => $order,
807
		) );
808
809
		if ( ! $result )
810
			$failed[] = $product_id;
811
	}
812
813
	// Validate data before exposing to action
814
	$category = isset( $_POST['category_id'] ) ? get_term_by( 'slug', $_POST['category_id'], 'wpsc_product_category' ) : false;
815
	do_action( 'wpsc_save_product_order', $products, $category );
816
817
	if ( ! empty( $failed ) ) {
818
		$error_data = array(
819
			'failed_ids' => $failed,
820
		);
821
822
		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 );
823
	}
824
825
	return array(
826
		'ids' => $products,
827
	);
828
}
829
830
/**
831
 * Save Category Product Order
832
 *
833
 * Note that this uses the 'term_order' field in the 'term_relationships' table to store
834
 * the order. Although this column presently seems to be unused by WordPress, the intention
835
 * is it should be used to store the order of terms associates to a post, not the order
836
 * of posts as we are doing. This shouldn't be an issue for WPEC unless WordPress adds a UI
837
 * for this. More info at http://core.trac.wordpress.org/ticket/9547
838
 *
839
 * @since 3.9
840
 * @access private
841
 *
842
 * @uses $wpdb   WordPress database object used for queries
843
 */
844
function _wpsc_save_category_product_order( $products, $category ) {
845
	global $wpdb;
846
847
	// Only save category product order if in category
848
	if ( ! $category )
849
		return;
850
851
	// Save product order in term_relationships table
852
	foreach ( $products as $order => $product_id ) {
853
		$wpdb->update( $wpdb->term_relationships,
854
			array( 'term_order' => $order ),
855
			array( 'object_id' => $product_id, 'term_taxonomy_id' => $category->term_taxonomy_id ),
856
			array( '%d' ),
857
			array( '%d', '%d' )
858
		);
859
	}
860
}
861
add_action( 'wpsc_save_product_order', '_wpsc_save_category_product_order', 10, 2 );
862
863
/**
864
 * Update Checkout fields order
865
 *
866
 * @since 3.8.9
867
 * @access private
868
 *
869
 * @uses $wpdb      WordPress database object used for queries
870
 * @uses WP_Error   WordPress error class
871
 *
872
 * @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...
873
 */
874
function _wpsc_ajax_update_checkout_fields_order() {
875
	global $wpdb;
876
877
	$checkout_fields = $_REQUEST['sort_order'];
878
	$order = 1;
879
	$failed = array();
880
	$modified = array();
881
	foreach ( $checkout_fields as &$checkout_field ) {
882
		// ignore new fields
883
		if ( strpos( $checkout_field, 'new-field' ) === 0 )
884
			continue;
885
		$checkout_field = absint( preg_replace('/[^0-9]+/', '', $checkout_field ) );
886
		$result = $wpdb->update(
887
			WPSC_TABLE_CHECKOUT_FORMS,
888
			array(
889
				'checkout_order' => $order
890
			),
891
			array(
892
				'id' => $checkout_field
893
			),
894
			'%d',
895
			'%d'
896
		);
897
		$order ++;
898
		if ( $result === false )
899
			$failed[] = $checkout_field;
900
		elseif ( $result > 0 )
901
			$modified[] = $checkout_field;
902
	}
903
904
	if ( ! empty( $failed ) )
905
		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 ) );
906
907
	return array(
908
		'modified' => $modified,
909
	);
910
}
911
912
/**
913
 * Save a downloadable file to a product
914
 *
915
 * @since 3.8.9
916
 * @access private
917
 *
918
 * @uses $wpdb                          WordPress database object for use in queries
919
 * @uses _wpsc_create_ajax_nonce()      Creates nonce for an ajax action
920
 * @uses wpsc_get_mimetype()            Returns mimetype of file
921
 * @uses wp_insert_post()               Inserts post to WordPress database
922
 * @uses wp_nonce_url()                 Retrieve URL with nonce added to URL query.
923
 * @uses wpsc_convert_bytes()           Formats bytes
924
 * @uses wpsc_get_extension()           Gets extension of file
925
 * @uses esc_attr()                     Escapes HTML attributes
926
 * @uses _x()                           Retrieve translated string with gettext context
927
 *
928
 * @return array|WP_Error Response args if successful, WP_Error if otherwise.
929
 */
930
function _wpsc_ajax_upload_product_file() {
931
	global $wpdb;
932
	$product_id = absint( $_POST["product_id"] );
933
	$output = '';
934
	$delete_nonce = _wpsc_create_ajax_nonce( 'delete_file' );
935
936
	foreach ( $_POST["select_product_file"] as $selected_file ) {
937
		// if we already use this file, there is no point doing anything more.
938
		$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()
939
		$file_post_data = $wpdb->get_row( $sql, ARRAY_A );
940
		$selected_file_path = WPSC_FILE_DIR . basename( $selected_file );
941
		$file_url = WPSC_FILE_URL . basename( $selected_file );
942
		$file_size = filesize( $selected_file_path );
943
		if ( empty( $file_post_data ) ) {
944
			$type = wpsc_get_mimetype( $selected_file_path );
945
			$attachment = array(
946
				'post_mime_type' => $type,
947
				'post_parent' => $product_id,
948
				'post_title' => $selected_file,
949
				'post_content' => '',
950
				'post_type' => "wpsc-product-file",
951
				'post_status' => 'inherit'
952
			);
953
			$id = wp_insert_post( $attachment );
954
		} else {
955
			// already attached
956
			if ( $file_post_data['post_parent'] == $product_id )
957
				continue;
958
			$type = $file_post_data["post_mime_type"];
959
			$url = $file_post_data["guid"];
960
			$title = $file_post_data["post_title"];
961
			$content = $file_post_data["post_content"];
962
			// Construct the attachment
963
			$attachment = array(
964
				'post_mime_type' => $type,
965
				'guid' => $url,
966
				'post_parent' => absint( $product_id ),
967
				'post_title' => $title,
968
				'post_content' => $content,
969
				'post_type' => "wpsc-product-file",
970
				'post_status' => 'inherit'
971
			);
972
			// Save the data
973
			$id = wp_insert_post( $attachment );
974
		}
975
976
		$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'] );
977
978
		$output .= '<tr class="wpsc_product_download_row">';
979
		$output .= '<td style="padding-right: 30px;">' . $attachment['post_title'] . '</td>';
980
		$output .= '<td>' . wpsc_convert_byte( $file_size ) . '</td>';
981
		$output .= '<td>.' . wpsc_get_extension( $attachment['post_title'] ) . '</td>';
982
		$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>";
983
		$output .= '<td><a href=' .$file_url .'>' . _x( 'Download', 'Digital Download UI row', 'wp-e-commerce' ) . '</a></td>';
984
		$output .= '</tr>';
985
	}
986
987
	return array(
988
		'content' => $output,
989
	);
990
}
991
992
/**
993
 * Generate variations
994
 *
995
 * @since 3.8.9
996
 * @access private
997
 *
998
 * @uses wpsc_update_variations()       Updates product variations given
999
 * @uses wpsc_admin_product_listing()   DEPRECATED
1000
 *
1001
 * @return array|WP_Error Response args if successful, WP_Error if otherwise
1002
 */
1003
function _wpsc_ajax_update_variations() {
1004
	$product_id = absint( $_REQUEST["product_id"] );
1005
	wpsc_update_variations();
1006
1007
	ob_start();
1008
	wpsc_admin_product_listing( $product_id );
1009
	$content = ob_get_clean();
1010
1011
	return array( 'content' => $content );
1012
}
1013
1014
/**
1015
 * Display the shortcode generator.
1016
 *
1017
 * @since  3.8.9
1018
 * @access private
1019
 */
1020
function _wpsc_action_tinymce_window() {
1021
	require_once( WPSC_CORE_JS_PATH . '/tinymce3/window.php' );
1022
	exit;
1023
}
1024
add_action( 'wp_ajax_wpsc_tinymce_window', '_wpsc_action_tinymce_window' );
1025
1026
/**
1027
 * Add tax rate
1028
 * @since  3.8.9
1029
 * @access private
1030
 *
1031
 * @uses wpec_taxes_controller                                                  Contains all the logic to communicate with the taxes system
1032
 * @uses wpec_taxes_controller::wpec_taxes::wpec_taxes_get_regions()            Gets tax regions based on input country code
1033
 * @uses wpec_taxes_controller::wpec_taxes_build_select_options()               Returns HTML formatted options from input array
1034
 * @uses wpec_taxes_controller::wpec_taxes_build_form()                         Builds the tax rate form
1035
 * @uses wpec_taxes_controller::wpec_taxes::wpec_taxes_get_band_from_index()    Retrieves tax band for given name
1036
 *
1037
 * @return array|WP_Error Response args if successful, WP_Error if otherwise
1038
 */
1039
function _wpsc_ajax_add_tax_rate() {
1040
	//include taxes controller
1041
	$wpec_taxes_controller = new wpec_taxes_controller;
1042
1043
	switch ( $_REQUEST['wpec_taxes_action'] ) {
1044
		case 'wpec_taxes_get_regions':
1045
			$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...
1046
			$key = $_REQUEST['current_key'];
1047
			$type = $_REQUEST['taxes_type'];
1048
			$default_option = array( 'region_code' => 'all-markets', 'name' => 'All Markets' );
1049
			$select_settings = array(
1050
				'id' => "{$type}-region-{$key}",
1051
				'name' => "wpsc_options[wpec_taxes_{$type}][{$key}][region_code]",
1052
				'class' => 'wpsc-taxes-region-drop-down'
1053
			);
1054
			$returnable = $wpec_taxes_controller->wpec_taxes_build_select_options( $regions, 'region_code', 'name', $default_option, $select_settings );
1055
			break;
1056
	}// switch
1057
1058
	return array(
1059
		'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...
1060
	);
1061
}
1062
1063
/**
1064
 * Displays the WPSC product variations table
1065
 *
1066
 * @uses check_admin_referrer()                     Makes sure user was referred from another admin page
1067
 * @uses WPSC_Product_Variations_Page               The WPSC Product variations class
1068
 * @uses WPSC_Product_Variations_Page::display()    Displays the product variations page
1069
 */
1070
function wpsc_product_variations_table() {
1071
	check_admin_referer( 'wpsc_product_variations_table' );
1072
	set_current_screen( 'wpsc-product' );
1073
	require_once( WPSC_FILE_PATH . '/wpsc-admin/includes/product-variations-page.class.php' );
1074
	$page = new WPSC_Product_Variations_Page();
1075
	$page->display();
1076
1077
	exit;
1078
}
1079
add_action( 'wp_ajax_wpsc_product_variations_table', 'wpsc_product_variations_table' );
1080
1081
/**
1082
 * @access private
1083
 *
1084
 * @uses current_user_can()             Checks user capabilities given string
1085
 * @uses delete_post_thumbnail()        Deletes post thumbnail given thumbnail id
1086
 * @uses set_post_thumbnail()           Sets post thumbnail given post_id and thumbnail_id
1087
 * @uses wpsc_the_product_thumbnail()   Returns URL to the product thumbnail
1088
 *
1089
 * @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...
1090
 */
1091
function _wpsc_ajax_set_variation_product_thumbnail() {
1092
	$response = array(
1093
		'success' => false
1094
	);
1095
1096
	$post_ID = intval( $_POST['post_id'] );
1097
	if ( current_user_can( 'edit_post', $post_ID ) ) {
1098
		$thumbnail_id = intval( $_POST['thumbnail_id'] );
1099
1100
		if ( $thumbnail_id == '-1' )
1101
			delete_post_thumbnail( $post_ID );
1102
1103
		set_post_thumbnail( $post_ID, $thumbnail_id );
1104
1105
		$thumbnail = wpsc_the_product_thumbnail( 50, 50, $post_ID, '' );
1106
		if ( ! $thumbnail )
1107
			$thumbnail = WPSC_CORE_IMAGES_URL . '/no-image-uploaded.gif';
1108
		$response['src'] = $thumbnail;
1109
		$response['success'] = true;
1110
	}
1111
1112
	echo json_encode( $response );
1113
	exit;
1114
}
1115
add_action( 'wp_ajax_wpsc_set_variation_product_thumbnail', '_wpsc_ajax_set_variation_product_thumbnail' );
1116
1117
/**
1118
 * Delete WPSC product image from gallery
1119
 *
1120
 * @uses check_ajax_referer()		Verifies the AJAX request to prevent processing external requests
1121
 * @uses get_post_meta()		Returns meta from the specified post
1122
 * @uses update_post_meta()		Updates meta from the specified post
1123
 */
1124
function product_gallery_image_delete_action() {
1125
1126
	$product_gallery = array();
1127
	$gallery_image_id = $gallery_post_id = '';
1128
1129
	$gallery_image_id = absint($_POST['product_gallery_image_id']);
1130
	$gallery_post_id = absint($_POST['product_gallery_post_id']);
1131
1132
	check_ajax_referer( 'wpsc_gallery_nonce', 'wpsc_gallery_nonce_check' );
1133
1134
	$product_gallery = get_post_meta( $gallery_post_id, '_wpsc_product_gallery', true );
1135
1136
	foreach ( $product_gallery as $index => $image_id ) {
1137
		if ( $image_id == $gallery_image_id ) {
1138
			unset( $product_gallery[$index] );
1139
		}
1140
	}
1141
1142
	update_post_meta( $gallery_post_id, '_wpsc_product_gallery', $product_gallery );
1143
}
1144
add_action( 'wp_ajax_product_gallery_image_delete', 'product_gallery_image_delete_action' );
1145