PluginProbe ʕ •ᴥ•ʔ
Secure Custom Fields / 6.9.5
Secure Custom Fields v6.9.5
6.9.5 6.9.4 6.9.3 6.9.2 6.9.1 6.9.0 6.8.9 6.8.7 6.8.8 6.8.6 6.8.4 6.8.5 trunk 6.4.0-beta1 6.4.0-beta2 6.4.1 6.4.1-beta3 6.4.1-beta4 6.4.1-beta5 6.4.1-beta6 6.4.1-beta7 6.4.2 6.5.0 6.5.1 6.5.2 6.5.3 6.5.4 6.5.5 6.5.6 6.5.7 6.6.0 6.7.0 6.7.1 6.8.0 6.8.1 6.8.2 6.8.3
secure-custom-fields / includes / admin / class-acf-admin-options-page.php
secure-custom-fields / includes / admin Last commit date
beta-features 8 months ago post-types 3 months ago tools 8 months ago views 1 month ago admin-commands.php 3 months ago admin-internal-post-type-list.php 11 months ago admin-internal-post-type.php 1 year ago admin-notices.php 1 year ago admin-tools.php 11 months ago admin-upgrade.php 1 year ago admin.php 2 weeks ago beta-features.php 8 months ago class-acf-admin-options-page.php 1 week ago index.php 1 year ago
class-acf-admin-options-page.php
388 lines
1 <?php
2 /**
3 * Admin Options Page Class
4 *
5 * Handles the admin interface for options pages.
6 *
7 * @package wordpress/secure-custom-fields
8 */
9
10 // phpcs:disable PEAR.NamingConventions.ValidClassName
11 if ( ! defined( 'ABSPATH' ) ) {
12 exit; // Exit if accessed directly
13 }
14
15 if ( ! class_exists( 'acf_admin_options_page' ) ) :
16
17 /**
18 * Class for managing options pages in the WordPress admin.
19 */
20 class acf_admin_options_page {
21
22
23 /**
24 * Current options page data.
25 *
26 * @var array Contains the current options page
27 */
28 public $page;
29
30
31 /**
32 * Initialize filters, action, variables and includes
33 *
34 * @since ACF 5.0.0
35 */
36 public function __construct() {
37 // add menu items
38 add_action( 'admin_menu', array( $this, 'admin_menu' ), 99, 0 );
39 }
40
41
42 /**
43 * Adds menu items for registered options pages.
44 *
45 * @since ACF 5.0.0
46 */
47 public function admin_menu() {
48
49 // vars
50 $pages = acf_get_options_pages();
51
52 // bail early if no pages
53 if ( empty( $pages ) ) {
54 return;
55 }
56
57 // loop
58 foreach ( $pages as $page ) {
59
60 // vars
61 $slug = '';
62 // parent
63 if ( empty( $page['parent_slug'] ) ) {
64 $slug = add_menu_page( $page['page_title'], $page['menu_title'], $page['capability'], $page['menu_slug'], array( $this, 'html' ), $page['icon_url'], $page['position'] );
65 // child
66 } else {
67 $slug = add_submenu_page( $page['parent_slug'], $page['page_title'], $page['menu_title'], $page['capability'], $page['menu_slug'], array( $this, 'html' ), $page['position'] );
68 }
69
70 // actions
71 add_action( "load-{$slug}", array( $this, 'admin_load' ) );
72 }
73 }
74
75
76 /**
77 * Handles the load action for the options page.
78 *
79 * Enqueues scripts, validates saves, and sets up the options page.
80 *
81 * @since ACF 3.6.0
82 */
83 public function admin_load() {
84
85 // globals
86 global $plugin_page;
87
88 // vars
89 $this->page = acf_get_options_page( $plugin_page );
90
91 // get post_id (allow lang modification)
92 $this->page['post_id'] = acf_get_valid_post_id( $this->page['post_id'] );
93
94 // verify and remove nonce
95 if ( acf_verify_nonce( 'options' ) ) {
96
97 // Restrict submitted values to fields assigned to the current options page.
98 // phpcs:disable WordPress.Security.NonceVerification.Missing -- Verified above.
99 if ( isset( $_POST['acf'] ) && is_array( $_POST['acf'] ) ) {
100 $_POST['acf'] = $this->filter_options_page_field_values( $_POST['acf'] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.ValidatedSanitizedInput.MissingUnslash -- Sanitized downstream; save pipeline expects slashed input.
101 }
102 // phpcs:enable WordPress.Security.NonceVerification.Missing
103
104 // save data
105 if ( acf_validate_save_post( true ) ) {
106
107 // set autoload
108 acf_update_setting( 'autoload', $this->page['autoload'] );
109
110 // save
111 acf_save_post( $this->page['post_id'] );
112
113 /**
114 * Fires after publishing a save on an options page.
115 *
116 * @since ACF 6.1.7
117 *
118 * @param string|int $post_id The current id.
119 * @param string $menu_slug The current options page menu slug.
120 */
121 do_action( 'acf/options_page/save', $this->page['post_id'], $this->page['menu_slug'] );
122
123 // redirect
124 wp_safe_redirect( add_query_arg( array( 'message' => '1' ) ) );
125 exit;
126 }
127 }
128
129 // load acf scripts
130 acf_enqueue_scripts();
131
132 // Localize options page slug for repeater pagination capability checks.
133 acf_localize_data( array( 'options_page_slug' => $this->page['menu_slug'] ) );
134
135 // actions
136 add_action( 'acf/input/admin_enqueue_scripts', array( $this, 'admin_enqueue_scripts' ) );
137 add_action( 'acf/input/admin_head', array( $this, 'admin_head' ) );
138
139 // add columns support
140 add_screen_option(
141 'layout_columns',
142 array(
143 'max' => 2,
144 'default' => 2,
145 )
146 );
147 }
148
149
150 /**
151 * This function will enqueue the 'post.js' script which adds support for 'Screen Options' column toggle
152 *
153 * @since ACF 5.3.2
154 */
155 public function admin_enqueue_scripts() {
156
157 wp_enqueue_script( 'post' );
158 }
159
160 /**
161 * Returns the field groups assigned to the current options page.
162 *
163 * @since SCF 6.9.3
164 *
165 * @return array
166 */
167 protected function get_options_page_field_groups() {
168 return acf_get_field_groups(
169 array(
170 'options_page' => $this->page['menu_slug'],
171 )
172 );
173 }
174
175 /**
176 * Returns the top-level submitted field keys accepted by the current options page.
177 *
178 * Seamless clone subfields are submitted below the clone field's key, which is
179 * extracted from their input prefix.
180 *
181 * @since SCF 6.9.3
182 *
183 * @return array
184 */
185 protected function get_options_page_allowed_field_keys() {
186 $keys = array();
187
188 foreach ( $this->get_options_page_field_groups() as $field_group ) {
189 $fields = acf_get_fields( $field_group );
190
191 if ( ! $fields ) {
192 continue;
193 }
194
195 foreach ( $fields as $field ) {
196 $prefix = $field['prefix'] ?? 'acf';
197
198 if ( 'acf' === $prefix ) {
199 if ( ! empty( $field['key'] ) ) {
200 $keys[] = $field['key'];
201 }
202 } elseif ( is_string( $prefix ) && preg_match( '/^acf\[([^]]+)]$/', $prefix, $matches ) ) {
203 $keys[] = $matches[1];
204 }
205 }
206 }
207
208 return array_values( array_unique( array_filter( $keys ) ) );
209 }
210
211 /**
212 * Filters submitted ACF values to the roots accepted by the current options page.
213 *
214 * @since SCF 6.9.3
215 *
216 * @param array $values Submitted ACF values.
217 * @return array
218 */
219 protected function filter_options_page_field_values( array $values ): array {
220 return array_intersect_key( $values, array_flip( $this->get_options_page_allowed_field_keys() ) );
221 }
222
223
224 /**
225 * This action will find and add field groups to the current edit page
226 *
227 * @type action (admin_head)
228 * @since ACF 3.1.8
229 */
230 public function admin_head() {
231
232 // get field groups
233 $field_groups = $this->get_options_page_field_groups();
234
235 // notices
236 if ( ! empty( $_GET['message'] ) && '1' === $_GET['message'] ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Used to display a notice.
237 acf_add_admin_notice( $this->page['updated_message'], 'success' );
238 }
239
240 // add submit div
241 add_meta_box( 'submitdiv', __( 'Publish', 'secure-custom-fields' ), array( $this, 'postbox_submitdiv' ), 'acf_options_page', 'side', 'high' );
242
243 if ( empty( $field_groups ) ) {
244 /* translators: %s: URL to create a new field group */
245 acf_add_admin_notice( sprintf( __( 'No Custom Field Groups found for this options page. <a href="%s">Create a Custom Field Group</a>', 'secure-custom-fields' ), admin_url( 'post-new.php?post_type=acf-field-group' ) ), 'warning' );
246 } else {
247 foreach ( $field_groups as $i => $field_group ) {
248
249 // vars
250 $id = "acf-{$field_group['key']}";
251 $context = $field_group['position'];
252 $priority = 'high';
253 $args = array( 'field_group' => $field_group );
254
255 // tweaks to vars
256 if ( 'acf_after_title' === $context ) {
257 $context = 'normal';
258 } elseif ( 'side' === $context ) {
259 $priority = 'core';
260 }
261
262 // filter for 3rd party customization
263 $priority = apply_filters( 'acf/input/meta_box_priority', $priority, $field_group );
264
265 // add meta box
266 add_meta_box(
267 $id,
268 acf_esc_html( acf_get_field_group_title( $field_group ) ),
269 array( $this, 'postbox_acf' ),
270 'acf_options_page',
271 $context,
272 $priority,
273 $args
274 );
275 }
276 // foreach
277 }
278 // if
279 }
280
281
282 /**
283 * This function will render the submitdiv metabox
284 *
285 * @since ACF 5.3.2
286 */
287 public function postbox_submitdiv() {
288
289 /**
290 * Fires before the major-publishing-actions div.
291 *
292 * @date 24/9/18
293 * @since ACF 5.7.7
294 *
295 * @param array $page The current options page.
296 */
297 do_action( 'acf/options_page/submitbox_before_major_actions', $this->page );
298 ?>
299 <div id="major-publishing-actions">
300
301 <div id="publishing-action">
302 <span class="spinner"></span>
303 <input type="submit" accesskey="p" value="<?php echo esc_attr( $this->page['update_button'] ); ?>" class="button button-primary button-large" id="publish" name="publish">
304 </div>
305
306 <?php
307 /**
308 * Fires before the major-publishing-actions div.
309 *
310 * @date 24/9/18
311 * @since ACF 5.7.7
312 *
313 * @param array $page The current options page.
314 */
315 do_action( 'acf/options_page/submitbox_major_actions', $this->page );
316 ?>
317 <div class="clear"></div>
318
319 </div>
320 <?php
321 }
322
323
324 /**
325 * Renders a postbox on an ACF options page.
326 *
327 * @since ACF 5.0.0
328 *
329 * @param object $post The post object.
330 * @param array $args The metabox arguments.
331 */
332 public function postbox_acf( $post, $args ) {
333 $id = $args['id'];
334 $field_group = $args['args']['field_group'];
335
336 // vars
337 $o = array(
338 'id' => $id,
339 'key' => $field_group['key'],
340 'style' => $field_group['style'],
341 'label' => $field_group['label_placement'],
342 'editLink' => '',
343 'editTitle' => __( 'Edit field group', 'secure-custom-fields' ),
344 'visibility' => true,
345 );
346
347 // edit_url
348 if ( $field_group['ID'] && acf_current_user_can_admin() ) {
349 $o['editLink'] = admin_url( 'post.php?post=' . $field_group['ID'] . '&action=edit' );
350 }
351
352 // load fields
353 $fields = acf_get_fields( $field_group );
354
355 // render
356 acf_render_fields( $fields, $this->page['post_id'], 'div', $field_group['instruction_placement'] );
357
358 ?>
359 <script type="text/javascript">
360 if (typeof acf !== 'undefined') {
361
362 acf.newPostbox(<?php echo wp_json_encode( $o ); ?>);
363
364 }
365 </script>
366 <?php
367 }
368
369
370 /**
371 * Renders the options page HTML content.
372 *
373 * @since ACF 2.0.4
374 */
375 public function html() {
376
377 // load view
378 acf_get_view( __DIR__ . '/views/html-options-page.php', $this->page );
379 }
380 }
381
382
383 // initialize
384 new acf_admin_options_page();
385 endif;
386
387 ?>
388