PluginProbe ʕ •ᴥ•ʔ
Pods – Custom Content Types and Fields / 3.3.2
Pods – Custom Content Types and Fields v3.3.2
trunk 1.14.8 2.7.31.3 2.8.23.3 2.9.19.3 3.0.10.3 3.1.4.1 3.2.0 3.2.1 3.2.1.1 3.2.2 3.2.4 3.2.5 3.2.6 3.2.7 3.2.7.1 3.2.8 3.2.8.1 3.2.8.2 3.3.0 3.3.1 3.3.2 3.3.3 3.3.4 3.3.5 3.3.6 3.3.7 3.3.8 3.3.9
pods / src / Pods / Integrations / WPGraphQL / Integration.php
pods / src / Pods / Integrations / WPGraphQL Last commit date
Connection_Resolver 3 years ago Connection.php 3 years ago Field.php 3 years ago Integration.php 1 year ago Service_Provider.php 3 years ago Settings.php 3 years ago
Integration.php
462 lines
1 <?php
2
3 namespace Pods\Integrations\WPGraphQL;
4
5 use Exception;
6 use Pods\Whatsit\Field as Pod_Field;
7 use Pods\Whatsit\Pod;
8 use Pods\Integrations\WPGraphQL\Field;
9 use PodsForm;
10
11 /**
12 * Integration specific functionality.
13 *
14 * @since 2.9.0
15 */
16 class Integration {
17
18 /**
19 * Get the list of requirement checks and error messages.
20 *
21 * @since 2.9.0
22 *
23 * @return array List of requirement checks and error messages.
24 */
25 public function get_requirements() {
26 return [
27 [
28 // WPGraphQL should be installed.
29 'check' => defined( 'WPGRAPHQL_VERSION' ),
30 // No message because we don't need to autoload this integration.
31 ],
32 [
33 // WPGraphQL should be the minimum required version.
34 'check' => defined( 'WPGRAPHQL_VERSION' ) && version_compare( '1.1.3', WPGRAPHQL_VERSION, '<=' ),
35 'message' => __( 'You need WPGraphQL 1.1.3+ installed and activated in order to use the Pods WPGraphQL integration.', 'pods' ),
36 ],
37 ];
38 }
39
40 /**
41 * Add the class hooks.
42 *
43 * @since 2.9.0
44 */
45 public function hook() {
46 add_filter( 'graphql_register_types', [ $this, 'register_types' ] );
47 add_filter( 'graphql_register_types', [ $this, 'register_connections' ], 99 );
48 add_filter( 'register_post_type_args', [ $this, 'add_graphql_support_for_post_type' ], 10, 2 );
49 add_filter( 'register_taxonomy_args', [ $this, 'add_graphql_support_for_taxonomy' ], 10, 2 );
50 }
51
52 /**
53 * Remove the class hooks.
54 *
55 * @since 2.9.0
56 */
57 public function unhook() {
58 remove_filter( 'graphql_register_types', [ $this, 'register_types' ] );
59 remove_filter( 'graphql_register_types', [ $this, 'register_connections' ], 99 );
60 remove_filter( 'register_post_type_args', [ $this, 'add_graphql_support_for_post_type' ] );
61 remove_filter( 'register_taxonomy_args', [ $this, 'add_graphql_support_for_taxonomy' ] );
62 }
63
64 /**
65 * Register the types and their fields with GraphQL.
66 *
67 * @since 2.9.0
68 */
69 public function register_types() {
70 // @todo Fetch list of Pods and set up custom types.
71 $api = pods_api();
72
73 $params = [
74 'options' => [
75 'wpgraphql_enabled' => 1,
76 ],
77 ];
78
79 $pods = $api->load_pods( $params );
80
81 foreach ( $pods as $pod ) {
82 $pod_graphql_info = $this->get_graphql_info_for_pod( $pod );
83
84 // Skip the Pod if GraphQL is not enabled.
85 if ( ! $pod_graphql_info ) {
86 continue;
87 }
88
89 $field_params = [];
90
91 // Only fetch the fields that are enabled if all are not enabled.
92 if ( ! $pod_graphql_info['all_fields_enabled'] ) {
93 $field_params = [
94 'options' => [
95 'wpgraphql_enabled' => 1,
96 ],
97 ];
98 }
99
100 $fields = $pod->get_fields( $field_params );
101
102 foreach ( $fields as $field ) {
103 $field_graphql_info = $this->get_graphql_info_for_field( $field, $pod_graphql_info );
104
105 // Skip the Field if GraphQL is not enabled.
106 if ( ! $pod_graphql_info['all_fields_enabled'] && ! $field_graphql_info ) {
107 continue;
108 }
109
110 $args = [
111 'type_name' => $pod_graphql_info['singular_name'],
112 'related_type_name' => $field_graphql_info['related_to_name'],
113 'field_name' => $field_graphql_info['singular_name'],
114 'graphql_type' => $field_graphql_info['type'],
115 'graphql_format' => '',
116 'related_limit' => $field_graphql_info['related_limit'],
117 ];
118
119 if ( 'pick' === $field['type'] ) {
120 $args['graphql_format'] = $field_graphql_info['pick_format'];
121 } elseif ( 'file' === $field['type'] ) {
122 $args['graphql_format'] = $field_graphql_info['file_format'];
123 }
124
125 $args = array_merge( $field_graphql_info, $args );
126
127 new Field( $field, $pod, $args );
128 }
129 }
130 }
131
132 /**
133 * Get the GraphQL information for the Pod.
134 *
135 * @since 2.9.0
136 *
137 * @param Pod $pod The pod object.
138 * @param null|array $labels The list of labels or null if not referenced.
139 *
140 * @return array|null The GraphQL information for the Pod or null if not setup correctly.
141 */
142 public function get_graphql_info_for_pod( $pod, $labels = null ) {
143 static $graphql_cached = [];
144
145 $pod_name = $pod->get_name();
146
147 if ( isset( $graphql_cached[ $pod_name ] ) ) {
148 return $graphql_cached[ $pod_name ];
149 }
150
151 $graphql_info = [
152 'enabled' => filter_var( $pod->get_arg( 'wpgraphql_enabled', $pod->get_arg( 'pods_pro_wpgraphql_enabled', false ) ), FILTER_VALIDATE_BOOLEAN ),
153 'all_fields_enabled' => filter_var( $pod->get_arg( 'wpgraphql_all_fields_enabled', $pod->get_arg( 'pods_pro_wpgraphql_all_fields_enabled', false ) ), FILTER_VALIDATE_BOOLEAN ),
154 'pick_format' => $pod->get_arg( 'wpgraphql_pick_format', $pod->get_arg( 'pods_pro_wpgraphql_pick_format', 'connection', true ), true ),
155 'file_format' => $pod->get_arg( 'wpgraphql_file_format', $pod->get_arg( 'pods_pro_wpgraphql_file_format', 'connection', true ), true ),
156 'singular_name' => $pod_name,
157 'plural_name' => $pod_name,
158 ];
159
160 $pod_wpgraphql_singular_name = $pod->get_arg( 'wpgraphql_singular_name', $pod->get_arg( 'pods_pro_wpgraphql_singular_name' ) );
161 $pod_wpgraphql_plural_name = $pod->get_arg( 'wpgraphql_plural_name', $pod->get_arg( 'pods_pro_wpgraphql_plural_name' ) );
162
163 // Get the singular name from the pod and fall back to the singular label of the object.
164 if ( ! empty( $pod_wpgraphql_singular_name ) ) {
165 $graphql_info['singular_name'] = $pod_wpgraphql_singular_name;
166 } elseif ( $labels && ! empty( $labels['singular_name'] ) ) {
167 $graphql_info['singular_name'] = $labels['singular_name'];
168 } elseif ( ! empty( $pod['label_singular'] ) ) {
169 $graphql_info['singular_name'] = $pod['label_singular'];
170 }
171
172 // Get the plural name from the pod and fall back to the plural label of the object.
173 if ( ! empty( $pod_wpgraphql_plural_name ) ) {
174 $graphql_info['plural_name'] = $pod_wpgraphql_plural_name;
175 } elseif ( $labels && ! empty( $labels['name'] ) ) {
176 $graphql_info['plural_name'] = $labels['name'];
177 } elseif ( ! empty( $pod['label'] ) ) {
178 $graphql_info['plural_name'] = $pod['label'];
179 }
180
181 // Enforce slugs for singular and plural names.
182 $graphql_info['singular_name'] = pods_js_name( pods_create_slug( $graphql_info['singular_name'] ) );
183 $graphql_info['plural_name'] = pods_js_name( pods_create_slug( $graphql_info['plural_name'] ) );
184
185 // If plural is the same as singular, add an "s" to plural.
186 if ( $graphql_info['singular_name'] === $graphql_info['plural_name'] ) {
187 $graphql_info['plural_name'] .= 's';
188 }
189
190 // If the names don't fit the requirements, we need to bail because WPGraphQL does not support that.
191 if ( false === preg_match( '/^[_a-zA-Z][_a-zA-Z0-9]*$/', $graphql_info['singular_name'] ) || false === preg_match( '/^[_a-zA-Z][_a-zA-Z0-9]*$/', $graphql_info['plural_name'] ) ) {
192 return null;
193 }
194
195 $graphql_cached[ $pod_name ] = $graphql_info;
196
197 return $graphql_cached[ $pod_name ];
198 }
199
200 /**
201 * Get the GraphQL information for the Field.
202 *
203 * @since 2.9.0
204 *
205 * @param Pod_Field $field The field object.
206 * @param array $pod_graphql_info The Pod GraphQL options.
207 *
208 * @return array|null The GraphQL information for the Field or null if not setup correctly.
209 */
210 public function get_graphql_info_for_field( $field, array $pod_graphql_info ) {
211 $graphql_info = [
212 'enabled' => filter_var( $field->get_arg( 'wpgraphql_enabled', $field->get_arg( 'pods_pro_wpgraphql_enabled', false ) ), FILTER_VALIDATE_BOOLEAN ),
213 'pick_format' => $field->get_arg( 'wpgraphql_pick_format', $field->get_arg( 'pods_pro_wpgraphql_pick_format', 'connection', true ), true ),
214 'file_format' => $field->get_arg( 'wpgraphql_file_format', $field->get_arg( 'pods_pro_wpgraphql_file_format', 'connection', true ), true ),
215 'singular_name' => $field->get_name(),
216 'plural_name' => $field->get_name(),
217 'type' => 'String',
218 'related_to_name' => '',
219 'related_object_type' => $field->get_related_object_type(),
220 'related_object_name' => $field->get_related_object_name(),
221 'related_limit' => $field->get_limit(),
222 ];
223
224 if ( ! empty( $pod_graphql_info['pick_format'] ) && 'inherit' !== $pod_graphql_info['pick_format'] ) {
225 $graphql_info['pick_format'] = $pod_graphql_info['pick_format'];
226 }
227
228 if ( ! empty( $pod_graphql_info['file_format'] ) && 'inherit' !== $pod_graphql_info['file_format'] ) {
229 $graphql_info['file_format'] = $pod_graphql_info['file_format'];
230 }
231
232 $field_wpgraphql_singular_name = $field->get_arg( 'wpgraphql_singular_name', $field->get_arg( 'pods_pro_wpgraphql_singular_name' ) );
233 $field_wpgraphql_plural_name = $field->get_arg( 'wpgraphql_plural_name', $field->get_arg( 'pods_pro_wpgraphql_plural_name' ) );
234
235 // Get the singular name from the pod and fall back to the singular label of the object.
236 if ( ! empty( $field_wpgraphql_singular_name ) ) {
237 $graphql_info['singular_name'] = $field_wpgraphql_singular_name;
238 }
239
240 // Get the plural name from the pod and fall back to the plural label of the object.
241 if ( ! empty( $field_wpgraphql_plural_name ) ) {
242 $graphql_info['plural_name'] = $field_wpgraphql_plural_name;
243 }
244
245 // Enforce slugs for singular and plural names.
246 $graphql_info['singular_name'] = pods_js_name( pods_create_slug( $graphql_info['singular_name'] ) );
247 $graphql_info['plural_name'] = pods_js_name( pods_create_slug( $graphql_info['plural_name'] ) );
248
249 // If plural is the same as singular, add an "s" to plural.
250 if ( $graphql_info['singular_name'] === $graphql_info['plural_name'] ) {
251 $graphql_info['plural_name'] .= 's';
252 }
253
254 // If the names don't fit the requirements, we need to bail because WPGraphQL does not support that.
255 if ( false === preg_match( '/^[_a-zA-Z][_a-zA-Z0-9]*$/', $graphql_info['singular_name'] ) || false === preg_match( '/^[_a-zA-Z][_a-zA-Z0-9]*$/', $graphql_info['plural_name'] ) ) {
256 return null;
257 }
258
259 $number_field_types = PodsForm::number_field_types();
260
261 $field_type = $field->get_type();
262
263 if ( in_array( $field_type, $number_field_types, true ) ) {
264 $graphql_info['type'] = 'Float';
265 } elseif ( 'boolean' === $field_type ) {
266 $graphql_info['type'] = 'Boolean';
267 } elseif ( 'pick' === $field_type ) {
268 // Set the related GraphQL name.
269 $graphql_info['related_to_name'] = $this->get_related_type_from_field( $field, $graphql_info );
270
271 // Handle single/multiple.
272 if ( null !== $graphql_info['related_limit'] && 1 !== $graphql_info['related_limit'] ) {
273 $graphql_info['type'] = [
274 'list_of' => $graphql_info['type'],
275 ];
276 }
277 } elseif ( 'file' === $field_type ) {
278 // Set the related GraphQL name.
279 $graphql_info['related_to_name'] = $this->get_related_type_from_field( $field, $graphql_info );
280
281 // Handle single/multiple.
282 if ( null !== $graphql_info['related_limit'] && 1 !== $graphql_info['related_limit'] ) {
283 $graphql_info['type'] = [
284 'list_of' => $graphql_info['type'],
285 ];
286 }
287 }
288
289 return $graphql_info;
290 }
291
292 /**
293 * Get the related GraphQL type from the field.
294 *
295 * @since 2.9.0
296 *
297 * @param Pod_Field $field The field object.
298 * @param array $graphql_info The GraphQL information for the field.
299 *
300 * @return string|null The GraphQL type or null if not found.
301 */
302 public function get_related_type_from_field( $field, array $graphql_info ) {
303 if ( empty( $graphql_info['related_object_type'] ) ) {
304 return null;
305 }
306
307 $object_type = $graphql_info['related_object_type'];
308 $object_name = $graphql_info['related_object_name'];
309
310 switch ( $object_type ) {
311 case 'post_type':
312 if ( empty( $object_name ) ) {
313 return null;
314 }
315
316 $post_type_object = get_post_type_object( $object_name );
317
318 if ( ! $post_type_object || ! $post_type_object->show_in_graphql || empty( $post_type_object->graphql_single_name ) ) {
319 return null;
320 }
321
322 return $post_type_object->graphql_single_name;
323 case 'post_type_object':
324 return 'contentType';
325 case 'taxonomy':
326 if ( empty( $object_name ) ) {
327 return null;
328 }
329
330 $taxonomy_object = get_taxonomy( $object_name );
331
332 if ( ! $taxonomy_object || ! $taxonomy_object->show_in_graphql || empty( $taxonomy_object->graphql_single_name ) ) {
333 return null;
334 }
335
336 return $taxonomy_object->graphql_single_name;
337 case 'taxonomy_object':
338 return 'taxonomy';
339 case 'user':
340 case 'comment':
341 case 'plugin':
342 case 'theme':
343 case 'menu':
344 return $object_type;
345 case 'user_role':
346 return 'userRole';
347 case 'attachment':
348 case 'media':
349 return 'mediaItem';
350 case 'menu_item':
351 return 'menuItem';
352 case 'pod':
353 // @todo Support ACTs.
354 return null;
355 case 'pod_type':
356 // @todo Support Pod types.
357 return null;
358 default:
359 return null;
360 }
361 }
362
363 /**
364 * Register the connections with GraphQL.
365 *
366 * @since 2.9.0
367 */
368 public function register_connections() {
369 // Register the connections that were found when registering the fields with GraphQL.
370 Field::register_connections();
371 }
372
373 /**
374 * Add GraphQL support to post types.
375 *
376 * @since 2.9.0
377 *
378 * @param array $args List of arguments for registering a post type.
379 * @param string $name The post type name.
380 *
381 * @return array List of arguments for registering a post type.
382 */
383 public function add_graphql_support_for_post_type( $args, $name ) {
384 return $this->add_graphql_support( $args, $name, 'post_type' );
385 }
386
387 /**
388 * Add GraphQL support to taxonomies.
389 *
390 * @since 2.9.0
391 *
392 * @param array $args List of arguments for registering a taxonomy.
393 * @param string $name The taxonomy name.
394 *
395 * @return array List of arguments for registering a taxonomy.
396 */
397 public function add_graphql_support_for_taxonomy( $args, $name ) {
398 return $this->add_graphql_support( $args, $name, 'taxonomy' );
399 }
400
401 /**
402 * Add GraphQL support to post types and taxonomies.
403 *
404 * @since 2.9.0
405 *
406 * @param array $args List of arguments for registering a post type or taxonomy.
407 * @param string $name The post type or taxonomy name.
408 * @param string $post_type_or_taxonomy Whether the type is a 'post_type' or 'taxonomy'.
409 *
410 * @return array List of arguments for registering a post type or taxonomy.
411 */
412 public function add_graphql_support( $args, $name, $post_type_or_taxonomy ) {
413 // Do not override other graphql integrations that may already be set up.
414 if ( isset( $args['show_in_graphql'] ) ) {
415 return $args;
416 }
417
418 try {
419 $api = pods_api();
420
421 $params = [
422 'name' => $name,
423 ];
424
425 $pod = $api->load_pod( $params );
426 } catch ( Exception $exception ) {
427 // Something else happened and we should bail.
428 pods_debug_log( $exception );
429
430 return $args;
431 }
432
433 // The pod does not exist.
434 if ( ! $pod ) {
435 return $args;
436 }
437
438 // The pod is not the right type.
439 if ( $post_type_or_taxonomy !== $pod['type'] ) {
440 return $args;
441 }
442
443 $pod_graphql_args = $this->get_graphql_info_for_pod( $pod, $args['labels'] );
444
445 // If the GraphQL is not enabled or not set up properly.
446 if ( ! $pod_graphql_args || ! $pod_graphql_args['enabled'] ) {
447 return $args;
448 }
449
450 // Set up WPGraphQL arguments.
451 $graphql_args = [
452 'show_in_graphql' => $pod_graphql_args['enabled'],
453 'graphql_single_name' => $pod_graphql_args['singular_name'],
454 'graphql_plural_name' => $pod_graphql_args['plural_name'],
455 ];
456
457 // Set the WPGraphQL arguments but do not override if they have already been manually set.
458 return array_merge( $graphql_args, $args );
459 }
460
461 }
462