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

wp-graphql / wp-graphql / #943

11 Feb 2025 10:07PM UTC coverage: 83.028% (-0.2%) from 83.19%
#943

push

php-coveralls

web-flow
Merge pull request #3306 from wp-graphql/release/v1.32.0

release: v1.32.0

66 of 113 new or added lines in 5 files covered. (58.41%)

1 existing line in 1 file now uncovered.

13057 of 15726 relevant lines covered (83.03%)

299.59 hits per line

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

96.06
/src/Registry/Utils/PostObject.php
1
<?php
2

3
namespace WPGraphQL\Registry\Utils;
4

5
use GraphQL\Type\Definition\ResolveInfo;
6
use WPGraphQL;
7
use WPGraphQL\AppContext;
8
use WPGraphQL\Data\Connection\CommentConnectionResolver;
9
use WPGraphQL\Data\Connection\PostObjectConnectionResolver;
10
use WPGraphQL\Data\Connection\TermObjectConnectionResolver;
11
use WPGraphQL\Model\Post;
12
use WPGraphQL\Type\Connection\Comments;
13
use WPGraphQL\Type\Connection\PostObjects;
14
use WPGraphQL\Type\Connection\TermObjects;
15
use WP_Post_Type;
16

17
/**
18
 * Class PostObject
19
 *
20
 * @package WPGraphQL\Data
21
 * @since   1.12.0
22
 */
