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

wp-graphql / wp-graphql-woocommerce / 10288284022

07 Aug 2024 04:39PM UTC coverage: 84.506% (-0.08%) from 84.583%
10288284022

push

github

web-flow
feat: QL Session Handler refactored to handle non-GraphQL requests (#870)

* feat: QL Session Handler functionality expanded to support cookies on non-GraphQL requests

* chore: Linter and PHPStan compliance met

* devops: QLSessionHandlerTest patched for suite testing

* chore: Linter and PHPStan compliance met

* fix: More cart session save triggered implemented

* fix: More cart session save triggered implemented

* chore: Linter compliance met

* chore: Linter compliance met

* feat: forgetSession mutation added

* feat: forgetSession mutation added

84 of 124 new or added lines in 18 files covered. (67.74%)

1 existing line in 1 file now uncovered.

12484 of 14773 relevant lines covered (84.51%)

72.58 hits per line

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

62.64
/access-functions.php
1
<?php
2
/**
3
 * This file contains access functions for various class methods
4
 *
5
 * @package WPGraphQL\WooCommerce
6
 * @since 0.0.1
7
 */
8

9
if ( ! function_exists( 'str_starts_with' ) ) {
10
        /**
11
         * Polyfill for PHP 8 str_starts_with function.
12
         * Checks if a string starts with a given substring.
13
         *
14
         * @see https://www.php.net/manual/en/function.str-starts-with.php
15
         *
16
         * @param string $haystack - Source string.
17
         * @param string $needle - Target string.
18
         *
19
         * @return bool - True if $haystack starts with $needle, false otherwise.
20
         */
21
        function str_starts_with( $haystack, $needle ) {
NEW
22
                return 0 === strpos( $haystack, $needle ); // phpcs:ignore PHPCompatibility.FunctionUse.NewFunctionParameters.str_starts_with
×
23
        }
24
}
25

26
if ( ! function_exists( 'str_ends_with' ) ) {
27
        /**
28
         * Polyfill for PHP 8 str_ends_with function.
29
         * Checks if a string ends with a given substring.
30
         *
31
         * @see https://www.php.net/manual/en/function.str-ends-with.php
32
         *
33
         * @param string $haystack - Source string.
34
         * @param string $needle - Target string.
35
         *
36
         * @return bool - True if $haystack ends with $needle, false otherwise.
37
         */
38
        function str_ends_with( $haystack, $needle ) {
39
                $length = strlen( $needle );
×
NEW
40
                return 0 === $length
×
NEW
41
                        || strpos( $haystack, $needle, - $length ) === $length - 1;
×
42
        }
43
}//end if
44

45
if ( ! function_exists( 'wc_graphql_map_tax_statements' ) ) {
46
        /**
47
         * Returns formatted array of tax statement objects.
48
         *
49
         * @param array $raw_taxes - array of raw taxes object from WC_Order_Item crud objects.
50
         *
51
         * @return array
52
         */
53
        function wc_graphql_map_tax_statements( $raw_taxes ) {
54
                $taxes = [];
×
55
                foreach ( $raw_taxes as $field => $values ) {
×
56
                        foreach ( $values as $id => $amount ) {
×
57
                                if ( empty( $taxes[ $id ] ) ) {
×
58
                                        $taxes[ $id ] = [];
×
59
                                }
60
                                $taxes[ $id ]['ID']     = $id;
×
61
                                $taxes[ $id ][ $field ] = $amount;
×
62
                        }
63
                }
64

65
                return array_values( $taxes );
×
66
        }
67
}//end if
68

69
if ( ! function_exists( 'wc_graphql_get_order_statuses' ) ) {
70
        /**
71
         * Get order statuses without prefixes.
72
         *
73
         * @return array
74
         */
75
        function wc_graphql_get_order_statuses() {
76
                $order_statuses = [];
×
77
                foreach ( array_keys( wc_get_order_statuses() ) as $status ) {
×
78
                        $order_statuses[] = str_replace( 'wc-', '', $status );
×
79
                }
80
                return $order_statuses;
×
81
        }
82
}
83

84
if ( ! function_exists( 'wc_graphql_price' ) ) {
85
        /**
86
         * Format the price with a currency symbol.
87
         *
88
         * @param  float|string $price Raw price.
89
         * @param  array        $args  Arguments to format a price {
90
         *            Array of arguments.
91
         *            Defaults to empty array.
92
         *
93
         *     @type string $currency           Currency code.
94
         *                                      Defaults to empty string (Use the result from get_woocommerce_currency()).
95
         *     @type string $decimal_separator  Decimal separator.
96
         *                                      Defaults the result of wc_get_price_decimal_separator().
97
         *     @type string $thousand_separator Thousand separator.
98
         *                                      Defaults the result of wc_get_price_thousand_separator().
99
         *     @type string $decimals           Number of decimals.
100
         *                                      Defaults the result of wc_get_price_decimals().
101
         *     @type string $price_format       Price format depending on the currency position.
102
         *                                      Defaults the result of get_woocommerce_price_format().
103
         * }
104
         * @return string
105
         */
106
        function wc_graphql_price( $price, $args = [] ) {
107
                $price = floatval( $price );
27✔
108
                $args  = apply_filters(
27✔
109
                        'wc_price_args', // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound
27✔
110
                        wp_parse_args(
27✔
111
                                $args,
27✔
112
                                [
27✔
113
                                        'currency'           => '',
27✔
114
                                        'decimal_separator'  => wc_get_price_decimal_separator(),
27✔
115
                                        'thousand_separator' => wc_get_price_thousand_separator(),
27✔
116
                                        'decimals'           => wc_get_price_decimals(),
27✔
117
                                        'price_format'       => get_woocommerce_price_format(),
27✔
118
                                ]
27✔
119
                        )
27✔
120
                );
27✔
121

122
                $unformatted_price = $price;
27✔
123
                $negative          = $price < 0;
27✔
124

125
                // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound
126
                $price = apply_filters( 'raw_woocommerce_price', floatval( $negative ? $price * -1 : $price ) );
27✔
127

128
                $price = apply_filters(
27✔
129
                        // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound
130
                        'formatted_woocommerce_price',
27✔
131
                        number_format(
27✔
132
                                $price,
27✔
133
                                $args['decimals'],
27✔
134
                                $args['decimal_separator'],
27✔
135
                                $args['thousand_separator']
27✔
136
                        ),
27✔
137
                        $price,
27✔
138
                        $args['decimals'],
27✔
139
                        $args['decimal_separator'],
27✔
140
                        $args['thousand_separator']
27✔
141
                );
27✔
142

143
                // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound
144
                if ( apply_filters( 'woocommerce_price_trim_zeros', false ) && $args['decimals'] > 0 ) {
27✔
145
                        $price = wc_trim_zeros( $price );
×
146
                }
147

148
                // phpcs:ignore PHPCompatibility.ParameterValues.NewHTMLEntitiesEncodingDefault.NotSet
149
                $symbol = html_entity_decode( get_woocommerce_currency_symbol( $args['currency'] ) );
27✔
150
                $return = ( $negative ? '-' : '' ) . sprintf( $args['price_format'], $symbol, $price );
27✔
151

152
                /**
153
                 * Filters the string of price markup.
154
                 *
155
                 * @param string $return            Price HTML markup.
156
                 * @param string $price             Formatted price.
157
                 * @param array  $args              Pass on the args.
158
                 * @param float  $unformatted_price Price as float to allow plugins custom formatting.
159
                 * @param string $symbol            Currency symbol.
160
                 */
161
                return apply_filters( 'graphql_woocommerce_price', $return, $price, $args, $unformatted_price, $symbol );
27✔
162
        }
163
}//end if
164

165
if ( ! function_exists( 'wc_graphql_price_range' ) ) {
166
        /**
167
         * Format a price range for display.
168
         *
169
         * @param  string|float $from Price from.
170
         * @param  string|float $to   Price to.
171
         * @return string
172
         */
173
        function wc_graphql_price_range( $from, $to ) {
174
                if ( $from === $to ) {
2✔
175
                        return wc_graphql_price( $from );
×
176
                }
177

178
                $price = sprintf(
2✔
179
                        /* translators: 1: price from 2: price to */
180
                        _x( '%1$s %2$s %3$s', 'Price range: from-to', 'wp-graphql-woocommerce' ),
2✔
181
                        is_numeric( $from ) ? wc_graphql_price( $from ) : $from,
2✔
182
                        apply_filters( 'graphql_woocommerce_format_price_range_separator', '-', $from, $to ),
2✔
183
                        is_numeric( $to ) ? wc_graphql_price( $to ) : $to
2✔
184
                );
2✔
185

186
                return apply_filters( 'graphql_woocommerce_format_price_range', $price, $from, $to );
2✔
187
        }
188
}//end if
189

190
if ( ! function_exists( 'wc_graphql_underscore_to_camel_case' ) ) {
191
        /**
192
         * Converts a camel case formatted string to a underscore formatted string.
193
         *
194
         * @param string $str         String to be formatted.
195
         *
196
         * @return string
197
         */
198
        function wc_graphql_underscore_to_camel_case( $str ) {
199
                return lcfirst( str_replace( ' ', '', ucwords( str_replace( '_', ' ', $str ) ) ) );
×
200
        }
201
}
202

203
if ( ! function_exists( 'wc_graphql_camel_case_to_underscore' ) ) {
204
        /**
205
         * Converts a camel case formatted string to a underscore formatted string.
206
         *
207
         * @param string $str String to be formatted.
208
         *
209
         * @return string
210
         */
211
        function wc_graphql_camel_case_to_underscore( $str ) {
212
                /**
213
                 * @var string  Sort mutated string.
214
                 */
215
                $replace = preg_replace( '/(?<!^)[A-Z]/', '_$0', $str );
4✔
216
                return strtolower( $replace );
4✔
217
        }
218
}//end if
219

220
if ( ! function_exists( 'woographql_setting' ) ) :
221
        /**
222
         * Get an option value from WooGraphQL settings
223
         *
224
         * @param string $option_name   The key of the option to return.
225
         * @param mixed  $default_value The default value the setting should return if no value is set.
226
         * @param string $section_name  The settings section name.
227
         *
228
         * @return mixed|string|int|boolean
229
         */
230
        function woographql_setting( string $option_name, $default_value = '', $section_name = 'woographql_settings' ) {
231
                $section_fields = get_option( $section_name );
142✔
232

233
                /**
234
                 * Filter the section fields
235
                 *
236
                 * @param array  $section_fields The values of the fields stored for the section
237
                 * @param string $section_name   The name of the section
238
                 * @param mixed  $default        The default value for the option being retrieved
239
                 */
240
                $section_fields = apply_filters( 'woographql_settings_section_fields', $section_fields, $section_name, $default_value );
142✔
241

242
                /**
243
                 * Get the value from the stored data, or return the default
244
                 */
245
                if ( is_array( $default_value ) ) {
142✔
246
                        $value = is_array( $section_fields ) && ! empty( $section_fields[ $option_name ] ) ? $section_fields[ $option_name ] : $default_value;
×
247
                } else {
248
                        $value = isset( $section_fields[ $option_name ] ) ? $section_fields[ $option_name ] : $default_value;
142✔
249
                }
250

251
                /**
252
                 * Filter the value before returning it
253
                 *
254
                 * @param mixed  $value          The value of the field
255
                 * @param mixed  $default_value  The default value if there is no value set
256
                 * @param string $option_name    The name of the option
257
                 * @param array  $section_fields The setting values within the section
258
                 * @param string $section_name   The name of the section the setting belongs to
259
                 */
260
                return apply_filters( 'woographql_settings_section_field_value', $value, $default_value, $option_name, $section_fields, $section_name );
142✔
261
        }
262
endif;
263

264
if ( ! function_exists( 'woographql_get_session_uid' ) ) :
265
        /**
266
         * Returns end-user's customer ID.
267
         *
268
         * @return int
269
         */
270
        function woographql_get_session_uid() {
271
                /**
272
                 * Session Handler
273
                 *
274
                 * @var \WPGraphQL\WooCommerce\Utils\QL_Session_Handler|\WPGraphQL\WooCommerce\Utils\Transfer_Session_Handler $session
275
                 */
276
                $session = WC()->session;
1✔
277
                return $session->get_customer_id();
1✔
278
        }
279
endif;
280

281
if ( ! function_exists( 'woographql_get_session_token' ) ) :
282
        /**
283
         * Returns session user's "client_session_id"
284
         *
285
         * @return string
286
         */
287
        function woographql_get_session_token() {
288
                /**
289
                 * Session Handler
290
                 *
291
                 * @var \WPGraphQL\WooCommerce\Utils\QL_Session_Handler|\WPGraphQL\WooCommerce\Utils\Transfer_Session_Handler $session
292
                 */
293
                $session = WC()->session;
1✔
294
                return $session->get_client_session_id();
1✔
295
        }
296
endif;
297

298
if ( ! function_exists( 'woographql_create_nonce' ) ) :
299
        /**
300
         * Creates WooGraphQL session transfer nonces.
301
         *
302
         * @param string|int $action  Nonce name.
303
         *
304
         * @return string The nonce.
305
         */
306
        function woographql_create_nonce( $action = -1 ) {
307
                $uid   = woographql_get_session_uid();
1✔
308
                $token = woographql_get_session_token();
1✔
309
                $i     = wp_nonce_tick( $action );
1✔
310

311
                return substr( wp_hash( $i . '|' . $action . '|' . $uid . '|' . $token, 'nonce' ), -12, 10 );
1✔
312
        }
313
endif;
314

315
if ( ! function_exists( 'woographql_verify_nonce' ) ) :
316
        /**
317
         * Validate WooGraphQL session transfer nonces.
318
         *
319
         * @param string         $nonce   Nonce to validated.
320
         * @param integer|string $action  Nonce name.
321
         *
322
         * @return false|int
323
         */
324
        function woographql_verify_nonce( $nonce, $action = -1 ) {
325
                $nonce = (string) $nonce;
×
326
                $uid   = woographql_get_session_uid();
×
327

328
                if ( empty( $nonce ) ) {
×
329
                        return false;
×
330
                }
331

332
                $token = woographql_get_session_token();
×
333
                $i     = wp_nonce_tick( $action );
×
334

335
                // Nonce generated 0-12 hours ago.
336
                $expected = substr( wp_hash( $i . '|' . $action . '|' . $uid . '|' . $token, 'nonce' ), -12, 10 );
×
337
                if ( hash_equals( $expected, $nonce ) ) {
×
338
                        return 1;
×
339
                }
340

341
                // Nonce generated 12-24 hours ago.
342
                $expected = substr( wp_hash( ( $i - 1 ) . '|' . $action . '|' . $uid . '|' . $token, 'nonce' ), -12, 10 );
×
343
                if ( hash_equals( $expected, $nonce ) ) {
×
344
                        return 2;
×
345
                }
346

347
                /**
348
                 * Fires when nonce verification fails.
349
                 *
350
                 * @since 4.4.0
351
                 *
352
                 * @param string     $nonce  The invalid nonce.
353
                 * @param string|int $action The nonce action.
354
                 * @param string|int $uid    User ID.
355
                 * @param string     $token  The user's session token.
356
                 */
357
                do_action( 'graphql_verify_nonce_failed', $nonce, $action, $uid, $token );
×
358

359
                // Invalid nonce.
360
                return false;
×
361
        }
362
endif;
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