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 / src / Site_Health / AI_Usage.php
secure-custom-fields / src / Site_Health Last commit date
AI_Usage.php 2 months ago Site_Health.php 1 month ago
AI_Usage.php
216 lines
1 <?php
2 /**
3 * ACF 6.8.0 feature port.
4 *
5 * @package wordpress/secure-custom-fields
6 */
7
8 // phpcs:disable -- Upstream ACF 6.8.0 feature-port files are kept close to source.
9
10 namespace SCF\Site_Health;
11
12 use WP_Error;
13 use WP_REST_Request;
14
15 // Exit if accessed directly.
16 defined( 'ABSPATH' ) || exit;
17
18 /**
19 * AI Usage
20 *
21 * Logs information about ACF AI/Abilities usage for the ACF Site Health report.
22 * Measures opt-in, potential (AI-ready objects), discovery (browsing), and utility (execution).
23 */
24 class AI_Usage {
25
26 /**
27 * An instance of the ACF Site_Health class.
28 *
29 * @var Site_Health
30 */
31 private Site_Health $site_health;
32
33 /**
34 * Constructs the class.
35 *
36 * @since 6.8.0
37 *
38 * @param Site_Health $site_health An instance of Site_Health.
39 * @return void
40 */
41 public function __construct( Site_Health $site_health ) {
42 $this->site_health = $site_health;
43
44 add_action( 'init', array( $this, 'init' ) );
45 }
46
47 /**
48 * Initializes the class on init if the ACF Abilities API is available.
49 *
50 * @since 6.8.0
51 *
52 * @return void
53 */
54 public function init() {
55 // Only hook if AI is enabled and Abilities API exists.
56 if ( ! $this->is_acf_abilities_api_available() ) {
57 return;
58 }
59
60 // Execution logging - hook after ability execution.
61 add_action( 'wp_after_execute_ability', array( $this, 'log_execution' ), 10, 3 );
62 }
63
64 /**
65 * Checks if ACF AI and the Abilities API are enabled.
66 *
67 * @since 6.8.0
68 *
69 * @return boolean
70 */
71 private function is_acf_abilities_api_available(): bool {
72 return acf_get_setting( 'enable_acf_ai' ) && function_exists( 'wp_register_ability' );
73 }
74
75 /**
76 * Log execution events (when agents execute ACF abilities).
77 *
78 * Hooks into wp_after_execute_ability to log successful ability executions.
79 *
80 * @since 6.8.0
81 *
82 * @param string $ability_name The namespaced ability name.
83 * @param mixed $input The input data passed to the ability.
84 * @param mixed $result The result returned by the ability.
85 * @return void
86 */
87 public function log_execution( string $ability_name, $input, $result ) {
88 // Only log ACF abilities.
89 if ( strpos( $ability_name, 'acf/' ) !== 0 ) {
90 return;
91 }
92
93 $is_error = $result instanceof WP_Error;
94
95 $this->increment_execution_count( $ability_name, $is_error );
96 }
97
98 /**
99 * Increment execution counts.
100 *
101 * @since 6.8.0
102 *
103 * @param string $ability_name The ability that was executed.
104 * @param boolean $is_error Whether the execution resulted in an error.
105 * @return boolean Success status.
106 */
107 private function increment_execution_count( string $ability_name, bool $is_error ): bool {
108 $data = $this->site_health->get_site_health();
109
110 if ( ! isset( $data['ai_usage'] ) ) {
111 $data['ai_usage'] = $this->get_default_usage_structure();
112 }
113
114 // Increment total executions.
115 ++$data['ai_usage']['total_executions'];
116 $data['ai_usage']['last_execution_at'] = time();
117
118 // Increment per-ability count.
119 if ( ! isset( $data['ai_usage']['executions_by_ability'][ $ability_name ] ) ) {
120 $data['ai_usage']['executions_by_ability'][ $ability_name ] = 0;
121 }
122 ++$data['ai_usage']['executions_by_ability'][ $ability_name ];
123
124 if ( $is_error ) {
125 ++$data['ai_usage']['error_count'];
126 }
127
128 return $this->site_health->update_site_health( $data );
129 }
130
131 /**
132 * Get the default log data structure.
133 *
134 * @since 6.8.0
135 *
136 * @return array
137 */
138 private function get_default_usage_structure(): array {
139 return array(
140 'total_executions' => 0,
141 'error_count' => 0,
142 'last_execution_at' => null,
143 'executions_by_ability' => array(),
144 );
145 }
146
147 /**
148 * Get AI-ready object counts for Site Health display.
149 *
150 * @since 6.8.0
151 *
152 * @param array $field_groups An array of ACF field groups.
153 * @param array $post_types An array of ACF post types.
154 * @param array $taxonomies An array of ACF taxonomies.
155 * @return array Counts of AI-ready objects by type.
156 */
157 public function get_ai_ready_counts( $field_groups, $post_types, $taxonomies ): array {
158 $counts = array(
159 'field_groups' => 0,
160 'post_types' => 0,
161 'taxonomies' => 0,
162 );
163
164 // Count AI-ready field groups.
165 foreach ( $field_groups as $field_group ) {
166 if ( ! empty( $field_group['allow_ai_access'] ) && ! empty( $field_group['active'] ) ) {
167 ++$counts['field_groups'];
168 }
169 }
170
171 // Count AI-ready post types.
172 foreach ( $post_types as $post_type ) {
173 if ( ! empty( $post_type['allow_ai_access'] ) && ! empty( $post_type['active'] ) ) {
174 ++$counts['post_types'];
175 }
176 }
177
178 // Count AI-ready taxonomies.
179 foreach ( $taxonomies as $taxonomy ) {
180 if ( ! empty( $taxonomy['allow_ai_access'] ) && ! empty( $taxonomy['active'] ) ) {
181 ++$counts['taxonomies'];
182 }
183 }
184
185 return $counts;
186 }
187
188 /**
189 * Get the usage metrics for Site Health display.
190 *
191 * @since 6.8.0
192 *
193 * @return array The usage metrics.
194 */
195 public function get_usage_metrics(): array {
196 $site_health = $this->site_health->get_site_health();
197
198 if ( ! isset( $site_health['ai_usage'] ) ) {
199 return array(
200 'total_discovery_hits' => 0,
201 'total_executions' => 0,
202 'error_count' => 0,
203 );
204 }
205
206 $usage = $site_health['ai_usage'];
207
208 return array(
209 'total_discovery_hits' => $usage['total_discovery_hits'] ?? 0,
210 'total_executions' => $usage['total_executions'] ?? 0,
211 'error_count' => $usage['error_count'] ?? 0,
212 'executions_by_ability' => $usage['executions_by_ability'] ?? array(),
213 );
214 }
215 }
216