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