23
class PostObject {
24

25
        /**
26
         * Registers a post_type type to the schema as either a GraphQL object, interface, or union.
27
         *
28
         * @param \WP_Post_Type $post_type_object Post type.
29
         *
30
         * @return void
31
         * @throws \Exception
32
         */
33
        public static function register_types( WP_Post_Type $post_type_object ) {
34
                $single_name = $post_type_object->graphql_single_name;
590✔
35

36
                $config = [
590✔
37
                        /* translators: post object singular name w/ description */
38
                        'description' => sprintf( __( 'The %s type', 'wp-graphql' ), $single_name ),
590✔
39
                        'connections' => static::get_connections( $post_type_object ),
590✔
40
                        'interfaces'  => static::get_interfaces( $post_type_object ),
590✔
41
                        'fields'      => static::get_fields( $post_type_object ),
590✔
42
                        'model'       => Post::class,
590✔
43
                ];
590✔
44

45
                // Register as GraphQL objects.
46
                if ( 'object' === $post_type_object->graphql_kind ) {
590✔
47
                        register_graphql_object_type( $single_name, $config );
590✔
48

49
                        // Register fields to the Type used for attachments (MediaItem)
50
                        if ( 'attachment' === $post_type_object->name && true === $post_type_object->show_in_graphql && isset( $post_type_object->graphql_single_name ) ) {
590✔
51
                                self::register_attachment_fields( $post_type_object );
589✔
52
                        }
53

54
                        return;
590✔
55
                }
56

57
                /**
58
                 * Register as GraphQL interfaces or unions.
59
                 *
60
                 * It's assumed that the types used in `resolveType` have already been registered to the schema.
61
                 */
62

63
                // Bail early if graphql_resolve_type isnt a vallable callback.
64
                if ( empty( $post_type_object->graphql_resolve_type ) || ! is_callable( $post_type_object->graphql_resolve_type ) ) {
3✔
65
                        graphql_debug(
1✔
66
                                sprintf(
1✔
67
                                        // translators: %1$s is the post type name, %2$s is the graphql kind.
68
                                        __( '%1$s is registered as a GraphQL %2$s, but has no way to resolve the type. Ensure "graphql_resolve_type" is a valid callback function', 'wp-graphql' ),
1✔
69
                                        $single_name,
1✔
70
                                        $post_type_object->graphql_kind
1✔
71
                                ),
1✔
72
                                [ 'registered_post_type_object' => $post_type_object ]
1✔
73
                        );
1✔
74

75
                        return;
1✔
76
                }
77

78
                $config['resolveType'] = $post_type_object->graphql_resolve_type;
3✔
79

80
                if ( 'interface' === $post_type_object->graphql_kind ) {
3✔
81
                        register_graphql_interface_type( $single_name, $config );
1✔
82

83
                        return;
1✔
84
                } elseif ( 'union' === $post_type_object->graphql_kind ) {
2✔
85

86
                        // Bail early if graphql_union_types is not defined.
87
                        if ( empty( $post_type_object->graphql_union_types ) || ! is_array( $post_type_object->graphql_union_types ) ) {
2✔
88
                                graphql_debug(
1✔
89
                                        __( 'Registering a post type with "graphql_kind" => "union" requires "graphql_union_types" to be a valid array of possible GraphQL type names.', 'wp-graphql' ),
1✔
90
                                        [ 'registered_post_type_object' => $post_type_object ]
1✔
91
                                );
1✔
92

93
                                return;
1✔
94
                        }
95

96
                        // Set the possible types for the union.
97
                        $config['typeNames'] = $post_type_object->graphql_union_types;
1✔
98

99
                        register_graphql_union_type( $single_name, $config );
1✔
100
                }
101
        }
102

103
        /**
104
         * Gets all the connections for the given post type.
105
         *
106
         * @param \WP_Post_Type $post_type_object
107
         *
108
         * @return array<string,array<string,mixed>>
109
         */
110
        protected static function get_connections( WP_Post_Type $post_type_object ) {
111
                $connections = [];
590✔
112

113
                // Comments.
114
                if ( post_type_supports( $post_type_object->name, 'comments' ) ) {
590✔
115
                        $connections['comments'] = [
590✔
116
                                'toType'         => 'Comment',
590✔
117
                                'connectionArgs' => Comments::get_connection_args(),
590✔
118
                                'resolve'        => static function ( Post $post, $args, $context, $info ) {
590✔
119
                                        if ( $post->isRevision ) {
3✔
120
                                                $id = $post->parentDatabaseId;
×
121
                                        } else {
122
                                                $id = $post->ID;
3✔
123
                                        }
124

125
                                        $resolver = new CommentConnectionResolver( $post, $args, $context, $info );
3✔
126

127
                                        return $resolver->set_query_arg( 'post_id', absint( $id ) )->get_connection();
3✔
128
                                },
590✔
129
                        ];
590✔
130
                }
131

132
                // Previews.
133
                if ( ! in_array( $post_type_object->name, [ 'attachment', 'revision' ], true ) ) {
590✔
134
                        $connections['preview'] = [
590✔
135
                                'toType'             => $post_type_object->graphql_single_name,
590✔
136
                                'connectionTypeName' => ucfirst( $post_type_object->graphql_single_name ) . 'ToPreviewConnection',
590✔
137
                                'oneToOne'           => true,
590✔
138
                                'deprecationReason'  => ( true === $post_type_object->publicly_queryable || true === $post_type_object->public ) ? null
590✔
139
                                        : sprintf(
590✔
140
                                                // translators: %s is the post type's GraphQL name.
141
                                                __( 'The "%s" Type is not publicly queryable and does not support previews. This field will be removed in the future.', 'wp-graphql' ),
590✔
142
                                                WPGraphQL\Utils\Utils::format_type_name( $post_type_object->graphql_single_name )
590✔
143
                                        ),
590✔
144
                                'resolve'            => static function ( Post $post, $args, AppContext $context, ResolveInfo $info ) {
590✔
145
                                        if ( $post->isRevision ) {
10✔
146
                                                return null;
×
147
                                        }
148

149
                                        if ( empty( $post->previewRevisionDatabaseId ) ) {
10✔
150
                                                return null;
1✔
151
                                        }
152

153
                                        $resolver = new PostObjectConnectionResolver( $post, $args, $context, $info, 'revision' );
9✔
154
                                        $resolver->set_query_arg( 'p', $post->previewRevisionDatabaseId );
9✔
155

156
                                        return $resolver->one_to_one()->get_connection();
9✔
157
                                },
590✔
158
                        ];
590✔
159
                }
160

161
                // Revisions.
162
                if ( true === post_type_supports( $post_type_object->name, 'revisions' ) ) {
590✔
163
                        $connections['revisions'] = [
590✔
164
                                'connectionTypeName' => ucfirst( $post_type_object->graphql_single_name ) . 'ToRevisionConnection',
590✔
165
                                'toType'             => $post_type_object->graphql_single_name,
590✔
166
                                'queryClass'         => 'WP_Query',
590✔
167
                                'connectionArgs'     => PostObjects::get_connection_args( [], $post_type_object ),
590✔
168
                                'resolve'            => static function ( Post $post, $args, $context, $info ) {
590✔
169
                                        $resolver = new PostObjectConnectionResolver( $post, $args, $context, $info, 'revision' );
3✔
170
                                        $resolver->set_query_arg( 'post_parent', $post->ID );
3✔
171

172
                                        return $resolver->get_connection();
3✔
173
                                },
590✔
174
                        ];
590✔
175
                }
176

177
                // Used to ensure TermNode connection doesn't get registered multiple times.
178
                $already_registered = false;
590✔
179
                $allowed_taxonomies = WPGraphQL::get_allowed_taxonomies( 'objects' );
590✔
180

181
                foreach ( $allowed_taxonomies as $tax_object ) {
590✔
182
                        if ( ! in_array( $post_type_object->name, $tax_object->object_type, true ) ) {
590✔
183
                                continue;
589✔
184
                        }
185

186
                        // TermNode.
187
                        if ( ! $already_registered ) {
590✔
188
                                $connections['terms'] = [
590✔
189
                                        'toType'         => 'TermNode',
590✔
190
                                        'queryClass'     => 'WP_Term_Query',
590✔
191
                                        'connectionArgs' => TermObjects::get_connection_args(
590✔
192
                                                [
590✔
193
                                                        'taxonomies' => [
590✔
194
                                                                'type'        => [ 'list_of' => 'TaxonomyEnum' ],
590✔
195
                                                                'description' => __( 'The Taxonomy to filter terms by', 'wp-graphql' ),
590✔
196
                                                        ],
590✔
197
                                                ]
590✔
198
                                        ),
590✔
199
                                        'resolve'        => static function ( Post $post, $args, AppContext $context, ResolveInfo $info ) {
590✔
200
                                                $taxonomies = \WPGraphQL::get_allowed_taxonomies();
×
201
                                                $object_id  = true === $post->isPreview && ! empty( $post->parentDatabaseId ) ? $post->parentDatabaseId : $post->ID;
×
202

203
                                                if ( empty( $object_id ) ) {
×
204
                                                        return null;
×
205
                                                }
206

207
                                                $resolver = new TermObjectConnectionResolver( $post, $args, $context, $info, $taxonomies );
×
208
                                                $resolver->set_query_arg( 'object_ids', absint( $object_id ) );
×
209
                                                return $resolver->get_connection();
×
210
                                        },
590✔
211
                                ];
590✔
212

213
                                // We won't need to register this connection again.
214
                                $already_registered = true;
590✔
215
                        }
216

217
                        // TermObjects.
218
                        $connections[ $tax_object->graphql_plural_name ] = [
590✔
219
                                'toType'         => $tax_object->graphql_single_name,
590✔
220
                                'queryClass'     => 'WP_Term_Query',
590✔
221
                                'connectionArgs' => TermObjects::get_connection_args(),
590✔
222
                                'resolve'        => static function ( Post $post, $args, AppContext $context, $info ) use ( $tax_object ) {
590✔
223
                                        $object_id = true === $post->isPreview && ! empty( $post->parentDatabaseId ) ? $post->parentDatabaseId : $post->ID;
15✔
224

225
                                        if ( empty( $object_id ) || ! absint( $object_id ) ) {
15✔
226
                                                return null;
×
227
                                        }
228

229
                                        $resolver = new TermObjectConnectionResolver( $post, $args, $context, $info, $tax_object->name );
15✔
230
                                        $resolver->set_query_arg( 'object_ids', absint( $object_id ) );
15✔
231

232
                                        return $resolver->get_connection();
15✔
233
                                },
590✔
234
                        ];
590✔
235
                }
236

237
                // Deprecated connections.
238
                if ( ! $post_type_object->hierarchical &&
590✔
239
                        ! in_array(
590✔
240
                                $post_type_object->name,
590✔
241
                                [
590✔
242
                                        'attachment',
590✔
243
                                        'revision',
590✔
244
                                ],
590✔
245
                                true
590✔
246
                        ) ) {
590✔
247
                        $connections['ancestors'] = [
590✔
248
                                'toType'            => $post_type_object->graphql_single_name,
590✔
249
                                'description'       => __( 'The ancestors of the content node.', 'wp-graphql' ),
590✔
250
                                'deprecationReason' => __( 'This content type is not hierarchical and typically will not have ancestors', 'wp-graphql' ),
590✔
251
                                'resolve'           => static function () {
590✔
252
                                        return null;
×
253
                                },
590✔
254
                        ];
590✔
255
                        $connections['parent']    = [
590✔
256
                                'toType'            => $post_type_object->graphql_single_name,
590✔
257
                                'oneToOne'          => true,
590✔
258
                                'description'       => __( 'The parent of the content node.', 'wp-graphql' ),
590✔
259
                                'deprecationReason' => __( 'This content type is not hierarchical and typically will not have a parent', 'wp-graphql' ),
590✔
260
                                'resolve'           => static function () {
590✔
261
                                        return null;
×
262
                                },
590✔
263
                        ];
590✔
264
                }
265

266
                // Merge with connections set in register_post_type.
267
                if ( ! empty( $post_type_object->graphql_connections ) ) {
590✔
268
                        $connections = array_merge( $connections, $post_type_object->graphql_connections );
1✔
269
                }
270

271
                // Remove excluded connections.
272
                if ( ! empty( $post_type_object->graphql_exclude_connections ) ) {
590✔
273
                        foreach ( $post_type_object->graphql_exclude_connections as $connection_name ) {
1✔
274
                                unset( $connections[ lcfirst( $connection_name ) ] );
1✔
275
                        }
276
                }
277

278
                return $connections;
590✔
279
        }
280

281
        /**
282
         * Gets all the interfaces for the given post type.
283
         *
284
         * @param \WP_Post_Type $post_type_object Post type.
285
         *
286
         * @return string[]
287
         */
288
        protected static function get_interfaces( WP_Post_Type $post_type_object ) {
289
                $interfaces = [ 'Node', 'ContentNode', 'DatabaseIdentifier', 'NodeWithTemplate' ];
590✔
290

291
                if ( true === $post_type_object->public ) {
590✔
292
                        $interfaces[] = 'UniformResourceIdentifiable';
590✔
293
                }
294

295
                // Only post types that are publicly_queryable are previewable
296
                if ( 'attachment' !== $post_type_object->name && ( true === $post_type_object->publicly_queryable || true === $post_type_object->public ) ) {
590✔
297
                        $interfaces[] = 'Previewable';
590✔
298
                }
299

300
                if ( post_type_supports( $post_type_object->name, 'title' ) ) {
590✔
301
                        $interfaces[] = 'NodeWithTitle';
590✔
302
                }
303

304
                if ( post_type_supports( $post_type_object->name, 'editor' ) ) {
590✔
305
                        $interfaces[] = 'NodeWithContentEditor';
590✔
306
                }
307

308
                if ( post_type_supports( $post_type_object->name, 'author' ) ) {
590✔
309
                        $interfaces[] = 'NodeWithAuthor';
590✔
310
                }
311

312
                if ( post_type_supports( $post_type_object->name, 'thumbnail' ) ) {
590✔
313
                        $interfaces[] = 'NodeWithFeaturedImage';
590✔
314
                }
315

316
                if ( post_type_supports( $post_type_object->name, 'excerpt' ) ) {
590✔
317
                        $interfaces[] = 'NodeWithExcerpt';
590✔
318
                }
319

320
                if ( post_type_supports( $post_type_object->name, 'comments' ) ) {
590✔
321
                        $interfaces[] = 'NodeWithComments';
590✔
322
                }
323

324
                if ( post_type_supports( $post_type_object->name, 'trackbacks' ) ) {
590✔
325
                        $interfaces[] = 'NodeWithTrackbacks';
590✔
326
                }
327

328
                if ( post_type_supports( $post_type_object->name, 'revisions' ) ) {
590✔
329
                        $interfaces[] = 'NodeWithRevisions';
590✔
330
                }
331

332
                if ( post_type_supports( $post_type_object->name, 'page-attributes' ) ) {
590✔
333
                        $interfaces[] = 'NodeWithPageAttributes';
589✔
334
                }
335

336
                if ( $post_type_object->hierarchical || in_array(
590✔
337
                        $post_type_object->name,
590✔
338
                        [
590✔
339
                                'attachment',
590✔
340
                                'revision',
590✔
341
                        ],
590✔
342
                        true
590✔
343
                ) ) {
590✔
344
                        $interfaces[] = 'HierarchicalContentNode';
589✔
345
                }
346

347
                if ( true === $post_type_object->show_in_nav_menus ) {
590✔
348
                        $interfaces[] = 'MenuItemLinkable';
590✔
349
                }
350

351
                // Merge with interfaces set in register_post_type.
352
                if ( ! empty( $post_type_object->graphql_interfaces ) ) {
590✔
353
                        $interfaces = array_merge( $interfaces, $post_type_object->graphql_interfaces );
1✔
354
                }
355

356
                // Remove excluded interfaces.
357
                if ( ! empty( $post_type_object->graphql_exclude_interfaces ) ) {
590✔
358
                        $interfaces = array_diff( $interfaces, $post_type_object->graphql_exclude_interfaces );
1✔
359
                }
360

361
                return $interfaces;
590✔
362
        }
363

364
        /**
365
         * Registers common post type fields on schema type corresponding to provided post type object.
366
         *
367
         * @param \WP_Post_Type $post_type_object Post type.
368
         *
369
         * @return array<string,array<string,mixed>>
370
         * @todo make protected after \Type\ObjectType\PostObject::get_fields() is removed.
371
         */
372
        public static function get_fields( WP_Post_Type $post_type_object ) {
373
                $single_name = $post_type_object->graphql_single_name;
590✔
374
                $fields      = [
590✔
375
                        'id'                => [
590✔
376
                                'description' => sprintf(
590✔
377
                                /* translators: %s: custom post-type name */
378
                                        __( 'The globally unique identifier of the %s object.', 'wp-graphql' ),
590✔
379
                                        $post_type_object->name
590✔
380
                                ),
590✔
381
                        ],
590✔
382
                        $single_name . 'Id' => [
590✔
383
                                'type'              => [
590✔
384
                                        'non_null' => 'Int',
590✔
385
                                ],
590✔
386
                                'deprecationReason' => __( 'Deprecated in favor of the databaseId field', 'wp-graphql' ),
590✔
387
                                'description'       => __( 'The id field matches the WP_Post->ID field.', 'wp-graphql' ),
590✔
388
                                'resolve'           => static function ( Post $post ) {
590✔
389
                                        return absint( $post->ID );
50✔
390
                                },
590✔
391
                        ],
590✔
392
                        'hasPassword'       => [
590✔
393
                                'type'        => 'Boolean',
590✔
394
                                'description' => sprintf(
590✔
395
                                        // translators: %s: custom post-type name.
396
                                        __( 'Whether the %s object is password protected.', 'wp-graphql' ),
590✔
397
                                        $post_type_object->name
590✔
398
                                ),
590✔
399
                        ],
590✔
400
                        'password'          => [
590✔
401
                                'type'        => 'String',
590✔
402
                                'description' => sprintf(
590✔
403
                                        // translators: %s: custom post-type name.
404
                                        __( 'The password for the %s object.', 'wp-graphql' ),
590✔
405
                                        $post_type_object->name
590✔
406
                                ),
590✔
407
                        ],
590✔
408
                ];
590✔
409

410
                if ( 'page' === $post_type_object->name ) {
590✔
411
                        $fields['isFrontPage'] = [
589✔
412
                                'type'        => [ 'non_null' => 'Bool' ],
589✔
413
                                'description' => __( 'Whether this page is set to the static front page.', 'wp-graphql' ),
589✔
414
                        ];
589✔
415

416
                        $fields['isPostsPage'] = [
589✔
417
                                'type'        => [ 'non_null' => 'Bool' ],
589✔
418
                                'description' => __( 'Whether this page is set to the blog posts page.', 'wp-graphql' ),
589✔
419
                        ];
589✔
420

421
                        $fields['isPrivacyPage'] = [
589✔
422
                                'type'        => [ 'non_null' => 'Bool' ],
589✔
423
                                'description' => __( 'Whether this page is set to the privacy page.', 'wp-graphql' ),
589✔
424
                        ];
589✔
425
                }
426

427
                if ( 'post' === $post_type_object->name ) {
590✔
428
                        $fields['isSticky'] = [
590✔
429
                                'type'        => [ 'non_null' => 'Bool' ],
590✔
430
                                'description' => __( 'Whether this page is sticky', 'wp-graphql' ),
590✔
431
                        ];
590✔
432
                }
433

434
                // Merge with fields set in register_post_type.
435
                if ( ! empty( $post_type_object->graphql_fields ) ) {
590✔
436
                        $fields = array_merge( $fields, $post_type_object->graphql_fields );
452✔
437
                }
438

439
                // Remove excluded fields.
440
                if ( ! empty( $post_type_object->graphql_exclude_fields ) ) {
590✔
441
                        foreach ( $post_type_object->graphql_exclude_fields as $field_name ) {
451✔
442
                                unset( $fields[ $field_name ] );
451✔
443
                        }
444
                }
445

446
                return $fields;
590✔
447
        }
448

449
        /**
450
         * Register fields to the Type used for attachments (MediaItem).
451
         *
452
         * @param \WP_Post_Type $post_type_object Post type.
453
         *
454
         * @return void
455
         */
456
        private static function register_attachment_fields( WP_Post_Type $post_type_object ) {
457
                /**
458
                 * Register fields custom to the MediaItem Type
459
                 */
460
                register_graphql_fields(
589✔
461
                        $post_type_object->graphql_single_name,
589✔
462
                        [
589✔
463
                                'caption'      => [
589✔
464
                                        'type'        => 'String',
589✔
465
                                        'description' => __( 'The caption for the resource', 'wp-graphql' ),
589✔
466
                                        'args'        => [
589✔
467
                                                'format' => [
589✔
468
                                                        'type'        => 'PostObjectFieldFormatEnum',
589✔
469
                                                        'description' => __( 'Format of the field output', 'wp-graphql' ),
589✔
470
                                                ],
589✔
471
                                        ],
589✔
472
                                        'resolve'     => static function ( $source, $args ) {
589✔
473
                                                if ( isset( $args['format'] ) && 'raw' === $args['format'] ) {
7✔
474
                                                        // @codingStandardsIgnoreLine.
475
                                                        return $source->captionRaw;
×
476
                                                }
477

478
                                                // @codingStandardsIgnoreLine.
479
                                                return $source->captionRendered;
7✔
480
                                        },
589✔
481
                                ],
589✔
482
                                'altText'      => [
589✔
483
                                        'type'        => 'String',
589✔
484
                                        'description' => __( 'Alternative text to display when resource is not displayed', 'wp-graphql' ),
589✔
485
                                ],
589✔
486
                                'srcSet'       => [
589✔
487
                                        'type'        => 'string',
589✔
488
                                        'args'        => [
589✔
489
                                                'size' => [
589✔
490
                                                        'type'        => 'MediaItemSizeEnum',
589✔
491
                                                        'description' => __( 'Size of the MediaItem to calculate srcSet with', 'wp-graphql' ),
589✔
492
                                                ],
589✔
493
                                        ],
589✔
494
                                        'description' => __( 'The srcset attribute specifies the URL of the image to use in different situations. It is a comma separated string of urls and their widths.', 'wp-graphql' ),
589✔
495
                                        'resolve'     => static function ( $source, $args ) {
589✔
496
                                                $size = 'medium';
3✔
497
                                                if ( ! empty( $args['size'] ) ) {
3✔
498
                                                        $size = $args['size'];
1✔
499
                                                }
500

501
                                                $src_set = wp_get_attachment_image_srcset( $source->ID, $size );
3✔
502

503
                                                return ! empty( $src_set ) ? $src_set : null;
3✔
504
                                        },
589✔
505
                                ],
589✔
506
                                'sizes'        => [
589✔
507
                                        'type'        => 'string',
589✔
508
                                        'args'        => [
589✔
509
                                                'size' => [
589✔
510
                                                        'type'        => 'MediaItemSizeEnum',
589✔
511
                                                        'description' => __( 'Size of the MediaItem to calculate sizes with', 'wp-graphql' ),
589✔
512
                                                ],
589✔
513
                                        ],
589✔
514
                                        'description' => __( 'The sizes attribute value for an image.', 'wp-graphql' ),
589✔
515
                                        'resolve'     => static function ( $source, $args ) {
589✔
516
                                                $size = 'medium';
1✔
517
                                                if ( ! empty( $args['size'] ) ) {
1✔
518
                                                        $size = $args['size'];
1✔
519
                                                }
520

521
                                                $image = wp_get_attachment_image_src( $source->ID, $size );
1✔
522
                                                if ( $image ) {
1✔
523
                                                        list( $src, $width, $height ) = $image;
1✔
524
                                                        $sizes                        = wp_calculate_image_sizes(
1✔
525
                                                                [
1✔
526
                                                                        absint( $width ),
1✔
527
                                                                        absint( $height ),
1✔
528
                                                                ],
1✔
529
                                                                $src,
1✔
530
                                                                null,
1✔
531
                                                                $source->ID
1✔
532
                                                        );
1✔
533

534
                                                        return ! empty( $sizes ) ? $sizes : null;
1✔
535
                                                }
536

537
                                                return null;
×
538
                                        },
589✔
539
                                ],
589✔
540
                                'description'  => [
589✔
541
                                        'type'        => 'String',
589✔
542
                                        'description' => __( 'Description of the image (stored as post_content)', 'wp-graphql' ),
589✔
543
                                        'args'        => [
589✔
544
                                                'format' => [
589✔
545
                                                        'type'        => 'PostObjectFieldFormatEnum',
589✔
546
                                                        'description' => __( 'Format of the field output', 'wp-graphql' ),
589✔
547
                                                ],
589✔
548
                                        ],
589✔
549
                                        'resolve'     => static function ( $source, $args ) {
589✔
550
                                                if ( isset( $args['format'] ) && 'raw' === $args['format'] ) {
8✔
551
                                                        // @codingStandardsIgnoreLine.
552
                                                        return $source->descriptionRaw;
×
553
                                                }
554

555
                                                // @codingStandardsIgnoreLine.
556
                                                return $source->descriptionRendered;
8✔
557
                                        },
589✔
558
                                ],
589✔
559
                                'mediaItemUrl' => [
589✔
560
                                        'type'        => 'String',
589✔
561
                                        'description' => __( 'Url of the mediaItem', 'wp-graphql' ),
589✔
562
                                ],
589✔
563
                                'mediaType'    => [
589✔
564
                                        'type'        => 'String',
589✔
565
                                        'description' => __( 'Type of resource', 'wp-graphql' ),
589✔
566
                                ],
589✔
567
                                'sourceUrl'    => [
589✔
568
                                        'type'        => 'String',
589✔
569
                                        'description' => __( 'Url of the mediaItem', 'wp-graphql' ),
589✔
570
                                        'args'        => [
589✔
571
                                                'size' => [
589✔
572
                                                        'type'        => 'MediaItemSizeEnum',
589✔
573
                                                        'description' => __( 'Size of the MediaItem to return', 'wp-graphql' ),
589✔
574
                                                ],
589✔
575
                                        ],
589✔
576
                                        'resolve'     => static function ( $image, $args ) {
589✔
577
                                                if ( empty( $args['size'] ) ) {
8✔
578
                                                        return $image->sourceUrl;
7✔
579
                                                }
580

581
                                                // @todo why do we coerce full to large?
582
                                                $size = 'full' === $args['size'] ? 'large' : $args['size'];
2✔
583

584
                                                /** @var \WPGraphQL\Model\Post $image */
585
                                                return $image->get_source_url_by_size( $size );
2✔
586
                                        },
589✔
587
                                ],
589✔
588
                                'file'         => [
589✔
589
                                        'type'        => 'String',
589✔
590
                                        'description' => __( 'The filename of the mediaItem for the specified size (default size is full)', 'wp-graphql' ),
589✔
591
                                        'args'        => [
589✔
592
                                                'size' => [
589✔
593
                                                        'type'        => 'MediaItemSizeEnum',
589✔
594
                                                        'description' => __( 'Size of the MediaItem to return', 'wp-graphql' ),
589✔
595
                                                ],
589✔
596
                                        ],
589✔
597
                                        'resolve'     => static function ( $source, $args ) {
589✔
598
                                                // If a size is specified, get the size-specific filename
599
                                                if ( ! empty( $args['size'] ) ) {
1✔
600
                                                        $size = 'full' === $args['size'] ? 'large' : $args['size'];
1✔
601

602
                                                        // Get the metadata which contains size information
603
                                                        $metadata = wp_get_attachment_metadata( $source->databaseId );
1✔
604

605
                                                        if ( ! empty( $metadata['sizes'][ $size ]['file'] ) ) {
1✔
606
                                                                return $metadata['sizes'][ $size ]['file'];
1✔
607
                                                        }
608
                                                }
609

610
                                                // Default to original file
611
                                                $attached_file = get_post_meta( $source->databaseId, '_wp_attached_file', true );
1✔
612
                                                return ! empty( $attached_file ) ? basename( $attached_file ) : null;
1✔
613
                                        },
589✔
614
                                ],
589✔
615
                                'filePath'     => [
589✔
616
                                        'type'        => 'String',
589✔
617
                                        'description' => __( 'The path to the original file relative to the uploads directory', 'wp-graphql' ),
589✔
618
                                        'args'        => [
589✔
619
                                                'size' => [
589✔
620
                                                        'type'        => 'MediaItemSizeEnum',
589✔
621
                                                        'description' => __( 'Size of the MediaItem to return', 'wp-graphql' ),
589✔
622
                                                ],
589✔
623
                                        ],
589✔
624
                                        'resolve'     => static function ( $source, $args ) {
589✔
625
                                                // Get the upload directory info
626
                                                $upload_dir           = wp_upload_dir();
1✔
627
                                                $relative_upload_path = wp_make_link_relative( $upload_dir['baseurl'] );
1✔
628

629
                                                // If a size is specified, get the size-specific path
630
                                                if ( ! empty( $args['size'] ) ) {
1✔
631
                                                        $size = 'full' === $args['size'] ? 'large' : $args['size'];
1✔
632

633
                                                        // Get the metadata which contains size information
634
                                                        $metadata = wp_get_attachment_metadata( $source->databaseId );
1✔
635

636
                                                        if ( ! empty( $metadata['sizes'][ $size ]['file'] ) ) {
1✔
637
                                                                $file_path = $metadata['file'];
1✔
638
                                                                return path_join( $relative_upload_path, dirname( $file_path ) . '/' . $metadata['sizes'][ $size ]['file'] );
1✔
639
                                                        }
640
                                                }
641

642
                                                // Default to original file path
643
                                                $attached_file = get_post_meta( $source->databaseId, '_wp_attached_file', true );
1✔
644

645
                                                if ( empty( $attached_file ) ) {
1✔
NEW
646
                                                        return null;
×
647
                                                }
648

649
                                                return path_join( $relative_upload_path, $attached_file );
1✔
650
                                        },
589✔
651
                                ],
589✔
652
                                'fileSize'     => [
589✔
653
                                        'type'        => 'Int',
589✔
654
                                        'description' => __( 'The filesize in bytes of the resource', 'wp-graphql' ),
589✔
655
                                        'args'        => [
589✔
656
                                                'size' => [
589✔
657
                                                        'type'        => 'MediaItemSizeEnum',
589✔
658
                                                        'description' => __( 'Size of the MediaItem to return', 'wp-graphql' ),
589✔
659
                                                ],
589✔
660
                                        ],
589✔
661
                                        'resolve'     => static function ( $image, $args ) {
589✔
662
                                                /**
663
                                                 * By default, use the mediaItemUrl.
664
                                                 *
665
                                                 * @var \WPGraphQL\Model\Post $image
666
                                                 */
667
                                                $source_url = $image->mediaItemUrl;
3✔
668

669
                                                // If there's a url for the provided size, use that instead.
670
                                                if ( ! empty( $args['size'] ) ) {
3✔
671
                                                        $size = ( 'full' === $args['size'] ) ? 'large' : $args['size'];
1✔
672

673
                                                        $source_url = $image->get_source_url_by_size( $size ) ?: $source_url;
1✔
674
                                                }
675

676
                                                // If there's no source_url, return null.
677
                                                if ( empty( $source_url ) ) {
3✔
678
                                                        return null;
×
679
                                                }
680

681
                                                $path_parts    = pathinfo( $source_url );
3✔
682
                                                $original_file = get_attached_file( absint( $image->databaseId ) );
3✔
683
                                                $filesize_path = ! empty( $original_file ) ? path_join( dirname( $original_file ), $path_parts['basename'] ) : null;
3✔
684

685
                                                return ! empty( $filesize_path ) ? filesize( $filesize_path ) : null;
3✔
686
                                        },
589✔
687
                                ],
589✔
688
                                'mimeType'     => [
589✔
689
                                        'type'        => 'String',
589✔
690
                                        'description' => __( 'The mime type of the mediaItem', 'wp-graphql' ),
589✔
691
                                ],
589✔
692
                                'mediaDetails' => [
589✔
693
                                        'type'        => 'MediaDetails',
589✔
694
                                        'description' => __( 'Details about the mediaItem', 'wp-graphql' ),
589✔
695
                                ],
589✔
696
                        ]
589✔
697
                );
589✔
698
        }
699
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc