Completed
Push — master ( 6b2386...2bf093 )
by Ahmad
04:44
created

TitanFrameworkAdminPage   C

Complexity

Total Complexity 62

Size/Duplication

Total Lines 432
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 3
Metric Value
wmc 62
lcom 1
cbo 3
dl 0
loc 432
rs 5.9494

12 Methods

Rating   Name   Duplication   Size   Complexity  
C __construct() 0 47 9
A createAdminPanel() 0 4 1
B register() 0 24 2
A addTitanCredit() 0 3 1
A addTitanCreditText() 0 3 1
A getOptionNamespace() 0 3 1
D saveOptions() 0 118 18
B verifySecurity() 0 20 6
B getActiveTab() 0 23 6
F createAdminPage() 0 127 14
A createTab() 0 8 1
A createOption() 0 12 2

How to fix   Complexity   

Complex Class

Complex classes like TitanFrameworkAdminPage 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 TitanFrameworkAdminPage, and based on these observations, apply Extract Interface, too.

1
<?php
0 ignored issues
show
Coding Style Compatibility introduced by
For compatibility and reusability of your code, PSR1 recommends that a file should introduce either new symbols (like classes, functions, etc.) or have side-effects (like outputting something, or including other files), but not both at the same time. The first symbol is defined on line 5 and the first side effect is on line 3.

The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.

The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.

To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.

Loading history...
2
3
if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly
4
}
5
class TitanFrameworkAdminPage {
6
7
	private $defaultSettings = array(
8
		'name' => '', // Name of the menu item
9
		'title' => '', // Title displayed on the top of the admin panel
10
		'parent' => null, // id of parent, if blank, then this is a top level menu
11
		'id' => '', // Unique ID of the menu item
12
		'capability' => 'manage_options', // User role
13
		'icon' => 'dashicons-admin-generic', // Menu icon for top level menus only http://melchoyce.github.io/dashicons/
14
		'position' => null, // Menu position. Can be used for both top and sub level menus
15
		'use_form' => true, // If false, options will not be wrapped in a form
16
		'desc' => '', // Description displayed below the title
17
	);
18
19
	public $settings;
20
	public $options = array();
21
	public $tabs = array();
22
	public $owner;
23
24
	public $panelID;
25
26
	private $activeTab = null;
27
	private static $idsUsed = array();
28
29
	function __construct( $settings, $owner ) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
30
		$this->owner = $owner;
31
32
		if ( ! is_admin() ) {
33
			return;
34
		}
35
36
		$this->settings = array_merge( $this->defaultSettings, $settings );
37
		// $this->options = $options;
0 ignored issues
show
Unused Code Comprehensibility introduced by
45% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
38
		if ( empty( $this->settings['name'] ) ) {
39
			return;
40
		}
41
42
		if ( empty( $this->settings['title'] ) ) {
43
			$this->settings['title'] = $this->settings['name'];
44
		}
45
46
		if ( empty( $this->settings['id'] ) ) {
47
			$prefix = '';
48
			if ( ! empty( $this->settings['parent'] ) ) {
49
				$prefix = str_replace( ' ', '-', trim( strtolower( $this->settings['parent'] ) ) ) . '-';
50
			}
51
			$this->settings['id'] = $prefix . str_replace( ' ', '-', trim( strtolower( $this->settings['name'] ) ) );
52
			$this->settings['id'] = str_replace( '&', '-', $this->settings['id'] );
53
		}
54
55
		// make sure all our IDs are unique
56
		$suffix = '';
57
		while ( in_array( $this->settings['id'] . $suffix, self::$idsUsed ) ) {
58
			if ( $suffix == '' ) {
59
				$suffix = 2;
60
			} else {
61
				$suffix++;
62
			}
63
		}
64
		$this->settings['id'] .= $suffix;
65
66
		// keep track of all IDs used
67
		self::$idsUsed[] = $this->settings['id'];
68
69
		$priority = -1;
70
		if ( $this->settings['parent'] ) {
71
			$priority = intval( $this->settings['position'] );
72
		}
73
74
		add_action( 'admin_menu', array( $this, 'register' ), $priority );
75
	}
