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

wp-graphql / wp-graphql / 14716683875

28 Apr 2025 07:58PM UTC coverage: 84.287% (+1.6%) from 82.648%
14716683875

push

github

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

15905 of 18870 relevant lines covered (84.29%)

257.23 hits per line

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

58.84
/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 self $instance;
31

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

39
        /**
40
         * Holds the TypeRegistry instance
41
         *
42
         * @var ?\WPGraphQL\Registry\TypeRegistry $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 ?array $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 ?array $allowed_taxonomies;
61

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

67
        /**
68
         * Whether an Introspection query is currently being processed.
69
         */
70
        protected static bool $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(): self {
3✔
79
                if ( ! isset( self::$instance ) ) {
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
         */
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 {
758✔
142
                self::$is_graphql_request = $is_graphql_request;
758✔
143
        }
144

145
        /**
146
         * Whether the request is a graphql request or not
147
         */
148
        public static function is_graphql_request(): bool {
732✔
149
                return self::$is_graphql_request;
732✔
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 {
746✔
160
                self::$is_introspection_query = $is_introspection_query;
746✔
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 {
606✔
169
                return (bool) self::$is_introspection_query;
606✔
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 {
754✔
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(
754✔
235
                        'init_graphql_request',
754✔
236
                        static function () {
754✔
237
                                $tracing = new \WPGraphQL\Utils\Tracing();
754✔
238
                                $tracing->init();
754✔
239

240
                                $query_log = new \WPGraphQL\Utils\QueryLog();
754✔
241
                                $query_log->init();
754✔
242
                        }
754✔
243
                );
754✔
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 {
748✔
261

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

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

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

281
                self::set_is_introspection_query( $is_introspection );
746✔
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 {
748✔
293
                if ( defined( 'GRAPHQL_MIN_PHP_VERSION' ) && version_compare( PHP_VERSION, GRAPHQL_MIN_PHP_VERSION, '<' ) ) {
748✔
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
         */
340
        private function filters(): void {
619✔
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
                 * Adds back compat support for the `graphql_object_type_interfaces` filter which was renamed
370
                 * to support both ObjectTypes and InterfaceTypes
371
                 *
372
                 * @deprecated
373
                 */
374
                add_filter(
×
375
                        'graphql_type_interfaces',
×
376
                        static function ( $interfaces, $config, $type ) {
×
377
                                if ( $type instanceof WPObjectType ) {
619✔
378
                                        /**
379
                                         * Filters the interfaces applied to an object type
380
                                         *
381
                                         * @param string[]                                                     $interfaces List of interfaces applied to the Object Type
382
                                         * @param array<string,mixed>                                          $config     The config for the Object Type
383
                                         * @param \WPGraphQL\Type\WPInterfaceType|\WPGraphQL\Type\WPObjectType $type       The Type instance
384
                                         */
385
                                        return apply_filters_deprecated( 'graphql_object_type_interfaces', [ $interfaces, $config, $type ], '1.4.1', 'graphql_type_interfaces' );
604✔
386
                                }
387

388
                                return $interfaces;
582✔
389
                        },
×
390
                        10,
×
391
                        3
×
392
                );
×
393

394
                /**
395
                 * Prevent WPML from redirecting within WPGraphQL requests
396
                 *
397
                 * @see https://github.com/wp-graphql/wp-graphql/issues/1626#issue-769089073
398
                 * @since 1.27.0
399
                 */
400
                add_filter(
×
401
                        'wpml_is_redirected',
×
402
                        static function ( bool $is_redirect ) {
×
403
                                if ( is_graphql_request() ) {
×
404
                                        return false;
×
405
                                }
406
                                return $is_redirect;
×
407
                        },
×
408
                        10,
×
409
                        1
×
410
                );
×
411
        }
412

413
        /**
414
         * Upgrade routine.
415
         */
416
        public function upgrade(): void {
×
417
                $version = get_option( 'wp_graphql_version', null );
×
418

419
                // If the version is not set, this is a fresh install, not an update.
420
                // set the version and return.
421
                if ( ! $version ) {
×
422
                        update_option( 'wp_graphql_version', WPGRAPHQL_VERSION );
×
423
                        return;
×
424
                }
425

426
                // If the version is less than the current version, run the update routine
427
                if ( version_compare( $version, WPGRAPHQL_VERSION, '<' ) ) {
×
428
                        $this->run_update_routines( $version );
×
429
                        update_option( 'wp_graphql_version', WPGRAPHQL_VERSION );
×
430
                }
431
        }
432

433
        /**
434
         * Executes update routines based on the previously stored version.
435
         *
436
         * This triggers an action that passes the previous version and new version and allows for specific actions or
437
         * modifications needed to bring installations up-to-date with the current plugin version.
438
         *
439
         * Each update routine (callback that hooks into "graphql_do_update_routine") should handle backward compatibility as gracefully as possible.
440
         *
441
         * @since 1.2.3
442
         * @param string|null $stored_version The version number currently stored in the database.
443
         *                                    Null if no version has been previously stored.
444
         */
445
        public function run_update_routines( ?string $stored_version = null ): void {
×
446

447
                // bail if the stored version is empty, or the WPGRAPHQL_VERSION constant is not set
448
                if ( ! defined( 'WPGRAPHQL_VERSION' ) || ! $stored_version ) {
×
449
                        return;
×
450
                }
451

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

455
                        // Clear the extensions cache
456
                        $this->clear_extensions_cache();
×
457

458
                        /**
459
                         * Fires the update routine.
460
                         *
461
                         * @param string $stored_version The version number currently stored in the database.
462
                         * @param string $new_version    The version number of the current plugin.
463
                         */
464
                        do_action( 'graphql_do_update_routine', $stored_version, WPGRAPHQL_VERSION );
×
465
                }
466
        }
467

468
        /**
469
         * Clear all caches in the "wpgraphql_extensions" cache group.
470
         */
471
        public function clear_extensions_cache(): void {
×
472
                global $wp_object_cache;
×
473

474
                if ( isset( $wp_object_cache->cache['wpgraphql_extensions'] ) ) {
×
475
                        foreach ( $wp_object_cache->cache['wpgraphql_extensions'] as $key => $value ) {
×
476
                                wp_cache_delete( $key, 'wpgraphql_extensions' );
×
477
                        }
478
                }
479
        }
480

481
        /**
482
         * Initialize admin functionality.
483
         */
484
        public function init_admin(): void {
×
485
                $admin = new Admin();
×
486
                $admin->init();
×
487
        }
488

489
        /**
490
         * This sets up built-in post_types and taxonomies to show in the GraphQL Schema.
491
         *
492
         * @since  0.0.2
493
         */
494
        public static function show_in_graphql(): void {
14✔
495
                add_filter( 'register_post_type_args', [ self::class, 'setup_default_post_types' ], 10, 2 );
14✔
496
                add_filter( 'register_taxonomy_args', [ self::class, 'setup_default_taxonomies' ], 10, 2 );
14✔
497

498
                // Run late so the user can filter the args themselves.
499
                add_filter( 'register_post_type_args', [ self::class, 'register_graphql_post_type_args' ], 99, 2 );
14✔
500
                add_filter( 'register_taxonomy_args', [ self::class, 'register_graphql_taxonomy_args' ], 99, 2 );
14✔
501
        }
502

503
        /**
504
         * Sets up the default post types to show_in_graphql.
505
         *
506
         * @param array<string,mixed> $args      Array of arguments for registering a post type.
507
         * @param string              $post_type Post type key.
508
         *
509
         * @return array<string,mixed>
510
         */
511
        public static function setup_default_post_types( $args, $post_type ) {
141✔
512
                // Adds GraphQL support for attachments.
513
                if ( 'attachment' === $post_type ) {
141✔
514
                        $args['show_in_graphql']     = true;
×
515
                        $args['graphql_single_name'] = 'mediaItem';
×
516
                        $args['graphql_plural_name'] = 'mediaItems';
×
517
                        $args['graphql_description'] = __( 'Represents uploaded media, including images, videos, documents, and audio files.', 'wp-graphql' );
×
518
                } elseif ( 'page' === $post_type ) { // Adds GraphQL support for pages.
141✔
519
                        $args['show_in_graphql']     = true;
×
520
                        $args['graphql_single_name'] = 'page';
×
521
                        $args['graphql_plural_name'] = 'pages';
×
522
                        $args['graphql_description'] = __( 'A standalone content entry generally used for static, non-chronological content such as "About Us" or "Contact" pages.', 'wp-graphql' );
×
523
                } elseif ( 'post' === $post_type ) { // Adds GraphQL support for posts.
141✔
524
                        $args['show_in_graphql']     = true;
×
525
                        $args['graphql_single_name'] = 'post';
×
526
                        $args['graphql_plural_name'] = 'posts';
×
527
                        $args['graphql_description'] = __( 'A chronological content entry typically used for blog posts, news articles, or similar date-based content.', 'wp-graphql' );
×
528
                }
529

530
                return $args;
141✔
531
        }
532

533
        /**
534
         * Sets up the default taxonomies to show_in_graphql.
535
         *
536
         * @param array<string,mixed> $args     Array of arguments for registering a taxonomy.
537
         * @param string              $taxonomy Taxonomy key.
538
         *
539
         * @return array<string,mixed>
540
         * @since 1.12.0
541
         */
542
        public static function setup_default_taxonomies( $args, $taxonomy ) {
154✔
543
                // Adds GraphQL support for categories.
544
                if ( 'category' === $taxonomy ) {
154✔
545
                        $args['show_in_graphql']     = true;
68✔
546
                        $args['graphql_single_name'] = 'category';
68✔
547
                        $args['graphql_plural_name'] = 'categories';
68✔
548
                        $args['graphql_description'] = __( 'A taxonomy term that classifies content. Categories support hierarchy and can be used to create a nested structure.', 'wp-graphql' );
68✔
549
                } elseif ( 'post_tag' === $taxonomy ) { // Adds GraphQL support for tags.
154✔
550
                        $args['show_in_graphql']     = true;
68✔
551
                        $args['graphql_single_name'] = 'tag';
68✔
552
                        $args['graphql_plural_name'] = 'tags';
68✔
553
                        $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✔
554
                } elseif ( 'post_format' === $taxonomy ) { // Adds GraphQL support for post formats.
154✔
555
                        $args['show_in_graphql']     = true;
68✔
556
                        $args['graphql_single_name'] = 'postFormat';
68✔
557
                        $args['graphql_plural_name'] = 'postFormats';
68✔
558
                        $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✔
559
                }
560

561
                return $args;
154✔
562
        }
563

564
        /**
565
         * Set the GraphQL Post Type Args and pass them through a filter.
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
         * @return array<string,mixed>
571
         * @throws \Exception
572
         * @since 1.12.0
573
         */
574
        public static function register_graphql_post_type_args( array $args, string $post_type_name ): array {
141✔
575
                // Bail early if the post type is hidden from the WPGraphQL schema.
576
                if ( empty( $args['show_in_graphql'] ) ) {
141✔
577
                        return $args;
1✔
578
                }
579

580
                $graphql_args = self::get_default_graphql_type_args();
141✔
581

582
                /**
583
                 * Filters the graphql args set on a post type
584
                 *
585
                 * @param array<string,mixed> $args           The graphql specific args for the post type
586
                 * @param string              $post_type_name The name of the post type being registered
587
                 */
588
                $graphql_args = apply_filters( 'register_graphql_post_type_args', $graphql_args, $post_type_name );
141✔
589

590
                return wp_parse_args( $args, $graphql_args );
141✔
591
        }
592

593
        /**
594
         * Set the GraphQL Taxonomy Args and pass them through a filter.
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
         * @return array<string,mixed>
600
         * @throws \Exception
601
         * @since 1.12.0
602
         */
603
        public static function register_graphql_taxonomy_args( array $args, string $taxonomy_name ): array {
154✔
604
                // Bail early if the taxonomy  is hidden from the WPGraphQL schema.
605
                if ( empty( $args['show_in_graphql'] ) ) {
154✔
606
                        return $args;
68✔
607
                }
608

609
                $graphql_args = self::get_default_graphql_type_args();
154✔
610

611
                /**
612
                 * Filters the graphql args set on a taxonomy
613
                 *
614
                 * @param array<string,mixed> $args          The graphql specific args for the taxonomy
615
                 * @param string              $taxonomy_name The name of the taxonomy being registered
616
                 */
617
                $graphql_args = apply_filters( 'register_graphql_taxonomy_args', $graphql_args, $taxonomy_name );
154✔
618

619
                return wp_parse_args( $args, $graphql_args );
154✔
620
        }
621

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

659
        /**
660
         * Get the post types that are allowed to be used in GraphQL.
661
         *
662
         * This gets all post_types that are set to show_in_graphql, but allows for external code
663
         * (plugins/theme) to filter the list of allowed_post_types to add/remove additional post_types
664
         *
665
         * @param 'names'|'objects'   $output Optional. The type of output to return. Accepts post type 'names' or 'objects'. Default 'names'.
666
         * @param array<string,mixed> $args   Optional. Arguments to filter allowed post types
667
         *
668
         * @return string[]|\WP_Post_Type[]
669
         * @phpstan-return ( $output is 'objects' ? \WP_Post_Type[] : string[] )
670
         *
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 = [] ): array {
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 'names'|'objects'   $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 string[]|\WP_Taxonomy[]
762
         * @phpstan-return ( $output is 'objects' ? \WP_Taxonomy[] : string[] )
763
         * @since  0.0.4
764
         */
765
        public static function get_allowed_taxonomies( $output = 'names', $args = [] ): array {
607✔
766

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

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

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

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

800
                                        /**
801
                                         * Validate that the post_types have a graphql_single_name and graphql_plural_name
802
                                         */
803
                                        if ( empty( $obj->graphql_single_name ) || empty( $obj->graphql_plural_name ) ) {
593✔
804
                                                graphql_debug(
1✔
805
                                                        sprintf(
1✔
806
                                                        /* translators: %s will replaced with the registered taxonomy */
807
                                                                __( '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✔
808
                                                                $obj->name
1✔
809
                                                        ),
1✔
810
                                                        [
1✔
811
                                                                'invalid_taxonomy' => $obj,
1✔
812
                                                        ]
1✔
813
                                                );
1✔
814
                                                return false;
1✔
815
                                        }
816

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

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

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

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

834
                return $taxonomies;
607✔
835
        }
836

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

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

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

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

877
                /**
878
                 * Return the Schema after applying filters
879
                 */
880
                return self::$schema;
754✔
881
        }
882

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

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

900
        /**
901
         * Returns the type registry, instantiating it if it doesn't exist.
902
         *
903
         * @return \WPGraphQL\Registry\TypeRegistry
904
         *
905
         * @throws \Exception
906
         */
907
        public static function get_type_registry() {
756✔
908
                if ( ! isset( self::$type_registry ) ) {
756✔
909
                        $type_registry = new TypeRegistry();
595✔
910

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

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

928
                /**
929
                 * Return the Schema after applying filters
930
                 */
931
                return self::$type_registry;
756✔
932
        }
933

934
        /**
935
         * Return the static schema if there is one.
936
         */
937
        public static function get_static_schema(): ?string {
1✔
938
                $schema_file = WPGRAPHQL_PLUGIN_DIR . 'schema.graphql';
1✔
939

940
                if ( ! file_exists( $schema_file ) ) {
1✔
941
                        return null;
×
942
                }
943

944
                $schema = file_get_contents( WPGRAPHQL_PLUGIN_DIR . 'schema.graphql' );
1✔
945

946
                return ! empty( $schema ) ? $schema : null;
1✔
947
        }
948

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

963
                return $app_context;
756✔
964
        }
965
}
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