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

ajax.php ➔ _wpsc_init_log_items()   B

Complexity

Conditions 5
Paths 6

Size

Total Lines 29
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

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