76
77
	public function createAdminPanel( $settings ) {
78
		$settings['parent'] = $this->settings['id'];
79
		return $this->owner->createAdminPanel( $settings );
80
	}
81
82
	public function register() {
83
		// Parent menu
84
		if ( empty( $this->settings['parent'] ) ) {
85
			$this->panelID = add_menu_page( $this->settings['name'],
86
				$this->settings['name'],
87
				$this->settings['capability'],
88
				$this->settings['id'],
89
				array( $this, 'createAdminPage' ),
90
				$this->settings['icon'],
91
			$this->settings['position'] );
92
			// Sub menu
93
		} else {
94
			$this->panelID = add_submenu_page( $this->settings['parent'],
95
				$this->settings['name'],
96
				$this->settings['name'],
97
				$this->settings['capability'],
98
				$this->settings['id'],
99
			array( $this, 'createAdminPage' ) );
100
		}
101
102
		add_action( 'load-' . $this->panelID, array( $this, 'saveOptions' ) );
103
104
		add_action( 'load-' . $this->panelID, array( $this, 'addTitanCredit' ) );
105
	}
106
107
108
	public function addTitanCredit() {
109
		add_filter( 'admin_footer_text', array( $this, 'addTitanCreditText' ) );
110
	}
111
112
113
	public function addTitanCreditText() {
114
		echo __( "<em>Options Page Created with <a href='http://titanframework.net?utm_source=admin&utm_medium=admin footer'>Titan Framework</a></em>", TF_I18NDOMAIN );
115
	}
116
117
118
	public function getOptionNamespace() {
119
		return $this->owner->optionNamespace;
120
	}
121
122
123
	public function saveOptions() {
124
		if ( ! $this->verifySecurity() ) {
125
			return;
126
		}
127
128
		$message = '';
129
		$activeTab = $this->getActiveTab();
130
131
		/*
132
		 *  Save
133
		 */
134
135
		if ( $_POST['action'] == 'save' ) {
136
137
			// we are in a tab
138
			if ( ! empty( $activeTab ) ) {
139
				foreach ( $activeTab->options as $option ) {
140
					if ( empty( $option->settings['id'] ) ) {
141
						continue;
142
					}
143
144
					if ( isset( $_POST[ $this->getOptionNamespace() . '_' . $option->settings['id'] ] ) ) {
145
						$value = $_POST[ $this->getOptionNamespace() . '_' . $option->settings['id'] ];
146
					} else {
147
						$value = '';
148
					}
149
150
					$option->setValue( $value );
151
				}
152
			}
153
154
			foreach ( $this->options as $option ) {
155
				if ( empty( $option->settings['id'] ) ) {
156
					continue;
157
				}
158
159
				if ( isset( $_POST[ $this->getOptionNamespace() . '_' . $option->settings['id'] ] ) ) {
160
					$value = $_POST[ $this->getOptionNamespace() . '_' . $option->settings['id'] ];
161
				} else {
162
					$value = '';
163
				}
164
165
				$option->setValue( $value );
166
			}
167
168
			// Hook 'tf_pre_save_options_{namespace}' - action pre-saving
169
			/**
170
			 * Fired right before options are saved.
171
			 *
172
			 * @since 1.0
173
			 *
174
			 * @param TitanFrameworkAdminPage|TitanFrameworkCustomizer|TitanFrameworkMetaBox $this The container currently being saved.
175
			 */
176
			$namespace = $this->getOptionNamespace();
177
			do_action( "tf_pre_save_options_{$namespace}", $this );
178
			do_action( "tf_pre_save_admin_{$namespace}", $this, $activeTab, $this->options );
179
180
			$this->owner->saveInternalAdminPageOptions();
181
182
			do_action( 'tf_save_admin_' . $this->getOptionNamespace(), $this, $activeTab, $this->options );
183
184
			$message = 'saved';
185
186
			/*
187
			* Reset
188
			*/
189
190
		} else if ( $_POST['action'] == 'reset' ) {
191
192
			// we are in a tab
193
			if ( ! empty( $activeTab ) ) {
194
				foreach ( $activeTab->options as $option ) {
195
					if ( empty( $option->settings['id'] ) ) {
196
						continue;
197
					}
198
199
					$option->setValue( $option->settings['default'] );
200
				}
201
			}
202
203
			foreach ( $this->options as $option ) {
204
				if ( empty( $option->settings['id'] ) ) {
205
					continue;
206
				}
207
208
				$option->setValue( $option->settings['default'] );
209
			}
210
211
			// Hook 'tf_pre_reset_options_{namespace}' - action pre-saving
212
			do_action( 'tf_pre_reset_options_' . $this->getOptionNamespace(), $this );
213
			do_action( 'tf_pre_reset_admin_' . $this->getOptionNamespace(), $this, $activeTab, $this->options );
214
215
			$this->owner->saveInternalAdminPageOptions();
216
217
			do_action( 'tf_reset_admin_' . $this->getOptionNamespace(), $this, $activeTab, $this->options );
218
219
			$message = 'reset';
220
		}
221
222
		/*
223
		 * Redirect to prevent refresh saving
224
		 */
225
226
		// urlencode to allow special characters in the url
227
		$url = wp_get_referer();
228
		$activeTab = $this->getActiveTab();
229
		$url = add_query_arg( 'page', urlencode( $this->settings['id'] ), $url );
230
		if ( ! empty( $activeTab ) ) {
231
			$url = add_query_arg( 'tab', urlencode( $activeTab->settings['id'] ), $url );
232
		}
233
		if ( ! empty( $message ) ) {
234
			$url = add_query_arg( 'message', $message, $url );
235
		}
236
237
		do_action( 'tf_admin_options_saved_' . $this->getOptionNamespace() );
238
239
		wp_redirect( esc_url_raw( $url ) );
240
	}
