• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

wp-graphql / wp-graphql / 15710056976

17 Jun 2025 02:27PM UTC coverage: 84.17% (-0.1%) from 84.287%
15710056976

push

github

actions-user
release: merge develop into master for v2.3.3

15925 of 18920 relevant lines covered (84.17%)

258.66 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

63.87
/src/Data/DataSource.php
1
<?php
2

3
namespace WPGraphQL\Data;
4

5
use GraphQL\Error\UserError;
6
use GraphQL\Type\Definition\ResolveInfo;
7
use GraphQLRelay\Relay;
8
use WPGraphQL\AppContext;
9
use WPGraphQL\Data\Connection\CommentConnectionResolver;
10
use WPGraphQL\Data\Connection\PluginConnectionResolver;
11
use WPGraphQL\Data\Connection\PostObjectConnectionResolver;
12
use WPGraphQL\Data\Connection\TermObjectConnectionResolver;
13
use WPGraphQL\Data\Connection\ThemeConnectionResolver;
14
use WPGraphQL\Data\Connection\UserConnectionResolver;
15
use WPGraphQL\Data\Connection\UserRoleConnectionResolver;
16
use WPGraphQL\Model\Avatar;
17
use WPGraphQL\Model\Comment;
18
use WPGraphQL\Model\CommentAuthor;
19
use WPGraphQL\Model\Menu;
20
use WPGraphQL\Model\Plugin;
21
use WPGraphQL\Model\Post;
22
use WPGraphQL\Model\PostType;
23
use WPGraphQL\Model\Taxonomy;
24
use WPGraphQL\Model\Term;
25
use WPGraphQL\Model\Theme;
26
use WPGraphQL\Model\User;
27
use WPGraphQL\Model\UserRole;
28
use WPGraphQL\Registry\TypeRegistry;
29

30
/**
31
 * Class DataSource
32
 *
33
 * This class serves as a factory for all the resolvers for queries and mutations. This layer of
34
 * abstraction over the actual resolve functions allows easier, granular control over versioning as
35
 * we can change big things behind the scenes if/when needed, and we just need to ensure the
36
 * call to the DataSource method returns the expected data later on. This should make it easy
37
 * down the road to version resolvers if/when changes to the WordPress API are rolled out.
38
 *
39
 * @package WPGraphQL\Data
40
 * @since   0.0.4
41
 */
