Completed
Push — master ( e590c5...014b04 )
by Marin
03:27
created

Theme_Options_Container::add_fields()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 3
Bugs 1 Features 0
Metric Value
c 3
b 1
f 0
dl 0
loc 9
rs 9.6666
ccs 0
cts 6
cp 0
cc 2
eloc 5
nc 2
nop 1
crap 6
1
<?php 
2
3
namespace Carbon_Fields\Container;
4
5
use Carbon_Fields\Datastore\Theme_Options_Datastore;
6
use Carbon_Fields\Exception\Incorrect_Syntax_Exception;
7
8
/**
9
 * Theme options container class. 
10
 */
11
class Theme_Options_Container extends Container {
12
	static protected $registered_pages = array();
13
14
	public $settings = array(
15
		'parent' => 'self',
16
		'file' => '',
17
		'permissions' => 'manage_options',
18
	);
19
20
	public $icon = '';
21
	
22
	/**
23
	 * Create a new theme options fields container
24
	 *
25
	 * @param string $title Unique title of the container
26
	 **/
27 1
	public function __construct( $title ) {
28 1
		parent::__construct( $title );
29
30 1
		if ( ! $this->get_datastore() ) {
31 1
			$this->set_datastore( new Theme_Options_Datastore() );
32 1
		}
33 1
	}
34
35
	/**
36
	 * Perform save operation after successful is_valid_save() check.
37
	 * The call is propagated to all fields in the container.
38
	 *
39
	 * @param mixed $user_data
40
	 **/
41
	public function save( $user_data = null ) {
42
		try {
43
			parent::save( $user_data );
44
		} catch ( Incorrect_Syntax_Exception $e ) {
45
			$this->errors[] = $e->getMessage();
46
		}
47
48
		do_action( 'carbon_after_save_theme_options', $user_data );
49
50
		if ( ! headers_sent() ) {
51
			wp_redirect( add_query_arg( array( 'settings-updated' => 'true' ) ) );
52
		}
53
	}
54
55
	/**
56
	 * Attach container as a theme options page/subpage.
57
	 **/
58
	public function init() {
59
		if ( ! $this->settings['parent'] || $this->settings['parent'] == 'self' ) {
60
			$this->settings['parent'] = '';
61
		} else if ( strpos( $this->settings['parent'], '.php' ) === false ) {
62
			$clear_title = $this->clear_string( $this->settings['parent'] );
63
			$this->settings['parent'] = 'crbn-' . $clear_title . '.php';
64
		}
65
66
		if ( ! $this->settings['file'] ) {
67
			$clear_title = $this->clear_string( $this->title );
68
			$this->settings['file'] .= 'crbn-' . $clear_title . '.php';
69
		}
70
71
		$this->verify_unique_page();
72
73
		add_action( 'admin_menu', array( $this, '_attach' ) );
74
	}
75
76
	/**
77
	 * Perform checks whether the current save() request is valid.
78
	 * 
79
	 * @return bool
80
	 **/
81 View Code Duplication
	public function is_valid_save() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
82
		if ( ! isset( $_POST[ $this->get_nonce_name() ] ) || ! wp_verify_nonce( $_POST[ $this->get_nonce_name() ], $this->get_nonce_name() ) ) { // Input var okay.
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
83
			return false;
84
		}
85
86
		return true;
87
	}
88
89
	/**
90
	 * Add theme options container pages.
91
	 * Hook the container saving action.
92
	 **/
93
	public function attach() {
94
95
		// Add menu page
96
		if ( ! $this->settings['parent'] ) {
97
			add_menu_page(
98
				$this->title, 
99
				$this->title, 
100
				$this->settings['permissions'], 
101
				$this->settings['file'],
102
				array( $this, 'render' ),
103
				$this->icon
104
			);
105
		}
106
107
		add_submenu_page(
108
			$this->settings['parent'],
109
			$this->title, 
110
			$this->title, 
111
			$this->settings['permissions'], 
112
			$this->settings['file'],
113
			array( $this, 'render' ),
114
			$this->icon
115
		);
116
117
		$page_hook = get_plugin_page_hookname( $this->settings['file'], '' );
118
		add_action( 'load-' . $page_hook, array( $this, '_save' ) );
119
	}
120
121
	/**
122
	 * Whether this container is currently viewed.
123
	 **/
124
	public function is_active() {
125
		if ( isset( $_GET['page'] ) && $_GET['page'] === $this->settings['file'] ) {
0 ignored issues
show
introduced by
Detected access of super global var $_GET, probably need manual inspection.
Loading history...
introduced by
Detected usage of a non-sanitized input variable: $_GET
Loading history...
126
			return true;
127
		}
128
129
		return false;
130
	}
131
132
	/**
133
	 * Revert the result of attach()
134
	 **/
135
	public function detach() {
136
		parent::detach();
137
138
		$this->drop_unique_page();
139
140
		$page_hook = get_plugin_page_hookname( $this->settings['file'], '' );
141
		remove_action( 'load-' . $page_hook, array( $this, '_save' ) );
142
	}
143
144
	/**
145
	 * Output the container markup
146
	 **/
147
	public function render() {
148
		if ( isset( $_GET['settings-updated'] ) && $_GET['settings-updated'] == 'true' ) {
149
			$this->notifications[] = __( 'Settings saved.', 'carbon_fields' );
150
		}
151
152
		include \Carbon_Fields\DIR . '/templates/Container/theme_options.php';
153
	}
154
155
	/**
156
	 * Make sure that there are no duplicate containers with the same name.
157
	 **/
158
	public function verify_unique_page() {
159
		$file = $this->settings['file'];
160
		$parent = $this->settings['parent'];
161
162
		// Register top level page
163
		if ( ! $parent ) {
164
			if ( isset( self::$registered_pages[ $file ] ) ) {
165
				Incorrect_Syntax_Exception::raise( 'Page "' . $file . '" already registered' );
166
			}
167
168
			self::$registered_pages[ $file ] = array();
169
			return;
170
		}
171
172
		// Register sub-page
173
		if ( ! isset( self::$registered_pages[ $parent ] ) ) {
174
			self::$registered_pages[ $parent ] = array( $file );
175
		}  elseif ( in_array( $file, self::$registered_pages[ $parent ] ) ) {
176
			Incorrect_Syntax_Exception::raise( 'Page "' . $file . '" with parent "' . $parent . '" is already registered. Please set a different file name using setup()' );
177
		} else {
178
			self::$registered_pages[ $parent ][] = $file;
179
		}
180
	}
181
182
	/**
183
	 * Unregister the container parent and child pages.
184
	 **/
185
	public function drop_unique_page() {
186
		$file = $this->settings['file'];
187
		$parent = $this->settings['parent'];
188
189
		// Register top level page
190
		if ( ! $parent ) {
191
			if ( isset( self::$registered_pages[ $file ] ) && empty( self::$registered_pages[ $file ] ) ) {
192
				unset( self::$registered_pages[ $file ] );
193
			}
194
195
			return;
196
		}
197
198
		// Register sub-page
199
		if ( isset( self::$registered_pages[ $parent ] ) && in_array( $file, self::$registered_pages[ $parent ] ) ) {
200
201
			$index = array_search( $file, self::$registered_pages[ $parent ] );
202
			if ( $index !== false ) {
203
				unset( self::$registered_pages[ $parent ][ $index ] );
204
			}
205
		}
206
	}
207
208
	/**
209
	 * Make sure a field certain name can't be registered multiple times.
210
	 **/
211
	public function verify_unique_field_name( $name ) {
212
		$page_id = $this->settings['parent'] . '/' . $this->settings['file'];
213
214
		if ( ! isset( self::$registered_field_names[ $page_id ] ) ) {
215
			self::$registered_field_names[ $page_id ] = array();
216
		}
217
218
		if ( in_array( $name, self::$registered_field_names[ $page_id ] ) ) {
219
			Incorrect_Syntax_Exception::raise( 'Field name "' . $name . '" already registered' );
220
		}
221
222
		self::$registered_field_names[ $page_id ][] = $name;
223
	}
224
225
	/**
226
	 * Remove field name $name from the list of unique field names
227
	 *
228
	 * @param string $name
229
	 **/
230
	public function drop_unique_field_name( $name ) {
231
		$page_id = $this->settings['parent'] . '/' . $this->settings['file'];
232
233
		$index = array_search( $name, self::$registered_field_names[ $page_id ] );
234
		if ( $index !== false ) {
235
			unset( self::$registered_field_names[ $page_id ][ $index ] );
236
		}
237
	}
238
239
	/**
240
	 * Append array of fields to the current fields set. All items of the array
241
	 * must be instances of Field and their names should be unique for all
242
	 * Carbon containers.
243
	 * If a field does not have DataStore already, the container data store is 
244
	 * assigned to them instead.
245
	 *
246
	 * @param array $fields
247
	 **/
248
	public function add_fields( $fields ) {
249
		parent::add_fields( $fields );
250
251
		foreach ( $this->fields as $field ) {
252
			$field->set_prefix( '' );
253
		}
254
255
		return $this;
256
	}
257
258
	/**
259
	 * Change the parent theme options page of this container
260
	 **/
261
	public function set_page_parent( $parent ) {
262
		if ( is_a( $parent, 'Carbon_Container' ) ) {
263
			$parent = $parent->title;
264
		}
265
		
266
		$this->settings['parent'] = $parent;
267
		return $this;
268
	}
269
270
	/**
271
	 * Set the icon of this theme options page.
272
	 * Applicable only for parent theme option pages.
273
	 **/
274
	public function set_icon( $icon ) {
275
		$this->icon = $icon;
276
		return $this;
277
	}
278
279
	/**
280
	 * Set the theme options file name of this container.
281
	 **/
282
	public function set_page_file( $file ) {
283
		$this->settings['file'] = $file;
284
		return $this;
285
	}
286
287
	/**
288
	 * Set the permissions necessary to view 
289
	 * the corresponding theme options page
290
	 **/
291
	public function set_page_permissions( $permissions ) {
292
		$this->settings['permissions'] = $permissions;
293
		return $this;
294
	}
295
296
	/**
297
	 * Sanitize the container title for use in 
298
	 * the theme options file name.
299
	 **/
300
	protected function clear_string( $string ) {
301
		return preg_replace( array( '~ +~', '~[^\w\d-]+~u', '~-+~' ), array( '-', '-', '-' ), strtolower( remove_accents( $string ) ) );
302
	}
303
304
}
305
306