241
242
	private function verifySecurity() {
243
		if ( empty( $_POST ) || empty( $_POST['action'] ) ) {
244
			return false;
245
		}
246
247
		$screen = get_current_screen();
248
		if ( $screen->id != $this->panelID ) {
249
			return false;
250
		}
251
252
		if ( ! current_user_can( $this->settings['capability'] ) ) {
253
			return false;
254
		}
255
256
		if ( ! check_admin_referer( $this->settings['id'], TF . '_nonce' ) ) {
257
			return false;
258
		}
259
260
		return true;
261
	}
262
263
	public function getActiveTab() {
264
		if ( ! count( $this->tabs ) ) {
265
			return '';
266
		}
267
		if ( ! empty( $this->activeTab ) ) {
268
			return $this->activeTab;
269
		}
270
271
		if ( empty( $_GET['tab'] ) ) {
272
			$this->activeTab = $this->tabs[0];
273
			return $this->activeTab;
274
		}
275
276
		foreach ( $this->tabs as $tab ) {
277
			if ( $tab->settings['id'] == $_GET['tab'] ) {
278
				$this->activeTab = $tab;
279
				return $this->activeTab;
280
			}
281
		}
282
283
		$this->activeTab = $this->tabs[0];
284
		return $this->activeTab;
285
	}
