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() { |
|
|
|
|
82
|
|
|
if ( ! isset( $_POST[ $this->get_nonce_name() ] ) || ! wp_verify_nonce( $_POST[ $this->get_nonce_name() ], $this->get_nonce_name() ) ) { // Input var okay. |
|
|
|
|
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'] ) { |
|
|
|
|
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
|
|
|
|
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.