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 / AI / Abilities / AbstractAbilityGroup.php
secure-custom-fields / src / AI / Abilities Last commit date
Abilities.php 2 months ago AbstractAbilityGroup.php 2 months ago FieldGroup.php 1 month ago PostType.php 2 months ago SCF_REST_Ability.php 2 months ago Taxonomy.php 1 month ago
AbstractAbilityGroup.php
221 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\AI\Abilities;
11
12 use WP_REST_Request;
13 use WP_Error;
14
15 // Exit if accessed directly.
16 defined( 'ABSPATH' ) || exit;
17
18 /**
19 * Abstract Ability Group
20 *
21 * Base class for all ability groups.
22 */
23 abstract class AbstractAbilityGroup {
24
25 const REST_ABILITY_CLASS = 'SCF\AI\Abilities\SCF_REST_Ability';
26
27 /**
28 * Register abilities for this ability group
29 *
30 * @since 6.8.0
31 *
32 * @return void
33 */
34 abstract public function register_abilities();
35
36 /**
37 * Check if the WordPress Abilities API is available
38 *
39 * @since 6.8.0
40 *
41 * @return boolean
42 */
43 protected function is_abilities_api_available() {
44 return function_exists( 'wp_register_ability' );
45 }
46
47 /**
48 * Register an ability with error handling.
49 *
50 * @since 6.8.0
51 *
52 * @param string $id Ability ID.
53 * @param array $ability_args Ability arguments.
54 * @return object|null Registered ability object or null on failure.
55 */
56 protected function register_ability( $id, $ability_args ) {
57 if ( ! $this->is_abilities_api_available() ) {
58 return null;
59 }
60
61 // Ensure meta array exists.
62 if ( ! isset( $ability_args['meta'] ) ) {
63 $ability_args['meta'] = array();
64 }
65
66 // Ensure mcp array exists.
67 if ( ! isset( $ability_args['meta']['mcp'] ) ) {
68 $ability_args['meta']['mcp'] = array();
69 }
70
71 // Set public to true by default for MCP exposure.
72 if ( ! isset( $ability_args['meta']['mcp']['public'] ) ) {
73 $ability_args['meta']['mcp']['public'] = true;
74 }
75
76 return wp_register_ability( $id, $ability_args );
77 }
78
79 /**
80 * Retrieves the AI-enabled ACF fields for the provided object.
81 *
82 * @since 6.8.0
83 *
84 * @param string $object_type The object type being queried.
85 * @param integer|string $object_id The object to get ACF fields for.
86 * @return array
87 */
88 protected function get_acf_fields_for_object( $object_type, $object_id ) {
89 // Get field groups that show on this object.
90 $field_groups = acf_get_field_groups(
91 array(
92 $object_type => $object_id,
93 )
94 );
95
96 $acf_fields = array();
97
98 foreach ( $field_groups as $field_group ) {
99 // Only include AI-accessible field groups that are exposed in REST.
100 if ( empty( $field_group['allow_ai_access'] ) || empty( $field_group['show_in_rest'] ) ) {
101 continue;
102 }
103
104 $fields = acf_get_fields( $field_group['key'] );
105
106 if ( $fields ) {
107 $acf_fields[ $field_group['key'] ] = array(
108 'title' => $field_group['title'],
109 'key' => $field_group['key'],
110 'fields' => $this->format_acf_fields_for_schema( $fields ),
111 );
112 }
113 }
114
115 return $acf_fields;
116 }
117
118 /**
119 * A helper function to format ACF fields for schema output.
120 *
121 * @since 6.8.0
122 *
123 * @param array $fields The ACF fields array.
124 * @return array
125 */
126 protected function format_acf_fields_for_schema( array $fields ): array {
127 $formatted_fields = array();
128
129 foreach ( $fields as $field ) {
130 $field_schema = array(
131 'key' => $field['key'],
132 'name' => $field['name'],
133 'label' => $field['label'],
134 'field_type' => $field['type'],
135 );
136
137 // Add description if available
138 if ( ! empty( $field['instructions'] ) ) {
139 $field_schema['description'] = $field['instructions'];
140 }
141
142 $field_schema = array_merge(
143 $field_schema,
144 acf_get_field_rest_schema( $field )
145 );
146
147 $formatted_fields[] = $field_schema;
148 }
149
150 return $formatted_fields;
151 }
152
153 /**
154 * Adds ACF fields to a schema.
155 *
156 * @since 6.8.0
157 *
158 * @param array $schema The schema to add fields to.
159 * @param array $acf_fields The ACF fields to add.
160 * @return array
161 */
162 protected function add_acf_fields_to_schema( array $schema, array $acf_fields ): array {
163 if ( empty( $acf_fields ) ) {
164 return $schema;
165 }
166
167 $schema['properties']['acf'] = array(
168 'type' => 'object',
169 'description' => 'SCF field values',
170 'required' => false,
171 'properties' => array(),
172 );
173
174 foreach ( $acf_fields as $field_group ) {
175 foreach ( $field_group['fields'] as $field ) {
176 $schema['properties']['acf']['properties'][ $field['name'] ] = $field;
177 }
178 }
179
180 return $schema;
181 }
182
183 /**
184 * Execute a REST API request.
185 *
186 * @since 6.8.0
187 *
188 * @param string $method HTTP method (GET, POST, PUT, DELETE).
189 * @param string $rest_base REST API base.
190 * @param array $input Input parameters.
191 * @param integer $item_id Optional item ID for single item operations.
192 * @return array|WP_Error Response data or error.
193 */
194 protected function execute_rest_request( string $method, string $rest_base, $input = array(), $item_id = null ) {
195 $endpoint = '/wp/v2/' . $rest_base;
196
197 if ( $item_id ) {
198 $endpoint .= '/' . intval( $item_id );
199 }
200
201 $request = new WP_REST_Request( $method, $endpoint );
202
203 // Set all input parameters.
204 foreach ( $input as $key => $value ) {
205 // Skip the ID since it's in the URL for single item operations.
206 if ( $key === 'id' && $item_id ) {
207 continue;
208 }
209 $request->set_param( $key, $value );
210 }
211
212 $response = rest_do_request( $request );
213
214 if ( $response->is_error() ) {
215 return $response->as_error();
216 }
217
218 return $response->get_data();
219 }
220 }
221