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

wp-graphql / wp-graphql-woocommerce / 23659243833

27 Mar 2026 05:31PM UTC coverage: 89.384% (+0.2%) from 89.165%
23659243833

Pull #1002

github

web-flow
Merge f11452603 into 66f840efc
Pull Request #1002: feat: WC Settings API, compatibility refactor, HPOS fix

515 of 570 new or added lines in 11 files covered. (90.35%)

31 existing lines in 4 files now uncovered.

15795 of 17671 relevant lines covered (89.38%)

137.86 hits per line

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

65.25
/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();
29✔
25
                self::add_acf_filters();
29✔
26
                self::add_jwt_auth_filters();
29✔
27
                self::add_swp_filters();
29✔
28
        }
29

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

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

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

NEW
67
                return $id;
×
68
        }
69

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

NEW
98
                return $source;
×
99
        }
100

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

NEW
113
                return null;
×
114
        }
115

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

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

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

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

146
                return $token;
8✔
147
        }
148

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

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

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

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

174
                return $refresh_token;
8✔
175
        }
176

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

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

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

203
                return $types;
271✔
204
        }
205

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

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

229
                                                return self::get_auth_token( $user );
8✔
230
                                        },
162✔
231
                                ],
162✔
232
                                'refreshToken' => [
162✔
233
                                        'type'        => $type_registry->get_type( 'String' ),
162✔
234
                                        'description' => __( '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' ),
162✔
235
                                        'resolve'     => static function ( $payload ) {
162✔
236
                                                $user = get_user_by( 'ID', $payload['id'] );
8✔
237

238
                                                if ( ! $user ) {
8✔
239
                                                        throw new UserError( __( 'User not found.', 'wp-graphql-woocommerce' ) );
×
240
                                                }
241

242
                                                return self::get_refresh_token( $user );
8✔
243
                                        },
162✔
244
                                ],
162✔
245
                        ]
162✔
246
                );
162✔
247
        }
248

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

268
                if ( ! WooCommerce_Filters::is_session_handler_disabled() ) {
271✔
269
                        $token_type = woographql_setting( 'set_session_token_type', 'legacy' );
271✔
270
                        if ( in_array( $token_type, [ 'legacy', 'both' ], true ) ) {
271✔
271
                                register_graphql_field(
270✔
272
                                        'LoginPayload',
270✔
273
                                        'sessionToken',
270✔
274
                                        [
270✔
275
                                                'type'        => 'String',
270✔
276
                                                'description' => __( 'A JWT token that can be used in future requests to for WooCommerce session identification', 'wp-graphql-woocommerce' ),
270✔
277
                                                'resolve'     => static function () {
270✔
278
                                                        /** @var \WPGraphQL\WooCommerce\Utils\QL_Session_Handler $session */
279
                                                        $session = \WC()->session;
15✔
280

281
                                                        return apply_filters( 'graphql_customer_session_token', $session->build_token() );
15✔
282
                                                },
270✔
283
                                        ]
270✔
284
                                );
270✔
285
                        }
286
                        if ( in_array( $token_type, [ 'store-api', 'both' ], true ) ) {
271✔
287
                                register_graphql_field(
2✔
288
                                        'LoginPayload',
2✔
289
                                        'cartToken',
2✔
290
                                        [
2✔
291
                                                'type'        => 'String',
2✔
292
                                                'description' => __( 'A JWT token that can be used in future requests to for WooCommerce session identification', 'wp-graphql-woocommerce' ),
2✔
293
                                                'resolve'     => static function () {
2✔
294
                                                        /** @var \WPGraphQL\WooCommerce\Utils\QL_Session_Handler $session */
295
                                                        $session = \WC()->session;
×
296

297
                                                        return apply_filters( 'graphql_customer_session_token', $session->build_cart_token() );
×
298
                                                },
2✔
299
                                        ]
2✔
300
                                );
2✔
301
                        }
302
                }
303
        }
304

305
        /**
306
         * Register SearchWP/QL Search compatibility filters.
307
         *
308
         * @return void
309
         */
310
        private static function add_swp_filters() {
311
                add_filter( 'graphql_swp_result_possible_types', [ self::class, 'searchwp_result_possible_types' ] );
29✔
312
        }
313

314
        /**
315
         * Adds product types to QL Search SWPResult possible types.
316
         *
317
         * @param array $type_names SWPResults possible types.
318
         *
319
         * @return array
320
         */
321
        public static function searchwp_result_possible_types( array $type_names ) {
NEW
322
                if ( in_array( 'Product', $type_names, true ) ) {
×
NEW
323
                        $type_names = array_merge(
×
NEW
324
                                array_filter(
×
NEW
325
                                        $type_names,
×
NEW
326
                                        static function ( $type_name ) {
×
NEW
327
                                                return 'Product' !== $type_name;
×
NEW
328
                                        }
×
NEW
329
                                ),
×
NEW
330
                                [
×
NEW
331
                                        'SimpleProduct',
×
NEW
332
                                        'VariableProduct',
×
NEW
333
                                        'GroupProduct',
×
NEW
334
                                        'ExternalProduct',
×
NEW
335
                                ]
×
NEW
336
                        );
×
337
                }
338

NEW
339
                return $type_names;
×
340
        }
341
}
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