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

wp-graphql / wp-graphql / 13316763745

13 Feb 2025 08:45PM UTC coverage: 82.712% (-0.3%) from 83.023%
13316763745

push

github

web-flow
Merge pull request #3307 from wp-graphql/release/v2.0.0

release: v2.0.0

195 of 270 new or added lines in 20 files covered. (72.22%)

180 existing lines in 42 files now uncovered.

13836 of 16728 relevant lines covered (82.71%)

299.8 hits per line

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

64.06
/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
         */
UNCOV
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
         */
UNCOV
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
         */
UNCOV
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
         */
UNCOV
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
         */
UNCOV
182
        public static function resolve_taxonomy( $taxonomy ) {
×
183

184
                /**
185
                 * Get the allowed_taxonomies
186
                 *
187
                 * @var string[] $allowed_taxonomies
188
                 */
189
                $allowed_taxonomies = \WPGraphQL::get_allowed_taxonomies();
×
190

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

196
                $tax_object = get_taxonomy( $taxonomy );
×
197

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

203
                return new Taxonomy( $tax_object );
×
204
        }
205

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

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

239
                return $resolver->get_connection();
27✔
240
        }
241

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

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

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

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

310
                return $resolver->get_connection();
48✔
311
        }
312

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

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

334
                        return new UserRole( $role );
1✔
335
                }
336
        }
337

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

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

355
                $avatar = new Avatar( $avatar );
6✔
356

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

361
                return $avatar;
6✔
362
        }
363

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

378
                return $resolver->get_connection();
×
379
        }
380

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

391
                if ( ! empty( $replaced_group ) ) {
593✔
392
                        $group = $replaced_group;
593✔
393
                }
394

395
                $group = lcfirst( str_replace( '_', ' ', ucwords( $group, '_' ) ) );
593✔
396
                $group = lcfirst( str_replace( '-', ' ', ucwords( $group, '_' ) ) );
593✔
397
                $group = lcfirst( str_replace( ' ', '', ucwords( $group, ' ' ) ) );
593✔
398

399
                return $group;
593✔
400
        }
401

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

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

418
                return ! empty( $settings_groups[ $group ] ) ? $settings_groups[ $group ] : [];
593✔
419
        }
420

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

430
                /**
431
                 * Get all registered settings
432
                 */
433
                $registered_settings = get_registered_settings();
593✔
434

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

447
                        $group = self::format_group_name( $setting['group'] );
593✔
448

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

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

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

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

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

486
                /**
487
                 * Get all registered settings
488
                 */
489
                $registered_settings = get_registered_settings();
593✔
490

491
                /**
492
                 * Set allowed settings variable.
493
                 */
494
                $allowed_settings = [];
593✔
495

496
                if ( ! empty( $registered_settings ) ) {
593✔
497

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

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

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

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

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

555
                        self::$node_definition = $node_definition;
×
556
                }
557

558
                return self::$node_definition;
×
559
        }
560

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

572
                if ( true === is_object( $node ) ) {
13✔
573
                        switch ( true ) {
574
                                case $node instanceof Post:
13✔
575
                                        if ( $node->isRevision ) {
4✔
576
                                                $parent_post = get_post( $node->parentDatabaseId );
×
577
                                                if ( ! empty( $parent_post ) ) {
×
578
                                                        $parent_post_type = $parent_post->post_type;
×
579
                                                        /** @var \WP_Post_Type $post_type_object */
580
                                                        $post_type_object = get_post_type_object( $parent_post_type );
×
581
                                                        $type             = $post_type_object->graphql_single_name;
×
582
                                                }
583
                                        } else {
584
                                                /** @var \WP_Post_Type $post_type_object */
585
                                                $post_type_object = get_post_type_object( $node->post_type );
4✔
586
                                                $type             = $post_type_object->graphql_single_name;
4✔
587
                                        }
588
                                        break;
4✔
589
                                case $node instanceof Term:
9✔
590
                                        /** @var \WP_Taxonomy $tax_object */
591
                                        $tax_object = get_taxonomy( $node->taxonomyName );
×
592
                                        $type       = $tax_object->graphql_single_name;
×
593
                                        break;
×
594
                                case $node instanceof Comment:
9✔
595
                                        $type = 'Comment';
1✔
596
                                        break;
1✔
597
                                case $node instanceof PostType:
8✔
598
                                        $type = 'ContentType';
1✔
599
                                        break;
1✔
600
                                case $node instanceof Taxonomy:
7✔
601
                                        $type = 'Taxonomy';
1✔
602
                                        break;
1✔
603
                                case $node instanceof Theme:
6✔
604
                                        $type = 'Theme';
1✔
605
                                        break;
1✔
606
                                case $node instanceof User:
5✔
607
                                        $type = 'User';
3✔
608
                                        break;
3✔
609
                                case $node instanceof Plugin:
2✔
610
                                        $type = 'Plugin';
1✔
611
                                        break;
1✔
612
                                case $node instanceof CommentAuthor:
1✔
613
                                        $type = 'CommentAuthor';
1✔
614
                                        break;
1✔
615
                                case $node instanceof Menu:
×
616
                                        $type = 'Menu';
×
617
                                        break;
×
618
                                case $node instanceof \_WP_Dependency:
×
619
                                        $type = isset( $node->type ) ? $node->type : null;
×
620
                                        break;
×
621
                                default:
622
                                        $type = null;
×
623
                        }
624
                }
625

626
                /**
627
                 * Add a filter to allow externally registered node types to return the proper type
628
                 * based on the node_object that's returned
629
                 *
630
                 * @param mixed|object|array $type The type definition the node should resolve to.
631
                 * @param mixed|object|array $node The $node that is being resolved
632
                 *
633
                 * @since 0.0.6
634
                 */
635
                $type = apply_filters( 'graphql_resolve_node_type', $type, $node );
13✔
636
                $type = ucfirst( $type );
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 $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 string|null
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
                 * If the $id_components is a proper array with a type and id
679
                 *
680
                 * @since 0.0.5
681
                 */
682
                if ( is_array( $id_components ) && ! empty( $id_components['id'] ) && ! empty( $id_components['type'] ) ) {
17✔
683

684
                        /**
685
                         * Get the allowed_post_types and allowed_taxonomies
686
                         *
687
                         * @since 0.0.5
688
                         */
689

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

692
                        if ( $loader ) {
16✔
693
                                return $loader->load_deferred( $id_components['id'] );
16✔
694
                        }
695

696
                        return null;
×
697
                } else {
698
                        // translators: %s is the global ID.
699
                        throw new UserError( esc_html( sprintf( __( 'The global ID isn\'t recognized ID: %s', 'wp-graphql' ), $global_id ) ) );
1✔
700
                }
701
        }
702

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

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

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

729
                return $node_resolver->resolve_uri( $uri );
×
730
        }
731
}
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

© 2026 Coveralls, Inc