PluginProbe ʕ •ᴥ•ʔ
Secure Custom Fields / trunk
Secure Custom Fields vtrunk
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 / post-types / class-acf-admin-ui-options-page.php
secure-custom-fields / includes / admin / post-types Last commit date
admin-field-group.php 2 months ago admin-field-groups.php 10 months ago admin-post-type.php 1 year ago admin-post-types.php 10 months ago admin-taxonomies.php 10 months ago admin-taxonomy.php 1 year ago class-acf-admin-ui-options-page.php 1 year ago class-acf-admin-ui-options-pages.php 10 months ago index.php 1 year ago
class-acf-admin-ui-options-page.php
490 lines
1 <?php
2 /**
3 * Admin Post Type Class
4 *
5 * @package ACF
6 */
7
8 if ( ! class_exists( 'ACF_Admin_UI_Options_Page' ) ) :
9
10 /**
11 * ACF Admin UI Options Page Class
12 *
13 * All the logic for editing an options page in the UI.
14 */
15 class ACF_Admin_UI_Options_Page extends ACF_Admin_Internal_Post_Type {
16
17 /**
18 * The slug for the internal post type.
19 *
20 * @since ACF 6.1
21 * @var string
22 */
23 public $post_type = 'acf-ui-options-page';
24
25 /**
26 * The admin body class used for the post type.
27 *
28 * @since ACF 6.1
29 * @var string
30 */
31 public $admin_body_class = 'acf-admin-single-options-page';
32
33 /**
34 * Constructs the class.
35 */
36 public function __construct() {
37 add_action( 'wp_ajax_acf/create_options_page', array( $this, 'ajax_create_options_page' ) );
38 add_action( 'acf/field_group/admin_enqueue_scripts', array( $this, 'add_js_parent_choices' ) );
39 parent::__construct();
40 }
41
42 /**
43 * Customizes the messages shown when editing a UI options page.
44 *
45 * @since ACF 6.2
46 *
47 * @param array $messages Post type messages.
48 * @return array
49 */
50 public function post_updated_messages( $messages ) {
51 $messages['acf-ui-options-page'] = array(
52 0 => '', // Unused. Messages start at index 1.
53 1 => $this->options_page_created_message(), // Updated.
54 2 => $this->options_page_created_message(),
55 3 => __( 'Options page deleted.', 'secure-custom-fields' ),
56 4 => __( 'Options page updated.', 'secure-custom-fields' ),
57 5 => false, // Post type does not support revisions.
58 6 => $this->options_page_created_message( true ), // Created.
59 7 => __( 'Options page saved.', 'secure-custom-fields' ),
60 8 => __( 'Options page submitted.', 'secure-custom-fields' ),
61 9 => __( 'Options page scheduled for.', 'secure-custom-fields' ),
62 10 => __( 'Options page draft updated.', 'secure-custom-fields' ),
63 );
64
65 return $messages;
66 }
67
68 /**
69 * Renders the options page created message.
70 *
71 * @since ACF 6.1
72 *
73 * @param boolean $created True if the options page was just created.
74 * @return string
75 */
76 public function options_page_created_message( $created = false ) {
77 global $post_id;
78
79 $title = get_the_title( $post_id );
80
81 /* translators: %s options page name */
82 $item_saved_text = sprintf( __( '%s options page updated', 'secure-custom-fields' ), $title );
83 /* translators: %s options page name */
84 $add_fields_text = sprintf( __( 'Add fields to %s', 'secure-custom-fields' ), $title );
85
86 if ( $created ) {
87 /* translators: %s options page name */
88 $item_saved_text = sprintf( __( '%s options page created', 'secure-custom-fields' ), $title );
89 }
90
91 $add_fields_link = wp_nonce_url(
92 admin_url( 'post-new.php?post_type=acf-field-group&use_options_page=' . $post_id ),
93 'add-fields-' . $post_id
94 );
95
96 ob_start();
97 ?>
98 <p class="acf-item-saved-text"><?php echo esc_html( $item_saved_text ); ?></p>
99 <div class="acf-item-saved-links">
100 <a href="<?php echo esc_url( $add_fields_link ); ?>"><?php echo esc_html( $add_fields_text ); ?></a>
101 <a class="acf-link-field-groups" href="#"><?php esc_html_e( 'Link existing field groups', 'secure-custom-fields' ); ?></a>
102 </div>
103 <?php
104 return ob_get_clean();
105 }
106
107 /**
108 * Allow other pages to get available option page parents.
109 *
110 * @since ACF 6.2
111 */
112 public function add_js_parent_choices() {
113 acf_localize_data(
114 array(
115 'optionPageParentOptions' => $this->get_parent_page_choices(),
116 )
117 );
118 }
119
120 /**
121 * Enqueues any scripts necessary for internal post type.
122 *
123 * @since ACF 6.2
124 */
125 public function admin_enqueue_scripts() {
126 wp_enqueue_style( 'acf-field-group' );
127
128 acf_localize_text(
129 array(
130 'Post' => __( 'Post', 'secure-custom-fields' ),
131 'Posts' => __( 'Posts', 'secure-custom-fields' ),
132 'Page' => __( 'Page', 'secure-custom-fields' ),
133 'Pages' => __( 'Pages', 'secure-custom-fields' ),
134 'Default' => __( 'Default', 'secure-custom-fields' ),
135 )
136 );
137
138 parent::admin_enqueue_scripts();
139
140 do_action( 'acf/ui_options_page/admin_enqueue_scripts' );
141 }
142
143 /**
144 * Sets up all functionality for the post type edit page to work.
145 *
146 * @since ACF 3.1.8
147 */
148 public function admin_head() {
149 // global.
150 global $post, $acf_ui_options_page;
151
152 // set global var.
153 $acf_ui_options_page = acf_get_internal_post_type( $post->ID, $this->post_type );
154
155 // metaboxes.
156 add_meta_box( 'acf-basic-settings', __( 'Basic Settings', 'secure-custom-fields' ), array( $this, 'mb_basic_settings' ), 'acf-ui-options-page', 'normal', 'high' );
157 add_meta_box( 'acf-advanced-settings', __( 'Advanced Settings', 'secure-custom-fields' ), array( $this, 'mb_advanced_settings' ), 'acf-ui-options-page', 'normal', 'high' );
158
159 // actions.
160 add_action( 'post_submitbox_misc_actions', array( $this, 'post_submitbox_misc_actions' ), 10, 0 );
161 add_action( 'edit_form_after_title', array( $this, 'edit_form_after_title' ), 10, 0 );
162
163 // filters.
164 add_filter( 'screen_settings', array( $this, 'screen_settings' ), 10, 1 );
165 add_filter( 'get_user_option_screen_layout_acf-ui-options-page', array( $this, 'screen_layout' ), 10, 1 );
166 add_filter( 'get_user_option_metaboxhidden_acf-ui-options-page', array( $this, 'force_basic_settings' ), 10, 1 );
167 add_filter( 'get_user_option_closedpostboxes_acf-ui-options-page', array( $this, 'force_basic_settings' ), 10, 1 );
168 add_filter( 'get_user_option_closedpostboxes_acf-ui-options-page', array( $this, 'force_advanced_settings' ), 10, 1 );
169
170 // 3rd party hook.
171 do_action( 'acf/ui_options_page/admin_head' );
172 }
173
174 /**
175 * This action will allow ACF to render metaboxes after the title.
176 */
177 public function edit_form_after_title() {
178
179 // globals.
180 global $post;
181
182 // render post data.
183 acf_form_data(
184 array(
185 'screen' => 'ui_options_page',
186 'post_id' => $post->ID,
187 'delete_fields' => 0,
188 'validation' => 1,
189 )
190 );
191 }
192
193 /**
194 * This function will add extra HTML to the acf form data element
195 *
196 * @since ACF 5.3.8
197 *
198 * @param array $args Arguments array to pass through to action.
199 * @return void
200 */
201 public function form_data( $args ) {
202 do_action( 'acf/ui_options_page/form_data', $args );
203 }
204
205 /**
206 * This function will append extra l10n strings to the acf JS object
207 *
208 * @since ACF 5.3.8
209 *
210 * @param array $l10n The array of translated strings.
211 * @return array $l10n
212 */
213 public function admin_l10n( $l10n ) {
214 return apply_filters( 'acf/ui_options_page/admin_l10n', $l10n );
215 }
216
217 /**
218 * Admin footer third party hook support
219 *
220 * @since ACF 5.3.2
221 */
222 public function admin_footer() {
223 do_action( 'acf/ui_options_page/admin_footer' );
224 }
225
226 /**
227 * Screen settings html output
228 *
229 * @since ACF 3.6.0
230 *
231 * @param string $html Current screen settings HTML.
232 * @return string $html
233 */
234 public function screen_settings( $html ) {
235 return $html;
236 }
237
238 /**
239 * Sets the "Edit Post Type" screen to use a one-column layout.
240 *
241 * @param integer $columns Number of columns for layout.
242 * @return integer
243 */
244 public function screen_layout( $columns = 0 ) {
245 return 1;
246 }
247
248 /**
249 * Force basic settings to always be visible
250 *
251 * @param array $hidden_metaboxes The metaboxes hidden on this page.
252 * @return array
253 */
254 public function force_basic_settings( $hidden_metaboxes ) {
255 if ( ! is_array( $hidden_metaboxes ) ) {
256 return $hidden_metaboxes;
257 }
258 return array_diff( $hidden_metaboxes, array( 'acf-basic-settings' ) );
259 }
260
261 /**
262 * Force advanced settings to be visible
263 *
264 * @param array $hidden_metaboxes The metaboxes hidden on this page.
265 * @return array
266 */
267 public function force_advanced_settings( $hidden_metaboxes ) {
268 if ( ! is_array( $hidden_metaboxes ) ) {
269 return $hidden_metaboxes;
270 }
271 return array_diff( $hidden_metaboxes, array( 'acf-advanced-settings' ) );
272 }
273
274 /**
275 * This function will customize the publish metabox
276 *
277 * @since ACF 5.2.9
278 */
279 public function post_submitbox_misc_actions() {
280 global $acf_ui_options_page;
281
282 $status_label = $acf_ui_options_page['active'] ? _x( 'Active', 'post status', 'secure-custom-fields' ) : _x( 'Inactive', 'post status', 'secure-custom-fields' );
283 ?>
284 <script type="text/javascript">
285 (function($) {
286 $('#post-status-display').html( '<?php echo esc_html( $status_label ); ?>' );
287 })(jQuery);
288 </script>
289 <?php
290 }
291
292 /**
293 * Saves post type data.
294 *
295 * @since ACF 1.0.0
296 *
297 * @param integer $post_id The post ID.
298 * @param WP_Post $post The post object.
299 * @return integer $post_id
300 */
301 public function save_post( $post_id, $post ) {
302 if ( ! $this->verify_save_post( $post_id, $post ) ) {
303 return $post_id;
304 }
305
306 // Disable filters to ensure ACF loads raw data from DB.
307 acf_disable_filters();
308
309 // phpcs:disable WordPress.Security.NonceVerification.Missing -- Validated in $this->verify_save_post() above.
310 // phpcs:disable WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Sanitized when saved.
311 // phpcs:disable WordPress.Security.ValidatedSanitizedInput.MissingUnslash -- Unslashed as part of the update_post() method.
312 $_POST['acf_ui_options_page']['ID'] = $post_id;
313 $_POST['acf_ui_options_page']['title'] = isset( $_POST['acf_ui_options_page']['page_title'] ) ? $_POST['acf_ui_options_page']['page_title'] : '';
314
315 // Save the post type.
316 acf_update_internal_post_type( $_POST['acf_ui_options_page'], $this->post_type ); // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Validated in verify_save_post
317 // phpcs:enable WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
318 // phpcs:enable WordPress.Security.NonceVerification.Missing
319 // phpcs:enable WordPress.Security.ValidatedSanitizedInput.MissingUnslash
320 return $post_id;
321 }
322
323 /**
324 * Renders HTML for the basic settings metabox.
325 *
326 * @since ACF 6.2
327 */
328 public function mb_basic_settings() {
329 global $acf_ui_options_page, $acf_parent_page_options;
330
331 if ( ! acf_is_internal_post_type_key( $acf_ui_options_page['key'], 'acf-ui-options-page' ) ) {
332 $acf_ui_options_page['key'] = uniqid( 'ui_options_page_' );
333 }
334
335 $acf_parent_page_options = $this->get_parent_page_choices( (int) $acf_ui_options_page['ID'] );
336
337 acf_get_view( __DIR__ . '/../views/acf-ui-options-page/basic-settings.php' );
338 }
339
340
341 /**
342 * Renders the HTML for the advanced settings metabox.
343 *
344 * @since ACF 6.2
345 */
346 public function mb_advanced_settings() {
347 acf_get_view( __DIR__ . '/../views/acf-ui-options-page/advanced-settings.php' );
348 }
349
350 /**
351 * Iterates through the registered options pages and finds eligible parent pages.
352 *
353 * @since ACF 6.2
354 *
355 * @param integer $post_id The post ID of a current ACF UI options page used to prevent selection of itself as a child.
356 * @return array
357 */
358 public function get_parent_page_choices( int $post_id = 0 ) {
359 global $menu;
360 $acf_all_options_pages = acf_get_options_pages();
361 $acf_parent_page_choices = array( 'None' => array( 'none' => __( 'No Parent', 'secure-custom-fields' ) ) );
362 $self_slug = false;
363
364 if ( is_array( $acf_all_options_pages ) ) {
365 foreach ( $acf_all_options_pages as $options_page ) {
366 // Can't assign to child pages.
367 if ( ! empty( $options_page['parent_slug'] ) ) {
368 continue;
369 }
370
371 // Can't be a child of itself.
372 if ( isset( $options_page['ID'] ) && $post_id === $options_page['ID'] ) {
373 $self_slug = $options_page['menu_slug'];
374 continue;
375 }
376
377 $acf_parent_menu_slug = ! empty( $options_page['menu_slug'] ) ? $options_page['menu_slug'] : '';
378
379 // ACF overrides the `menu_slug` of parent pages with one child so they redirect to the child.
380 if ( ! empty( $options_page['_menu_slug'] ) ) {
381 $acf_parent_menu_slug = $options_page['_menu_slug'];
382 }
383
384 $acf_parent_page_choices['acfOptionsPages'][ $acf_parent_menu_slug ] = ! empty( $options_page['page_title'] ) ? $options_page['page_title'] : $options_page['menu_slug'];
385 }
386 }
387
388 foreach ( $menu as $item ) {
389 if ( ! empty( $item[0] ) ) {
390 $page_name = $item[0];
391 $markup = '/<[^>]+>.*<\/[^>]+>/';
392 $sanitized_name = preg_replace( $markup, '', $page_name );
393
394 // Prevent options pages being parents of themselves.
395 if ( ! empty( $item[2] ) && $item[2] === $self_slug ) {
396 continue;
397 }
398
399 // If the current item is not an ACF-created options page, add it to the "Others" list.
400 if ( empty( $acf_parent_page_choices['acfOptionsPages'][ $item[2] ] ) ) {
401 $acf_parent_page_choices['Others'][ $item[2] ] = acf_esc_html( $sanitized_name );
402 }
403 }
404 }
405 return $acf_parent_page_choices;
406 }
407
408 /**
409 * Creates a simple options page over AJAX.
410 *
411 * @since ACF 6.2
412 * @return void
413 */
414 public function ajax_create_options_page() {
415 // Disable filters to ensure ACF loads raw data from DB.
416 acf_disable_filters();
417
418 // phpcs:disable WordPress.Security.NonceVerification.Missing
419 $args = acf_parse_args(
420 $_POST,
421 array(
422 'nonce' => '',
423 'post_id' => 0,
424 'acf_ui_options_page' => array(),
425 'field_group_title' => '',
426 'acf_parent_page_choices' => array(),
427 )
428 );
429 // phpcs:enable WordPress.Security.NonceVerification.Missing
430
431 // Verify nonce and user capability.
432 if ( ! wp_verify_nonce( $args['nonce'], 'acf_nonce' ) || ! acf_current_user_can_admin() || ! $args['post_id'] ) {
433 die();
434 }
435
436 // Process form data.
437 if ( ! empty( $args['acf_ui_options_page'] ) ) {
438 // Prepare for save.
439 $options_page = acf_validate_internal_post_type( $args['acf_ui_options_page'], 'acf-ui-options-page' );
440 $options_page['key'] = uniqid( 'ui_options_page_' );
441 $options_page['title'] = ! empty( $args['acf_ui_options_page']['page_title'] ) ? $args['acf_ui_options_page']['page_title'] : '';
442 $existing_options_pages = acf_get_options_pages();
443
444 // Check for duplicates.
445 if ( ! empty( $existing_options_pages ) ) {
446 foreach ( $existing_options_pages as $existing_options_page ) {
447 if ( $existing_options_page['menu_slug'] === $options_page['menu_slug'] ) {
448 wp_send_json_error(
449 array(
450 'error' => __( 'The provided Menu Slug already exists.', 'secure-custom-fields' ),
451 )
452 );
453 }
454 }
455 }
456
457 // Save the options page.
458 acf_update_internal_post_type( $options_page, 'acf-ui-options-page' );
459
460 wp_send_json_success(
461 array(
462 'page_title' => esc_html( $options_page['page_title'] ),
463 'menu_slug' => esc_attr( $options_page['menu_slug'] ),
464 )
465 );
466 }
467
468 // Render the form.
469 ob_start();
470 acf_get_view(
471 __DIR__ . '/../views/acf-ui-options-page/create-options-page-modal.php',
472 array(
473 'field_group_title' => $args['field_group_title'],
474 'acf_parent_page_choices' => $args['acf_parent_page_choices'],
475 )
476 );
477 $content = ob_get_clean();
478
479 wp_send_json_success(
480 array(
481 'content' => $content,
482 'title' => esc_html__( 'Add New Options Page', 'secure-custom-fields' ),
483 )
484 );
485 }
486 }
487
488 new ACF_Admin_UI_Options_Page();
489 endif; // Class exists check.
490