PluginProbe ʕ •ᴥ•ʔ
Secure Custom Fields / 6.4.0-beta2
Secure Custom Fields v6.4.0-beta2
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 / class-acf-site-health.php
secure-custom-fields / includes Last commit date
Blocks 1 year ago admin 1 year ago ajax 1 year ago api 1 year ago fields 1 year ago forms 1 year ago legacy 1 year ago locations 1 year ago post-types 1 year ago rest-api 1 year ago walkers 1 year ago acf-bidirectional-functions.php 1 year ago acf-field-functions.php 1 year ago acf-field-group-functions.php 1 year ago acf-form-functions.php 1 year ago acf-helper-functions.php 1 year ago acf-hook-functions.php 1 year ago acf-input-functions.php 1 year ago acf-internal-post-type-functions.php 1 year ago acf-meta-functions.php 1 year ago acf-post-functions.php 1 year ago acf-post-type-functions.php 1 year ago acf-taxonomy-functions.php 1 year ago acf-user-functions.php 1 year ago acf-utility-functions.php 1 year ago acf-value-functions.php 1 year ago acf-wp-functions.php 1 year ago assets.php 1 year ago class-acf-data.php 1 year ago class-acf-internal-post-type.php 1 year ago class-acf-site-health.php 1 year ago compatibility.php 1 year ago deprecated.php 1 year ago fields.php 1 year ago index.php 1 year ago l10n.php 1 year ago local-fields.php 1 year ago local-json.php 1 year ago local-meta.php 1 year ago locations.php 1 year ago loop.php 1 year ago media.php 1 year ago rest-api.php 1 year ago revisions.php 1 year ago third-party.php 1 year ago upgrades.php 1 year ago validation.php 1 year ago wpml.php 1 year ago
class-acf-site-health.php
654 lines
1 <?php
2 /**
3 * Adds helpful debugging information to a new "Advanced Custom Fields"
4 * panel in the WordPress Site Health screen.
5 *
6 * @package ACF
7 */
8
9 // Exit if accessed directly.
10 defined( 'ABSPATH' ) || exit;
11
12 if ( ! class_exists( 'ACF_Site_Health' ) ) {
13
14 /**
15 * The ACF Site Health class responsible for populating ACF debug information in WordPress Site Health.
16 */
17 class ACF_Site_Health {
18 /**
19 * The option name used to store site health data.
20 *
21 * @var string
22 */
23 public string $option_name = 'acf_site_health';
24
25 /**
26 * Constructs the ACF_Site_Health class.
27 *
28 * @since 6.3
29 */
30 public function __construct() {
31 add_action( 'debug_information', array( $this, 'render_tab_content' ) );
32 add_action( 'acf_update_site_health_data', array( $this, 'update_site_health_data' ) );
33
34 if ( ! wp_next_scheduled( 'acf_update_site_health_data' ) ) {
35 wp_schedule_event( time(), 'weekly', 'acf_update_site_health_data' );
36 }
37
38 // ACF events.
39 add_action( 'acf/first_activated', array( $this, 'add_activation_event' ) );
40 add_filter( 'acf/pre_update_field_group', array( $this, 'pre_update_acf_internal_cpt' ) );
41 add_filter( 'acf/pre_update_post_type', array( $this, 'pre_update_acf_internal_cpt' ) );
42 add_filter( 'acf/pre_update_taxonomy', array( $this, 'pre_update_acf_internal_cpt' ) );
43 add_filter( 'acf/pre_update_ui_options_page', array( $this, 'pre_update_acf_internal_cpt' ) );
44 }
45
46 /**
47 * Gets the stored site health information.
48 *
49 * @since 6.3
50 *
51 * @return array
52 */
53 public function get_site_health(): array {
54 $site_health = get_option( $this->option_name, '' );
55
56 if ( is_string( $site_health ) ) {
57 $site_health = json_decode( $site_health, true );
58 }
59
60 return is_array( $site_health ) ? $site_health : array();
61 }
62
63 /**
64 * Updates the site health information.
65 *
66 * @since 6.3
67 *
68 * @param array $data An array of site health information to update.
69 * @return boolean
70 */
71 public function update_site_health( array $data = array() ): bool {
72 return update_option( $this->option_name, wp_json_encode( $data ), false );
73 }
74
75 /**
76 * Stores debug data in the ACF site health option.
77 *
78 * @since 6.3
79 *
80 * @param array $data Data to update with (optional).
81 * @return boolean
82 */
83 public function update_site_health_data( array $data = array() ): bool {
84 if ( wp_doing_cron() ) {
85 // Bootstrap wp-admin, as WP_Cron doesn't do this for us.
86 require_once trailingslashit( ABSPATH ) . 'wp-admin/includes/admin.php';
87 }
88
89 $site_health = $this->get_site_health();
90 $values = ! empty( $data ) ? $data : $this->get_site_health_values();
91 $updated = array();
92
93 if ( ! empty( $values ) ) {
94 foreach ( $values as $key => $value ) {
95 $updated[ $key ] = $value['debug'] ?? $value['value'];
96 }
97 }
98
99 foreach ( $site_health as $key => $value ) {
100 if ( 'event_' === substr( $key, 0, 6 ) ) {
101 $updated[ $key ] = $value;
102 }
103 }
104
105 $updated['last_updated'] = time();
106
107 return $this->update_site_health( $updated );
108 }
109
110 /**
111 * Pushes an event to the ACF site health option.
112 *
113 * @since 6.3
114 *
115 * @param string $event_name The name of the event to push.
116 * @return boolean
117 */
118 public function add_site_health_event( string $event_name = '' ): bool {
119 $site_health = $this->get_site_health();
120
121 // Allow using action/filter hooks to set events.
122 if ( empty( $event_name ) ) {
123 $current_filter = current_filter();
124
125 if ( strpos( $current_filter, 'acf/' ) !== false ) {
126 $event_name = str_replace( 'acf/', '', $current_filter );
127 }
128 }
129
130 // Bail if this event was already stored.
131 if ( empty( $event_name ) || ! empty( $site_health[ 'event_' . $event_name ] ) ) {
132 return false;
133 }
134
135 $time = time();
136
137 $site_health[ 'event_' . $event_name ] = $time;
138 $site_health['last_updated'] = $time;
139
140 return $this->update_site_health( $site_health );
141 }
142
143 /**
144 * Logs activation events for free/pro.
145 *
146 * @since 6.3
147 *
148 * @return boolean
149 */
150 public function add_activation_event() {
151 $event_name = 'first_activated';
152
153 return $this->add_site_health_event( $event_name );
154 }
155
156 /**
157 * Adds events when ACF internal post types are created.
158 *
159 * @since 6.3
160 *
161 * @param array $post The post about to be updated.
162 * @return array
163 */
164 public function pre_update_acf_internal_cpt( array $post = array() ): array {
165 if ( empty( $post['key'] ) ) {
166 return $post;
167 }
168
169 $post_type = acf_determine_internal_post_type( $post['key'] );
170
171 if ( $post_type ) {
172 $posts = acf_get_internal_post_type_posts( $post_type );
173
174 if ( empty( $posts ) ) {
175 $post_type = str_replace(
176 array(
177 'acf-',
178 '-',
179 ),
180 array(
181 '',
182 '_',
183 ),
184 $post_type
185 );
186 $this->add_site_health_event( 'first_created_' . $post_type );
187 }
188 }
189
190 return $post;
191 }
192
193 /**
194 * Appends the ACF section to the "Info" tab of the WordPress Site Health screen.
195 *
196 * @since 6.3
197 *
198 * @param array $debug_info The current debug info for site health.
199 * @return array The debug info appended with the ACF section.
200 */
201 public function render_tab_content( array $debug_info ): array {
202 $data = $this->get_site_health_values();
203
204 $this->update_site_health_data( $data );
205
206 // Unset values we don't want to display yet.
207 $fields_to_unset = array(
208 'wp_version',
209 'mysql_version',
210 'is_multisite',
211 'active_theme',
212 'parent_theme',
213 'active_plugins',
214 'number_of_fields_by_type',
215 'number_of_third_party_fields_by_type',
216 );
217
218 foreach ( $fields_to_unset as $field ) {
219 if ( isset( $data[ $field ] ) ) {
220 unset( $data[ $field ] );
221 }
222 }
223
224 foreach ( $data as $key => $value ) {
225 if ( 'event_' === substr( $key, 0, 6 ) ) {
226 unset( $data[ $key ] );
227 }
228 }
229
230 $debug_info['acf'] = array(
231 'label' => __( 'SCF', 'acf' ),
232 'description' => __( 'This section contains debug information about your SCF configuration which can be useful to provide to support.', 'acf' ),
233 'fields' => $data,
234 );
235
236 return $debug_info;
237 }
238
239 /**
240 * Gets the values for all data in the ACF site health section.
241 *
242 * @since 6.3
243 *
244 * @return array
245 */
246 public function get_site_health_values(): array {
247 global $wpdb;
248
249 $fields = array();
250 $field_groups = acf_get_field_groups();
251 $post_types = acf_get_post_types();
252 $taxonomies = acf_get_taxonomies();
253
254 $yes = __( 'Yes', 'acf' );
255 $no = __( 'No', 'acf' );
256
257 $fields['version'] = array(
258 'label' => __( 'Plugin Version', 'acf' ),
259 'value' => defined( 'ACF_VERSION' ) ? ACF_VERSION : '',
260 );
261
262 $fields['plugin_type'] = array(
263 'label' => __( 'Plugin Type', 'acf' ),
264 'value' => __( 'PRO', 'acf' ),
265 'debug' => 'PRO',
266 );
267
268 $fields['wp_version'] = array(
269 'label' => __( 'WordPress Version', 'acf' ),
270 'value' => get_bloginfo( 'version' ),
271 );
272
273 $fields['mysql_version'] = array(
274 'label' => __( 'MySQL Version', 'acf' ),
275 'value' => $wpdb->db_server_info(),
276 );
277
278 $fields['is_multisite'] = array(
279 'label' => __( 'Is Multisite', 'acf' ),
280 'value' => is_multisite() ? __( 'Yes', 'acf' ) : __( 'No', 'acf' ),
281 'debug' => is_multisite(),
282 );
283
284 $active_theme = wp_get_theme();
285 $parent_theme = $active_theme->parent();
286
287 $fields['active_theme'] = array(
288 'label' => __( 'Active Theme', 'acf' ),
289 'value' => array(
290 'name' => $active_theme->get( 'Name' ),
291 'version' => $active_theme->get( 'Version' ),
292 'theme_uri' => $active_theme->get( 'ThemeURI' ),
293 'stylesheet' => $active_theme->get( 'Stylesheet' ),
294 ),
295 );
296
297 if ( $parent_theme ) {
298 $fields['parent_theme'] = array(
299 'label' => __( 'Parent Theme', 'acf' ),
300 'value' => array(
301 'name' => $parent_theme->get( 'Name' ),
302 'version' => $parent_theme->get( 'Version' ),
303 'theme_uri' => $parent_theme->get( 'ThemeURI' ),
304 'stylesheet' => $parent_theme->get( 'Stylesheet' ),
305 ),
306 );
307 }
308
309 $active_plugins = array();
310 $plugins = get_plugins();
311
312 foreach ( $plugins as $plugin_path => $plugin ) {
313 if ( ! is_plugin_active( $plugin_path ) ) {
314 continue;
315 }
316
317 $active_plugins[ $plugin_path ] = array(
318 'name' => $plugin['Name'],
319 'version' => $plugin['Version'],
320 'plugin_uri' => empty( $plugin['PluginURI'] ) ? '' : $plugin['PluginURI'],
321 );
322 }
323
324 $fields['active_plugins'] = array(
325 'label' => __( 'Active Plugins', 'acf' ),
326 'value' => $active_plugins,
327 );
328
329 $ui_field_groups = array_filter(
330 $field_groups,
331 function ( $field_group ) {
332 return empty( $field_group['local'] );
333 }
334 );
335
336 $fields['ui_field_groups'] = array(
337 'label' => __( 'Registered Field Groups (UI)', 'acf' ),
338 'value' => number_format_i18n( count( $ui_field_groups ) ),
339 );
340
341 $php_field_groups = array_filter(
342 $field_groups,
343 function ( $field_group ) {
344 return ! empty( $field_group['local'] ) && 'PHP' === $field_group['local'];
345 }
346 );
347
348 $fields['php_field_groups'] = array(
349 'label' => __( 'Registered Field Groups (PHP)', 'acf' ),
350 'value' => number_format_i18n( count( $php_field_groups ) ),
351 );
352
353 $json_field_groups = array_filter(
354 $field_groups,
355 function ( $field_group ) {
356 return ! empty( $field_group['local'] ) && 'json' === $field_group['local'];
357 }
358 );
359
360 $fields['json_field_groups'] = array(
361 'label' => __( 'Registered Field Groups (JSON)', 'acf' ),
362 'value' => number_format_i18n( count( $json_field_groups ) ),
363 );
364
365 $rest_field_groups = array_filter(
366 $field_groups,
367 function ( $field_group ) {
368 return ! empty( $field_group['show_in_rest'] );
369 }
370 );
371
372 $fields['rest_field_groups'] = array(
373 'label' => __( 'Field Groups Enabled for REST API', 'acf' ),
374 'value' => number_format_i18n( count( $rest_field_groups ) ),
375 );
376
377 $graphql_field_groups = array_filter(
378 $field_groups,
379 function ( $field_group ) {
380 return ! empty( $field_group['show_in_graphql'] );
381 }
382 );
383
384 if ( is_plugin_active( 'wpgraphql-acf/wpgraphql-acf.php' ) ) {
385 $fields['graphql_field_groups'] = array(
386 'label' => __( 'Field Groups Enabled for GraphQL', 'acf' ),
387 'value' => number_format_i18n( count( $graphql_field_groups ) ),
388 );
389 }
390
391 $all_fields = array();
392 foreach ( $field_groups as $field_group ) {
393 $all_fields = array_merge( $all_fields, acf_get_fields( $field_group ) );
394 }
395
396 $fields_by_type = array();
397 $third_party_fields_by_type = array();
398 $core_field_types = array_keys( acf_get_field_types() );
399
400 foreach ( $all_fields as $field ) {
401 if ( in_array( $field['type'], $core_field_types, true ) ) {
402 if ( ! isset( $fields_by_type[ $field['type'] ] ) ) {
403 $fields_by_type[ $field['type'] ] = 0;
404 }
405
406 ++$fields_by_type[ $field['type'] ];
407
408 continue;
409 }
410
411 if ( ! isset( $third_party_fields_by_type[ $field['type'] ] ) ) {
412 $third_party_fields_by_type[ $field['type'] ] = 0;
413 }
414
415 ++$third_party_fields_by_type[ $field['type'] ];
416 }
417
418 $fields['number_of_fields_by_type'] = array(
419 'label' => __( 'Number of Fields by Field Type', 'acf' ),
420 'value' => $fields_by_type,
421 );
422
423 $fields['number_of_third_party_fields_by_type'] = array(
424 'label' => __( 'Number of Third Party Fields by Field Type', 'acf' ),
425 'value' => $third_party_fields_by_type,
426 );
427
428 $enable_post_types = acf_get_setting( 'enable_post_types' );
429
430 $fields['post_types_enabled'] = array(
431 'label' => __( 'Post Types and Taxonomies Enabled', 'acf' ),
432 'value' => $enable_post_types ? $yes : $no,
433 'debug' => $enable_post_types,
434 );
435
436 $ui_post_types = array_filter(
437 $post_types,
438 function ( $post_type ) {
439 return empty( $post_type['local'] );
440 }
441 );
442
443 $fields['ui_post_types'] = array(
444 'label' => __( 'Registered Post Types (UI)', 'acf' ),
445 'value' => number_format_i18n( count( $ui_post_types ) ),
446 );
447
448 $json_post_types = array_filter(
449 $post_types,
450 function ( $post_type ) {
451 return ! empty( $post_type['local'] ) && 'json' === $post_type['local'];
452 }
453 );
454
455 $fields['json_post_types'] = array(
456 'label' => __( 'Registered Post Types (JSON)', 'acf' ),
457 'value' => number_format_i18n( count( $json_post_types ) ),
458 );
459
460 $ui_taxonomies = array_filter(
461 $taxonomies,
462 function ( $taxonomy ) {
463 return empty( $taxonomy['local'] );
464 }
465 );
466
467 $fields['ui_taxonomies'] = array(
468 'label' => __( 'Registered Taxonomies (UI)', 'acf' ),
469 'value' => number_format_i18n( count( $ui_taxonomies ) ),
470 );
471
472 $json_taxonomies = array_filter(
473 $taxonomies,
474 function ( $taxonomy ) {
475 return ! empty( $taxonomy['local'] ) && 'json' === $taxonomy['local'];
476 }
477 );
478
479 $fields['json_taxonomies'] = array(
480 'label' => __( 'Registered Taxonomies (JSON)', 'acf' ),
481 'value' => number_format_i18n( count( $json_taxonomies ) ),
482 );
483
484 $enable_options_pages_ui = acf_get_setting( 'enable_options_pages_ui' );
485
486 $fields['ui_options_pages_enabled'] = array(
487 'label' => __( 'Options Pages UI Enabled', 'acf' ),
488 'value' => $enable_options_pages_ui ? $yes : $no,
489 'debug' => $enable_options_pages_ui,
490 );
491
492 $options_pages = acf_get_options_pages();
493 $ui_options_pages = array();
494
495 if ( empty( $options_pages ) || ! is_array( $options_pages ) ) {
496 $options_pages = array();
497 }
498
499 if ( $enable_options_pages_ui ) {
500 $ui_options_pages = acf_get_ui_options_pages();
501
502 $ui_options_pages_in_ui = array_filter(
503 $ui_options_pages,
504 function ( $ui_options_page ) {
505 return empty( $ui_options_page['local'] );
506 }
507 );
508
509 $json_options_pages = array_filter(
510 $ui_options_pages,
511 function ( $ui_options_page ) {
512 return ! empty( $ui_options_page['local'] );
513 }
514 );
515
516 $fields['ui_options_pages'] = array(
517 'label' => __( 'Registered Options Pages (UI)', 'acf' ),
518 'value' => number_format_i18n( count( $ui_options_pages_in_ui ) ),
519 );
520
521 $fields['json_options_pages'] = array(
522 'label' => __( 'Registered Options Pages (JSON)', 'acf' ),
523 'value' => number_format_i18n( count( $json_options_pages ) ),
524 );
525 }
526
527 $ui_options_page_slugs = array_column( $ui_options_pages, 'menu_slug' );
528 $php_options_pages = array_filter(
529 $options_pages,
530 function ( $options_page ) use ( $ui_options_page_slugs ) {
531 return ! in_array( $options_page['menu_slug'], $ui_options_page_slugs, true );
532 }
533 );
534
535 $fields['php_options_pages'] = array(
536 'label' => __( 'Registered Options Pages (PHP)', 'acf' ),
537 'value' => number_format_i18n( count( $php_options_pages ) ),
538 );
539
540
541 $rest_api_format = acf_get_setting( 'rest_api_format' );
542
543 $fields['rest_api_format'] = array(
544 'label' => __( 'REST API Format', 'acf' ),
545 'value' => 'standard' === $rest_api_format ? __( 'Standard', 'acf' ) : __( 'Light', 'acf' ),
546 'debug' => $rest_api_format,
547 );
548
549 $blocks = acf_get_block_types();
550 $block_api_versions = array();
551 $acf_block_versions = array();
552 $blocks_using_post_meta = 0;
553
554 foreach ( $blocks as $block ) {
555 if ( ! isset( $block_api_versions[ 'v' . $block['api_version'] ] ) ) {
556 $block_api_versions[ 'v' . $block['api_version'] ] = 0;
557 }
558
559 if ( ! isset( $acf_block_versions[ 'v' . $block['acf_block_version'] ] ) ) {
560 $acf_block_versions[ 'v' . $block['acf_block_version'] ] = 0;
561 }
562
563 if ( ! empty( $block['use_post_meta'] ) ) {
564 ++$blocks_using_post_meta;
565 }
566
567 ++$block_api_versions[ 'v' . $block['api_version'] ];
568 ++$acf_block_versions[ 'v' . $block['acf_block_version'] ];
569 }
570
571 $fields['blocks_per_api_version'] = array(
572 'label' => __( 'Blocks Per API Version', 'acf' ),
573 'value' => $block_api_versions,
574 );
575
576 $fields['blocks_per_acf_block_version'] = array(
577 'label' => __( 'Blocks Per SCF Block Version', 'acf' ),
578 'value' => $acf_block_versions,
579 );
580
581 $fields['blocks_using_post_meta'] = array(
582 'label' => __( 'Blocks Using Post Meta', 'acf' ),
583 'value' => number_format_i18n( $blocks_using_post_meta ),
584 );
585
586 $preload_blocks = acf_get_setting( 'preload_blocks' );
587
588 $fields['preload_blocks'] = array(
589 'label' => __( 'Block Preloading Enabled', 'acf' ),
590 'value' => ! empty( $preload_blocks ) ? $yes : $no,
591 'debug' => $preload_blocks,
592 );
593
594
595 $show_admin = acf_get_setting( 'show_admin' );
596
597 $fields['admin_ui_enabled'] = array(
598 'label' => __( 'Admin UI Enabled', 'acf' ),
599 'value' => $show_admin ? $yes : $no,
600 'debug' => $show_admin,
601 );
602
603 $field_type_modal_enabled = apply_filters( 'acf/field_group/enable_field_browser', true );
604
605 $fields['field_type-modal_enabled'] = array(
606 'label' => __( 'Field Type Modal Enabled', 'acf' ),
607 'value' => ! empty( $field_type_modal_enabled ) ? $yes : $no,
608 'debug' => $field_type_modal_enabled,
609 );
610
611 $field_settings_tabs_enabled = apply_filters( 'acf/field_group/disable_field_settings_tabs', false );
612
613 $fields['field_settings_tabs_enabled'] = array(
614 'label' => __( 'Field Settings Tabs Enabled', 'acf' ),
615 'value' => empty( $field_settings_tabs_enabled ) ? $yes : $no,
616 'debug' => $field_settings_tabs_enabled,
617 );
618
619 $shortcode_enabled = acf_get_setting( 'enable_shortcode' );
620
621 $fields['shortcode_enabled'] = array(
622 'label' => __( 'Shortcode Enabled', 'acf' ),
623 'value' => ! empty( $shortcode_enabled ) ? $yes : $no,
624 'debug' => $shortcode_enabled,
625 );
626
627 $fields['registered_acf_forms'] = array(
628 'label' => __( 'Registered SCF Forms', 'acf' ),
629 'value' => number_format_i18n( count( acf_get_forms() ) ),
630 );
631
632 $local_json = acf_get_instance( 'ACF_Local_JSON' );
633 $save_paths = $local_json->get_save_paths();
634 $load_paths = $local_json->get_load_paths();
635
636 $fields['json_save_paths'] = array(
637 'label' => __( 'JSON Save Paths', 'acf' ),
638 'value' => number_format_i18n( count( $save_paths ) ),
639 'debug' => count( $save_paths ),
640 );
641
642 $fields['json_load_paths'] = array(
643 'label' => __( 'JSON Load Paths', 'acf' ),
644 'value' => number_format_i18n( count( $load_paths ) ),
645 'debug' => count( $load_paths ),
646 );
647
648 return $fields;
649 }
650 }
651
652 acf_new_instance( 'ACF_Site_Health' );
653 }
654