2019-10-03 14:31:47 -04:00
<? php
/**
2026-03-27 16:32:30 -04:00
* Compatibility integrations with third-party plugins.
2019-10-03 14:31:47 -04:00
*
2019-10-25 19:13:36 -04:00
* @package \WPGraphQL\WooCommerce
2026-03-31 11:06:51 -04:00
* @since 1.0.0
2019-10-03 14:31:47 -04:00
*/
2019-10-25 19:13:36 -04:00
namespace WPGraphQL\WooCommerce ;
2019-10-03 14:31:47 -04:00
use GraphQL\Error\UserError ;
2020-01-11 14:27:04 -05:00
use WPGraphQL\WooCommerce\Model\Customer ;
2023-06-13 23:17:02 +03:00
2019-10-03 14:31:47 -04:00
/**
2026-03-27 16:32:30 -04:00
* Class Compatibility
2019-10-03 14:31:47 -04:00
*/
2026-03-27 16:32:30 -04:00
class Compatibility {
2023-10-16 18:55:16 -04:00
/**
2026-03-27 16:32:30 -04:00
* Register all compatibility filters.
*
* @return void
*/
public static function setup () {
self :: register_wc_admin_settings ();
self :: add_acf_filters ();
self :: add_jwt_auth_filters ();
self :: add_stripe_gateway_filters ();
self :: add_swp_filters ();
}
/**
* Register WC admin settings for GraphQL requests.
*
* WooCommerce only registers settings groups during rest_api_init.
* We need them available for GraphQL settings queries and mutations.
*
* @return void
*/
private static function register_wc_admin_settings () {
if ( method_exists ( WC (), 'register_wp_admin_settings' ) ) {
WC () -> register_wp_admin_settings (); // @phpstan-ignore method.private (public since WC 9.0)
}
}
/**
* Register WPGraphQL ACF compatibility filters.
*
* @return void
*/
private static function add_acf_filters () {
add_filter ( 'graphql_acf_get_root_id' , [ self :: class , 'resolve_crud_root_id' ], 10 , 2 );
add_filter ( 'graphql_acf_post_object_source' , [ self :: class , 'resolve_post_object_source' ], 10 , 2 );
}
/**
* Resolve post object ID from CRUD object Model.
*
* @param integer|null $id Post object database ID.
* @param mixed $root Root resolver.
*
* @return integer|null
*/
public static function resolve_crud_root_id ( $id , $root ) {
if ( $root instanceof Model\WC_Post ) {
$id = absint ( $root -> ID );
}
return $id ;
}
/**
* Filters ACF "post_object" field type resolver to ensure that
* the proper Type source is provided for WooCommerce CPTs.
*
* @param mixed|null $source source of the data being provided.
* @param mixed|null $value Post ID.
*
* @return mixed|null
*/
public static function resolve_post_object_source ( $source , $value ) {
$post = get_post ( $value );
if ( $post instanceof \WP_Post ) {
switch ( $post -> post_type ) {
case 'shop_coupon' :
$source = new Model\Coupon ( $post -> ID );
break ;
case 'shop_order' :
$source = new Model\Order ( $post -> ID );
break ;
case 'product' :
$source = new Model\Product ( $post -> ID );
break ;
case 'product_variation' :
$source = new Model\Product_Variation ( $post -> ID );
break ;
}
}
return $source ;
}
/**
* Get the JWT auth class if available.
2023-10-16 18:55:16 -04:00
*
* @return string|null
*/
public static function get_auth_class () {
if ( class_exists ( 'WPGraphQL\JWT_Authentication\Auth' ) ) {
return \WPGraphQL\JWT_Authentication\Auth :: class ;
} elseif ( class_exists ( 'WPGraphQL\Login\Auth\TokenManager' ) ) {
return \WPGraphQL\Login\Auth\TokenManager :: class ;
}
2026-03-27 16:32:30 -04:00
return null ;
2023-10-16 18:55:16 -04:00
}
/**
* Get the auth token for a user.
*
* @param \WP_User $user The user object.
2024-05-16 21:27:54 -04:00
*
2023-10-16 18:55:16 -04:00
* @throws \GraphQL\Error\UserError If the token cannot be retrieved.
*
* @return string|null
*/
public static function get_auth_token ( \WP_User $user ) {
$auth_class = self :: get_auth_class ();
if ( ! $auth_class ) {
return null ;
}
2026-03-27 16:32:30 -04:00
2023-10-16 18:55:16 -04:00
/**
2026-03-27 16:32:30 -04:00
* @var \WP_Error|string|null $token
*/
2023-10-16 18:55:16 -04:00
$token = null ;
if ( 'WPGraphQL\JWT_Authentication\Auth' === $auth_class ) {
$token = $auth_class :: get_token ( $user );
} elseif ( 'WPGraphQL\Login\Auth\TokenManager' === $auth_class ) {
$token = $auth_class :: get_auth_token ( $user );
}
if ( is_wp_error ( $token ) ) {
throw new UserError ( $token -> get_error_message () );
}
return $token ;
}
/**
* Get the refresh token for a user.
*
* @param \WP_User $user The user object.
2024-05-16 21:27:54 -04:00
*
2023-10-16 18:55:16 -04:00
* @throws \GraphQL\Error\UserError If the token cannot be retrieved.
*
* @return string|null
*/
public static function get_refresh_token ( \WP_User $user ) {
$auth_class = self :: get_auth_class ();
if ( ! $auth_class ) {
return null ;
}
/**
* @var \WP_Error|string|null $refresh_token
*/
$refresh_token = $auth_class :: get_refresh_token ( $user );
if ( is_wp_error ( $refresh_token ) ) {
throw new UserError ( $refresh_token -> get_error_message () );
}
return $refresh_token ;
}
2019-10-03 14:31:47 -04:00
/**
2026-03-27 16:32:30 -04:00
* Register WPGraphQL JWT Authentication compatibility filters.
2023-06-13 23:17:02 +03:00
*
* @return void
2019-10-03 14:31:47 -04:00
*/
2026-03-27 16:32:30 -04:00
private static function add_jwt_auth_filters () {
2023-10-16 18:55:16 -04:00
$auth_class = self :: get_auth_class ();
2026-03-27 16:32:30 -04:00
if ( is_null ( $auth_class ) ) {
return ;
2019-10-03 14:31:47 -04:00
}
2026-03-27 16:32:30 -04:00
add_filter ( 'graphql_jwt_user_types' , [ self :: class , 'add_customer_to_jwt_user_types' ], 10 );
add_filter ( 'graphql_registerCustomerPayload_fields' , [ self :: class , 'add_jwt_output_fields' ], 10 , 3 );
add_filter ( 'graphql_updateCustomerPayload_fields' , [ self :: class , 'add_jwt_output_fields' ], 10 , 3 );
add_action ( 'graphql_register_types' , [ self :: class , 'add_customer_to_login_payload' ], 10 );
2019-10-03 14:31:47 -04:00
}
/**
2020-01-14 18:22:35 -05:00
* Adds Customer type to the JWT User type list.
2019-10-03 14:31:47 -04:00
*
2020-04-30 22:11:09 -03:00
* @param array $types JWT User types.
2020-01-14 18:22:35 -05:00
* @return array
2019-10-03 14:31:47 -04:00
*/
2020-04-30 22:11:09 -03:00
public static function add_customer_to_jwt_user_types ( array $types ) {
2020-01-14 18:22:35 -05:00
$types [] = 'Customer' ;
2019-10-03 14:31:47 -04:00
2020-01-14 18:22:35 -05:00
return $types ;
2019-10-03 14:31:47 -04:00
}
/**
* Adds all JWT related fields to the Customer mutation output.
*
2019-12-20 13:07:49 -05:00
* @param array $fields Mutation output field definitions.
2023-11-30 15:41:32 +02:00
* @param \WPGraphQL\Type\WPInputObjectType $object_type The WPInputObjectType the fields are be added to.
2019-12-20 13:07:49 -05:00
* @param \WPGraphQL\Registry\TypeRegistry $type_registry TypeRegistry instance.
2023-06-13 23:17:02 +03:00
*
2020-04-30 22:11:09 -03:00
* @return array
2019-10-03 14:31:47 -04:00
*/
2023-11-30 15:41:32 +02:00
public static function add_jwt_output_fields ( $fields , $object_type , $type_registry ) : array {
2026-03-27 16:32:30 -04:00
return array_merge (
2019-10-03 14:31:47 -04:00
$fields ,
2022-08-26 14:53:36 -04:00
[
'authToken' => [
2019-12-20 13:07:49 -05:00
'type' => $type_registry -> get_type ( 'String' ),
2026-03-30 23:37:51 -04:00
'description' => static function () {
2026-06-30 10:16:21 -04:00
return __ ( 'JWT Token that can be used in future requests for Authentication' , 'graphql-for-ecommerce' );
2026-03-30 23:37:51 -04:00
},
2023-07-20 00:11:25 +03:00
'resolve' => static function ( $payload ) {
2023-06-13 23:17:02 +03:00
$user = get_user_by ( 'ID' , $payload [ 'id' ] );
if ( ! $user ) {
2026-06-30 10:16:21 -04:00
throw new UserError ( __ ( 'User not found.' , 'graphql-for-ecommerce' ) );
2023-06-13 23:17:02 +03:00
}
2023-10-16 18:55:16 -04:00
return self :: get_auth_token ( $user );
2019-10-03 14:31:47 -04:00
},
2022-08-26 14:53:36 -04:00
],
'refreshToken' => [
2019-12-20 13:07:49 -05:00
'type' => $type_registry -> get_type ( 'String' ),
2026-03-30 23:37:51 -04:00
'description' => static function () {
2026-06-30 10:16:21 -04:00
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.' , 'graphql-for-ecommerce' );
2026-03-30 23:37:51 -04:00
},
2023-07-20 00:11:25 +03:00
'resolve' => static function ( $payload ) {
2023-06-13 23:17:02 +03:00
$user = get_user_by ( 'ID' , $payload [ 'id' ] );
if ( ! $user ) {
2026-06-30 10:16:21 -04:00
throw new UserError ( __ ( 'User not found.' , 'graphql-for-ecommerce' ) );
2023-06-13 23:17:02 +03:00
}
2023-10-16 18:55:16 -04:00
return self :: get_refresh_token ( $user );
2019-10-03 14:31:47 -04:00
},
2022-08-26 14:53:36 -04:00
],
]
2019-10-03 14:31:47 -04:00
);
}
2020-01-11 14:27:04 -05:00
/**
2020-04-30 22:11:09 -03:00
* Adds "customer" field to "login" mutation payload.
2023-06-13 23:17:02 +03:00
*
* @return void
2020-01-11 14:27:04 -05:00
*/
public static function add_customer_to_login_payload () {
2023-06-13 23:17:02 +03:00
register_graphql_field (
2020-01-11 14:27:04 -05:00
'LoginPayload' ,
2023-06-13 23:17:02 +03:00
'customer' ,
2022-08-26 14:53:36 -04:00
[
2023-06-13 23:17:02 +03:00
'type' => 'Customer' ,
2026-03-30 23:37:51 -04:00
'description' => static function () {
2026-06-30 10:16:21 -04:00
return __ ( 'Customer object of authenticated user.' , 'graphql-for-ecommerce' );
2026-03-30 23:37:51 -04:00
},
2023-07-20 00:11:25 +03:00
'resolve' => static function ( $payload ) {
2023-06-13 23:17:02 +03:00
$id = $payload [ 'id' ];
return new Customer ( $id );
},
]
);
2026-03-27 16:32:30 -04:00
if ( ! wc_graphql_is_session_handler_disabled () ) {
2026-01-16 12:28:23 -05:00
$token_type = woographql_setting ( 'set_session_token_type' , 'legacy' );
if ( in_array ( $token_type , [ 'legacy' , 'both' ], true ) ) {
register_graphql_field (
'LoginPayload' ,
'sessionToken' ,
[
'type' => 'String' ,
2026-03-30 23:37:51 -04:00
'description' => static function () {
2026-06-30 10:16:21 -04:00
return __ ( 'A JWT token that can be used in future requests to for WooCommerce session identification' , 'graphql-for-ecommerce' );
2026-03-30 23:37:51 -04:00
},
2026-01-16 12:28:23 -05:00
'resolve' => static function () {
2026-03-27 16:32:30 -04:00
/** @var \WPGraphQL\WooCommerce\Utils\QL_Session_Handler $session */
2026-01-16 12:28:23 -05:00
$session = \WC () -> session ;
2023-06-13 23:17:02 +03:00
2026-01-16 12:28:23 -05:00
return apply_filters ( 'graphql_customer_session_token' , $session -> build_token () );
},
]
);
}
if ( in_array ( $token_type , [ 'store-api' , 'both' ], true ) ) {
register_graphql_field (
'LoginPayload' ,
'cartToken' ,
[
'type' => 'String' ,
2026-03-30 23:37:51 -04:00
'description' => static function () {
2026-06-30 10:16:21 -04:00
return __ ( 'A JWT token that can be used in future requests to for WooCommerce session identification' , 'graphql-for-ecommerce' );
2026-03-30 23:37:51 -04:00
},
2026-01-16 12:28:23 -05:00
'resolve' => static function () {
2026-03-27 16:32:30 -04:00
/** @var \WPGraphQL\WooCommerce\Utils\QL_Session_Handler $session */
2026-01-16 12:28:23 -05:00
$session = \WC () -> session ;
return apply_filters ( 'graphql_customer_session_token' , $session -> build_cart_token () );
},
]
);
}
2023-06-13 23:17:02 +03:00
}
2020-01-11 14:27:04 -05:00
}
2026-03-27 16:32:30 -04:00
/**
* Register WooCommerce Stripe Gateway compatibility filters.
*
* @return void
*/
private static function add_stripe_gateway_filters () {
add_filter ( 'graphql_stripe_process_payment_args' , [ self :: class , 'woocommerce_gateway_stripe_args' ], 10 , 2 );
}
/**
* Adds extra arguments to the Stripe Gateway process payment call.
*
* @param array $gateway_args Arguments to be passed to the gateway `process_payment` method.
* @param string $payment_method Payment gateway ID.
*
* @return array
*/
public static function woocommerce_gateway_stripe_args ( $gateway_args , $payment_method ) {
/** @var false|\WC_Order|\WC_Order_Refund $order */
$order = wc_get_order ( $gateway_args [ 0 ] );
if ( false === $order ) {
return $gateway_args ;
}
$stripe_source_id = $order -> get_meta ( '_stripe_source_id' );
if ( 'stripe' === $payment_method && ! empty ( $stripe_source_id ) ) {
$gateway_args = [
$gateway_args [ 0 ],
true ,
false ,
false ,
true ,
];
}
return $gateway_args ;
}
/**
* Register SearchWP/QL Search compatibility filters.
*
* @return void
*/
private static function add_swp_filters () {
add_filter ( 'graphql_swp_result_possible_types' , [ self :: class , 'searchwp_result_possible_types' ] );
}
/**
* Adds product types to QL Search SWPResult possible types.
*
* @param array $type_names SWPResults possible types.
*
* @return array
*/
public static function searchwp_result_possible_types ( array $type_names ) {
if ( in_array ( 'Product' , $type_names , true ) ) {
$type_names = array_merge (
array_filter (
$type_names ,
static function ( $type_name ) {
return 'Product' !== $type_name ;
}
),
[
'SimpleProduct' ,
'VariableProduct' ,
'GroupProduct' ,
'ExternalProduct' ,
]
);
}
return $type_names ;
}
2019-10-03 14:31:47 -04:00
}