286
287
	public function createAdminPage() {
288
		do_action( 'tf_admin_page_before' );
289
		do_action( 'tf_admin_page_before_' . $this->getOptionNamespace() );
290
291
		?>
292
		<div class="wrap">
293
		<h2><?php echo $this->settings['title'] ?></h2>
294
		<?php
295
		if ( ! empty( $this->settings['desc'] ) ) {
296
			?><p class='description'><?php echo $this->settings['desc'] ?></p><?php
297
		}
298
		?>
299
300
		<div class='titan-framework-panel-wrap'>
301
		<?php
302
303
		do_action( 'tf_admin_page_start' );
304
		do_action( 'tf_admin_page_start_' . $this->getOptionNamespace() );
305
306
		if ( count( $this->tabs ) ) :
307
			?>
308
			<h2 class="nav-tab-wrapper">
309
			<?php
310
311
			do_action( 'tf_admin_page_tab_start' );
312
			do_action( 'tf_admin_page_tab_start_' . $this->getOptionNamespace() );
313
314
			foreach ( $this->tabs as $tab ) {
315
				$tab->displayTab();
316
			}
317
318
			do_action( 'tf_admin_page_tab_end' );
319
			do_action( 'tf_admin_page_tab_end_' . $this->getOptionNamespace() );
320
321
			?>
322
			</h2>
323
			<?php
324
		endif;
325
326
		?>
327
		<div class='options-container'>
328
		<?php
329
330
		// Display notification if we did something
331
		if ( ! empty( $_GET['message'] ) ) {
332
			if ( $_GET['message'] == 'saved' ) {
333
				echo TitanFrameworkAdminNotification::formNotification( __( 'Settings saved.', TF_I18NDOMAIN ), esc_html( $_GET['message'] ) );
334
			} else if ( $_GET['message'] == 'reset' ) {
335
				echo TitanFrameworkAdminNotification::formNotification( __( 'Settings reset to default.', TF_I18NDOMAIN ), esc_html( $_GET['message'] ) );
336
			}
337
		}
338
339
		if ( $this->settings['use_form'] ) :
340
			?>
341
			<form method='post'>
342
			<?php
343
		endif;
344
345
		if ( $this->settings['use_form'] ) {
346
			// security
347
			wp_nonce_field( $this->settings['id'], TF . '_nonce' );
348
		}
349
350
		?>
351
		<table class='form-table'>
352
			<tbody>
353
		<?php
354
355
		do_action( 'tf_admin_page_table_start' );
356
		do_action( 'tf_admin_page_table_start_' . $this->getOptionNamespace() );
357
358
		$activeTab = $this->getActiveTab();
359
		if ( ! empty( $activeTab ) ) {
360
361
			if ( ! empty( $activeTab->settings['desc'] ) ) {
362
				?><p class='description'><?php echo $activeTab->settings['desc'] ?></p><?php
363
			}
364
365
			$activeTab->displayOptions();
366
		}
367
368
		foreach ( $this->options as $option ) {
369
			$option->display();
370
		}
371
372
		do_action( 'tf_admin_page_table_end' );
373
		do_action( 'tf_admin_page_table_end_' . $this->getOptionNamespace() );
374
375
		?>
376
			</tbody>
377
		</table>
378
		<?php
379
380
		if ( $this->settings['use_form'] ) :
381
			?>
382
			</form>
383
			<?php
384
		endif;
385
386
		// Reset form. We use JS to trigger a reset from other buttons within the main form
387
		// This is used by class-option-save.php
388
		if ( $this->settings['use_form'] ) :
389
			?>
390
			<form method='post' id='tf-reset-form'>
391
				<?php
392
				// security
393
				wp_nonce_field( $this->settings['id'], TF . '_nonce' );
394
				?>
395
				<input type='hidden' name='action' value='reset'/>
396
			</form>
397
			<?php
398
		endif;
399
400
		do_action( 'tf_admin_page_end' );
401
		do_action( 'tf_admin_page_end_' . $this->getOptionNamespace() );
402
403
		?>
404
		<div class='options-container'>
405
		</div>
406
		</div>
407
		</div>
408
		</div>
409
		<?php
410
411
		do_action( 'tf_admin_page_after' );
412
		do_action( 'tf_admin_page_after_' . $this->getOptionNamespace() );
413
	}
414
415
	public function createTab( $settings ) {
416
		$obj = new TitanFrameworkAdminTab( $settings, $this );
417
		$this->tabs[] = $obj;
418
419
		do_action( 'tf_admin_tab_created_' . $this->getOptionNamespace(), $obj );
420
421
		return $obj;
422
	}
423
424
	public function createOption( $settings ) {
425
		if ( ! apply_filters( 'tf_create_option_continue_' . $this->getOptionNamespace(), true, $settings ) ) {
426
			return null;
427
		}
428
429
		$obj = TitanFrameworkOption::factory( $settings, $this );
430
		$this->options[] = $obj;
431
432
		do_action( 'tf_create_option_' . $this->getOptionNamespace(), $obj );
433
434
		return $obj;
435
	}
436
}
437