42
class DataSource {
43

44
        /**
45
         * Stores an array of node definitions
46
         *
47
         * @var mixed[] $node_definition
48
         * @since  0.0.4
49
         */
50
        protected static $node_definition;
51

52
        /**
53
         * Retrieves a WP_Comment object for the id that gets passed
54
         *
55
         * @param int                   $id      ID of the comment we want to get the object for.
56
         * @param \WPGraphQL\AppContext $context The context of the request.
57
         *
58
         * @return \GraphQL\Deferred object
59
         * @throws \GraphQL\Error\UserError Throws UserError.
60
         * @throws \Exception Throws UserError.
61
         *
62
         * @since 0.0.5
63
         *
64
         * @deprecated Use the Loader passed in $context instead
65
         */
66
        public static function resolve_comment( $id, $context ) {
×
67
                _deprecated_function( __METHOD__, '0.8.4', 'Use $context->get_loader( \'comment\' )->load_deferred( $id ) instead.' );
×
68

69
                return $context->get_loader( 'comment' )->load_deferred( $id );
×
70
        }
71

72
        /**
73
         * Retrieves a WP_Comment object for the ID that gets passed
74
         *
75
         * @param int $comment_id The ID of the comment the comment author is associated with.
76
         *
77
         * @return \WPGraphQL\Model\CommentAuthor|null
78
         * @throws \Exception Throws Exception.
79
         */
80
        public static function resolve_comment_author( int $comment_id ) {
×
81
                $comment_author = get_comment( $comment_id );
×
82

83
                return ! empty( $comment_author ) ? new CommentAuthor( $comment_author ) : null;
×
84
        }
85

86
        /**
87
         * Wrapper for the CommentsConnectionResolver class
88
         *
89
         * @param mixed                                $source  The object the connection is coming from
90
         * @param array<string,mixed>                  $args    Query args to pass to the connection resolver
91
         * @param \WPGraphQL\AppContext                $context The context of the query to pass along
92
         * @param \GraphQL\Type\Definition\ResolveInfo $info The ResolveInfo object
93
         *
94
         * @return \GraphQL\Deferred
95
         * @throws \Exception
96
         * @since 0.0.5
97
         */
98
        public static function resolve_comments_connection( $source, array $args, AppContext $context, ResolveInfo $info ) {
17✔
99
                $resolver = new CommentConnectionResolver( $source, $args, $context, $info );
17✔
100

101
                return $resolver->get_connection();
17✔
102
        }
103

104
        /**
105
         * Wrapper for PluginsConnectionResolver::resolve
106
         *
107
         * @param mixed                                $source  The object the connection is coming from
108
         * @param array<string,mixed>                  $args    Array of arguments to pass to resolve method
109
         * @param \WPGraphQL\AppContext                $context AppContext object passed down
110
         * @param \GraphQL\Type\Definition\ResolveInfo $info The ResolveInfo object
111
         *
112
         * @return \GraphQL\Deferred
113
         * @throws \Exception
114
         * @since  0.0.5
115
         */
116
        public static function resolve_plugins_connection( $source, array $args, AppContext $context, ResolveInfo $info ) {
7✔
117
                $resolver = new PluginConnectionResolver( $source, $args, $context, $info );
7✔
118
                return $resolver->get_connection();
7✔
119
        }
120

121
        /**
122
         * Returns the post object for the ID and post type passed
123
         *
124
         * @param int                   $id      ID of the post you are trying to retrieve
125
         * @param \WPGraphQL\AppContext $context The context of the GraphQL Request
126
         *
127
         * @return \GraphQL\Deferred
128
         *
129
         * @throws \GraphQL\Error\UserError
130
         * @throws \Exception
131
         *
132
         * @since      0.0.5
133
         * @deprecated Use the Loader passed in $context instead
134
         */
135
        public static function resolve_post_object( int $id, AppContext $context ) {
×
136
                _deprecated_function( __METHOD__, '0.8.4', 'Use $context->get_loader( \'post\' )->load_deferred( $id ) instead.' );
×
137
                return $context->get_loader( 'post' )->load_deferred( $id );
×
138
        }
139

140
        /**
141
         * @param int                   $id      The ID of the menu item to load
142
         * @param \WPGraphQL\AppContext $context The context of the GraphQL request
143
         *
144
         * @return \GraphQL\Deferred|null
145
         * @throws \Exception
146
         *
147
         * @deprecated Use the Loader passed in $context instead
148
         */
149
        public static function resolve_menu_item( int $id, AppContext $context ) {
×
150
                _deprecated_function( __METHOD__, '0.8.4', 'Use $context->get_loader( \'post\' )->load_deferred( $id ) instead.' );
×
151
                return $context->get_loader( 'post' )->load_deferred( $id );
×
152
        }
153

154
        /**
155
         * Wrapper for PostObjectsConnectionResolver
156
         *
157
         * @param mixed                                $source    The object the connection is coming from
158
         * @param array<string,mixed>                  $args      Arguments to pass to the resolve method
159
         * @param \WPGraphQL\AppContext                $context AppContext object to pass down
160
         * @param \GraphQL\Type\Definition\ResolveInfo $info The ResolveInfo object
161
         * @param mixed|string|string[]                $post_type Post type of the post we are trying to resolve
162
         *
163
         * @return \GraphQL\Deferred
164
         * @throws \Exception
165
         * @since  0.0.5
166
         */
167
        public static function resolve_post_objects_connection( $source, array $args, AppContext $context, ResolveInfo $info, $post_type ) {
113✔
168
                $resolver = new PostObjectConnectionResolver( $source, $args, $context, $info, $post_type );
113✔
169

170
                return $resolver->get_connection();
113✔
171
        }
172

173
        /**
174
         * Retrieves the taxonomy object for the name of the taxonomy passed
175
         *
176
         * @param string $taxonomy Name of the taxonomy you want to retrieve the taxonomy object for
177
         *
178
         * @return \WPGraphQL\Model\Taxonomy object
179
         * @throws \GraphQL\Error\UserError If no taxonomy is found with the name passed.
180
         * @since  0.0.5
181
         */
182
        public static function resolve_taxonomy( $taxonomy ) {
×
183

184
                /**
185
                 * Get the allowed_taxonomies.
186
                 */
187
                $allowed_taxonomies = \WPGraphQL::get_allowed_taxonomies();
×
188

189
                if ( ! in_array( $taxonomy, $allowed_taxonomies, true ) ) {
×
190
                        // translators: %s is the name of the taxonomy.
191
                        throw new UserError( esc_html( sprintf( __( 'No taxonomy was found with the name %s', 'wp-graphql' ), $taxonomy ) ) );
×
192
                }
193

194
                $tax_object = get_taxonomy( $taxonomy );
×
195

196
                if ( ! $tax_object instanceof \WP_Taxonomy ) {
×
197
                        // translators: %s is the name of the taxonomy.
198
                        throw new UserError( esc_html( sprintf( __( 'No taxonomy was found with the name %s', 'wp-graphql' ), $taxonomy ) ) );
×
199
                }
200

201
                return new Taxonomy( $tax_object );
×
202
        }
203

204
        /**
205
         * Get the term object for a term
206
         *
207
         * @param int                   $id      ID of the term you are trying to retrieve the object for
208
         * @param \WPGraphQL\AppContext $context The context of the GraphQL Request
209
         *
210
         * @return \GraphQL\Deferred
211
         * @throws \Exception
212
         * @since      0.0.5
213
         *
214
         * @deprecated Use the Loader passed in $context instead
215
         */
216
        public static function resolve_term_object( $id, AppContext $context ) {
×
217
                _deprecated_function( __METHOD__, '0.8.4', 'Use $context->get_loader( \'term\' )->load_deferred( $id ) instead.' );
×
218
                return $context->get_loader( 'term' )->load_deferred( $id );
×
219
        }
220

221
        /**
222
         * Wrapper for TermObjectConnectionResolver::resolve
223
         *
224
         * @param mixed                                $source   The object the connection is coming from
225
         * @param array<string,mixed>                  $args     Array of args to be passed to the resolve method
226
         * @param \WPGraphQL\AppContext                $context The AppContext object to be passed down
227
         * @param \GraphQL\Type\Definition\ResolveInfo $info The ResolveInfo object
228
         * @param string                               $taxonomy The name of the taxonomy the term belongs to
229
         *
230
         * @return \GraphQL\Deferred
231
         * @throws \Exception
232
         * @since  0.0.5
233
         */
234
        public static function resolve_term_objects_connection( $source, array $args, AppContext $context, ResolveInfo $info, string $taxonomy ) {
27✔
235
                $resolver = new TermObjectConnectionResolver( $source, $args, $context, $info, $taxonomy );
27✔
236

237
                return $resolver->get_connection();
27✔
238
        }
239

240
        /**
241
         * Retrieves the theme object for the theme you are looking for
242
         *
243
         * @param string $stylesheet Directory name for the theme.
244
         *
245
         * @return \WPGraphQL\Model\Theme object
246
         * @throws \GraphQL\Error\UserError
247
         * @since  0.0.5
248
         */
249
        public static function resolve_theme( $stylesheet ) {
2✔
250
                $theme = wp_get_theme( $stylesheet );
2✔
251
                if ( $theme->exists() ) {
2✔
252
                        return new Theme( $theme );
1✔
253
                } else {
254
                        // translators: %s is the name of the theme stylesheet.
255
                        throw new UserError( esc_html( sprintf( __( 'No theme was found with the stylesheet: %s', 'wp-graphql' ), $stylesheet ) ) );
1✔
256
                }
257
        }
258

259
        /**
260
         * Wrapper for the ThemesConnectionResolver::resolve method
261
         *
262
         * @param mixed                                $source  The object the connection is coming from
263
         * @param array<string,mixed>                  $args    Passes an array of arguments to the resolve method
264
         * @param \WPGraphQL\AppContext                $context The AppContext object to be passed down
265
         * @param \GraphQL\Type\Definition\ResolveInfo $info The ResolveInfo object
266
         *
267
         * @return \GraphQL\Deferred
268
         * @throws \Exception
269
         * @since  0.0.5
270
         */
271
        public static function resolve_themes_connection( $source, array $args, AppContext $context, ResolveInfo $info ) {
×
272
                $resolver = new ThemeConnectionResolver( $source, $args, $context, $info );
×
273
                return $resolver->get_connection();
×
274
        }
275

276
        /**
277
         * Gets the user object for the user ID specified
278
         *
279
         * @param int                   $id      ID of the user you want the object for
280
         * @param \WPGraphQL\AppContext $context The AppContext
281
         *
282
         * @return \GraphQL\Deferred
283
         * @throws \Exception
284
         *
285
         * @since      0.0.5
286
         * @deprecated Use the Loader passed in $context instead
287
         */
288
        public static function resolve_user( $id, AppContext $context ) {
×
289
                _deprecated_function( __METHOD__, '0.8.4', 'Use $context->get_loader( \'user\' )->load_deferred( $id ) instead.' );
×
290
                return $context->get_loader( 'user' )->load_deferred( $id );
×
291
        }
292

293
        /**
294
         * Wrapper for the UsersConnectionResolver::resolve method
295
         *
296
         * @param mixed                                $source  The object the connection is coming from
297
         * @param array<string,mixed>                  $args    Array of args to be passed down to the resolve method
298
         * @param \WPGraphQL\AppContext                $context The AppContext object to be passed down
299
         * @param \GraphQL\Type\Definition\ResolveInfo $info The ResolveInfo object
300
         *
301
         * @return \GraphQL\Deferred
302
         * @throws \Exception
303
         * @since  0.0.5
304
         */
305
        public static function resolve_users_connection( $source, array $args, AppContext $context, ResolveInfo $info ) {
51✔
306
                $resolver = new UserConnectionResolver( $source, $args, $context, $info );
51✔
307

308
                return $resolver->get_connection();
48✔
309
        }
310

311
        /**
312
         * Returns an array of data about the user role you are requesting
313
         *
314
         * @param string $name Name of the user role you want info for
315
         *
316
         * @return \WPGraphQL\Model\UserRole
317
         * @throws \GraphQL\Error\UserError If no user role is found with the name passed.
318
         * @since  0.0.30
319
         */
320
        public static function resolve_user_role( $name ) {
2✔
321
                $role = isset( wp_roles()->roles[ $name ] ) ? wp_roles()->roles[ $name ] : null;
2✔
322

323
                if ( null === $role ) {
2✔
324
                        // translators: %s is the name of the user role.
325
                        throw new UserError( esc_html( sprintf( __( 'No user role was found with the name %s', 'wp-graphql' ), $name ) ) );
1✔
326
                } else {
327
                        $role                = (array) $role;
1✔
328
                        $role['id']          = $name;
1✔
329
                        $role['displayName'] = $role['name'];
1✔
330
                        $role['name']        = $name;
1✔
331

332
                        return new UserRole( $role );
1✔
333
                }
334
        }
335

336
        /**
337
         * Resolve the avatar for a user
338
         *
339
         * @param int                 $user_id ID of the user to get the avatar data for
340
         * @param array<string,mixed> $args    The args to pass to the get_avatar_data function
341
         *
342
         * @return \WPGraphQL\Model\Avatar|null
343
         * @throws \Exception
344
         */
345
        public static function resolve_avatar( int $user_id, array $args ) {
6✔
346
                $avatar = get_avatar_data( absint( $user_id ), $args );
6✔
347

348
                // if there's no url returned, return null
349
                if ( empty( $avatar['url'] ) ) {
6✔
350
                        return null;
×
351
                }
352

353
                $avatar = new Avatar( $avatar );
6✔
354

355
                if ( 'private' === $avatar->get_visibility() ) {
6✔
356
                        return null;
1✔
357
                }
358

359
                return $avatar;
6✔
360
        }
361

362
        /**
363
         * Resolve the connection data for user roles
364
         *
365
         * @param mixed[]                              $source  The Query results
366
         * @param array<string,mixed>                  $args    The query arguments
367
         * @param \WPGraphQL\AppContext                $context The AppContext passed down to the query
368
         * @param \GraphQL\Type\Definition\ResolveInfo $info The ResolveInfo object
369
         *
370
         * @return \GraphQL\Deferred
371
         * @throws \Exception
372
         */
373
        public static function resolve_user_role_connection( $source, array $args, AppContext $context, ResolveInfo $info ) {
×
374
                $resolver = new UserRoleConnectionResolver( $source, $args, $context, $info );
×
375

376
                return $resolver->get_connection();
×
377
        }
378

379
        /**
380
         * Format the setting group name to our standard.
381
         *
382
         * @param string $group
383
         *
384
         * @return string $group
385
         */
386
        public static function format_group_name( string $group ) {
599✔
387
                $replaced_group = graphql_format_name( $group, ' ', '/[^a-zA-Z0-9 -]/' );
599✔
388

389
                if ( ! empty( $replaced_group ) ) {
599✔
390
                        $group = $replaced_group;
599✔
391
                }
392

393
                $group = lcfirst( str_replace( '_', ' ', ucwords( $group, '_' ) ) );
599✔
394
                $group = lcfirst( str_replace( '-', ' ', ucwords( $group, '_' ) ) );
599✔
395
                $group = lcfirst( str_replace( ' ', '', ucwords( $group, ' ' ) ) );
599✔
396

397
                return $group;
599✔
398
        }
399

400
        /**
401
         * Get all of the allowed settings by group and return the
402
         * settings group that matches the group param
403
         *
404
         * @param string                           $group
405
         * @param \WPGraphQL\Registry\TypeRegistry $type_registry The WPGraphQL TypeRegistry
406
         *
407
         * @return array<string,mixed>
408
         */
409
        public static function get_setting_group_fields( string $group, TypeRegistry $type_registry ) {
599✔
410

411
                /**
412
                 * Get all of the settings, sorted by group
413
                 */
414
                $settings_groups = self::get_allowed_settings_by_group( $type_registry );
599✔
415

416
                return ! empty( $settings_groups[ $group ] ) ? $settings_groups[ $group ] : [];
599✔
417
        }
418

419
        /**
420
         * Get all of the allowed settings by group
421
         *
422
         * @param \WPGraphQL\Registry\TypeRegistry $type_registry The WPGraphQL TypeRegistry
423
         *
424
         * @return array<string,array<string,mixed>> $allowed_settings_by_group
425
         */
426
        public static function get_allowed_settings_by_group( TypeRegistry $type_registry ) {
599✔
427

428
                /**
429
                 * Get all registered settings
430
                 */
431
                $registered_settings = get_registered_settings();
599✔
432

433
                /**
434
                 * Loop through the $registered_settings array and build an array of
435
                 * settings for each group ( general, reading, discussion, writing, reading, etc. )
436
                 * if the setting is allowed in REST or GraphQL
437
                 */
438
                $allowed_settings_by_group = [];
599✔
439
                foreach ( $registered_settings as $key => $setting ) {
599✔
440
                        // Bail if the setting doesn't have a group.
441
                        if ( empty( $setting['group'] ) ) {
599✔
442
                                continue;
×
443
                        }
444

445
                        $group = self::format_group_name( $setting['group'] );
599✔
446

447
                        if ( ! isset( $setting['type'] ) || ! $type_registry->get_type( $setting['type'] ) ) {
599✔
448
                                continue;
×
449
                        }
450

451
                        if ( ! isset( $setting['show_in_graphql'] ) ) {
599✔
452
                                if ( isset( $setting['show_in_rest'] ) && false !== $setting['show_in_rest'] ) {
599✔
453
                                        $setting['key']                              = $key;
599✔
454
                                        $allowed_settings_by_group[ $group ][ $key ] = $setting;
599✔
455
                                }
456
                        } elseif ( true === $setting['show_in_graphql'] ) {
116✔
457
                                $setting['key']                              = $key;
116✔
458
                                $allowed_settings_by_group[ $group ][ $key ] = $setting;
116✔
459
                        }
460
                }
461

462
                /**
463
                 * Set the setting groups that are allowed
464
                 */
465
                $allowed_settings_by_group = ! empty( $allowed_settings_by_group ) ? $allowed_settings_by_group : [];
599✔
466

467
                /**
468
                 * Filter the $allowed_settings_by_group to allow enabling or disabling groups in the GraphQL Schema.
469
                 *
470
                 * @param array<string,array<string,mixed>> $allowed_settings_by_group
471
                 */
472
                return apply_filters( 'graphql_allowed_settings_by_group', $allowed_settings_by_group );
599✔
473
        }
474

475
        /**
476
         * Get all of the $allowed_settings
477
         *
478
         * @param \WPGraphQL\Registry\TypeRegistry $type_registry The WPGraphQL TypeRegistry
479
         *
480
         * @return array<string,array<string,mixed>> $allowed_settings
481
         */
482
        public static function get_allowed_settings( TypeRegistry $type_registry ) {
599✔
483

484
                /**
485
                 * Get all registered settings
486
                 */
487
                $registered_settings = get_registered_settings();
599✔
488

489
                /**
490
                 * Set allowed settings variable.
491
                 */
492
                $allowed_settings = [];
599✔
493

494
                if ( ! empty( $registered_settings ) ) {
599✔
495

496
                        /**
497
                         * Loop through the $registered_settings and if the setting is allowed in REST or GraphQL
498
                         * add it to the $allowed_settings array
499
                         */
500
                        foreach ( $registered_settings as $key => $setting ) {
599✔
501
                                if ( ! isset( $setting['type'] ) || ! $type_registry->get_type( $setting['type'] ) ) {
599✔
502
                                        continue;
×
503
                                }
504

505
                                if ( ! isset( $setting['show_in_graphql'] ) ) {
599✔
506
                                        if ( isset( $setting['show_in_rest'] ) && false !== $setting['show_in_rest'] ) {
599✔
507
                                                $setting['key']           = $key;
599✔
508
                                                $allowed_settings[ $key ] = $setting;
599✔
509
                                        }
510
                                } elseif ( true === $setting['show_in_graphql'] ) {
116✔
511
                                        $setting['key']           = $key;
116✔
512
                                        $allowed_settings[ $key ] = $setting;
116✔
513
                                }
514
                        }
515
                }
516

517
                /**
518
                 * Verify that we have the allowed settings
519
                 */
520
                $allowed_settings = ! empty( $allowed_settings ) ? $allowed_settings : [];
599✔
521

522
                /**
523
                 * Filter the $allowed_settings to allow some to be enabled or disabled from showing in
524
                 * the GraphQL Schema.
525
                 *
526
                 * @param array<string,array<string,mixed>> $allowed_settings
527
                 */
528
                return apply_filters( 'graphql_allowed_setting_groups', $allowed_settings );
599✔
529
        }
530

531
        /**
532
         * We get the node interface and field from the relay library.
533
         *
534
         * The first method is the way we resolve an ID to its object. The second is the way we resolve
535
         * an object that implements node to its type.
536
         *
537
         * @return mixed[]
538
         * @throws \GraphQL\Error\UserError
539
         */
540
        public static function get_node_definition() {
×
541
                if ( null === self::$node_definition ) {
×
542
                        $node_definition = Relay::nodeDefinitions(
×
543
                        // The ID fetcher definition
544
                                static function ( $global_id, AppContext $context, ResolveInfo $info ) {
×
545
                                        self::resolve_node( $global_id, $context, $info );
×
546
                                },
×
547
                                // Type resolver
548
                                static function ( $node ) {
×
549
                                        self::resolve_node_type( $node );
×
550
                                }
×
551
                        );
×
552

553
                        self::$node_definition = $node_definition;
×
554
                }
555

556
                return self::$node_definition;
×
557
        }
558

559
        /**
560
         * Given a node, returns the GraphQL Type
561
         *
562
         * @param mixed $node The node to resolve the type of
563
         *
564
         * @return string
565
         * @throws \GraphQL\Error\UserError If no type is found for the node.
566
         */
567
        public static function resolve_node_type( $node ) {
13✔
568
                $type = null;
13✔
569

570
                if ( true === is_object( $node ) ) {
13✔
571
                        switch ( true ) {
572
                                case $node instanceof Post:
13✔
573
                                        if ( $node->isRevision ) {
4✔
574
                                                /** @var ?\WP_Post */
575
                                                $parent_post = get_post( $node->parentDatabaseId );
×
576

577
                                                if ( ! empty( $parent_post ) ) {
×
578
                                                        /** @var \WP_Post_Type $post_type_object */
579
                                                        $post_type_object = get_post_type_object( $parent_post->post_type );
×
580
                                                        $type             = $post_type_object->graphql_single_name ?? null;
×
581

582
                                                        break;
×
583
                                                }
584
                                        }
585

586
                                        /** @var \WP_Post_Type $post_type_object */
587
                                        $post_type_object = isset( $node->post_type ) ? get_post_type_object( $node->post_type ) : null;
4✔
588
                                        $type             = $post_type_object->graphql_single_name ?? null;
4✔
589
                                        break;
4✔
590
                                case $node instanceof Term:
9✔
591
                                        /** @var \WP_Taxonomy $tax_object */
592
                                        $tax_object = isset( $node->taxonomyName ) ? get_taxonomy( $node->taxonomyName ) : null;
×
593
                                        $type       = $tax_object->graphql_single_name;
×
594
                                        break;
×
595
                                case $node instanceof Comment:
9✔
596
                                        $type = 'Comment';
1✔
597
                                        break;
1✔
598
                                case $node instanceof PostType:
8✔
599
                                        $type = 'ContentType';
1✔
600
                                        break;
1✔
601
                                case $node instanceof Taxonomy:
7✔
602
                                        $type = 'Taxonomy';
1✔
603
                                        break;
1✔
604
                                case $node instanceof Theme:
6✔
605
                                        $type = 'Theme';
1✔
606
                                        break;
1✔
607
                                case $node instanceof User:
5✔
608
                                        $type = 'User';
3✔
609
                                        break;
3✔
610
                                case $node instanceof Plugin:
2✔
611
                                        $type = 'Plugin';
1✔
612
                                        break;
1✔
613
                                case $node instanceof CommentAuthor:
1✔
614
                                        $type = 'CommentAuthor';
1✔
615
                                        break;
1✔
616
                                case $node instanceof Menu:
×
617
                                        $type = 'Menu';
×
618
                                        break;
×
619
                                case $node instanceof \_WP_Dependency:
×
620
                                        $type = isset( $node->type ) ? $node->type : null;
×
621
                                        break;
×
622
                                default:
623
                                        $type = null;
×
624
                        }
625
                }
626

627
                /**
628
                 * Add a filter to allow externally registered node types to return the proper type
629
                 * based on the node_object that's returned
630
                 *
631
                 * @param mixed|object|array $type The type definition the node should resolve to.
632
                 * @param mixed|object|array $node The $node that is being resolved
633
                 *
634
                 * @since 0.0.6
635
                 */
636
                $type = apply_filters( 'graphql_resolve_node_type', $type, $node );
13✔
637

638
                /**
639
                 * If the $type is not properly resolved, throw an exception
640
                 *
641
                 * @since 0.0.6
642
                 */
643
                if ( empty( $type ) ) {
13✔
644
                        throw new UserError( esc_html__( 'No type was found matching the node', 'wp-graphql' ) );
×
645
                }
646

647
                /**
648
                 * Return the resolved $type for the $node
649
                 *
650
                 * @since 0.0.5
651
                 */
652
                return ucfirst( $type );
13✔
653
        }
654

655
        /**
656
         * Given the ID of a node, this resolves the data
657
         *
658
         * @param string                               $global_id The Global ID of the node
659
         * @param \WPGraphQL\AppContext                $context The Context of the GraphQL Request
660
         * @param \GraphQL\Type\Definition\ResolveInfo $info The ResolveInfo for the GraphQL Request
661
         *
662
         * @return ?\GraphQL\Deferred
663
         * @throws \GraphQL\Error\UserError If no ID is passed.
664
         */
665
        public static function resolve_node( $global_id, AppContext $context, ResolveInfo $info ) {
17✔
666
                if ( empty( $global_id ) ) {
17✔
667
                        throw new UserError( esc_html__( 'An ID needs to be provided to resolve a node.', 'wp-graphql' ) );
×
668
                }
669

670
                /**
671
                 * Convert the encoded ID into an array we can work with
672
                 *
673
                 * @since 0.0.4
674
                 */
675
                $id_components = Relay::fromGlobalId( $global_id );
17✔
676

677
                /**
678
                 * $id_components is an array with the id and type
679
                 *
680
                 * @since 0.0.5
681
                 */
682
                if ( empty( $id_components['id'] ) || empty( $id_components['type'] ) ) {
17✔
683
                        // translators: %s is the global ID.
684
                        throw new UserError( esc_html( sprintf( __( 'The global ID isn\'t recognized ID: %s', 'wp-graphql' ), $global_id ) ) );
1✔
685
                }
686

687
                /**
688
                 * Get the allowed_post_types and allowed_taxonomies
689
                 *
690
                 * @since 0.0.5
691
                 */
692

693
                $loader = $context->get_loader( $id_components['type'] );
16✔
694

695
                if ( $loader ) {
16✔
696
                        return $loader->load_deferred( $id_components['id'] );
16✔
697
                }
698

699
                return null;
×
700
        }
701

702
        /**
703
         * Returns array of nav menu location names
704
         *
705
         * @return string[]
706
         */
707
        public static function get_registered_nav_menu_locations() {
599✔
708
                global $_wp_registered_nav_menus;
599✔
709

710
                return ! empty( $_wp_registered_nav_menus ) && is_array( $_wp_registered_nav_menus ) ? array_keys( $_wp_registered_nav_menus ) : [];
599✔
711
        }
712

713
        /**
714
         * This resolves a resource, given a URI (the path / permalink to a resource)
715
         *
716
         * Based largely on the core parse_request function in wp-includes/class-wp.php
717
         *
718
         * @param string                               $uri     The URI to fetch a resource from
719
         * @param \WPGraphQL\AppContext                $context The AppContext passed through the GraphQL Resolve Tree
720
         * @param \GraphQL\Type\Definition\ResolveInfo $info The ResolveInfo passed through the GraphQL Resolve tree
721
         *
722
         * @return \GraphQL\Deferred
723
         * @throws \Exception
724
         */
725
        public static function resolve_resource_by_uri( $uri, $context, $info ) {
×
726
                $node_resolver = new NodeResolver( $context );
×
727

728
                return $node_resolver->resolve_uri( $uri );
×
729
        }
730
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc