Completed
Push — master ( 2bf967...a643ba )
by Justin
30:16 queued 22:16
created

WPSC_Product_Variations_Page   D

Complexity

Total Complexity 80

Size/Duplication

Total Lines 402
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 402
rs 4.8717
wmc 80
lcom 1
cbo 1

19 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 19 3
B merge_meta_deep() 0 19 6
D save_variation_meta() 0 58 13
B save_variations_meta() 0 18 5
B display() 0 29 2
A display_tabs() 0 15 3
A callback_tab_manage() 0 6 1
A callback_tab_setup() 0 6 1
A generate_variations() 0 15 3
A display_current_tab() 0 3 1
A process_bulk_action_delete_all() 0 7 2
A process_bulk_action_trash() 0 14 4
A process_bulk_action_untrash() 0 14 4
B process_bulk_action_delete() 0 20 6
A process_bulk_action_hide() 0 11 2
A process_bulk_action_show() 0 11 2
C save_bulk_edited_items() 0 68 13
A process_bulk_action_edit() 0 3 1
C process_bulk_action() 0 40 8

How to fix   Complexity   

Complex Class

Complex classes like WPSC_Product_Variations_Page often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use WPSC_Product_Variations_Page, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/**
4
 * The Product Variations page class in the WordPress admin
5
 *
6
 * @package wp-e-commerce
7
 */
