• 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

59.01
/src/WPGraphQL.php
1
<?php
2
/**
3
 * The global WPGraphQL class.
4
 *
5
 * @package WPGraphQL
6
 */
7

8
use WPGraphQL\Admin\Admin;
9
use WPGraphQL\AppContext;
10
use WPGraphQL\Registry\SchemaRegistry;
11
use WPGraphQL\Registry\TypeRegistry;
12
use WPGraphQL\Router;
13
use WPGraphQL\Type\WPObjectType;
14
use WPGraphQL\Utils\InstrumentSchema;
15
use WPGraphQL\Utils\Preview;
16

17
/**
18
 * Class WPGraphQL
19
 *
20
 * This is the one true WPGraphQL class
21
 */
22
final class WPGraphQL {
23

24
        /**
25
         * Stores the instance of the WPGraphQL class
26
         *
27
         * @var ?\WPGraphQL The one true WPGraphQL
28
         * @since  0.0.1
29
         */
30
        private static $instance;
31

32
        /**
33
         * Holds the Schema def
34
         *
35
         * @var mixed|\WPGraphQL\WPSchema|null $schema The Schema used for the GraphQL API
36
         */
37
        protected static $schema;
38

39
        /**
40
         * Holds the TypeRegistry instance
41
         *
42
         * @var mixed|\WPGraphQL\Registry\TypeRegistry|null $type_registry The registry that holds all GraphQL Types
43
         */
44
        protected static $type_registry;
45

46
        /**
47
         * Stores an array of allowed post types
48
         *
49
         * @var ?\WP_Post_Type[] allowed_post_types
50
         * @since  0.0.5
51
         */
52
        protected static $allowed_post_types;
53

54
        /**
55
         * Stores an array of allowed taxonomies
56
         *
57
         * @var ?\WP_Taxonomy[] allowed_taxonomies
58
         * @since  0.0.5
59
         */
60
        protected static $allowed_taxonomies;
61

62
        /**
63
         * @var bool
64
         */
65
        protected static $is_graphql_request = false;
66

67
        /**
68
         * @var bool
69
         */
70
        protected static $is_introspection_query = false;
71

72
        /**
73
         * The instance of the WPGraphQL object
74
         *
75
         * @return \WPGraphQL - The one true WPGraphQL
76
         * @since  0.0.1
77
         */
78
        public static function instance() {
3✔
79
                if ( ! isset( self::$instance ) || ! ( self::$instance instanceof self ) ) {
3✔
80
                        self::$instance = new self();
×
81
                        self::$instance->setup_constants();
×
82
                        self::$instance->includes();
×
83
                        self::$instance->actions();
×
84
                        self::$instance->filters();
×
85
                        self::$instance->upgrade();
×
86
                }
87

88
                /**
89
                 * Return the WPGraphQL Instance
90
                 */
91
                return self::$instance;
3✔
92
        }
93

94
        /**
95
         * Throw error on object clone.
96
         * The whole idea of the singleton design pattern is that there is a single object
97
         * therefore, we don't want the object to be cloned.
98
         *
99
         * @return void
100
         * @since  0.0.1
101
         */
UNCOV
102
        public function __clone() {
×
103
                // Cloning instances of the class is forbidden.
104
                _doing_it_wrong( __FUNCTION__, esc_html__( 'The WPGraphQL class should not be cloned.', 'wp-graphql' ), '0.0.1' );
×
105
        }
106

107
        /**
108
         * Disable unserializing of the class.
109
         *
110
         * @return void
111
         * @since  0.0.1
112
         */
UNCOV
113
        public function __wakeup() {
×
114
                // De-serializing instances of the class is forbidden.
115
                _doing_it_wrong( __FUNCTION__, esc_html__( 'De-serializing instances of the WPGraphQL class is not allowed', 'wp-graphql' ), '0.0.1' );
×
116
        }
117

118
        /**
119
         * Setup plugin constants.
120
         *
121
         * @return void
122
         * @since  0.0.1
123
         */
UNCOV
124
        private function setup_constants() {
×
125
                graphql_setup_constants();
×
126
        }
127

128
        /**
129
         * Include required files.
130
         * Uses composer's autoload
131
         *
132
         * @since  0.0.1
133
         */
UNCOV
134
        private function includes(): void {
×
135
        }
×
136

137
        /**
138
         * Set whether the request is a GraphQL request or not
139
         *
140
         * @param bool $is_graphql_request
141
         *
142
         * @return void
143
         */
144
        public static function set_is_graphql_request( $is_graphql_request = false ) {
758✔
145
                self::$is_graphql_request = $is_graphql_request;
758✔
146
        }
147

148
        /**
149
         * Whether the request is a graphql request or not
150
         */
151
        public static function is_graphql_request(): bool {
732✔
152
                return self::$is_graphql_request;
732✔
153
        }
154

155
        /**
156
         * Set whether the request is an introspection query or not
157
         *
158
         * @param bool $is_introspection_query
159
         *
160
         * @since 1.28.0
161
         */
162
        public static function set_is_introspection_query( bool $is_introspection_query = false ): void {
746✔
163
                self::$is_introspection_query = $is_introspection_query;
746✔
164
        }
165

166
        /**
167
         * Whether the request is an introspection query or not (query for __type or __schema)
168
         *
169
         * @since 1.28.0
170
         */
171
        public static function is_introspection_query(): bool {
593✔
172
                return self::$is_introspection_query;
593✔
173
        }
174

175
        /**
176
         * Sets up actions to run at certain spots throughout WordPress and the WPGraphQL execution
177
         * cycle
178
         */
179
        private function actions(): void {
754✔
180
                /**
181
                 * Init WPGraphQL after themes have been set up,
182
                 * allowing for both plugins and themes to register
183
                 * things before graphql_init
184
                 */
185
                add_action(
×
186
                        'after_setup_theme',
×
187
                        static function () {
×
188
                                new \WPGraphQL\Data\Config();
×
189
                                $router = new Router();
×
190
                                $router->init();
×
191
                                $instance = self::instance();
×
192

193
                                /**
194
                                 * Fire off init action
195
                                 *
196
                                 * @param \WPGraphQL $instance The instance of the WPGraphQL class
197
                                 */
198
                                do_action( 'graphql_init', $instance );
×
199
                        }
×
200
                );
×
201

202
                // Initialize the plugin url constant
203
                // see: https://developer.wordpress.org/reference/functions/plugins_url/#more-information
204
                add_action( 'init', [ $this, 'setup_plugin_url' ] );
×
205

206
                // Prevent WPGraphQL Insights from running
207
                remove_action( 'init', '\WPGraphQL\Extensions\graphql_insights_init' );
×
208

209
                /**
210
                 * Flush permalinks if the registered GraphQL endpoint has not yet been registered.
211
                 */
212
                add_action( 'wp_loaded', [ $this, 'maybe_flush_permalinks' ] );
×
213

214
                /**
215
                 * Hook in before fields resolve to check field permissions
216
                 */
217
                add_action(
×
218
                        'graphql_before_resolve_field',
×
219
                        [
×
220
                                '\WPGraphQL\Utils\InstrumentSchema',
×
221
                                'check_field_permissions',
×
222
                        ],
×
223
                        10,
×
224
                        8
×
225
                );
×
226

227
                // Determine what to show in graphql
228
                add_action( 'init_graphql_request', 'register_initial_settings', 10 );
×
229

230
                // Throw an exception
231
                add_action( 'do_graphql_request', [ $this, 'min_php_version_check' ] );
×
232
                add_action( 'do_graphql_request', [ $this, 'introspection_check' ], 10, 4 );
×
233

234
                // Initialize Admin functionality
235
                add_action( 'after_setup_theme', [ $this, 'init_admin' ] );
×
236

237
                add_action(
754✔
238
                        'init_graphql_request',
754✔
239
                        static function () {
754✔
240
                                $tracing = new \WPGraphQL\Utils\Tracing();
754✔
241
                                $tracing->init();
754✔
242

243
                                $query_log = new \WPGraphQL\Utils\QueryLog();
754✔
244
                                $query_log->init();
754✔
245
                        }
754✔
246
                );
754✔
247

248
                // Initialize Update functionality.
249
                ( new \WPGraphQL\Admin\Updates\Updates() )->init();
×
250
        }
251

252
        /**
253
         * @param ?string                         $query     The GraphQL query
254
         * @param ?string                         $operation The name of the operation
255
         * @param ?array<mixed>                   $variables Variables to be passed to your GraphQL
256
         *                                                   request
257
         * @param \GraphQL\Server\OperationParams $params    The Operation Params. This includes any
258
         *                                                   extra params,
259
         *
260
         * @throws \GraphQL\Error\SyntaxError
261
         * @throws \Exception
262
         */
263
        public function introspection_check( ?string $query, ?string $operation, ?array $variables, \GraphQL\Server\OperationParams $params ): void {
748✔
264

265
                if ( empty( $query ) ) {
748✔
266
                        return;
1✔
267
                }
268

269
                $ast              = \GraphQL\Language\Parser::parse( $query );
747✔
270
                $is_introspection = false;
746✔
271

272
                \GraphQL\Language\Visitor::visit(
746✔
273
                        $ast,
746✔
274
                        [
746✔
275
                                'Field' => static function ( \GraphQL\Language\AST\Node $node ) use ( &$is_introspection ) {
746✔
276
                                        if ( $node instanceof \GraphQL\Language\AST\FieldNode && ( '__schema' === $node->name->value || '__type' === $node->name->value ) ) {
746✔
277
                                                $is_introspection = true;
73✔
278
                                                return \GraphQL\Language\Visitor::stop();
73✔
279
                                        }
280
                                },
746✔
281
                        ]
746✔
282
                );
746✔
283

284
                self::set_is_introspection_query( $is_introspection );
746✔
285
        }
286

287
        /**
288
         * Check if the minimum PHP version requirement is met before execution begins.
289
         *
290
         * If the server is running a lower version than required, throw an exception and prevent
291
         * further execution.
292
         *
293
         * @return void
294
         * @throws \Exception
295
         */
296
        public function min_php_version_check() {
748✔
297
                if ( defined( 'GRAPHQL_MIN_PHP_VERSION' ) && version_compare( PHP_VERSION, GRAPHQL_MIN_PHP_VERSION, '<' ) ) {
748✔
298
                        throw new \Exception(
×
299
                                esc_html(
×
300
                                        sprintf(
×
301
                                        // translators: %1$s is the current PHP version, %2$s is the minimum required PHP version.
302
                                                __( 'The server\'s current PHP version %1$s is lower than the WPGraphQL minimum required version: %2$s', 'wp-graphql' ),
×
303
                                                PHP_VERSION,
×
304
                                                GRAPHQL_MIN_PHP_VERSION
×
305
                                        )
×
306
                                )
×
307
                        );
×
308
                }
309
        }
310

311
        /**
312
         * Sets up the plugin url
313
         *
314
         * @return void
315
         */
UNCOV
316
        public function setup_plugin_url() {
×
317
                // Plugin Folder URL.
318
                if ( ! defined( 'WPGRAPHQL_PLUGIN_URL' ) ) {
×
319
                        define( 'WPGRAPHQL_PLUGIN_URL', plugin_dir_url( dirname( __DIR__ ) . '/wp-graphql.php' ) );
×
320
                }
321
        }
322

323
        /**
324
         * Determine the post_types and taxonomies, etc that should show in GraphQL
325
         *
326
         * @return void
327
         */
UNCOV
328
        public function setup_types() {
×
329
                /**
330
                 * Set up the settings, post_types and taxonomies to show_in_graphql
331
                 */
332
                self::show_in_graphql();
×
333
        }
334

335
        /**
336
         * Flush permalinks if the GraphQL Endpoint route isn't yet registered
337
         *
338
         * @return void
339
         */
UNCOV
340
        public function maybe_flush_permalinks() {
×
341
                $rules = get_option( 'rewrite_rules' );
×
342
                if ( ! isset( $rules[ graphql_get_endpoint() . '/?$' ] ) ) {
×
343
                        flush_rewrite_rules(); // phpcs:ignore WordPressVIPMinimum.Functions.RestrictedFunctions.flush_rewrite_rules_flush_rewrite_rules
×
344
                }
345
        }
346

347
        /**
348
         * Setup filters
349
         */
350
        private function filters(): void {
619✔
351
                // Filter the post_types and taxonomies to show in the GraphQL Schema
352
                $this->setup_types();
×
353

354
                /**
355
                 * Instrument the Schema to provide Resolve Hooks and sanitize Schema output
356
                 */
357
                add_filter(
×
358
                        'graphql_get_type',
×
359
                        [
×
360
                                InstrumentSchema::class,
×
361
                                'instrument_resolvers',
×
362
                        ],
×
363
                        10,
×
364
                        2
×
365
                );
×
366

367
                // Filter how metadata is retrieved during GraphQL requests
368
                add_filter(
×
369
                        'get_post_metadata',
×
370
                        [
×
371
                                Preview::class,
×
372
                                'filter_post_meta_for_previews',
×
373
                        ],
×
374
                        10,
×
375
                        4
×
376
                );
×
377

378
                /**
379
                 * Adds back compat support for the `graphql_object_type_interfaces` filter which was renamed
380
                 * to support both ObjectTypes and InterfaceTypes
381
                 *
382
                 * @deprecated
383
                 */
384
                add_filter(
×
385
                        'graphql_type_interfaces',
×
386
                        static function ( $interfaces, $config, $type ) {
×
387
                                if ( $type instanceof WPObjectType ) {
619✔
388
                                        /**
389
                                         * Filters the interfaces applied to an object type
390
                                         *
391
                                         * @param string[]                                                           $interfaces List of interfaces applied to the Object Type
392
                                         * @param array<string,mixed>                                                $config     The config for the Object Type
393
                                         * @param mixed|\WPGraphQL\Type\WPInterfaceType|\WPGraphQL\Type\WPObjectType $type       The Type instance
394
                                         */
395
                                        return apply_filters_deprecated( 'graphql_object_type_interfaces', [ $interfaces, $config, $type ], '1.4.1', 'graphql_type_interfaces' );
604✔
396
                                }
397

398
                                return $interfaces;
582✔
399
                        },
×
400
                        10,
×
401
                        3
×
402
                );
×
403

404
                /**
405
                 * Prevent WPML from redirecting within WPGraphQL requests
406
                 *
407
                 * @see https://github.com/wp-graphql/wp-graphql/issues/1626#issue-769089073
408
                 * @since 1.27.0
409
                 */
410
                add_filter(
×
411
                        'wpml_is_redirected',
×
412
                        static function ( bool $is_redirect ) {
×
413
                                if ( is_graphql_request() ) {
×
414
                                        return false;
×
415
                                }
416
                                return $is_redirect;
×
417
                        },
×
418
                        10,
×
419
                        1
×
420
                );
×
421
        }
422

423
        /**
424
         * Upgrade routine
425
         *
426
         * @return void
427
         */
UNCOV
428
        public function upgrade() {
×
429
                $version = get_option( 'wp_graphql_version', null );
×
430

431
                // If the version is not set, this is a fresh install, not an update.
432
                // set the version and return.
433
                if ( ! $version ) {
×
434
                        update_option( 'wp_graphql_version', WPGRAPHQL_VERSION );
×
435
                        return;
×
436
                }
437

438
                // If the version is less than the current version, run the update routine
439
                if ( version_compare( $version, WPGRAPHQL_VERSION, '<' ) ) {
×
440
                        $this->run_update_routines( $version );
×
441
                        update_option( 'wp_graphql_version', WPGRAPHQL_VERSION );
×
442
                }
443
        }
444

445
        /**
446
         * Executes update routines based on the previously stored version.
447
         *
448
         * This triggers an action that passes the previous version and new version and allows for specific actions or
449
         * modifications needed to bring installations up-to-date with the current plugin version.
450
         *
451
         * Each update routine (callback that hooks into "graphql_do_update_routine") should handle backward compatibility as gracefully as possible.
452
         *
453
         * @since 1.2.3
454
         * @param string|null $stored_version The version number currently stored in the database.
455
         *                                    Null if no version has been previously stored.
456
         */
UNCOV
457
        public function run_update_routines( ?string $stored_version = null ): void {
×
458

459
                // bail if the stored version is empty, or the WPGRAPHQL_VERSION constant is not set
460
                if ( ! defined( 'WPGRAPHQL_VERSION' ) || ! $stored_version ) {
×
461
                        return;
×
462
                }
463

464
                // If the stored version is less than the current version, run the upgrade routine
465
                if ( version_compare( $stored_version, WPGRAPHQL_VERSION, '<' ) ) {
×
466

467
                        // Clear the extensions cache
468
                        $this->clear_extensions_cache();
×
469

470
                        /**
471
                         * Fires the update routine.
472
                         *
473
                         * @param string $stored_version The version number currently stored in the database.
474
                         * @param string $new_version    The version number of the current plugin.
475
                         */
476
                        do_action( 'graphql_do_update_routine', $stored_version, WPGRAPHQL_VERSION );
×
477
                }
478
        }
479

480
        /**
481
         * Clear all caches in the "wpgraphql_extensions" cache group.
482
         *
483
         * @return void
484
         */
UNCOV
485
        public function clear_extensions_cache() {
×
486
                global $wp_object_cache;
×
487

488
                if ( isset( $wp_object_cache->cache['wpgraphql_extensions'] ) ) {
×
489
                        foreach ( $wp_object_cache->cache['wpgraphql_extensions'] as $key => $value ) {
×
490
                                wp_cache_delete( $key, 'wpgraphql_extensions' );
×
491
                        }
492
                }
493
        }
494

495
        /**
496
         * Initialize admin functionality
497
         *
498
         * @return void
499
         */
UNCOV
500
        public function init_admin() {
×
501
                $admin = new Admin();
×
502
                $admin->init();
×
503
        }
504

505
        /**
506
         * This sets up built-in post_types and taxonomies to show in the GraphQL Schema
507
         *
508
         * @return void
509
         * @since  0.0.2
510
         */
511
        public static function show_in_graphql() {
14✔
512
                add_filter( 'register_post_type_args', [ self::class, 'setup_default_post_types' ], 10, 2 );
14✔
513
                add_filter( 'register_taxonomy_args', [ self::class, 'setup_default_taxonomies' ], 10, 2 );
14✔
514

515
                // Run late so the user can filter the args themselves.
516
                add_filter( 'register_post_type_args', [ self::class, 'register_graphql_post_type_args' ], 99, 2 );
14✔
517
                add_filter( 'register_taxonomy_args', [ self::class, 'register_graphql_taxonomy_args' ], 99, 2 );
14✔
518
        }
519

520
        /**
521
         * Sets up the default post types to show_in_graphql.
522
         *
523
         * @param array<string,mixed> $args      Array of arguments for registering a post type.
524
         * @param string              $post_type Post type key.
525
         *
526
         * @return array<string,mixed>
527
         */
528
        public static function setup_default_post_types( $args, $post_type ) {
141✔
529
                // Adds GraphQL support for attachments.
530
                if ( 'attachment' === $post_type ) {
141✔
531
                        $args['show_in_graphql']     = true;
×
532
                        $args['graphql_single_name'] = 'mediaItem';
×
533
                        $args['graphql_plural_name'] = 'mediaItems';
×
534
                } elseif ( 'page' === $post_type ) { // Adds GraphQL support for pages.
141✔
535
                        $args['show_in_graphql']     = true;
×
536
                        $args['graphql_single_name'] = 'page';
×
537
                        $args['graphql_plural_name'] = 'pages';
×
538
                } elseif ( 'post' === $post_type ) { // Adds GraphQL support for posts.
141✔
539
                        $args['show_in_graphql']     = true;
×
540
                        $args['graphql_single_name'] = 'post';
×
541
                        $args['graphql_plural_name'] = 'posts';
×
542
                }
543

544
                return $args;
141✔
545
        }
546

547
        /**
548
         * Sets up the default taxonomies to show_in_graphql.
549
         *
550
         * @param array<string,mixed> $args     Array of arguments for registering a taxonomy.
551
         * @param string              $taxonomy Taxonomy key.
552
         *
553
         * @return array<string,mixed>
554
         * @since 1.12.0
555
         */
556
        public static function setup_default_taxonomies( $args, $taxonomy ) {
154✔
557
                // Adds GraphQL support for categories.
558
                if ( 'category' === $taxonomy ) {
154✔
559
                        $args['show_in_graphql']     = true;
68✔
560
                        $args['graphql_single_name'] = 'category';
68✔
561
                        $args['graphql_plural_name'] = 'categories';
68✔
562
                } elseif ( 'post_tag' === $taxonomy ) { // Adds GraphQL support for tags.
154✔
563
                        $args['show_in_graphql']     = true;
68✔
564
                        $args['graphql_single_name'] = 'tag';
68✔
565
                        $args['graphql_plural_name'] = 'tags';
68✔
566
                } elseif ( 'post_format' === $taxonomy ) { // Adds GraphQL support for post formats.
154✔
567
                        $args['show_in_graphql']     = true;
68✔
568
                        $args['graphql_single_name'] = 'postFormat';
68✔
569
                        $args['graphql_plural_name'] = 'postFormats';
68✔
570
                }
571

572
                return $args;
154✔
573
        }
574

575
        /**
576
         * Set the GraphQL Post Type Args and pass them through a filter.
577
         *
578
         * @param array<string,mixed> $args           The graphql specific args for the post type
579
         * @param string              $post_type_name The name of the post type being registered
580
         *
581
         * @return array<string,mixed>
582
         * @throws \Exception
583
         * @since 1.12.0
584
         */
585
        public static function register_graphql_post_type_args( array $args, string $post_type_name ) {
141✔
586
                // Bail early if the post type is hidden from the WPGraphQL schema.
587
                if ( empty( $args['show_in_graphql'] ) ) {
141✔
588
                        return $args;
1✔
589
                }
590

591
                $graphql_args = self::get_default_graphql_type_args();
141✔
592

593
                /**
594
                 * Filters the graphql args set on a post type
595
                 *
596
                 * @param array<string,mixed> $args           The graphql specific args for the post type
597
                 * @param string              $post_type_name The name of the post type being registered
598
                 */
599
                $graphql_args = apply_filters( 'register_graphql_post_type_args', $graphql_args, $post_type_name );
141✔
600

601
                return wp_parse_args( $args, $graphql_args );
141✔
602
        }
603

604
        /**
605
         * Set the GraphQL Taxonomy Args and pass them through a filter.
606
         *
607
         * @param array<string,mixed> $args          The graphql specific args for the taxonomy
608
         * @param string              $taxonomy_name The name of the taxonomy being registered
609
         *
610
         * @return array<string,mixed>
611
         * @throws \Exception
612
         * @since 1.12.0
613
         */
614
        public static function register_graphql_taxonomy_args( array $args, string $taxonomy_name ) {
154✔
615
                // Bail early if the taxonomy  is hidden from the WPGraphQL schema.
616
                if ( empty( $args['show_in_graphql'] ) ) {
154✔
617
                        return $args;
68✔
618
                }
619

620
                $graphql_args = self::get_default_graphql_type_args();
154✔
621

622
                /**
623
                 * Filters the graphql args set on a taxonomy
624
                 *
625
                 * @param array<string,mixed> $args          The graphql specific args for the taxonomy
626
                 * @param string              $taxonomy_name The name of the taxonomy being registered
627
                 */
628
                $graphql_args = apply_filters( 'register_graphql_taxonomy_args', $graphql_args, $taxonomy_name );
154✔
629

630
                return wp_parse_args( $args, $graphql_args );
154✔
631
        }
632

633
        /**
634
         * This sets the post type /taxonomy GraphQL properties.
635
         *
636
         * @since 1.12.0
637
         *
638
         * @return array<string,mixed>
639
         */
640
        public static function get_default_graphql_type_args(): array {
176✔
641
                return [
176✔
642
                        // The "kind" of GraphQL type to register. Can be `interface`, `object`, or `union`.
643
                        'graphql_kind'                     => 'object',
176✔
644
                        // The callback used to resolve the type. Only used if `graphql_kind` is an `interface` or `union`.
645
                        'graphql_resolve_type'             => null,
176✔
646
                        // An array of custom interfaces the type should implement.
647
                        'graphql_interfaces'               => [],
176✔
648
                        // An array of default interfaces the type should exclude.
649
                        'graphql_exclude_interfaces'       => [],
176✔
650
                        // An array of custom connections the type should implement.
651
                        'graphql_connections'              => [],
176✔
652
                        // An array of default connection field names the type should exclude.
653
                        'graphql_exclude_connections'      => [],
176✔
654
                        // An array of possible type the union can resolve to. Only used if `graphql_kind` is a `union`.
655
                        'graphql_union_types'              => [],
176✔
656
                        // Whether to register default connections to the schema.
657
                        'graphql_register_root_field'      => true,
176✔
658
                        'graphql_register_root_connection' => true,
176✔
659
                ];
176✔
660
        }
661

662
        /**
663
         * Get the post types that are allowed to be used in GraphQL.
664
         * This gets all post_types that are set to show_in_graphql, but allows for external code
665
         * (plugins/theme) to filter the list of allowed_post_types to add/remove additional post_types
666
         *
667
         * @param string|mixed[]      $output Optional. The type of output to return. Accepts post type 'names' or 'objects'. Default 'names'.
668
         * @param array<string,mixed> $args   Optional. Arguments to filter allowed post types
669
         *
670
         * @return array<string,mixed>
671
         * @since  0.0.4
672
         * @since  1.8.1 adds $output as first param, and stores post type objects in class property.
673
         */
674
        public static function get_allowed_post_types( $output = 'names', $args = [] ) {
674✔
675
                // Support deprecated param order.
676
                if ( is_array( $output ) ) {
674✔
677
                        _deprecated_argument( __METHOD__, '1.8.1', '$args should be passed as the second parameter.' );
×
678
                        $args   = $output;
×
679
                        $output = 'names';
×
680
                }
681

682
                // Initialize array of allowed post type objects.
683
                if ( empty( self::$allowed_post_types ) ) {
674✔
684
                        /**
685
                         * Get all post types objects.
686
                         *
687
                         * @var \WP_Post_Type[] $post_type_objects
688
                         */
689
                        $post_type_objects = get_post_types(
593✔
690
                                [ 'show_in_graphql' => true ],
593✔
691
                                'objects'
593✔
692
                        );
593✔
693

694
                        $post_type_names = wp_list_pluck( $post_type_objects, 'name' );
593✔
695

696
                        /**
697
                         * Pass through a filter to allow the post_types to be modified.
698
                         * For example if a certain post_type should not be exposed to the GraphQL API.
699
                         *
700
                         * @param string[]        $post_type_names   Array of post type names.
701
                         * @param \WP_Post_Type[] $post_type_objects Array of post type objects.
702
                         *
703
                         * @since 1.8.1 add $post_type_objects parameter.
704
                         * @since 0.0.2
705
                         */
706
                        $allowed_post_type_names = apply_filters( 'graphql_post_entities_allowed_post_types', $post_type_names, $post_type_objects );
593✔
707

708
                        // Filter the post type objects if the list of allowed types have changed.
709
                        $post_type_objects = array_filter(
593✔
710
                                $post_type_objects,
593✔
711
                                static function ( $obj ) use ( $allowed_post_type_names ) {
593✔
712
                                        if ( empty( $obj->graphql_plural_name ) && ! empty( $obj->graphql_single_name ) ) {
593✔
713
                                                $obj->graphql_plural_name = $obj->graphql_single_name;
2✔
714
                                        }
715

716
                                        /**
717
                                         * Validate that the post_types have a graphql_single_name and graphql_plural_name
718
                                         */
719
                                        if ( empty( $obj->graphql_single_name ) || empty( $obj->graphql_plural_name ) ) {
593✔
720
                                                graphql_debug(
1✔
721
                                                        sprintf(
1✔
722
                                                        /* translators: %s will replaced with the registered type */
723
                                                                __( 'The "%s" post_type isn\'t configured properly to show in GraphQL. It needs a "graphql_single_name" and a "graphql_plural_name"', 'wp-graphql' ),
1✔
724
                                                                $obj->name
1✔
725
                                                        ),
1✔
726
                                                        [
1✔
727
                                                                'invalid_post_type' => $obj,
1✔
728
                                                        ]
1✔
729
                                                );
1✔
730
                                                return false;
1✔
731
                                        }
732

733
                                        return in_array( $obj->name, $allowed_post_type_names, true );
593✔
734
                                }
593✔
735
                        );
593✔
736

737
                        self::$allowed_post_types = $post_type_objects;
593✔
738
                }
739

740
                /**
741
                 * Filter the list of allowed post types either by the provided args or to only return an array of names.
742
                 */
743
                if ( ! empty( $args ) || 'names' === $output ) {
674✔
744
                        $field = 'names' === $output ? 'name' : false;
672✔
745

746
                        return wp_filter_object_list( self::$allowed_post_types, $args, 'and', $field );
672✔
747
                }
748

749
                return self::$allowed_post_types;
595✔
750
        }
751

752
        /**
753
         * Get the taxonomies that are allowed to be used in GraphQL.
754
         * This gets all taxonomies that are set to "show_in_graphql" but allows for external code
755
         * (plugins/themes) to filter the list of allowed_taxonomies to add/remove additional
756
         * taxonomies
757
         *
758
         * @param string              $output Optional. The type of output to return. Accepts taxonomy 'names' or 'objects'. Default 'names'.
759
         * @param array<string,mixed> $args   Optional. Arguments to filter allowed taxonomies.
760
         *
761
         * @return array<string,mixed>
762
         * @since  0.0.4
763
         */
764
        public static function get_allowed_taxonomies( $output = 'names', $args = [] ) {
607✔
765

766
                // Initialize array of allowed post type objects.
767
                if ( empty( self::$allowed_taxonomies ) ) {
607✔
768
                        /**
769
                         * Get all post types objects.
770
                         *
771
                         * @var \WP_Taxonomy[] $tax_objects
772
                         */
773
                        $tax_objects = get_taxonomies(
593✔
774
                                [ 'show_in_graphql' => true ],
593✔
775
                                'objects'
593✔
776
                        );
593✔
777

778
                        $tax_names = wp_list_pluck( $tax_objects, 'name' );
593✔
779

780
                        /**
781
                         * Pass through a filter to allow the taxonomies to be modified.
782
                         * For example if a certain taxonomy should not be exposed to the GraphQL API.
783
                         *
784
                         * @param string[]       $tax_names   Array of taxonomy names
785
                         * @param \WP_Taxonomy[] $tax_objects Array of taxonomy objects.
786
                         *
787
                         * @since 1.8.1 add $tax_names and $tax_objects parameters.
788
                         * @since 0.0.2
789
                         */
790
                        $allowed_tax_names = apply_filters( 'graphql_term_entities_allowed_taxonomies', $tax_names, $tax_objects );
593✔
791

792
                        $tax_objects = array_filter(
593✔
793
                                $tax_objects,
593✔
794
                                static function ( $obj ) use ( $allowed_tax_names ) {
593✔
795
                                        if ( empty( $obj->graphql_plural_name ) && ! empty( $obj->graphql_single_name ) ) {
593✔
796
                                                $obj->graphql_plural_name = $obj->graphql_single_name;
1✔
797
                                        }
798

799
                                        /**
800
                                         * Validate that the post_types have a graphql_single_name and graphql_plural_name
801
                                         */
802
                                        if ( empty( $obj->graphql_single_name ) || empty( $obj->graphql_plural_name ) ) {
593✔
803
                                                graphql_debug(
1✔
804
                                                        sprintf(
1✔
805
                                                        /* translators: %s will replaced with the registered taxonomty */
806
                                                                __( 'The "%s" taxonomy isn\'t configured properly to show in GraphQL. It needs a "graphql_single_name" and a "graphql_plural_name"', 'wp-graphql' ),
1✔
807
                                                                $obj->name
1✔
808
                                                        ),
1✔
809
                                                        [
1✔
810
                                                                'invalid_taxonomy' => $obj,
1✔
811
                                                        ]
1✔
812
                                                );
1✔
813
                                                return false;
1✔
814
                                        }
815

816
                                        return in_array( $obj->name, $allowed_tax_names, true );
593✔
817
                                }
593✔
818
                        );
593✔
819

820
                        self::$allowed_taxonomies = $tax_objects;
593✔
821
                }
822

823
                $taxonomies = self::$allowed_taxonomies;
607✔
824
                /**
825
                 * Filter the list of allowed taxonomies either by the provided args or to only return an array of names.
826
                 */
827
                if ( ! empty( $args ) || 'names' === $output ) {
607✔
828
                        $field = 'names' === $output ? 'name' : false;
604✔
829

830
                        $taxonomies = wp_filter_object_list( $taxonomies, $args, 'and', $field );
604✔
831
                }
832

833
                return $taxonomies;
607✔
834
        }
835

836
        /**
837
         * Allow Schema to be cleared
838
         *
839
         * @return void
840
         */
841
        public static function clear_schema() {
599✔
842
                self::$type_registry      = null;
599✔
843
                self::$schema             = null;
599✔
844
                self::$allowed_post_types = null;
599✔
845
                self::$allowed_taxonomies = null;
599✔
846
        }
847

848
        /**
849
         * Returns the Schema as defined by static registrations throughout
850
         * the WP Load.
851
         *
852
         * @return \WPGraphQL\WPSchema
853
         *
854
         * @throws \Exception
855
         */
856
        public static function get_schema() {
754✔
857
                if ( null === self::$schema ) {
754✔
858
                        $schema_registry = new SchemaRegistry();
593✔
859
                        $schema          = $schema_registry->get_schema();
593✔
860

861
                        /**
862
                         * Generate & Filter the schema.
863
                         *
864
                         * @param \WPGraphQL\WPSchema $schema The executable Schema that GraphQL executes against
865
                         * @param \WPGraphQL\AppContext $app_context Object The AppContext object containing all of the
866
                         * information about the context we know at this point
867
                         *
868
                         * @since 0.0.5
869
                         */
870
                        self::$schema = apply_filters( 'graphql_schema', $schema, self::get_app_context() );
593✔
871
                }
872

873
                /**
874
                 * Fire an action when the Schema is returned
875
                 */
876
                do_action( 'graphql_get_schema', self::$schema );
754✔
877

878
                /**
879
                 * Return the Schema after applying filters
880
                 */
881
                return ! empty( self::$schema ) ? self::$schema : null;
754✔
882
        }
883

884
        /**
885
         * Whether WPGraphQL is operating in Debug mode
886
         */
887
        public static function debug(): bool {
754✔
888
                if ( defined( 'GRAPHQL_DEBUG' ) ) {
754✔
889
                        $enabled = (bool) GRAPHQL_DEBUG;
754✔
890
                } else {
891
                        $enabled = get_graphql_setting( 'debug_mode_enabled', 'off' );
×
892
                        $enabled = 'on' === $enabled;
×
893
                }
894

895
                /**
896
                 * @param bool $enabled Whether GraphQL Debug is enabled or not
897
                 */
898
                return (bool) apply_filters( 'graphql_debug_enabled', $enabled );
754✔
899
        }
900

901
        /**
902
         * Returns the Schema as defined by static registrations throughout
903
         * the WP Load.
904
         *
905
         * @return \WPGraphQL\Registry\TypeRegistry
906
         *
907
         * @throws \Exception
908
         */
909
        public static function get_type_registry() {
756✔
910
                if ( null === self::$type_registry ) {
756✔
911
                        $type_registry = new TypeRegistry();
595✔
912

913
                        /**
914
                         * Generate & Filter the schema.
915
                         *
916
                         * @param \WPGraphQL\Registry\TypeRegistry $type_registry The TypeRegistry for the API
917
                         * @param \WPGraphQL\AppContext $app_context Object The AppContext object containing all of the
918
                         * information about the context we know at this point
919
                         *
920
                         * @since 0.0.5
921
                         */
922
                        self::$type_registry = apply_filters( 'graphql_type_registry', $type_registry, self::get_app_context() );
595✔
923
                }
924

925
                /**
926
                 * Fire an action when the Type Registry is returned
927
                 */
928
                do_action( 'graphql_get_type_registry', self::$type_registry );
756✔
929

930
                /**
931
                 * Return the Schema after applying filters
932
                 */
933
                return ! empty( self::$type_registry ) ? self::$type_registry : null;
756✔
934
        }
935

936
        /**
937
         * Return the static schema if there is one
938
         *
939
         * @return ?string
940
         */
941
        public static function get_static_schema() {
1✔
942
                $schema_file = WPGRAPHQL_PLUGIN_DIR . 'schema.graphql';
1✔
943

944
                if ( ! file_exists( $schema_file ) ) {
1✔
945
                        return null;
×
946
                }
947

948
                $schema = file_get_contents( WPGRAPHQL_PLUGIN_DIR . 'schema.graphql' );
1✔
949

950
                return ! empty( $schema ) ? $schema : null;
1✔
951
        }
952

953
        /**
954
         * Get the AppContext for use in passing down the Resolve Tree
955
         *
956
         * @return \WPGraphQL\AppContext
957
         */
958
        public static function get_app_context() {
756✔
959
                /**
960
                 * Configure the app_context which gets passed down to all the resolvers.
961
                 *
962
                 * @since 0.0.4
963
                 */
964
                $app_context           = new AppContext();
756✔
965
                $app_context->viewer   = wp_get_current_user();
756✔
966
                $app_context->root_url = get_bloginfo( 'url' );
756✔
967
                $app_context->request  = ! empty( $_REQUEST ) ? $_REQUEST : null; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
756✔
968

969
                return $app_context;
756✔
970
        }
971
}
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