14
14
/**
15
15
* Class SCF_Rest_Types_Endpoint
16
16
*
17
- * Extends the /wp/v2/types endpoint to include SCF fields.
17
+ * Extends the /wp/v2/types endpoint to include SCF fields and source filtering .
18
18
*
19
19
* @since SCF 6.5.0
20
20
*/
@@ -27,6 +27,133 @@ class SCF_Rest_Types_Endpoint {
27
27
*/
28
28
public function __construct () {
29
29
add_action ( 'rest_api_init ' , array ( $ this , 'register_extra_fields ' ) );
30
+ add_action ( 'rest_api_init ' , array ( $ this , 'register_parameters ' ) );
31
+
32
+ // Add filter to process REST API requests by route
33
+ add_filter ( 'rest_request_before_callbacks ' , array ( $ this , 'filter_types_request ' ), 10 , 3 );
34
+
35
+ // Add filter to process each post type individually
36
+ add_filter ( 'rest_prepare_post_type ' , array ( $ this , 'filter_post_type ' ), 10 , 3 );
37
+
38
+ // Clean up null entries from the response
39
+ add_filter ( 'rest_pre_echo_response ' , array ( $ this , 'clean_types_response ' ), 10 , 3 );
40
+ }
41
+
42
+ /**
43
+ * Filter post types requests, fires for both collection and individual requests.
44
+ * We only want to handle individual requets to ensure the post type requested matches the source.
45
+ *
46
+ * @since SCF 6.5.0
47
+ *
48
+ * @param mixed $response The current response, either response or null.
49
+ * @param array $handler The handler for the route.
50
+ * @param WP_REST_Request $request The request object.
51
+ * @return mixed The response or null.
52
+ */
53
+ public function filter_types_request ( $ response , $ handler , $ request ) {
54
+ // We only want to handle individual requests
55
+ $ route = $ request ->get_route ();
56
+ if ( ! preg_match ( '#^/wp/v2/types/([^/]+)$# ' , $ route , $ matches ) ) {
57
+ return $ response ;
58
+ }
59
+
60
+ $ source = $ request ->get_param ( 'source ' );
61
+
62
+ // Only proceed if source parameter is provided and valid
63
+ if ( ! $ source || ! in_array ( $ source , array ( 'core ' , 'scf ' , 'other ' ), true ) ) {
64
+ return $ response ;
65
+ }
66
+
67
+ $ source_post_types = $ this ->get_source_post_types ( $ source );
68
+
69
+ // Check if the requested type matches the source
70
+ $ requested_type = $ matches [1 ];
71
+ if ( ! in_array ( $ requested_type , $ source_post_types , true ) ) {
72
+ return new WP_Error (
73
+ 'rest_post_type_invalid ' ,
74
+ __ ( 'Invalid post type. ' , 'secure-custom-fields ' ),
75
+ array ( 'status ' => 404 )
76
+ );
77
+ }
78
+
79
+ return $ response ;
80
+ }
81
+
82
+ /**
83
+ * Filter individual post type in the response.
84
+ *
85
+ * @since SCF 6.5.0
86
+ *
87
+ * @param WP_REST_Response $response The response object.
88
+ * @param WP_Post_Type $post_type The post type object.
89
+ * @param WP_REST_Request $request The request object.
90
+ * @return WP_REST_Response|null The filtered response or null to filter it out.
91
+ */
92
+ public function filter_post_type ( $ response , $ post_type , $ request ) {
93
+ $ source = $ request ->get_param ( 'source ' );
94
+
95
+ // Only apply filtering if source parameter is provided and valid
96
+ if ( ! $ source || ! in_array ( $ source , array ( 'core ' , 'scf ' , 'other ' ), true ) ) {
97
+ return $ response ;
98
+ }
99
+
100
+ $ source_post_types = $ this ->get_source_post_types ( $ source );
101
+
102
+ if ( ! in_array ( $ post_type ->name , $ source_post_types , true ) ) {
103
+ return null ;
104
+ }
105
+
106
+ return $ response ;
107
+ }
108
+
109
+ /**
110
+ * Get an array of post types for each source.
111
+ *
112
+ * @since SCF 6.5.0
113
+ *
114
+ * @param string $source The source to get post types for.
115
+ * @return array An array of post type names for the specified source.
116
+ */
117
+ private function get_source_post_types ( $ source ) {
118
+
119
+ $ core_types = array ();
120
+ $ scf_types = array ();
121
+
122
+ if ( 'core ' === $ source || 'other ' === $ source ) {
123
+ $ all_post_types = get_post_types ( array ( '_builtin ' => true ), 'objects ' );
124
+ foreach ( $ all_post_types as $ post_type ) {
125
+ $ core_types [] = $ post_type ->name ;
126
+ }
127
+ }
128
+
129
+ if ( 'scf ' === $ source || 'other ' === $ source ) {
130
+ // Get SCF-managed post types
131
+ if ( function_exists ( 'acf_get_internal_post_type_posts ' ) ) {
132
+ $ scf_managed_post_types = acf_get_internal_post_type_posts ( 'acf-post-type ' );
133
+ foreach ( $ scf_managed_post_types as $ scf_post_type ) {
134
+ $ scf_types [] = $ scf_post_type ['post_type ' ];
135
+ }
136
+ }
137
+ }
138
+
139
+ switch ( $ source ) {
140
+ case 'core ' :
141
+ $ result = $ core_types ;
142
+ break ;
143
+ case 'scf ' :
144
+ $ result = $ scf_types ;
145
+ break ;
146
+ case 'other ' :
147
+ $ result = array_diff (
148
+ array_keys ( get_post_types ( array (), 'objects ' ) ),
149
+ array_merge ( $ core_types , $ scf_types )
150
+ );
151
+ break ;
152
+ default :
153
+ $ result = array ();
154
+ }
155
+
156
+ return $ result ;
30
157
}
31
158
32
159
/**
@@ -40,6 +167,7 @@ public function register_extra_fields() {
40
167
if ( ! (bool ) get_option ( 'scf_beta_feature_editor_sidebar_enabled ' , false ) ) {
41
168
return ;
42
169
}
170
+
43
171
register_rest_field (
44
172
'type ' ,
45
173
'scf_field_groups ' ,
@@ -123,4 +251,109 @@ private function get_field_schema() {
123
251
'context ' => array ( 'view ' , 'edit ' , 'embed ' ),
124
252
);
125
253
}
254
+
255
+ /**
256
+ * Register the source parameter for the post types endpoint.
257
+ *
258
+ * @since SCF 6.5.0
259
+ */
260
+ public function register_parameters () {
261
+ if ( ! acf_get_setting ( 'rest_api_enabled ' ) ) {
262
+ return ;
263
+ }
264
+
265
+ // Register the query parameter with the REST API
266
+ add_filter ( 'rest_type_collection_params ' , array ( $ this , 'add_collection_params ' ) );
267
+ add_filter ( 'rest_types_collection_params ' , array ( $ this , 'add_collection_params ' ) );
268
+
269
+ // Direct registration for OpenAPI documentation
270
+ add_filter ( 'rest_endpoints ' , array ( $ this , 'add_parameter_to_endpoints ' ) );
271
+ }
272
+
273
+ /**
274
+ * Get the source parameter definition
275
+ *
276
+ * @since SCF 6.5.0
277
+ *
278
+ * @return array Parameter definition
279
+ */
280
+ private function get_source_param_definition () {
281
+ return array (
282
+ 'description ' => __ ( 'Filter post types by their source. ' , 'secure-custom-fields ' ),
283
+ 'type ' => 'string ' ,
284
+ 'enum ' => array ( 'core ' , 'scf ' , 'other ' ),
285
+ 'required ' => false ,
286
+ 'validate_callback ' => 'rest_validate_request_arg ' ,
287
+ 'sanitize_callback ' => 'sanitize_text_field ' ,
288
+ 'default ' => null ,
289
+ 'in ' => 'query ' ,
290
+ );
291
+ }
292
+
293
+ /**
294
+ * Add source parameter directly to the endpoints for proper documentation
295
+ *
296
+ * @since SCF 6.5.0
297
+ *
298
+ * @param array $endpoints The REST API endpoints.
299
+ * @return array Modified endpoints
300
+ */
301
+ public function add_parameter_to_endpoints ( $ endpoints ) {
302
+ $ source_param = $ this ->get_source_param_definition ();
303
+ $ endpoints_to_modify = array ( '/wp/v2/types ' , '/wp/v2/types/(?P<type>[\w-]+) ' );
304
+
305
+ foreach ( $ endpoints_to_modify as $ route ) {
306
+ if ( isset ( $ endpoints [ $ route ] ) ) {
307
+ foreach ( $ endpoints [ $ route ] as &$ endpoint ) {
308
+ if ( isset ( $ endpoint ['args ' ] ) ) {
309
+ $ endpoint ['args ' ]['source ' ] = $ source_param ;
310
+ }
311
+ }
312
+ }
313
+ }
314
+
315
+ return $ endpoints ;
316
+ }
317
+
318
+ /**
319
+ * Add source parameter to the collection parameters for the types endpoint.
320
+ *
321
+ * @since SCF 6.5.0
322
+ *
323
+ * @param array $query_params JSON Schema-formatted collection parameters.
324
+ * @return array Modified collection parameters.
325
+ */
326
+ public function add_collection_params ( $ query_params ) {
327
+ $ query_params ['source ' ] = $ this ->get_source_param_definition ();
328
+ return $ query_params ;
329
+ }
330
+
331
+ /**
332
+ * Clean up null entries from the response
333
+ *
334
+ * @since SCF 6.5.0
335
+ *
336
+ * @param array $response The response data.
337
+ * @param WP_REST_Server $server The REST server instance.
338
+ * @param WP_REST_Request $request The original request.
339
+ * @return array The filtered response data.
340
+ */
341
+ public function clean_types_response ( $ response , $ server , $ request ) {
342
+ if ( ! preg_match ( '#^/wp/v2/types(?:/|$)# ' , $ request ->get_route () ) ) {
343
+ return $ response ;
344
+ }
345
+
346
+ // Only process collection responses (not single post type responses)
347
+ // Single post type responses have a 'slug' property, collections don't
348
+ if ( is_array ( $ response ) && ! isset ( $ response ['slug ' ] ) ) {
349
+ $ response = array_filter (
350
+ $ response ,
351
+ function ( $ entry ) {
352
+ return null !== $ entry ;
353
+ }
354
+ );
355
+ }
356
+
357
+ return $ response ;
358
+ }
126
359
}
0 commit comments