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

wp-graphql / wp-graphql-woocommerce / 23779262545

31 Mar 2026 03:37AM UTC coverage: 91.718% (+1.0%) from 90.757%
23779262545

push

github

web-flow
perf: Migrate type descriptions to lazy lambdas (#1005)

* perf: Migrate type descriptions to lazy lambdas

Convert all eager description strings from:
  'description' => __( '...', 'wp-graphql-woocommerce' ),
to deferred lambdas:
  'description' => static function () { return __( '...', 'wp-graphql-woocommerce' ); },

This defers the __() translation call until the description is actually
needed (e.g. during schema introspection), avoiding unnecessary
translation overhead on every GraphQL request. Mirrors the pattern
used in WPGraphQL core.

1206 descriptions converted across 169 files.

* chore: Linter compliances met

3598 of 3630 new or added lines in 167 files covered. (99.12%)

1 existing line in 1 file now uncovered.

18328 of 19983 relevant lines covered (91.72%)

145.82 hits per line

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

62.05
/includes/class-compatibility.php
1
<?php
2
/**
3
 * Compatibility integrations with third-party plugins.
4
 *
5
 * @package \WPGraphQL\WooCommerce
6
 * @since   TBD
7
 */
8

9
namespace WPGraphQL\WooCommerce;
10

11
use GraphQL\Error\UserError;
12
use WPGraphQL\WooCommerce\Model\Customer;
13

14
/**
15
 * Class Compatibility
16
 */
17
class Compatibility {
18
        /**
19
         * Register all compatibility filters.
20
         *
21
         * @return void
22
         */
23
        public static function setup() {
24
                self::register_wc_admin_settings();
31✔
25
                self::add_acf_filters();
31✔
26
                self::add_jwt_auth_filters();
31✔
27
                self::add_stripe_gateway_filters();
31✔
28
                self::add_swp_filters();
31✔
29
        }
30

31
        /**
32
         * Register WC admin settings for GraphQL requests.
33
         *
34
         * WooCommerce only registers settings groups during rest_api_init.
35
         * We need them available for GraphQL settings queries and mutations.
36
         *
37
         * @return void
38
         */
39
        private static function register_wc_admin_settings() {
40
                if ( method_exists( WC(), 'register_wp_admin_settings' ) ) {
31✔
41
                        WC()->register_wp_admin_settings(); // @phpstan-ignore method.private (public since WC 9.0)
31✔
42
                }
43
        }
44

45
        /**
46
         * Register WPGraphQL ACF compatibility filters.
47
         *
48
         * @return void
49
         */
50
        private static function add_acf_filters() {
51
                add_filter( 'graphql_acf_get_root_id', [ self::class, 'resolve_crud_root_id' ], 10, 2 );
31✔
52
                add_filter( 'graphql_acf_post_object_source', [ self::class, 'resolve_post_object_source' ], 10, 2 );
31✔
53
        }
54

55
        /**
56
         * Resolve post object ID from CRUD object Model.
57
         *
58
         * @param integer|null $id    Post object database ID.
59
         * @param mixed        $root  Root resolver.
60
         *
61
         * @return integer|null
62
         */
63
        public static function resolve_crud_root_id( $id, $root ) {
64
                if ( $root instanceof Model\WC_Post ) {
×
65
                        $id = absint( $root->ID );
×
66
                }
67

68
                return $id;
×
69
        }
70

71
        /**
72
         * Filters ACF "post_object" field type resolver to ensure that
73
         * the proper Type source is provided for WooCommerce CPTs.
74
         *
75
         * @param mixed|null $source  source of the data being provided.
76
         * @param mixed|null $value  Post ID.
77
         *
78
         * @return mixed|null
79
         */
80
        public static function resolve_post_object_source( $source, $value ) {
81
                $post = get_post( $value );
×
82
                if ( $post instanceof \WP_Post ) {
×
83
                        switch ( $post->post_type ) {
×
84
                                case 'shop_coupon':
×
85
                                        $source = new Model\Coupon( $post->ID );
×
86
                                        break;
×
87
                                case 'shop_order':
×
88
                                        $source = new Model\Order( $post->ID );
×
89
                                        break;
×
90
                                case 'product':
×
91
                                        $source = new Model\Product( $post->ID );
×
92
                                        break;
×
93
                                case 'product_variation':
×
94
                                        $source = new Model\Product_Variation( $post->ID );
×
95
                                        break;
×
96
                        }
97
                }
98

99
                return $source;
×
100
        }
101

102
        /**
103
         * Get the JWT auth class if available.
104
         *
105
         * @return string|null
106
         */
107
        public static function get_auth_class() {
108
                if ( class_exists( 'WPGraphQL\JWT_Authentication\Auth' ) ) {
39✔
109
                        return \WPGraphQL\JWT_Authentication\Auth::class;
39✔
110
                } elseif ( class_exists( 'WPGraphQL\Login\Auth\TokenManager' ) ) {
×
111
                        return \WPGraphQL\Login\Auth\TokenManager::class;
×
112
                }
113

114
                return null;
×
115
        }
116

117
        /**
118
         * Get the auth token for a user.
119
         *
120
         * @param \WP_User $user The user object.
121
         *
122
         * @throws \GraphQL\Error\UserError If the token cannot be retrieved.
123
         *
124
         * @return string|null
125
         */
126
        public static function get_auth_token( \WP_User $user ) {
127
                $auth_class = self::get_auth_class();
8✔
128

129
                if ( ! $auth_class ) {
8✔
130
                        return null;
×
131
                }
132

133
                /**
134
                 * @var \WP_Error|string|null $token
135
                 */
136
                $token = null;
8✔
137
                if ( 'WPGraphQL\JWT_Authentication\Auth' === $auth_class ) {
8✔
138
                        $token = $auth_class::get_token( $user );
8✔
139
                } elseif ( 'WPGraphQL\Login\Auth\TokenManager' === $auth_class ) {
×
140
                        $token = $auth_class::get_auth_token( $user );
×
141
                }
142

143
                if ( is_wp_error( $token ) ) {
8✔
144
                        throw new UserError( $token->get_error_message() );
×
145
                }
146

147
                return $token;
8✔
148
        }
149

150
        /**
151
         * Get the refresh token for a user.
152
         *
153
         * @param \WP_User $user The user object.
154
         *
155
         * @throws \GraphQL\Error\UserError If the token cannot be retrieved.
156
         *
157
         * @return string|null
158
         */
159
        public static function get_refresh_token( \WP_User $user ) {
160
                $auth_class = self::get_auth_class();
8✔
161

162
                if ( ! $auth_class ) {
8✔
163
                        return null;
×
164
                }
165

166
                /**
167
                 * @var \WP_Error|string|null $refresh_token
168
                 */
169
                $refresh_token = $auth_class::get_refresh_token( $user );
8✔
170

171
                if ( is_wp_error( $refresh_token ) ) {
8✔
172
                        throw new UserError( $refresh_token->get_error_message() );
×
173
                }
174

175
                return $refresh_token;
8✔
176
        }
177

178
        /**
179
         * Register WPGraphQL JWT Authentication compatibility filters.
180
         *
181
         * @return void
182
         */
183
        private static function add_jwt_auth_filters() {
184
                $auth_class = self::get_auth_class();
31✔
185
                if ( is_null( $auth_class ) ) {
31✔
186
                        return;
×
187
                }
188

189
                add_filter( 'graphql_jwt_user_types', [ self::class, 'add_customer_to_jwt_user_types' ], 10 );
31✔
190
                add_filter( 'graphql_registerCustomerPayload_fields', [ self::class, 'add_jwt_output_fields' ], 10, 3 );
31✔
191
                add_filter( 'graphql_updateCustomerPayload_fields', [ self::class, 'add_jwt_output_fields' ], 10, 3 );
31✔
192
                add_action( 'graphql_register_types', [ self::class, 'add_customer_to_login_payload' ], 10 );
31✔
193
        }
194

195
        /**
196
         * Adds Customer type to the JWT User type list.
197
         *
198
         * @param array $types JWT User types.
199
         * @return array
200
         */
201
        public static function add_customer_to_jwt_user_types( array $types ) {
202
                $types[] = 'Customer';
285✔
203

204
                return $types;
285✔
205
        }
206

207
        /**
208
         * Adds all JWT related fields to the Customer mutation output.
209
         *
210
         * @param array                             $fields         Mutation output field definitions.
211
         * @param \WPGraphQL\Type\WPInputObjectType $object_type    The WPInputObjectType the fields are be added to.
212
         * @param \WPGraphQL\Registry\TypeRegistry  $type_registry  TypeRegistry instance.
213
         *
214
         * @return array
215
         */
216
        public static function add_jwt_output_fields( $fields, $object_type, $type_registry ): array {
217
                return array_merge(
144✔
218
                        $fields,
144✔
219
                        [
144✔
220
                                'authToken'    => [
144✔
221
                                        'type'        => $type_registry->get_type( 'String' ),
144✔
222
                                        'description' => static function () {
144✔
223
                                                return __( 'JWT Token that can be used in future requests for Authentication', 'wp-graphql-woocommerce' );
2✔
224
                                        },
144✔
225
                                        'resolve'     => static function ( $payload ) {
144✔
226
                                                $user = get_user_by( 'ID', $payload['id'] );
8✔
227

228
                                                if ( ! $user ) {
8✔
229
                                                        throw new UserError( __( 'User not found.', 'wp-graphql-woocommerce' ) );
×
230
                                                }
231

232
                                                return self::get_auth_token( $user );
8✔
233
                                        },
144✔
234
                                ],
144✔
235
                                'refreshToken' => [
144✔
236
                                        'type'        => $type_registry->get_type( 'String' ),
144✔
237
                                        'description' => static function () {
144✔
238
                                                return __( 'A JWT token that can be used in future requests to get a refreshed jwtAuthToken. If the refresh token used in a request is revoked or otherwise invalid, a valid Auth token will NOT be issued in the response headers.', 'wp-graphql-woocommerce' );
2✔
239
                                        },
144✔
240
                                        'resolve'     => static function ( $payload ) {
144✔
241
                                                $user = get_user_by( 'ID', $payload['id'] );
8✔
242

243
                                                if ( ! $user ) {
8✔
244
                                                        throw new UserError( __( 'User not found.', 'wp-graphql-woocommerce' ) );
×
245
                                                }
246

247
                                                return self::get_refresh_token( $user );
8✔
248
                                        },
144✔
249
                                ],
144✔
250
                        ]
144✔
251
                );
144✔
252
        }
253

254
        /**
255
         * Adds "customer" field to "login" mutation payload.
256
         *
257
         * @return void
258
         */
259
        public static function add_customer_to_login_payload() {
260
                register_graphql_field(
285✔
261
                        'LoginPayload',
285✔
262
                        'customer',
285✔
263
                        [
285✔
264
                                'type'        => 'Customer',
285✔
265
                                'description' => static function () {
285✔
266
                                        return __( 'Customer object of authenticated user.', 'wp-graphql-woocommerce' );
2✔
267
                                },
285✔
268
                                'resolve'     => static function ( $payload ) {
285✔
269
                                        $id = $payload['id'];
15✔
270
                                        return new Customer( $id );
15✔
271
                                },
285✔
272
                        ]
285✔
273
                );
285✔
274

275
                if ( ! wc_graphql_is_session_handler_disabled() ) {
285✔
276
                        $token_type = woographql_setting( 'set_session_token_type', 'legacy' );
285✔
277
                        if ( in_array( $token_type, [ 'legacy', 'both' ], true ) ) {
285✔
278
                                register_graphql_field(
284✔
279
                                        'LoginPayload',
284✔
280
                                        'sessionToken',
284✔
281
                                        [
284✔
282
                                                'type'        => 'String',
284✔
283
                                                'description' => static function () {
284✔
284
                                                        return __( 'A JWT token that can be used in future requests to for WooCommerce session identification', 'wp-graphql-woocommerce' );
2✔
285
                                                },
284✔
286
                                                'resolve'     => static function () {
284✔
287
                                                        /** @var \WPGraphQL\WooCommerce\Utils\QL_Session_Handler $session */
288
                                                        $session = \WC()->session;
15✔
289

290
                                                        return apply_filters( 'graphql_customer_session_token', $session->build_token() );
15✔
291
                                                },
284✔
292
                                        ]
284✔
293
                                );
284✔
294
                        }
295
                        if ( in_array( $token_type, [ 'store-api', 'both' ], true ) ) {
285✔
296
                                register_graphql_field(
2✔
297
                                        'LoginPayload',
2✔
298
                                        'cartToken',
2✔
299
                                        [
2✔
300
                                                'type'        => 'String',
2✔
301
                                                'description' => static function () {
2✔
NEW
302
                                                        return __( 'A JWT token that can be used in future requests to for WooCommerce session identification', 'wp-graphql-woocommerce' );
×
303
                                                },
2✔
304
                                                'resolve'     => static function () {
2✔
305
                                                        /** @var \WPGraphQL\WooCommerce\Utils\QL_Session_Handler $session */
306
                                                        $session = \WC()->session;
×
307

308
                                                        return apply_filters( 'graphql_customer_session_token', $session->build_cart_token() );
×
309
                                                },
2✔
310
                                        ]
2✔
311
                                );
2✔
312
                        }
313
                }
314
        }
315

316
        /**
317
         * Register WooCommerce Stripe Gateway compatibility filters.
318
         *
319
         * @return void
320
         */
321
        private static function add_stripe_gateway_filters() {
322
                add_filter( 'graphql_stripe_process_payment_args', [ self::class, 'woocommerce_gateway_stripe_args' ], 10, 2 );
31✔
323
        }
324

325
        /**
326
         * Adds extra arguments to the Stripe Gateway process payment call.
327
         *
328
         * @param array  $gateway_args    Arguments to be passed to the gateway `process_payment` method.
329
         * @param string $payment_method  Payment gateway ID.
330
         *
331
         * @return array
332
         */
333
        public static function woocommerce_gateway_stripe_args( $gateway_args, $payment_method ) {
334
                /** @var false|\WC_Order|\WC_Order_Refund $order */
335
                $order = wc_get_order( $gateway_args[0] );
×
336
                if ( false === $order ) {
×
337
                        return $gateway_args;
×
338
                }
339

340
                $stripe_source_id = $order->get_meta( '_stripe_source_id' );
×
341
                if ( 'stripe' === $payment_method && ! empty( $stripe_source_id ) ) {
×
342
                        $gateway_args = [
×
343
                                $gateway_args[0],
×
344
                                true,
×
345
                                false,
×
346
                                false,
×
347
                                true,
×
348
                        ];
×
349
                }
350

351
                return $gateway_args;
×
352
        }
353

354
        /**
355
         * Register SearchWP/QL Search compatibility filters.
356
         *
357
         * @return void
358
         */
359
        private static function add_swp_filters() {
360
                add_filter( 'graphql_swp_result_possible_types', [ self::class, 'searchwp_result_possible_types' ] );
31✔
361
        }
362

363
        /**
364
         * Adds product types to QL Search SWPResult possible types.
365
         *
366
         * @param array $type_names SWPResults possible types.
367
         *
368
         * @return array
369
         */
370
        public static function searchwp_result_possible_types( array $type_names ) {
371
                if ( in_array( 'Product', $type_names, true ) ) {
×
372
                        $type_names = array_merge(
×
373
                                array_filter(
×
374
                                        $type_names,
×
375
                                        static function ( $type_name ) {
×
376
                                                return 'Product' !== $type_name;
×
377
                                        }
×
378
                                ),
×
379
                                [
×
380
                                        'SimpleProduct',
×
381
                                        'VariableProduct',
×
382
                                        'GroupProduct',
×
383
                                        'ExternalProduct',
×
384
                                ]
×
385
                        );
×
386
                }
387

388
                return $type_names;
×
389
        }
390
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc