| Server IP : 62.72.47.131 / Your IP : 216.73.217.34 Web Server : Apache/2.4.66 (Debian) System : Linux 975cdb959a49 5.14.0-611.55.1.el9_7.x86_64 #1 SMP PREEMPT_DYNAMIC Tue May 19 15:19:29 EDT 2026 x86_64 User : ( 501) PHP Version : 8.3.30 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : OFF | Perl : ON | Python : OFF | Sudo : OFF | Pkexec : OFF Directory : /var/www/html/wp-content/plugins/advanced-custom-fields/src/Site_Health/ |
Upload File : |
<?php
/**
* @package ACF
* @author WP Engine
*
* © 2026 Advanced Custom Fields (ACF®). All rights reserved.
* "ACF" is a trademark of WP Engine.
* Licensed under the GNU General Public License v2 or later.
* https://www.gnu.org/licenses/gpl-2.0.html
*/
namespace ACF\Site_Health;
use WP_Error;
use WP_REST_Request;
// Exit if accessed directly.
defined( 'ABSPATH' ) || exit;
/**
* AI Usage
*
* Logs information about ACF AI/Abilities usage for the ACF Site Health report.
* Measures opt-in, potential (AI-ready objects), discovery (browsing), and utility (execution).
*/
class AI_Usage {
/**
* An instance of the ACF Site_Health class.
*
* @var Site_Health
*/
private Site_Health $site_health;
/**
* Constructs the class.
*
* @since 6.8.0
*
* @param Site_Health $site_health An instance of Site_Health.
* @return void
*/
public function __construct( Site_Health $site_health ) {
$this->site_health = $site_health;
add_action( 'init', array( $this, 'init' ) );
}
/**
* Initializes the class on init if the ACF Abilities API is available.
*
* @since 6.8.0
*
* @return void
*/
public function init() {
// Only hook if AI is enabled and Abilities API exists.
if ( ! $this->is_acf_abilities_api_available() ) {
return;
}
// Execution logging - hook after ability execution.
add_action( 'wp_after_execute_ability', array( $this, 'log_execution' ), 10, 3 );
}
/**
* Checks if ACF AI and the Abilities API are enabled.
*
* @since 6.8.0
*
* @return boolean
*/
private function is_acf_abilities_api_available(): bool {
return acf_get_setting( 'enable_acf_ai' ) && function_exists( 'wp_register_ability' );
}
/**
* Log execution events (when agents execute ACF abilities).
*
* Hooks into wp_after_execute_ability to log successful ability executions.
*
* @since 6.8.0
*
* @param string $ability_name The namespaced ability name.
* @param mixed $input The input data passed to the ability.
* @param mixed $result The result returned by the ability.
* @return void
*/
public function log_execution( string $ability_name, $input, $result ) {
// Only log ACF abilities.
if ( strpos( $ability_name, 'acf/' ) !== 0 ) {
return;
}
$is_error = $result instanceof WP_Error;
$this->increment_execution_count( $ability_name, $is_error );
}
/**
* Increment execution counts.
*
* @since 6.8.0
*
* @param string $ability_name The ability that was executed.
* @param boolean $is_error Whether the execution resulted in an error.
* @return boolean Success status.
*/
private function increment_execution_count( string $ability_name, bool $is_error ): bool {
$data = $this->site_health->get_site_health();
if ( ! isset( $data['ai_usage'] ) ) {
$data['ai_usage'] = $this->get_default_usage_structure();
}
// Increment total executions.
++$data['ai_usage']['total_executions'];
$data['ai_usage']['last_execution_at'] = time();
// Increment per-ability count.
if ( ! isset( $data['ai_usage']['executions_by_ability'][ $ability_name ] ) ) {
$data['ai_usage']['executions_by_ability'][ $ability_name ] = 0;
}
++$data['ai_usage']['executions_by_ability'][ $ability_name ];
if ( $is_error ) {
++$data['ai_usage']['error_count'];
}
return $this->site_health->update_site_health( $data );
}
/**
* Get the default log data structure.
*
* @since 6.8.0
*
* @return array
*/
private function get_default_usage_structure(): array {
return array(
'total_executions' => 0,
'error_count' => 0,
'last_execution_at' => null,
'executions_by_ability' => array(),
);
}
/**
* Get AI-ready object counts for Site Health display.
*
* @since 6.8.0
*
* @param array $field_groups An array of ACF field groups.
* @param array $post_types An array of ACF post types.
* @param array $taxonomies An array of ACF taxonomies.
* @return array Counts of AI-ready objects by type.
*/
public function get_ai_ready_counts( $field_groups, $post_types, $taxonomies ): array {
$counts = array(
'field_groups' => 0,
'post_types' => 0,
'taxonomies' => 0,
);
// Count AI-ready field groups.
foreach ( $field_groups as $field_group ) {
if ( ! empty( $field_group['allow_ai_access'] ) && ! empty( $field_group['active'] ) ) {
++$counts['field_groups'];
}
}
// Count AI-ready post types.
foreach ( $post_types as $post_type ) {
if ( ! empty( $post_type['allow_ai_access'] ) && ! empty( $post_type['active'] ) ) {
++$counts['post_types'];
}
}
// Count AI-ready taxonomies.
foreach ( $taxonomies as $taxonomy ) {
if ( ! empty( $taxonomy['allow_ai_access'] ) && ! empty( $taxonomy['active'] ) ) {
++$counts['taxonomies'];
}
}
return $counts;
}
/**
* Get the usage metrics for Site Health display.
*
* @since 6.8.0
*
* @return array The usage metrics.
*/
public function get_usage_metrics(): array {
$site_health = $this->site_health->get_site_health();
if ( ! isset( $site_health['ai_usage'] ) ) {
return array(
'total_discovery_hits' => 0,
'total_executions' => 0,
'error_count' => 0,
);
}
$usage = $site_health['ai_usage'];
return array(
'total_discovery_hits' => $usage['total_discovery_hits'] ?? 0,
'total_executions' => $usage['total_executions'] ?? 0,
'error_count' => $usage['error_count'] ?? 0,
'executions_by_ability' => $usage['executions_by_ability'] ?? array(),
);
}
}