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