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

wp-graphql / wp-graphql / 17562196906

08 Sep 2025 07:44PM UTC coverage: 84.575% (+0.4%) from 84.17%
17562196906

push

github

web-flow
Merge pull request #3389 from wp-graphql/develop

release: next version 📦

238 of 308 new or added lines in 13 files covered. (77.27%)

6 existing lines in 6 files now uncovered.

15884 of 18781 relevant lines covered (84.57%)

261.69 hits per line

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

58.7
/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\Utils\InstrumentSchema;
14
use WPGraphQL\Utils\Preview;
15

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

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

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

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

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

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

61
        /**
62
         * Whether a GraphQL request is currently being processed.
63
         */
64
        protected static bool $is_graphql_request = false;
65

66
        /**
67
         * Whether an Introspection query is currently being processed.
68
         */
69
        protected static bool $is_introspection_query = false;
70

71
        /**
72
         * The instance of the WPGraphQL object
73
         *
74
         * @return \WPGraphQL - The one true WPGraphQL
75
         * @since  0.0.1
76
         */
77
        public static function instance(): self {
3✔
78
                if ( ! isset( self::$instance ) ) {
3✔
79
                        self::$instance = new self();
×
80
                        self::$instance->setup_constants();
×
81
                        self::$instance->includes();
×
82
                        self::$instance->actions();
×
83
                        self::$instance->filters();
×
84
                        self::$instance->upgrade();
×
NEW
85
                        self::$instance->deprecated();
×
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
         */
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
         */
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
         * @since  0.0.1
122
         */
123
        private function setup_constants(): void {
×
124
                graphql_setup_constants();
×
125
        }
126

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

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

145
        /**
146
         * Whether the request is a graphql request or not
147
         */
148
        public static function is_graphql_request(): bool {
757✔
149
                return self::$is_graphql_request;
757✔
150
        }
151

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

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

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

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

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

203
                // Prevent WPGraphQL Insights from running
204
                remove_action( 'init', '\WPGraphQL\Extensions\graphql_insights_init' );
×
205

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

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

224
                // Determine what to show in graphql
225
                add_action( 'init_graphql_request', 'register_initial_settings', 10 );
×
226

227
                // Throw an exception
228
                add_action( 'do_graphql_request', [ $this, 'min_php_version_check' ] );
×
229
                add_action( 'do_graphql_request', [ $this, 'introspection_check' ], 10, 4 );
×
230

231
                // Initialize Admin functionality
232
                add_action( 'after_setup_theme', [ $this, 'init_admin' ] );
×
233

234
                add_action(
779✔
235
                        'init_graphql_request',
779✔
236
                        static function () {
779✔
237
                                $tracing = new \WPGraphQL\Utils\Tracing();
779✔
238
                                $tracing->init();
779✔
239

240
                                $query_log = new \WPGraphQL\Utils\QueryLog();
779✔
241
                                $query_log->init();
779✔
242
                        }
779✔
243
                );
779✔
244

245
                // Initialize Update functionality.
246
                ( new \WPGraphQL\Admin\Updates\Updates() )->init();
×
247
        }
248

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

262
                if ( empty( $query ) ) {
773✔
263
                        return;
1✔
264
                }
265

266
                $ast              = \GraphQL\Language\Parser::parse( $query );
772✔
267
                $is_introspection = false;
771✔
268

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

281
                self::set_is_introspection_query( $is_introspection );
771✔
282
        }
283

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

307
        /**
308
         * Sets up the plugin url
309
         */
310
        public function setup_plugin_url(): void {
×
311
                // Plugin Folder URL.
312
                if ( ! defined( 'WPGRAPHQL_PLUGIN_URL' ) ) {
×
313
                        define( 'WPGRAPHQL_PLUGIN_URL', plugin_dir_url( dirname( __DIR__ ) . '/wp-graphql.php' ) );
×
314
                }
315
        }
316

317
        /**
318
         * Determine the post_types and taxonomies, etc that should show in GraphQL.
319
         */
320
        public function setup_types(): void {
×
321
                /**
322
                 * Set up the settings, post_types and taxonomies to show_in_graphql
323
                 */
324
                self::show_in_graphql();
×
325
        }
326

327
        /**
328
         * Flush permalinks if the GraphQL Endpoint route isn't yet registered.
329
         */