8
9
class WPSC_Product_Variations_Page {
10
	private $list_table;
11
	private $parent_id;
12
	private $current_tab;
13
	private $post;
0 ignored issues
show
Unused Code introduced by
The property $post is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
14
15
	public function __construct() {
16
		require_once( WPSC_FILE_PATH . '/wpsc-admin/includes/product-variation-list-table.class.php' );
17
		$GLOBALS['hook_suffix'] = 'wpsc-product-variations-iframe';
0 ignored issues
show
introduced by
Overridding WordPress globals is prohibited
Loading history...
18
		$this->parent_id = absint( $_REQUEST['product_id'] );
19
		set_current_screen();
20
21
		if ( ! empty( $_REQUEST['tab'] ) ) {
22
			$this->current_tab = $_REQUEST['tab'];
23
		} else {
24
			$args = array(
25
				'post_parent' => $this->parent_id,
26
				'post_type'   => 'wpsc-product',
27
				'post_status' => 'any');
28
29
			$number_of_variations = count(get_children($args));
30
31
			$this->current_tab = ($number_of_variations > 0) ? 'manage' : 'setup';
32
		}
33
	}
34
35
	private function merge_meta_deep( $original, $updated ) {
36
		$keys = array_merge( array_keys( $original ), array_keys( $updated ) );
37
38
		foreach ( $keys as $key ) {
39
			if ( ! isset( $updated[$key] ) )
40
				continue;
41
42
			if ( isset( $original[$key] ) && is_array( $original[$key] ) ) {
43
				$original[$key] = $this->merge_meta_deep( $original[$key]	, $updated[$key] );
44
			} else {
45
				$original[$key] = $updated[$key];
46
				if ( in_array( $key, array( 'weight', 'wpec_taxes_taxable_amount', 'height', 'width', 'length' ) ) )
47
					$original[$key] = (float) $original[$key];
48
			}
0 ignored issues
show
introduced by
Blank line found after control structure
Loading history...
49
50
		}
51
52
		return $original;
53
	}
54
55
	/*   */
56
	private function save_variation_meta( $id, $data ) {
57
58
		$product_meta = get_product_meta( $id, 'product_metadata', true );
59
60
		if ( ! is_array( $product_meta ) ) {
61
			$product_meta = array();
62
		}
63
64
		$product_meta = $this->merge_meta_deep( $product_meta, $data['product_metadata'] );
65
66
		// convert to pound to maintain backward compat with shipping modules
67
		if ( isset( $data['product_metadata']['weight'] ) || isset( $data['product_metadata']['weight_unit'] ) ) {
68
			$product_meta['weight'] = wpsc_convert_weight( $product_meta['weight'], $product_meta['weight_unit'], 'pound', true );
69
		}
70
71
		update_product_meta( $id, 'product_metadata', $product_meta );
72
73
		if ( isset( $data['price'] ) ) {
74
			update_product_meta( $id, 'price', wpsc_string_to_float( $data['price'] ) );
75
		}
76
77
		if ( isset( $data['sale_price'] ) ) {
78
79
			$sale_price = wpsc_string_to_float( $data['sale_price'] );
80
81
			if ( is_numeric( $sale_price ) ) {
82
				update_product_meta( $id, 'special_price', wpsc_string_to_float( $data['sale_price'] ) );
83
			} else {
84
				update_product_meta( $id, 'special_price', '' );
85
			}
86
		}
87
88
		if ( isset( $data['sku'] ) ) {
89
			update_product_meta( $id, 'sku', sanitize_text_field( $data['sku'] ) );
90
		}
91
92
		if ( isset( $data['stock'] ) ) {
93
			if ( is_numeric( $data['stock'] ) ) {
94
				update_product_meta( $id, 'stock', (int) $data['stock'] );
95
				$parent_id = wpsc_product_is_variation( $id );
96
97
				if( $parent_id ) {
98
					// If product is a variatio get the notification threshold from parent product
99
					$parent_meta = get_product_meta( $parent_id, 'product_metadata', true );
100
					$notify_limit = $parent_meta['stock_limit_notify'];
101
					if ( (int) $data['stock'] > $notify_limit ) {
102
						// Check if notification has been sent
103
						$notify_sent = get_product_meta( $id, 'stock_limit_notify_sent', true );
104
						if( ! empty( $notify_sent ) ) {
105
							delete_product_meta( $id, 'stock_limit_notify_sent' );
106
						}
107
					}
108
				}
109
			} else {
110
				update_product_meta( $id, 'stock', '' );
111
			}
112
		}
113
	}
114
115
	private function save_variations_meta(){
116
		if ( empty( $_REQUEST['wpsc_variations'] ) )
117
			return;
118
119
		check_admin_referer( 'wpsc_save_variations_meta', '_wpsc_save_meta_nonce' );
120
		$post_type_object = get_post_type_object( 'wpsc-product' );
121
		if ( ! current_user_can( $post_type_object->cap->edit_posts ) )
122
			wp_die( __( 'Cheatin&#8217; uh?', 'wp-e-commerce' ) );
123
124
		/* Long-term, we should have a better saving routine here.  Can't unset these currently. *
125
		/* That said, the only thing that fails hard if we can't unset it is the checkbox. */
126
		foreach ( $_REQUEST['wpsc_variations'] as $id => $data ) {
127
			if ( ! isset( $data['product_metadata']['no_shipping'] ) ) {
128
				$data['product_metadata']['no_shipping'] = '';
129
			}
130
			$this->save_variation_meta( $id, $data );
131
		}
132
	}
133
134
	public function display() {
135
		global $title, $hook_suffix, $wp_locale, $pagenow, $wp_version, $is_iphone,
136
		$current_site, $update_title, $total_update_count, $parent_file;
137
138
		$current_screen = get_current_screen();
139
		$admin_body_class = $hook_suffix;
140
		$post_type_object = get_post_type_object( 'wpsc-product' );
141
142
		wp_enqueue_style( 'global' );
143
		wp_enqueue_style( 'wp-admin' );
144
		wp_enqueue_style( 'buttons' );
145
		wp_enqueue_style( 'colors' );
146
		wp_enqueue_style( 'ie'     );
147
		wp_enqueue_script( 'common'       );
148
		wp_enqueue_script( 'jquery-color' );
149
		wp_enqueue_script( 'utils'        );
150
		wp_enqueue_script( 'jquery-query' );
151
		wp_enqueue_media( array( 'post' => absint( $_REQUEST['product_id'] ) ) );
152
0 ignored issues
show
Coding Style introduced by
Functions must not contain multiple empty lines in a row; found 2 empty lines
Loading history...
153
154
		$callback = "callback_tab_{$this->current_tab}";
155
		if ( ! is_callable( array( $this, "callback_tab_{$this->current_tab}" ) ) )
156
			$callback = "callback_tab_manage";
157
158
		$this->$callback();
159
160
		@header('Content-Type: ' . get_option('html_type') . '; charset=' . get_option('blog_charset'));
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
Coding Style introduced by
Silencing errors is discouraged
Loading history...
161
		require_once( WPSC_FILE_PATH . "/wpsc-admin/includes/product-variations.page.php" );
162
	}
163
164
	private function display_tabs() {
165
		$tabs = array(
166
			'manage'   => _x( 'Manage', 'manage product variations', 'wp-e-commerce' ),
167
			'setup' => __( 'Setup', 'wp-e-commerce' ),
168
		);
169
170
		echo '<ul id="wpsc-product-variations-tabs" class="category-tabs">';
171
		foreach ( $tabs as $tab => $title ) {
172
			$class = ( $tab == $this->current_tab ) ? ' class="tabs"' : '';
173
			$item = '<li' . $class . '>';
174
			$item .= '<a href="' . esc_url( add_query_arg( 'tab', $tab ) ) . '">' . esc_html( $title ) . '</a></li> ';
175
			echo $item;
176
		}
177
		echo '</ul>';
178
	}
179
180
	private function callback_tab_manage() {
181
		$this->list_table = new WPSC_Product_Variation_List_Table( $this->parent_id );
182
		$this->save_variations_meta();
183
		$this->process_bulk_action();
184
		$this->list_table->prepare_items();
185
	}
186
187
	private function callback_tab_setup() {
188
		global $post;
189
		require_once( 'walker-variation-checklist.php' );
190
191
		$this->generate_variations();
192
	}
193
194
	private function generate_variations() {
195
		if ( ! isset( $_REQUEST['action2'] ) || $_REQUEST['action2'] != 'generate' )
196
			return;
197
198
		check_admin_referer( 'wpsc_generate_product_variations', '_wpsc_generate_product_variations_nonce' );
199
200
		wpsc_update_variations();
201
202
		$sendback = remove_query_arg( array(
203
			'_wp_http_referer',
204
			'updated',
205
		) );
206
		wp_redirect( esc_url_raw( add_query_arg( 'tab', 'manage', $sendback ) ) );
207
		exit;
208
	}
209
210
	public function display_current_tab() {
211
		require_once( WPSC_FILE_PATH . "/wpsc-admin/includes/product-variations-{$this->current_tab}.page.php" );
212
	}
213
214
	public function process_bulk_action_delete_all( $post_ids ) {
215
		$post_status = preg_replace( '/[^a-z0-9_-]+/i', '', $_REQUEST['post_status'] );
216
		if ( get_post_status_object( $post_status ) ) // Check the post status exists first
217
			$post_ids = $wpdb->get_col( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_type='wpsc-product' AND post_status = %s", $post_type, $post_status ) );
0 ignored issues
show
Bug introduced by
The variable $wpdb does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
Bug introduced by
The variable $post_type does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
218
219
		return $this->process_bulk_action_delete( $post_ids );
220
	}
221
222
	public function process_bulk_action_trash( $post_ids ) {
223
		$post_type_object = get_post_type_object( 'wpsc-product' );
224
		$trashed = 0;
225
		foreach( (array) $post_ids as $post_id ) {
226
			if ( !current_user_can( $post_type_object->cap->delete_post, $post_id ) )
227
				wp_die( __( 'You are not allowed to move this item to the Trash.', 'wp-e-commerce' ) );
228
229
			if ( !wp_trash_post( $post_id ) )
230
				wp_die( __( 'Error in moving to Trash.', 'wp-e-commerce' ) );
231
232
			$trashed++;
233
		}
234
		return esc_url( add_query_arg( array( 'trashed' => $trashed, 'ids' => join( ',', $post_ids ) ) ) );
235
	}
236
237
	public function process_bulk_action_untrash( $post_ids ) {
238
		$post_type_object = get_post_type_object( 'wpsc-product' );
239
		$untrashed = 0;
240
		foreach( (array) $post_ids as $post_id ) {
241
			if ( ! current_user_can( $post_type_object->cap->delete_post, $post_id ) )
242
				wp_die( __( 'You are not allowed to restore this item from the Trash.', 'wp-e-commerce' ) );
243
244
			if ( !wp_untrash_post( $post_id ) )
245
				wp_die( __( 'Error in restoring from Trash.', 'wp-e-commerce' ) );
246
247
			$untrashed++;
248
		}
249
		return esc_url( add_query_arg( 'untrashed', $untrashed ) );
250
	}
251
252
	public function process_bulk_action_delete( $post_ids ) {
253
		$deleted = 0;
254
		$post_type_object = get_post_type_object( 'wpsc-product' );
255
		foreach( (array) $post_ids as $post_id ) {
256
			$post_del = & get_post( $post_id );
257
258
			if ( ! current_user_can( $post_type_object->cap->delete_post, $post_id ) )
259
				wp_die( __( 'You are not allowed to delete this item.', 'wp-e-commerce' ) );
260
261
			if ( $post_del->post_type == 'attachment' ) {
262
				if ( ! wp_delete_attachment( $post_id ) )
263
					wp_die( __( 'Error in deleting...', 'wp-e-commerce' ) );
264
			} else {
265
				if ( ! wp_delete_post( $post_id ) )
266
					wp_die( __( 'Error in deleting...', 'wp-e-commerce' ) );
267
			}
268
			$deleted++;
269
		}
270
		return esc_url( add_query_arg( 'deleted', $deleted ) );
271
	}
272
273
	public function process_bulk_action_hide( $post_ids ) {
274
		$updated = 0;
275
		foreach( $post_ids as $id ) {
276
			wp_update_post( array(
277
				'ID'          => $id,
278
				'post_status' => 'draft',
279
			) );
280
			$updated ++;
281
		}
282
		return esc_url( add_query_arg( 'updated', $updated ) );
283
	}
284
285
	public function process_bulk_action_show( $post_ids ) {
286
		$updated = 0;
287
		foreach ( $post_ids as $id ) {
288
			wp_update_post( array(
289
				'ID' => $id,
290
				'post_status' => 'publish',
291
			) );
292
			$updated ++;
293
		}
294
		return esc_url( add_query_arg( 'updated', $updated ) );
295
	}
296
297
	private function save_bulk_edited_items() {
298
		$ids = array_map( 'absint', $_REQUEST['wpsc_bulk_edit']['post'] );
299
		$data = $_REQUEST['wpsc_bulk_edit'];
300
301
		if ( empty( $_REQUEST['wpsc_bulk_edit']['fields'] ) )
302
			return;
303
304
		$fields = $_REQUEST['wpsc_bulk_edit']['fields'];
305
306
		foreach ( array( 'stock', 'price', 'sale_price', 'sku' ) as $field ) {
307
			if ( empty( $fields[$field] ) )
308
				unset( $data[$field] );
309
		}
310
311
		if ( empty( $fields['shipping'] ) )
312
			unset( $data['product_metadata']['shipping'] );
313
		else {
314
			foreach ( array( 'local', 'international' ) as $field ) {
315
				if ( empty( $fields['shipping'][$field] ) )
316
					unset( $data['product_metadata'][$field] );
317
			}
318
		}
319
320
		if ( empty( $fields['measurements'] ) ) {
321
			unset( $data['product_metadata']['dimensions'] );
322
			unset( $data['product_metadata']['weight'] );
323
			unset( $data['product_metadata']['weight_unit'] );
324
		} else {
325
			if ( empty( $fields['measurements']['weight'] ) ) {
326
				unset( $data['product_metadata']['weight'] );
327
				unset( $data['product_metadata']['weight_unit'] );
328
			}
329
330
			if ( empty( $fields['measurements']['dimensions'] ) ) {
331
				foreach ( array( 'height', 'width', 'length' ) as $field ) {
332
					unset( $data['product_metadata']['dimensions'][$field] );
333
					unset( $data['product_metadata']['dimensions'][$field . '_unit'] );
334
				}
335
			} else {
336
				foreach ( array( 'height', 'width', 'length' ) as $field ) {
337
					$data['product_metadata']['dimensions'][$field . '_unit'] = "cm";
338
				}
339
			}
340
341
			unset( $data['product_metadata']['dimensions_unit'] );
342
		}
343
344
		unset( $data['post'] );
345
		unset( $data['fields'] );
346
347
		foreach ( $ids as $id ) {
348
			$this->save_variation_meta( $id, $data );
349
		}
350
351
		$sendback = $_SERVER['REQUEST_URI'];
352
		$sendback = remove_query_arg( array(
353
			'_wp_http_referer',
354
			'bulk_action',
355
			'bulk_action2',
356
			'bulk_action_nonce',
357
			'confirm',
358
			'post',
359
			'last_paged'
360
		), $sendback );
361
		$sendback = add_query_arg( 'updated', count( $ids ), $sendback );
362
		wp_redirect( esc_url_raw( $sendback ) );
363
		exit;
364
	}
365
366
	public function process_bulk_action_edit( $post_ids ) {
367
		$this->list_table->set_bulk_edited_items( $post_ids );
368
	}
369
370
	public function process_bulk_action() {
371
		if ( ! empty( $_REQUEST['wpsc_bulk_edit']['post'] ) ) {
372
			$this->save_bulk_edited_items();
373
			return;
374
		}
375
376
		$current_action = $this->list_table->current_action();
377
		if ( empty( $current_action ) )
378
			return;
379
380
		_wpsc_remove_refresh_variation_parent_term_hooks();
381
382
		check_admin_referer( 'wpsc_product_variations_bulk_action', 'bulk_action_nonce' );
383
		$sendback = $_SERVER['REQUEST_URI'];
384
		$callback = 'process_bulk_action_' . $current_action;
385
386
		$post_ids = isset( $_REQUEST['post'] ) ? $_REQUEST['post'] : array();
387
		if ( ! is_array( $post_ids ) )
388
			$post_ids = explode( ',', $post_ids );
389
		$post_ids = array_map('intval', $post_ids);
390
		if ( ! empty( $post_ids ) && is_callable( array( $this, $callback ) ) )
391
			$sendback = $this->$callback( $post_ids );
392
393
		$sendback = remove_query_arg( array(
394
			'_wp_http_referer',
395
			'bulk_action',
396
			'bulk_action2',
397
			'bulk_action_nonce',
398
			'confirm',
399
			'post',
400
			'last_paged'
401
		), $sendback );
402
403
		_wpsc_refresh_parent_product_terms( $this->parent_id );
404
		_wpsc_add_refresh_variation_parent_term_hooks();
405
		if ( $current_action != 'edit' ) {
406
			wp_redirect( esc_url_raw( $sendback ) );
407
			exit;
408
		}
409
	}
410
}
411
412
/**
413
 * Wrapper for _wp_admin_html_begin(), which might not be available on older
414
 * WordPress versions.
415
 *
416
 * @access private
417
 * @since 3.8.9.4
418
 */
419
function _wpsc_admin_html_begin() {
420
	if ( function_exists( '_wp_admin_html_begin' ) ) {
421
		_wp_admin_html_begin();
422
		return;
423
	}
424
425
	$admin_html_class = ( is_admin_bar_showing() ) ? 'wp-toolbar' : '';
426
	?>
427
<!DOCTYPE html>
428
<!--[if IE 8]>
429
<html xmlns="http://www.w3.org/1999/xhtml" class="ie8 <?php echo $admin_html_class; ?>" <?php do_action('admin_xml_ns'); ?> <?php language_attributes(); ?>>
430
<![endif]-->
431
<!--[if !(IE 8) ]><!-->
432
<html xmlns="http://www.w3.org/1999/xhtml" class="<?php echo $admin_html_class; ?>" <?php do_action('admin_xml_ns'); ?> <?php language_attributes(); ?>>
433
<!--<![endif]-->
434
<head>
435
<meta http-equiv="Content-Type" content="<?php bloginfo('html_type'); ?>; charset=<?php echo get_option('blog_charset'); ?>" />
436
<?php
437
}
438