330
        public function maybe_flush_permalinks(): void {
×
331
                $rules = get_option( 'rewrite_rules' );
×
332
                if ( ! isset( $rules[ graphql_get_endpoint() . '/?$' ] ) ) {
×
333
                        flush_rewrite_rules(); // phpcs:ignore WordPressVIPMinimum.Functions.RestrictedFunctions.flush_rewrite_rules_flush_rewrite_rules
×
334
                }
335
        }
336

337
        /**
338
         * Setup filters
339
         */
UNCOV
340
        private function filters(): void {
×
341
                // Filter the post_types and taxonomies to show in the GraphQL Schema
342
                $this->setup_types();
×
343

344
                /**
345
                 * Instrument the Schema to provide Resolve Hooks and sanitize Schema output
346
                 */
347
                add_filter(
×
348
                        'graphql_get_type',
×
349
                        [
×
350
                                InstrumentSchema::class,
×
351
                                'instrument_resolvers',
×
352
                        ],
×
353
                        10,
×
354
                        2
×
355
                );
×
356

357
                // Filter how metadata is retrieved during GraphQL requests
358
                add_filter(
×
359
                        'get_post_metadata',
×
360
                        [
×
361
                                Preview::class,
×
362
                                'filter_post_meta_for_previews',
×
363
                        ],
×
364
                        10,
×
365
                        4
×
366
                );
×
367

368
                /**
369
                 * Prevent WPML from redirecting within WPGraphQL requests
370
                 *
371
                 * @see https://github.com/wp-graphql/wp-graphql/issues/1626#issue-769089073
372
                 * @since 1.27.0
373
                 */
374
                add_filter(
×
375
                        'wpml_is_redirected',
×
376
                        static function ( bool $is_redirect ) {
×
377
                                if ( is_graphql_request() ) {
×
378
                                        return false;
×
379
                                }
380
                                return $is_redirect;
×
381
                        },
×
382
                        10,
×
383
                        1
×
384
                );
×
385
        }
386

387
        /**
388
         * Private function to register deprecated functionality.
389
         */
NEW
390
        private function deprecated(): void {
×
NEW
391
                $deprecated = new WPGraphQL\Deprecated();
×
NEW
392
                $deprecated->register();
×
393
        }
394

395
        /**
396
         * Upgrade routine.
397
         */
398
        public function upgrade(): void {
×
399
                $version = get_option( 'wp_graphql_version', null );
×
400

401
                // If the version is not set, this is a fresh install, not an update.
402
                // set the version and return.
403
                if ( ! $version ) {
×
404
                        update_option( 'wp_graphql_version', WPGRAPHQL_VERSION );
×
405
                        return;
×
406
                }
407

408
                // If the version is less than the current version, run the update routine
409
                if ( version_compare( $version, WPGRAPHQL_VERSION, '<' ) ) {
×
410
                        $this->run_update_routines( $version );
×
411
                        update_option( 'wp_graphql_version', WPGRAPHQL_VERSION );
×
412
                }
413
        }
414

415
        /**
416
         * Executes update routines based on the previously stored version.
417
         *
418
         * This triggers an action that passes the previous version and new version and allows for specific actions or
419
         * modifications needed to bring installations up-to-date with the current plugin version.
420
         *
421
         * Each update routine (callback that hooks into "graphql_do_update_routine") should handle backward compatibility as gracefully as possible.
422
         *
423
         * @since 1.2.3
424
         * @param string|null $stored_version The version number currently stored in the database.
425
         *                                    Null if no version has been previously stored.
426
         */
427
        public function run_update_routines( ?string $stored_version = null ): void {
×
428

429
                // bail if the stored version is empty, or the WPGRAPHQL_VERSION constant is not set
430
                if ( ! defined( 'WPGRAPHQL_VERSION' ) || ! $stored_version ) {
×
431
                        return;
×
432
                }
433

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

437
                        // Clear the extensions cache
438
                        $this->clear_extensions_cache();
×
439

440
                        /**
441
                         * Fires the update routine.
442
                         *
443
                         * @param string $stored_version The version number currently stored in the database.
444
                         * @param string $new_version    The version number of the current plugin.
445
                         */
446
                        do_action( 'graphql_do_update_routine', $stored_version, WPGRAPHQL_VERSION );
×
447
                }
448
        }
449

450
        /**
451
         * Clear all caches in the "wpgraphql_extensions" cache group.
452
         */
453
        public function clear_extensions_cache(): void {
×
454
                global $wp_object_cache;
×
455

456
                if ( isset( $wp_object_cache->cache['wpgraphql_extensions'] ) ) {
×
457
                        foreach ( $wp_object_cache->cache['wpgraphql_extensions'] as $key => $value ) {
×
458
                                wp_cache_delete( $key, 'wpgraphql_extensions' );
×
459
                        }
460
                }
461
        }
462

463
        /**
464
         * Initialize admin functionality.
465
         */
466
        public function init_admin(): void {
×
467
                $admin = new Admin();
×
468
                $admin->init();
×
469
        }
470

471
        /**
472
         * This sets up built-in post_types and taxonomies to show in the GraphQL Schema.
473
         *
474
         * @since  0.0.2
475
         */
476
        public static function show_in_graphql(): void {
14✔
477
                add_filter( 'register_post_type_args', [ self::class, 'setup_default_post_types' ], 10, 2 );
14✔
478
                add_filter( 'register_taxonomy_args', [ self::class, 'setup_default_taxonomies' ], 10, 2 );
14✔
479

480
                // Run late so the user can filter the args themselves.
481
                add_filter( 'register_post_type_args', [ self::class, 'register_graphql_post_type_args' ], 99, 2 );
14✔
482
                add_filter( 'register_taxonomy_args', [ self::class, 'register_graphql_taxonomy_args' ], 99, 2 );
14✔
483
        }
484

485
        /**
486
         * Sets up the default post types to show_in_graphql.
487
         *
488
         * @param array<string,mixed> $args      Array of arguments for registering a post type.
489
         * @param string              $post_type Post type key.
490
         *
491
         * @return array<string,mixed>
492
         */
493
        public static function setup_default_post_types( $args, $post_type ) {
142✔
494
                // Adds GraphQL support for attachments.
495
                if ( 'attachment' === $post_type ) {
142✔
496
                        $args['show_in_graphql']     = true;
×
497
                        $args['graphql_single_name'] = 'mediaItem';
×
498
                        $args['graphql_plural_name'] = 'mediaItems';
×
499
                        $args['graphql_description'] = __( 'Represents uploaded media, including images, videos, documents, and audio files.', 'wp-graphql' );
×
500
                } elseif ( 'page' === $post_type ) { // Adds GraphQL support for pages.
142✔
501
                        $args['show_in_graphql']     = true;
×
502
                        $args['graphql_single_name'] = 'page';
×
503
                        $args['graphql_plural_name'] = 'pages';
×
504
                        $args['graphql_description'] = __( 'A standalone content entry generally used for static, non-chronological content such as "About Us" or "Contact" pages.', 'wp-graphql' );
×
505
                } elseif ( 'post' === $post_type ) { // Adds GraphQL support for posts.
142✔
506
                        $args['show_in_graphql']     = true;
×
507
                        $args['graphql_single_name'] = 'post';
×
508
                        $args['graphql_plural_name'] = 'posts';
×
509
                        $args['graphql_description'] = __( 'A chronological content entry typically used for blog posts, news articles, or similar date-based content.', 'wp-graphql' );
×
510
                }
511

512
                return $args;
142✔
513
        }
514

515
        /**
516
         * Sets up the default taxonomies to show_in_graphql.
517
         *
518
         * @param array<string,mixed> $args     Array of arguments for registering a taxonomy.
519
         * @param string              $taxonomy Taxonomy key.
520
         *
521
         * @return array<string,mixed>
522
         * @since 1.12.0
523
         */
524
        public static function setup_default_taxonomies( $args, $taxonomy ) {
155✔
525
                // Adds GraphQL support for categories.
526
                if ( 'category' === $taxonomy ) {
155✔
527
                        $args['show_in_graphql']     = true;
68✔
528
                        $args['graphql_single_name'] = 'category';
68✔
529
                        $args['graphql_plural_name'] = 'categories';
68✔
530
                        $args['graphql_description'] = __( 'A taxonomy term that classifies content. Categories support hierarchy and can be used to create a nested structure.', 'wp-graphql' );
68✔
531
                } elseif ( 'post_tag' === $taxonomy ) { // Adds GraphQL support for tags.
155✔
532
                        $args['show_in_graphql']     = true;
68✔
533
                        $args['graphql_single_name'] = 'tag';
68✔
534
                        $args['graphql_plural_name'] = 'tags';
68✔
535
                        $args['graphql_description'] = __( 'A taxonomy term used to organize and classify content. Tags do not have a hierarchy and are generally used for more specific classifications.', 'wp-graphql' );
68✔
536
                } elseif ( 'post_format' === $taxonomy ) { // Adds GraphQL support for post formats.
155✔
537
                        $args['show_in_graphql']     = true;
68✔
538
                        $args['graphql_single_name'] = 'postFormat';
68✔
539
                        $args['graphql_plural_name'] = 'postFormats';
68✔
540
                        $args['graphql_description'] = __( 'A standardized classification system for content presentation styles. These formats can be used to display content differently based on type, such as "standard", "gallery", "video", etc.', 'wp-graphql' );
68✔
541
                }
542

543
                return $args;
155✔
544
        }
545

546
        /**
547
         * Set the GraphQL Post Type Args and pass them through a filter.
548
         *
549
         * @param array<string,mixed> $args           The graphql specific args for the post type
550
         * @param string              $post_type_name The name of the post type being registered
551
         *
552
         * @return array<string,mixed>
553
         * @throws \Exception
554
         * @since 1.12.0
555
         */
556
        public static function register_graphql_post_type_args( array $args, string $post_type_name ): array {
142✔
557
                // Bail early if the post type is hidden from the WPGraphQL schema.
558
                if ( empty( $args['show_in_graphql'] ) ) {
142✔
559
                        return $args;
1✔
560
                }
561

562
                $graphql_args = self::get_default_graphql_type_args();
142✔
563

564
                /**
565
                 * Filters the graphql args set on a post type
566
                 *
567
                 * @param array<string,mixed> $args           The graphql specific args for the post type
568
                 * @param string              $post_type_name The name of the post type being registered
569
                 */
570
                $graphql_args = apply_filters( 'register_graphql_post_type_args', $graphql_args, $post_type_name );
142✔
571

572
                return wp_parse_args( $args, $graphql_args );
142✔
573
        }
574

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

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

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

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

604
        /**
605
         * This sets the post type /taxonomy GraphQL properties.
606
         *
607
         * @since 1.12.0
608
         *
609
         * @return array{
610
         *   graphql_kind: 'interface'|'object'|'union',
611
         *   graphql_resolve_type: ?callable,
612
         *   graphql_interfaces: string[],
613
         *   graphql_connections: string[],
614
         *   graphql_union_types: string[],
615
         *   graphql_register_root_field: bool,
616
         *   graphql_register_root_connection: bool,
617
         * }
618
         */
619
        public static function get_default_graphql_type_args(): array {
177✔
620
                return [
177✔
621
                        // The "kind" of GraphQL type to register. Can be `interface`, `object`, or `union`.
622
                        'graphql_kind'                     => 'object',
177✔
623
                        // The callback used to resolve the type. Only used if `graphql_kind` is an `interface` or `union`.
624
                        'graphql_resolve_type'             => null,
177✔
625
                        // An array of custom interfaces the type should implement.
626
                        'graphql_interfaces'               => [],
177✔
627
                        // An array of default interfaces the type should exclude.
628
                        'graphql_exclude_interfaces'       => [],
177✔
629
                        // An array of custom connections the type should implement.
630
                        'graphql_connections'              => [],
177✔
631
                        // An array of default connection field names the type should exclude.
632
                        'graphql_exclude_connections'      => [],
177✔
633
                        // An array of possible type the union can resolve to. Only used if `graphql_kind` is a `union`.
634
                        'graphql_union_types'              => [],
177✔
635
                        // Whether to register default connections to the schema.
636
                        'graphql_register_root_field'      => true,
177✔
637
                        'graphql_register_root_connection' => true,
177✔
638
                ];
177✔
639
        }
640

641
        /**
642
         * Get the post types that are allowed to be used in GraphQL.
643
         *
644
         * This gets all post_types that are set to show_in_graphql, but allows for external code
645
         * (plugins/theme) to filter the list of allowed_post_types to add/remove additional post_types
646
         *
647
         * @param 'names'|'objects'   $output Optional. The type of output to return. Accepts post type 'names' or 'objects'. Default 'names'.
648
         * @param array<string,mixed> $args   Optional. Arguments to filter allowed post types
649
         *
650
         * @return string[]|\WP_Post_Type[]
651
         * @phpstan-return ( $output is 'objects' ? \WP_Post_Type[] : string[] )
652
         *
653
         * @since  0.0.4
654
         * @since  1.8.1 adds $output as first param, and stores post type objects in class property.
655
         */
656
        public static function get_allowed_post_types( $output = 'names', $args = [] ): array {
686✔
657
                // Support deprecated param order.
658
                if ( is_array( $output ) ) {
686✔
NEW
659
                        _deprecated_argument( __METHOD__, '1.8.1', 'Passing `$args` to the first parameter will no longer be supported in the next major version of WPGraphQL.' );
×
660
                        $args   = $output;
×
661
                        $output = 'names';
×
662
                }
663

664
                // Initialize array of allowed post type objects.
665
                if ( empty( self::$allowed_post_types ) ) {
686✔
666
                        /**
667
                         * Get all post types objects.
668
                         *
669
                         * @var \WP_Post_Type[] $post_type_objects
670
                         */
671
                        $post_type_objects = get_post_types(
602✔
672
                                [ 'show_in_graphql' => true ],
602✔
673
                                'objects'
602✔
674
                        );
602✔
675

676
                        $post_type_names = wp_list_pluck( $post_type_objects, 'name' );
602✔
677

678
                        /**
679
                         * Pass through a filter to allow the post_types to be modified.
680
                         * For example if a certain post_type should not be exposed to the GraphQL API.
681
                         *
682
                         * @param string[]        $post_type_names   Array of post type names.
683
                         * @param \WP_Post_Type[] $post_type_objects Array of post type objects.
684
                         *
685
                         * @since 1.8.1 add $post_type_objects parameter.
686
                         * @since 0.0.2
687
                         */
688
                        $allowed_post_type_names = apply_filters( 'graphql_post_entities_allowed_post_types', $post_type_names, $post_type_objects );
602✔
689

690
                        // Filter the post type objects if the list of allowed types have changed.
691
                        $post_type_objects = array_filter(
602✔
692
                                $post_type_objects,
602✔
693
                                static function ( $obj ) use ( $allowed_post_type_names ) {
602✔
694
                                        if ( empty( $obj->graphql_plural_name ) && ! empty( $obj->graphql_single_name ) ) {
602✔
695
                                                $obj->graphql_plural_name = $obj->graphql_single_name;
2✔
696
                                        }
697

698
                                        /**
699
                                         * Validate that the post_types have a graphql_single_name and graphql_plural_name
700
                                         */
701
                                        if ( empty( $obj->graphql_single_name ) || empty( $obj->graphql_plural_name ) ) {
602✔
702
                                                graphql_debug(
1✔
703
                                                        sprintf(
1✔
704
                                                        /* translators: %s will replaced with the registered type */
705
                                                                __( '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✔
706
                                                                $obj->name
1✔
707
                                                        ),
1✔
708
                                                        [
1✔
709
                                                                'invalid_post_type' => $obj,
1✔
710
                                                        ]
1✔
711
                                                );
1✔
712
                                                return false;
1✔
713
                                        }
714

715
                                        return in_array( $obj->name, $allowed_post_type_names, true );
602✔
716
                                }
602✔
717
                        );
602✔
718

719
                        self::$allowed_post_types = $post_type_objects;
602✔
720
                }
721

722
                /**
723
                 * Filter the list of allowed post types either by the provided args or to only return an array of names.
724
                 */
725
                if ( ! empty( $args ) || 'names' === $output ) {
686✔
726
                        $field = 'names' === $output ? 'name' : false;
684✔
727

728
                        return wp_filter_object_list( self::$allowed_post_types, $args, 'and', $field );
684✔
729
                }
730

731
                return self::$allowed_post_types;
604✔
732
        }
733

734
        /**
735
         * Get the taxonomies that are allowed to be used in GraphQL.
736
         * This gets all taxonomies that are set to "show_in_graphql" but allows for external code
737
         * (plugins/themes) to filter the list of allowed_taxonomies to add/remove additional
738
         * taxonomies
739
         *
740
         * @param 'names'|'objects'   $output Optional. The type of output to return. Accepts taxonomy 'names' or 'objects'. Default 'names'.
741
         * @param array<string,mixed> $args   Optional. Arguments to filter allowed taxonomies.
742
         *
743
         * @return string[]|\WP_Taxonomy[]
744
         * @phpstan-return ( $output is 'objects' ? \WP_Taxonomy[] : string[] )
745
         * @since  0.0.4
746
         */
747
        public static function get_allowed_taxonomies( $output = 'names', $args = [] ): array {
617✔
748

749
                // Initialize array of allowed post type objects.
750
                if ( empty( self::$allowed_taxonomies ) ) {
617✔
751
                        /**
752
                         * Get all post types objects.
753
                         *
754
                         * @var \WP_Taxonomy[] $tax_objects
755
                         */
756
                        $tax_objects = get_taxonomies(
602✔
757
                                [ 'show_in_graphql' => true ],
602✔
758
                                'objects'
602✔
759
                        );
602✔
760

761
                        $tax_names = wp_list_pluck( $tax_objects, 'name' );
602✔
762

763
                        /**
764
                         * Pass through a filter to allow the taxonomies to be modified.
765
                         * For example if a certain taxonomy should not be exposed to the GraphQL API.
766
                         *
767
                         * @param string[]       $tax_names   Array of taxonomy names
768
                         * @param \WP_Taxonomy[] $tax_objects Array of taxonomy objects.
769
                         *
770
                         * @since 1.8.1 add $tax_names and $tax_objects parameters.
771
                         * @since 0.0.2
772
                         */
773
                        $allowed_tax_names = apply_filters( 'graphql_term_entities_allowed_taxonomies', $tax_names, $tax_objects );
602✔
774

775
                        $tax_objects = array_filter(
602✔
776
                                $tax_objects,
602✔
777
                                static function ( $obj ) use ( $allowed_tax_names ) {
602✔
778
                                        if ( empty( $obj->graphql_plural_name ) && ! empty( $obj->graphql_single_name ) ) {
602✔
779
                                                $obj->graphql_plural_name = $obj->graphql_single_name;
1✔
780
                                        }
781

782
                                        /**
783
                                         * Validate that the post_types have a graphql_single_name and graphql_plural_name
784
                                         */
785
                                        if ( empty( $obj->graphql_single_name ) || empty( $obj->graphql_plural_name ) ) {
602✔
786
                                                graphql_debug(
1✔
787
                                                        sprintf(
1✔
788
                                                        /* translators: %s will replaced with the registered taxonomy */
789
                                                                __( '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✔
790
                                                                $obj->name
1✔
791
                                                        ),
1✔
792
                                                        [
1✔
793
                                                                'invalid_taxonomy' => $obj,
1✔
794
                                                        ]
1✔
795
                                                );
1✔
796
                                                return false;
1✔
797
                                        }
798

799
                                        return in_array( $obj->name, $allowed_tax_names, true );
602✔
800
                                }
602✔
801
                        );
602✔
802

803
                        self::$allowed_taxonomies = $tax_objects;
602✔
804
                }
805

806
                $taxonomies = self::$allowed_taxonomies;
617✔
807
                /**
808
                 * Filter the list of allowed taxonomies either by the provided args or to only return an array of names.
809
                 */
810
                if ( ! empty( $args ) || 'names' === $output ) {
617✔
811
                        $field = 'names' === $output ? 'name' : false;
613✔
812

813
                        $taxonomies = wp_filter_object_list( $taxonomies, $args, 'and', $field );
613✔
814
                }
815

816
                return $taxonomies;
617✔
817
        }
818

819
        /**
820
         * Allow Schema to be cleared.
821
         */
822
        public static function clear_schema(): void {
608✔
823
                self::$type_registry      = null;
608✔
824
                self::$schema             = null;
608✔
825
                self::$allowed_post_types = null;
608✔
826
                self::$allowed_taxonomies = null;
608✔
827
        }
828

829
        /**
830
         * Returns the Schema as defined by static registrations throughout
831
         * the WP Load.
832
         *
833
         * @return \WPGraphQL\WPSchema
834
         *
835
         * @throws \Exception
836
         */
837
        public static function get_schema() {
779✔
838
                if ( ! isset( self::$schema ) ) {
779✔
839
                        $schema_registry = new SchemaRegistry();
602✔
840
                        $schema          = $schema_registry->get_schema();
602✔
841

842
                        /**
843
                         * Generate & Filter the schema.
844
                         *
845
                         * @param \WPGraphQL\WPSchema $schema The executable Schema that GraphQL executes against
846
                         * @param \WPGraphQL\AppContext $app_context Object The AppContext object containing all of the
847
                         * information about the context we know at this point
848
                         *
849
                         * @since 0.0.5
850
                         */
851
                        self::$schema = apply_filters( 'graphql_schema', $schema, self::get_app_context() );
602✔
852
                }
853

854
                /**
855
                 * Fire an action when the Schema is returned
856
                 */
857
                do_action( 'graphql_get_schema', self::$schema );
779✔
858

859
                /**
860
                 * Return the Schema after applying filters
861
                 */
862
                return self::$schema;
779✔
863
        }
864

865
        /**
866
         * Whether WPGraphQL is operating in Debug mode
867
         */
868
        public static function debug(): bool {
780✔
869
                if ( defined( 'GRAPHQL_DEBUG' ) ) {
780✔
870
                        $enabled = (bool) GRAPHQL_DEBUG;
780✔
871
                } else {
872
                        $enabled = get_graphql_setting( 'debug_mode_enabled', 'off' );
×
873
                        $enabled = 'on' === $enabled;
×
874
                }
875

876
                /**
877
                 * @param bool $enabled Whether GraphQL Debug is enabled or not
878
                 */
879
                return (bool) apply_filters( 'graphql_debug_enabled', $enabled );
780✔
880
        }
881

882
        /**
883
         * Returns the type registry, instantiating it if it doesn't exist.
884
         *
885
         * @return \WPGraphQL\Registry\TypeRegistry
886
         *
887
         * @throws \Exception
888
         */
889
        public static function get_type_registry() {
781✔
890
                if ( ! isset( self::$type_registry ) ) {
781✔
891
                        $type_registry = new TypeRegistry();
604✔
892

893
                        /**
894
                         * Generate & Filter the schema.
895
                         *
896
                         * @param \WPGraphQL\Registry\TypeRegistry $type_registry The TypeRegistry for the API
897
                         * @param \WPGraphQL\AppContext $app_context Object The AppContext object containing all of the
898
                         * information about the context we know at this point
899
                         *
900
                         * @since 0.0.5
901
                         */
902
                        self::$type_registry = apply_filters( 'graphql_type_registry', $type_registry, self::get_app_context() );
604✔
903
                }
904

905
                /**
906
                 * Fire an action when the Type Registry is returned
907
                 */
908
                do_action( 'graphql_get_type_registry', self::$type_registry );
781✔
909

910
                /**
911
                 * Return the Schema after applying filters
912
                 */
913
                return self::$type_registry;
781✔
914
        }
915

916
        /**
917
         * Return the static schema if there is one.
918
         */
919
        public static function get_static_schema(): ?string {
1✔
920
                $schema_file = WPGRAPHQL_PLUGIN_DIR . 'schema.graphql';
1✔
921

922
                if ( ! file_exists( $schema_file ) ) {
1✔
923
                        return null;
×
924
                }
925

926
                $schema = file_get_contents( WPGRAPHQL_PLUGIN_DIR . 'schema.graphql' );
1✔
927

928
                return ! empty( $schema ) ? $schema : null;
1✔
929
        }
930

931
        /**
932
         * Get the AppContext for use in passing down the Resolve Tree
933
         */
934
        public static function get_app_context(): AppContext {
781✔
935
                /**
936
                 * Configure the app_context which gets passed down to all the resolvers.
937
                 *
938
                 * @since 0.0.4
939
                 */
940
                $app_context           = new AppContext();
781✔
941
                $app_context->viewer   = wp_get_current_user();
781✔
942
                $app_context->root_url = get_bloginfo( 'url' );
781✔
943
                $app_context->request  = ! empty( $_REQUEST ) ? $_REQUEST : null; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
781✔
944

945
                return $app_context;
781✔
946
        }
947
}
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