From c068671d9381c8643803effcad77316decd22e96 Mon Sep 17 00:00:00 2001 From: Geoffrey K Taylor Date: Tue, 4 Apr 2023 12:02:25 -0400 Subject: [PATCH] feat: WooGraphQL settings tab added. (#726) * feat: WooGraphQL settings tab added. * chore: WPCS compliance met * bugfix: Order Item Node ID implemented. * chore: Deprecated "AppContext::getLoader" calls replaced. * chore: WPCS compliance met. * fix: DownloadableItem "id" field implemented --- composer.lock | 13 +- includes/admin/class-general.php | 31 + includes/admin/class-section.php | 21 + includes/admin/class-substitutions.php | 62 ++ includes/class-admin.php | 49 ++ includes/class-core-schema-filters.php | 19 + includes/class-woocommerce-filters.php | 11 +- includes/class-wp-graphql-woocommerce.php | 9 + includes/data/class-factory.php | 14 +- .../class-order-item-connection-resolver.php | 20 +- includes/data/loader/class-wc-cpt-loader.php | 4 +- includes/model/class-order-item.php | 6 + includes/type/enum/class-product-types.php | 10 +- includes/type/object/class-cart-type.php | 702 +++++++++-------- includes/type/object/class-customer-type.php | 274 ++++--- .../object/class-downloadable-item-type.php | 10 +- .../type/object/class-order-item-type.php | 4 + includes/type/object/class-order-type.php | 713 +++++++++--------- tests/_support/Helper/Wpunit.php | 2 +- 19 files changed, 1169 insertions(+), 805 deletions(-) create mode 100644 includes/admin/class-general.php create mode 100644 includes/admin/class-section.php create mode 100644 includes/admin/class-substitutions.php create mode 100644 includes/class-admin.php diff --git a/composer.lock b/composer.lock index 3ee419c58..ccbacc6cb 100644 --- a/composer.lock +++ b/composer.lock @@ -8,16 +8,16 @@ "packages": [ { "name": "firebase/php-jwt", - "version": "v6.3.2", + "version": "v6.4.0", "source": { "type": "git", "url": "https://github.com/firebase/php-jwt.git", - "reference": "ea7dda77098b96e666c5ef382452f94841e439cd" + "reference": "4dd1e007f22a927ac77da5a3fbb067b42d3bc224" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/firebase/php-jwt/zipball/ea7dda77098b96e666c5ef382452f94841e439cd", - "reference": "ea7dda77098b96e666c5ef382452f94841e439cd", + "url": "https://api.github.com/repos/firebase/php-jwt/zipball/4dd1e007f22a927ac77da5a3fbb067b42d3bc224", + "reference": "4dd1e007f22a927ac77da5a3fbb067b42d3bc224", "shasum": "" }, "require": { @@ -32,6 +32,7 @@ "psr/http-factory": "^1.0" }, "suggest": { + "ext-sodium": "Support EdDSA (Ed25519) signatures", "paragonie/sodium_compat": "Support EdDSA (Ed25519) signatures when libsodium is not present" }, "type": "library", @@ -64,9 +65,9 @@ ], "support": { "issues": "https://github.com/firebase/php-jwt/issues", - "source": "https://github.com/firebase/php-jwt/tree/v6.3.2" + "source": "https://github.com/firebase/php-jwt/tree/v6.4.0" }, - "time": "2022-12-19T17:10:46+00:00" + "time": "2023-02-09T21:01:23+00:00" } ], "packages-dev": [ diff --git a/includes/admin/class-general.php b/includes/admin/class-general.php new file mode 100644 index 000000000..3791d7755 --- /dev/null +++ b/includes/admin/class-general.php @@ -0,0 +1,31 @@ + 'disable_ql_session_handler', + 'label' => __( 'Disable QL Session Handler', 'wp-graphql-woocommerce' ), + 'desc' => __( 'The QL Session Handler takes over management of WooCommerce Session Management on WPGraphQL request replacing the usage of HTTP Cookies with JSON Web Tokens.', 'wp-graphql-woocommerce' ), + 'type' => 'checkbox', + 'default' => 'off', + ], + ]; + } +} diff --git a/includes/admin/class-section.php b/includes/admin/class-section.php new file mode 100644 index 000000000..7da621815 --- /dev/null +++ b/includes/admin/class-section.php @@ -0,0 +1,21 @@ + "{$product_type}_substitution_type", + 'label' => sprintf( + /* translators: product type */ + __( 'Substitution type for %s', 'wp-graphql-woocommerce' ), + $type_labels[ $product_type ] + ), + 'desc' => sprintf( + /* translators: product type */ + __( 'Set a replacement GraphQL type for %s because it\'s unregistered', 'wp-graphql-woocommerce' ), + $type_labels[ $product_type ] + ), + 'type' => 'select', + 'options' => self::get_dropdown_list(), + ]; + } + + return $fields; + } +} diff --git a/includes/class-admin.php b/includes/class-admin.php new file mode 100644 index 000000000..5ae309d63 --- /dev/null +++ b/includes/class-admin.php @@ -0,0 +1,49 @@ +settings_api->register_section( + 'woographql_settings', + [ 'title' => __( 'WooGraphQL', 'wp-graphql-woocommerce' ) ] + ); + + $manager->settings_api->register_fields( + 'woographql_settings', + General::get_fields(), + ); + + $manager->settings_api->register_fields( + 'woographql_settings', + Substitutions::get_fields(), + ); + } +} diff --git a/includes/class-core-schema-filters.php b/includes/class-core-schema-filters.php index cef9720e8..f359d76a6 100644 --- a/includes/class-core-schema-filters.php +++ b/includes/class-core-schema-filters.php @@ -130,6 +130,18 @@ public static function add_filters() { ); } + /** + * Check and returns a GraphQL type from the + * "{$product_type}_substitution_type" in the WooGraphQL settings. + * + * @param string $product_type Product type in need of a GraphQL type. + * + * @return string|null + */ + public static function get_substitution_type( $product_type ) { + return get_graphql_setting( "{$product_type}_substitution_type", null, 'woographql_settings' ); + } + /** * Registers WooCommerce post-types to be used in GraphQL schema * @@ -152,6 +164,13 @@ public static function register_post_types( $args, $post_type ) { if ( isset( $possible_types[ $value->type ] ) ) { return $type_registry->get_type( $possible_types[ $value->type ] ); } + + // Look for substitution type. + $substitution_type = self::get_substitution_type( $value->type ); + if ( ! empty( $substitution_type ) ) { + return $type_registry->get_type( $substitution_type ); + } + throw new UserError( sprintf( /* translators: %s: Product type */ diff --git a/includes/class-woocommerce-filters.php b/includes/class-woocommerce-filters.php index f8999d441..c1512ec45 100644 --- a/includes/class-woocommerce-filters.php +++ b/includes/class-woocommerce-filters.php @@ -27,7 +27,7 @@ public static function setup() { self::$session_header = apply_filters( 'graphql_woocommerce_cart_session_http_header', 'woocommerce-session' ); // Check if request is a GraphQL POST request. - if ( ! defined( 'NO_QL_SESSION_HANDLER' ) ) { + if ( ! self::is_session_handler_disabled() ) { add_filter( 'woocommerce_session_handler', [ __CLASS__, 'woocommerce_session_handler' ] ); add_filter( 'graphql_response_headers_to_send', [ __CLASS__, 'add_session_header_to_expose_headers' ] ); add_filter( 'graphql_access_control_allow_headers', [ __CLASS__, 'add_session_header_to_allow_headers' ] ); @@ -37,6 +37,15 @@ public static function setup() { add_filter( 'graphql_stripe_process_payment_args', [ __CLASS__, 'woographql_stripe_gateway_args' ], 10, 2 ); } + /** + * Returns true if the "Disable QL Session Handler" option is checked on the settings page. + * + * @return boolean + */ + public static function is_session_handler_disabled() { + return 'on' === get_graphql_setting( 'disable_ql_session_handler', 'off', 'woographql_settings' ); + } + /** * WooCommerce Session Handler callback * diff --git a/includes/class-wp-graphql-woocommerce.php b/includes/class-wp-graphql-woocommerce.php index c04163364..4c55c2dd6 100644 --- a/includes/class-wp-graphql-woocommerce.php +++ b/includes/class-wp-graphql-woocommerce.php @@ -301,7 +301,13 @@ private function includes() { require $include_directory_path . 'connection/class-variation-attributes.php'; require $include_directory_path . 'connection/class-wc-terms.php'; + // Include admin files. + require $include_directory_path . 'admin/class-section.php'; + require $include_directory_path . 'admin/class-general.php'; + require $include_directory_path . 'admin/class-substitutions.php'; + // Include main plugin class files. + require $include_directory_path . 'class-admin.php'; require $include_directory_path . 'class-core-schema-filters.php'; require $include_directory_path . 'class-jwt-auth-schema-filters.php'; require $include_directory_path . 'class-woocommerce-filters.php'; @@ -358,6 +364,9 @@ function () { * Sets up WooGraphQL schema. */ private function setup() { + // Initialize WooGraphQL Settings. + new Admin(); + // Setup minor integrations. Functions\setup_minor_integrations(); diff --git a/includes/data/class-factory.php b/includes/data/class-factory.php index 1044b9ef5..d40f62fa3 100644 --- a/includes/data/class-factory.php +++ b/includes/data/class-factory.php @@ -49,7 +49,7 @@ public static function resolve_customer( $id, AppContext $context ) { return null; } $customer_id = absint( $id ); - $loader = $context->getLoader( 'wc_customer' ); + $loader = $context->get_loader( 'wc_customer' ); $loader->buffer( [ $customer_id ] ); return new Deferred( function () use ( $loader, $customer_id ) { @@ -72,10 +72,10 @@ public static function resolve_crud_object( $id, AppContext $context ) { return null; } - $context->getLoader( 'wc_post' )->buffer( [ $id ] ); + $context->get_loader( 'wc_post' )->buffer( [ $id ] ); return new Deferred( function () use ( $id, $context ) { - return $context->getLoader( 'wc_post' )->load( $id ); + return $context->get_loader( 'wc_post' )->load( $id ); } ); } @@ -114,7 +114,7 @@ public static function resolve_tax_rate( $id, AppContext $context ) { } $id = absint( $id ); - $loader = $context->getLoader( 'tax_rate' ); + $loader = $context->get_loader( 'tax_rate' ); $loader->buffer( [ $id ] ); return new Deferred( function () use ( $loader, $id ) { @@ -169,10 +169,10 @@ public static function resolve_cart_item( $key, AppContext $context ) { return null; } - $context->getLoader( 'cart_item' )->buffer( [ $key ] ); + $context->get_loader( 'cart_item' )->buffer( [ $key ] ); return new Deferred( function () use ( $key, $context ) { - return $context->getLoader( 'cart_item' )->load( $key ); + return $context->get_loader( 'cart_item' )->load( $key ); } ); } @@ -205,7 +205,7 @@ public static function resolve_downloadable_item( $id, AppContext $context ) { return null; } $object_id = absint( $id ); - $loader = $context->getLoader( 'downloadable_item' ); + $loader = $context->get_loader( 'downloadable_item' ); $loader->buffer( [ $object_id ] ); return new Deferred( function () use ( $loader, $object_id ) { diff --git a/includes/data/connection/class-order-item-connection-resolver.php b/includes/data/connection/class-order-item-connection-resolver.php index 6a6bb135c..7afb038cb 100644 --- a/includes/data/connection/class-order-item-connection-resolver.php +++ b/includes/data/connection/class-order-item-connection-resolver.php @@ -84,9 +84,25 @@ public function get_query() { $type = 'coupon'; break; default: - $type = 'line_item'; + /** + * Filter the $item_type to allow non-core item types. + * + * @param array $query_args The args that will be passed to the WP_Query. + * @param mixed $source The source that's passed down the GraphQL queries. + * @param array $args The inputArgs on the field. + * @param AppContext $context The AppContext passed down the GraphQL tree. + * @param ResolveInfo $info The ResolveInfo passed down the GraphQL tree. + */ + $type = apply_filters( + 'graphql_order_item_connection_item_type', + 'line_item', + $this->source, + $this->args, + $this->context, + $this->info + ); break; - } + }//end switch $items = []; foreach ( $this->source->get_items( $type ) as $id => $item ) { diff --git a/includes/data/loader/class-wc-cpt-loader.php b/includes/data/loader/class-wc-cpt-loader.php index 8f50bf7a9..69d88a3da 100644 --- a/includes/data/loader/class-wc-cpt-loader.php +++ b/includes/data/loader/class-wc-cpt-loader.php @@ -158,7 +158,7 @@ function ( $split, \WP_Query $query ) { case 'shop_order': $customer_id = get_post_meta( $key, '_customer_user', true ); if ( ! empty( $customer_id ) ) { - $this->context->getLoader( 'wc_customer' )->buffer( [ $customer_id ] ); + $this->context->get_loader( 'wc_customer' )->buffer( [ $customer_id ] ); } break; case 'product_variation': @@ -180,7 +180,7 @@ function ( $split, \WP_Query $query ) { $load_dependencies = new Deferred( function() use ( $key, $post_type, $customer_id, $parent_id, $context ) { if ( ! empty( $customer_id ) ) { - $context->getLoader( 'wc_customer' )->load( $customer_id ); + $context->get_loader( 'wc_customer' )->load( $customer_id ); } if ( ! empty( $parent_id ) ) { $this->load( $parent_id ); diff --git a/includes/model/class-order-item.php b/includes/model/class-order-item.php index 744cf4564..1c6ca9dcc 100644 --- a/includes/model/class-order-item.php +++ b/includes/model/class-order-item.php @@ -11,6 +11,7 @@ namespace WPGraphQL\WooCommerce\Model; use WPGraphQL\Model\Model; +use GraphQLRelay\Relay; /** * Class Order_Item @@ -76,12 +77,17 @@ protected function init() { 'ID' => function() { return $this->data->get_id(); }, + 'databaseId' => function() { return $this->ID; }, 'orderId' => function() { return ! empty( $this->data->get_order_id() ) ? $this->data->get_order_id() : null; }, + 'id' => function() { + // phpcs:ignore + return Relay::toGlobalId( 'order_item', $this->orderId . '+' . $this->ID ); + }, 'type' => function() { return ! empty( $this->data->get_type() ) ? $this->data->get_type() : null; }, diff --git a/includes/type/enum/class-product-types.php b/includes/type/enum/class-product-types.php index e2167bc44..016323b53 100644 --- a/includes/type/enum/class-product-types.php +++ b/includes/type/enum/class-product-types.php @@ -16,7 +16,7 @@ class Product_Types { * Registers type */ public static function register() { - $values = apply_filters( + $values = apply_filters( 'graphql_product_types_enum_values', [ 'SIMPLE' => [ @@ -41,6 +41,14 @@ public static function register() { ], ] ); + $product_types = \wc_get_product_types(); + array_walk( + $product_types, + function( $description, $value ) { + $key = strtoupper( str_replace( '-', '_', $value ) ); + $values[ $key ] = compact( 'description', 'value' ); + } + ); register_graphql_enum_type( 'ProductTypesEnum', diff --git a/includes/type/object/class-cart-type.php b/includes/type/object/class-cart-type.php index bc00f9ac5..780fbc9f0 100644 --- a/includes/type/object/class-cart-type.php +++ b/includes/type/object/class-cart-type.php @@ -35,388 +35,428 @@ public static function register() { } /** - * Registers Cart type + * Returns the "Cart" type fields. + * + * @param array $other_fields Extra fields configs to be added or override the default field definitions. + * @return array */ - public static function register_cart() { - register_graphql_object_type( - 'Cart', + public static function get_cart_fields( $other_fields = [] ) { + return array_merge( [ - 'description' => __( 'The cart object', 'wp-graphql-woocommerce' ), - 'fields' => [ - 'subtotal' => [ - 'type' => 'String', - 'description' => __( 'Cart subtotal', 'wp-graphql-woocommerce' ), - 'args' => [ - 'format' => [ - 'type' => 'PricingFieldFormatEnum', - 'description' => __( 'Format of the price', 'wp-graphql-woocommerce' ), - ], + 'subtotal' => [ + 'type' => 'String', + 'description' => __( 'Cart subtotal', 'wp-graphql-woocommerce' ), + 'args' => [ + 'format' => [ + 'type' => 'PricingFieldFormatEnum', + 'description' => __( 'Format of the price', 'wp-graphql-woocommerce' ), ], - 'resolve' => function( $source, array $args ) { - $price = ! is_null( $source->get_subtotal() ) ? $source->get_subtotal() : 0; - - if ( isset( $args['format'] ) && 'raw' === $args['format'] ) { - return $price; - } - - return \wc_graphql_price( $price ); - }, ], - 'subtotalTax' => [ - 'type' => 'String', - 'description' => __( 'Cart subtotal tax', 'wp-graphql-woocommerce' ), - 'args' => [ - 'format' => [ - 'type' => 'PricingFieldFormatEnum', - 'description' => __( 'Format of the price', 'wp-graphql-woocommerce' ), - ], - ], - 'resolve' => function( $source, array $args ) { - $price = ! is_null( $source->get_subtotal_tax() ) ? $source->get_subtotal_tax() : 0; + 'resolve' => function( $source, array $args ) { + $price = ! is_null( $source->get_subtotal() ) ? $source->get_subtotal() : 0; - if ( isset( $args['format'] ) && 'raw' === $args['format'] ) { - return $price; - } + if ( isset( $args['format'] ) && 'raw' === $args['format'] ) { + return $price; + } - return \wc_graphql_price( $price ); - }, - ], - 'discountTotal' => [ - 'type' => 'String', - 'description' => __( 'Cart discount total', 'wp-graphql-woocommerce' ), - 'args' => [ - 'format' => [ - 'type' => 'PricingFieldFormatEnum', - 'description' => __( 'Format of the price', 'wp-graphql-woocommerce' ), - ], + return \wc_graphql_price( $price ); + }, + ], + 'subtotalTax' => [ + 'type' => 'String', + 'description' => __( 'Cart subtotal tax', 'wp-graphql-woocommerce' ), + 'args' => [ + 'format' => [ + 'type' => 'PricingFieldFormatEnum', + 'description' => __( 'Format of the price', 'wp-graphql-woocommerce' ), ], - 'resolve' => function( $source, array $args ) { - $price = ! is_null( $source->get_discount_total() ) ? $source->get_discount_total() : 0; - - if ( isset( $args['format'] ) && 'raw' === $args['format'] ) { - return $price; - } - - return \wc_graphql_price( $price ); - }, ], - 'discountTax' => [ - 'type' => 'String', - 'description' => __( 'Cart discount tax', 'wp-graphql-woocommerce' ), - 'args' => [ - 'format' => [ - 'type' => 'PricingFieldFormatEnum', - 'description' => __( 'Format of the price', 'wp-graphql-woocommerce' ), - ], - ], - 'resolve' => function( $source, array $args ) { - $price = ! is_null( $source->get_discount_tax() ) ? $source->get_discount_tax() : 0; + 'resolve' => function( $source, array $args ) { + $price = ! is_null( $source->get_subtotal_tax() ) ? $source->get_subtotal_tax() : 0; - if ( isset( $args['format'] ) && 'raw' === $args['format'] ) { - return $price; - } + if ( isset( $args['format'] ) && 'raw' === $args['format'] ) { + return $price; + } - return \wc_graphql_price( $price ); - }, + return \wc_graphql_price( $price ); + }, + ], + 'discountTotal' => [ + 'type' => 'String', + 'description' => __( 'Cart discount total', 'wp-graphql-woocommerce' ), + 'args' => [ + 'format' => [ + 'type' => 'PricingFieldFormatEnum', + 'description' => __( 'Format of the price', 'wp-graphql-woocommerce' ), + ], ], - 'availableShippingMethods' => [ - 'type' => [ 'list_of' => 'ShippingPackage' ], - 'description' => __( 'Available shipping methods for this order.', 'wp-graphql-woocommerce' ), - 'resolve' => function( $source ) { - $packages = []; - - $available_packages = $source->needs_shipping() - ? \WC()->shipping()->calculate_shipping( $source->get_shipping_packages() ) - : []; + 'resolve' => function( $source, array $args ) { + $price = ! is_null( $source->get_discount_total() ) ? $source->get_discount_total() : 0; - foreach ( $available_packages as $index => $package ) { - $package['index'] = $index; - $packages[] = $package; - } + if ( isset( $args['format'] ) && 'raw' === $args['format'] ) { + return $price; + } - return $packages; - }, + return \wc_graphql_price( $price ); + }, + ], + 'discountTax' => [ + 'type' => 'String', + 'description' => __( 'Cart discount tax', 'wp-graphql-woocommerce' ), + 'args' => [ + 'format' => [ + 'type' => 'PricingFieldFormatEnum', + 'description' => __( 'Format of the price', 'wp-graphql-woocommerce' ), + ], ], - 'chosenShippingMethods' => [ - 'type' => [ 'list_of' => 'String' ], - 'description' => __( 'Shipping method chosen for this order.', 'wp-graphql-woocommerce' ), - 'resolve' => function( $source ) { - $chosen_shipping_methods = []; + 'resolve' => function( $source, array $args ) { + $price = ! is_null( $source->get_discount_tax() ) ? $source->get_discount_tax() : 0; - $available_packages = $source->needs_shipping() - ? \WC()->shipping()->calculate_shipping( $source->get_shipping_packages() ) - : []; + if ( isset( $args['format'] ) && 'raw' === $args['format'] ) { + return $price; + } - foreach ( $available_packages as $i => $package ) { - if ( isset( \WC()->session->chosen_shipping_methods[ $i ] ) ) { - $chosen_shipping_methods[] = \WC()->session->chosen_shipping_methods[ $i ]; - } + return \wc_graphql_price( $price ); + }, + ], + 'availableShippingMethods' => [ + 'type' => [ 'list_of' => 'ShippingPackage' ], + 'description' => __( 'Available shipping methods for this order.', 'wp-graphql-woocommerce' ), + 'resolve' => function( $source ) { + $packages = []; + + $available_packages = $source->needs_shipping() + ? \WC()->shipping()->calculate_shipping( $source->get_shipping_packages() ) + : []; + + foreach ( $available_packages as $index => $package ) { + $package['index'] = $index; + $packages[] = $package; + } + + return $packages; + }, + ], + 'chosenShippingMethods' => [ + 'type' => [ 'list_of' => 'String' ], + 'description' => __( 'Shipping method chosen for this order.', 'wp-graphql-woocommerce' ), + 'resolve' => function( $source ) { + $chosen_shipping_methods = []; + + $available_packages = $source->needs_shipping() + ? \WC()->shipping()->calculate_shipping( $source->get_shipping_packages() ) + : []; + + foreach ( $available_packages as $i => $package ) { + if ( isset( \WC()->session->chosen_shipping_methods[ $i ] ) ) { + $chosen_shipping_methods[] = \WC()->session->chosen_shipping_methods[ $i ]; } + } - return $chosen_shipping_methods; - }, - ], - 'shippingTotal' => [ - 'type' => 'String', - 'description' => __( 'Cart shipping total', 'wp-graphql-woocommerce' ), - 'args' => [ - 'format' => [ - 'type' => 'PricingFieldFormatEnum', - 'description' => __( 'Format of the price', 'wp-graphql-woocommerce' ), - ], + return $chosen_shipping_methods; + }, + ], + 'shippingTotal' => [ + 'type' => 'String', + 'description' => __( 'Cart shipping total', 'wp-graphql-woocommerce' ), + 'args' => [ + 'format' => [ + 'type' => 'PricingFieldFormatEnum', + 'description' => __( 'Format of the price', 'wp-graphql-woocommerce' ), ], - 'resolve' => function( $source, array $args ) { - $price = ! is_null( $source->get_shipping_total() ) ? $source->get_shipping_total() : 0; + ], + 'resolve' => function( $source, array $args ) { + $price = ! is_null( $source->get_shipping_total() ) ? $source->get_shipping_total() : 0; - if ( isset( $args['format'] ) && 'raw' === $args['format'] ) { - return $price; - } + if ( isset( $args['format'] ) && 'raw' === $args['format'] ) { + return $price; + } - return \wc_graphql_price( $price ); - }, - ], - 'shippingTax' => [ - 'type' => 'String', - 'description' => __( 'Cart shipping tax', 'wp-graphql-woocommerce' ), - 'args' => [ - 'format' => [ - 'type' => 'PricingFieldFormatEnum', - 'description' => __( 'Format of the price', 'wp-graphql-woocommerce' ), - ], + return \wc_graphql_price( $price ); + }, + ], + 'shippingTax' => [ + 'type' => 'String', + 'description' => __( 'Cart shipping tax', 'wp-graphql-woocommerce' ), + 'args' => [ + 'format' => [ + 'type' => 'PricingFieldFormatEnum', + 'description' => __( 'Format of the price', 'wp-graphql-woocommerce' ), ], - 'resolve' => function( $source, array $args ) { - $price = ! is_null( $source->get_shipping_tax() ) ? $source->get_shipping_tax() : 0; + ], + 'resolve' => function( $source, array $args ) { + $price = ! is_null( $source->get_shipping_tax() ) ? $source->get_shipping_tax() : 0; - if ( isset( $args['format'] ) && 'raw' === $args['format'] ) { - return $price; - } + if ( isset( $args['format'] ) && 'raw' === $args['format'] ) { + return $price; + } - return \wc_graphql_price( $price ); - }, - ], - 'contentsTotal' => [ - 'type' => 'String', - 'description' => __( 'Cart contents total', 'wp-graphql-woocommerce' ), - 'args' => [ - 'format' => [ - 'type' => 'PricingFieldFormatEnum', - 'description' => __( 'Format of the price', 'wp-graphql-woocommerce' ), - ], + return \wc_graphql_price( $price ); + }, + ], + 'contentsTotal' => [ + 'type' => 'String', + 'description' => __( 'Cart contents total', 'wp-graphql-woocommerce' ), + 'args' => [ + 'format' => [ + 'type' => 'PricingFieldFormatEnum', + 'description' => __( 'Format of the price', 'wp-graphql-woocommerce' ), ], - 'resolve' => function( $source, array $args ) { - if ( $source->display_prices_including_tax() ) { - $cart_subtotal = $source->get_subtotal() + $source->get_subtotal_tax(); - } else { - $cart_subtotal = $source->get_subtotal(); - } + ], + 'resolve' => function( $source, array $args ) { + if ( $source->display_prices_including_tax() ) { + $cart_subtotal = $source->get_subtotal() + $source->get_subtotal_tax(); + } else { + $cart_subtotal = $source->get_subtotal(); + } - $price = ! is_null( $cart_subtotal ) - ? $cart_subtotal - : 0; + $price = ! is_null( $cart_subtotal ) + ? $cart_subtotal + : 0; - if ( isset( $args['format'] ) && 'raw' === $args['format'] ) { - return $price; - } + if ( isset( $args['format'] ) && 'raw' === $args['format'] ) { + return $price; + } - return \wc_graphql_price( $price ); - }, - ], - 'contentsTax' => [ - 'type' => 'String', - 'description' => __( 'Cart contents tax', 'wp-graphql-woocommerce' ), - 'args' => [ - 'format' => [ - 'type' => 'PricingFieldFormatEnum', - 'description' => __( 'Format of the price', 'wp-graphql-woocommerce' ), - ], + return \wc_graphql_price( $price ); + }, + ], + 'contentsTax' => [ + 'type' => 'String', + 'description' => __( 'Cart contents tax', 'wp-graphql-woocommerce' ), + 'args' => [ + 'format' => [ + 'type' => 'PricingFieldFormatEnum', + 'description' => __( 'Format of the price', 'wp-graphql-woocommerce' ), ], - 'resolve' => function( $source, array $args ) { - $price = ! is_null( $source->get_cart_contents_tax() ) - ? $source->get_cart_contents_tax() - : 0; - - if ( isset( $args['format'] ) && 'raw' === $args['format'] ) { - return $price; - } - - return \wc_graphql_price( $price ); - }, ], - 'feeTotal' => [ - 'type' => 'String', - 'description' => __( 'Cart fee total', 'wp-graphql-woocommerce' ), - 'args' => [ - 'format' => [ - 'type' => 'PricingFieldFormatEnum', - 'description' => __( 'Format of the price', 'wp-graphql-woocommerce' ), - ], - ], - 'resolve' => function( $source, array $args ) { - $price = ! is_null( $source->get_fee_total() ) ? $source->get_fee_total() : 0; + 'resolve' => function( $source, array $args ) { + $price = ! is_null( $source->get_cart_contents_tax() ) + ? $source->get_cart_contents_tax() + : 0; - if ( isset( $args['format'] ) && 'raw' === $args['format'] ) { - return $price; - } + if ( isset( $args['format'] ) && 'raw' === $args['format'] ) { + return $price; + } - return \wc_graphql_price( $price ); - }, - ], - 'feeTax' => [ - 'type' => 'String', - 'description' => __( 'Cart fee tax', 'wp-graphql-woocommerce' ), - 'args' => [ - 'format' => [ - 'type' => 'PricingFieldFormatEnum', - 'description' => __( 'Format of the price', 'wp-graphql-woocommerce' ), - ], + return \wc_graphql_price( $price ); + }, + ], + 'feeTotal' => [ + 'type' => 'String', + 'description' => __( 'Cart fee total', 'wp-graphql-woocommerce' ), + 'args' => [ + 'format' => [ + 'type' => 'PricingFieldFormatEnum', + 'description' => __( 'Format of the price', 'wp-graphql-woocommerce' ), ], - 'resolve' => function( $source, array $args ) { - $price = ! is_null( $source->get_fee_tax() ) ? $source->get_fee_tax() : 0; + ], + 'resolve' => function( $source, array $args ) { + $price = ! is_null( $source->get_fee_total() ) ? $source->get_fee_total() : 0; - if ( isset( $args['format'] ) && 'raw' === $args['format'] ) { - return $price; - } + if ( isset( $args['format'] ) && 'raw' === $args['format'] ) { + return $price; + } - return \wc_graphql_price( $price ); - }, - ], - 'total' => [ - 'type' => 'String', - 'description' => __( 'Cart total after calculation', 'wp-graphql-woocommerce' ), - 'args' => [ - 'format' => [ - 'type' => 'PricingFieldFormatEnum', - 'description' => __( 'Format of the price', 'wp-graphql-woocommerce' ), - ], + return \wc_graphql_price( $price ); + }, + ], + 'feeTax' => [ + 'type' => 'String', + 'description' => __( 'Cart fee tax', 'wp-graphql-woocommerce' ), + 'args' => [ + 'format' => [ + 'type' => 'PricingFieldFormatEnum', + 'description' => __( 'Format of the price', 'wp-graphql-woocommerce' ), ], - 'resolve' => function( $source, array $args ) { - $source->calculate_totals(); - $price = isset( $source->get_totals()['total'] ) - ? apply_filters( 'graphql_woocommerce_cart_get_total', $source->get_totals()['total'] ) - : 0; + ], + 'resolve' => function( $source, array $args ) { + $price = ! is_null( $source->get_fee_tax() ) ? $source->get_fee_tax() : 0; - if ( isset( $args['format'] ) && 'raw' === $args['format'] ) { - return $price; - } + if ( isset( $args['format'] ) && 'raw' === $args['format'] ) { + return $price; + } - return \wc_graphql_price( $price ); - }, - ], - 'totalTax' => [ - 'type' => 'String', - 'description' => __( 'Cart total tax amount', 'wp-graphql-woocommerce' ), - 'args' => [ - 'format' => [ - 'type' => 'PricingFieldFormatEnum', - 'description' => __( 'Format of the price', 'wp-graphql-woocommerce' ), - ], + return \wc_graphql_price( $price ); + }, + ], + 'total' => [ + 'type' => 'String', + 'description' => __( 'Cart total after calculation', 'wp-graphql-woocommerce' ), + 'args' => [ + 'format' => [ + 'type' => 'PricingFieldFormatEnum', + 'description' => __( 'Format of the price', 'wp-graphql-woocommerce' ), ], - 'resolve' => function( $source, array $args ) { - $price = ! is_null( $source->get_total_tax() ) ? $source->get_total_tax() : 0; + ], + 'resolve' => function( $source, array $args ) { + $source->calculate_totals(); + $price = isset( $source->get_totals()['total'] ) + ? apply_filters( 'graphql_woocommerce_cart_get_total', $source->get_totals()['total'] ) + : 0; - if ( isset( $args['format'] ) && 'raw' === $args['format'] ) { - return $price; - } + if ( isset( $args['format'] ) && 'raw' === $args['format'] ) { + return $price; + } - return \wc_graphql_price( $price ); - }, - ], - 'totalTaxes' => [ - 'type' => [ 'list_of' => 'CartTax' ], - 'description' => __( 'Cart total taxes itemized', 'wp-graphql-woocommerce' ), - 'resolve' => function( $source ) { - $taxes = $source->get_tax_totals(); - return ! empty( $taxes ) ? array_values( $taxes ) : null; - }, - ], - 'isEmpty' => [ - 'type' => 'Boolean', - 'description' => __( 'Is cart empty', 'wp-graphql-woocommerce' ), - 'resolve' => function( $source ) { - return ! is_null( $source->is_empty() ) ? $source->is_empty() : null; - }, - ], - 'displayPricesIncludeTax' => [ - 'type' => 'Boolean', - 'description' => __( 'Do display prices include taxes', 'wp-graphql-woocommerce' ), - 'resolve' => function( $source ) { - return ! is_null( $source->display_prices_including_tax() ) - ? $source->display_prices_including_tax() - : null; - }, - ], - 'needsShippingAddress' => [ - 'type' => 'Boolean', - 'description' => __( 'Is customer shipping address needed', 'wp-graphql-woocommerce' ), - 'resolve' => function( $source ) { - return ! is_null( $source->needs_shipping_address() ) - ? $source->needs_shipping_address() - : null; - }, - ], - 'fees' => [ - 'type' => [ 'list_of' => 'CartFee' ], - 'description' => __( 'Additional fees on the cart.', 'wp-graphql-woocommerce' ), - 'resolve' => function( $source ) { - $fees = $source->get_fees(); - return ! empty( $fees ) ? array_values( $fees ) : null; - }, + return \wc_graphql_price( $price ); + }, + ], + 'totalTax' => [ + 'type' => 'String', + 'description' => __( 'Cart total tax amount', 'wp-graphql-woocommerce' ), + 'args' => [ + 'format' => [ + 'type' => 'PricingFieldFormatEnum', + 'description' => __( 'Format of the price', 'wp-graphql-woocommerce' ), + ], ], - 'appliedCoupons' => [ - 'type' => [ 'list_of' => 'AppliedCoupon' ], - 'description' => __( 'Coupons applied to the cart', 'wp-graphql-woocommerce' ), - 'resolve' => function( $source ) { - $applied_coupons = $source->get_applied_coupons(); + 'resolve' => function( $source, array $args ) { + $price = ! is_null( $source->get_total_tax() ) ? $source->get_total_tax() : 0; - return ! empty( $applied_coupons ) ? $applied_coupons : null; - }, - ], + if ( isset( $args['format'] ) && 'raw' === $args['format'] ) { + return $price; + } + + return \wc_graphql_price( $price ); + }, ], - 'connections' => [ - 'contents' => [ - 'toType' => 'CartItem', - 'connectionArgs' => [ - 'needsShipping' => [ - 'type' => 'Boolean', - 'description' => __( 'Limit results to cart items that require shipping', 'wp-graphql-woocommerce' ), - ], - ], - 'connectionFields' => [ - 'itemCount' => [ - 'type' => 'Int', - 'description' => __( 'Total number of items in the cart.', 'wp-graphql-woocommerce' ), - 'resolve' => function( $source ) { - if ( empty( $source['edges'] ) ) { - return 0; - } + 'totalTaxes' => [ + 'type' => [ 'list_of' => 'CartTax' ], + 'description' => __( 'Cart total taxes itemized', 'wp-graphql-woocommerce' ), + 'resolve' => function( $source ) { + $taxes = $source->get_tax_totals(); + return ! empty( $taxes ) ? array_values( $taxes ) : null; + }, + ], + 'isEmpty' => [ + 'type' => 'Boolean', + 'description' => __( 'Is cart empty', 'wp-graphql-woocommerce' ), + 'resolve' => function( $source ) { + return ! is_null( $source->is_empty() ) ? $source->is_empty() : null; + }, + ], + 'displayPricesIncludeTax' => [ + 'type' => 'Boolean', + 'description' => __( 'Do display prices include taxes', 'wp-graphql-woocommerce' ), + 'resolve' => function( $source ) { + return ! is_null( $source->display_prices_including_tax() ) + ? $source->display_prices_including_tax() + : null; + }, + ], + 'needsShippingAddress' => [ + 'type' => 'Boolean', + 'description' => __( 'Is customer shipping address needed', 'wp-graphql-woocommerce' ), + 'resolve' => function( $source ) { + return ! is_null( $source->needs_shipping_address() ) + ? $source->needs_shipping_address() + : null; + }, + ], + 'fees' => [ + 'type' => [ 'list_of' => 'CartFee' ], + 'description' => __( 'Additional fees on the cart.', 'wp-graphql-woocommerce' ), + 'resolve' => function( $source ) { + $fees = $source->get_fees(); + return ! empty( $fees ) ? array_values( $fees ) : null; + }, + ], + 'appliedCoupons' => [ + 'type' => [ 'list_of' => 'AppliedCoupon' ], + 'description' => __( 'Coupons applied to the cart', 'wp-graphql-woocommerce' ), + 'resolve' => function( $source ) { + $applied_coupons = $source->get_applied_coupons(); + + return ! empty( $applied_coupons ) ? $applied_coupons : null; + }, + ], + ], + $other_fields + ); + } - $items = array_values( $source['edges'][0]['source']->get_cart() ); - if ( empty( $items ) ) { - return 0; - } + /** + * Returns the "Cart" type connections. + * + * @param array $other_connections Extra connections configs to be added or override the default connection definitions. + * @return array + */ + public static function get_cart_connections( $other_connections = [] ) { + return array_merge( + [ + 'contents' => [ + 'toType' => 'CartItem', + 'connectionArgs' => [ + 'needsShipping' => [ + 'type' => 'Boolean', + 'description' => __( 'Limit results to cart items that require shipping', 'wp-graphql-woocommerce' ), + ], + ], + 'connectionFields' => [ + 'itemCount' => [ + 'type' => 'Int', + 'description' => __( 'Total number of items in the cart.', 'wp-graphql-woocommerce' ), + 'resolve' => function( $source ) { + if ( empty( $source['edges'] ) ) { + return 0; + } - return array_sum( array_column( $items, 'quantity' ) ); - }, - ], - 'productCount' => [ - 'type' => 'Int', - 'description' => __( 'Total number of different products in the cart', 'wp-graphql-woocommerce' ), - 'resolve' => function( $source ) { - if ( empty( $source['edges'] ) ) { - return 0; - } + $items = array_values( $source['edges'][0]['source']->get_cart() ); + if ( empty( $items ) ) { + return 0; + } - return count( array_values( $source['edges'][0]['source']->get_cart() ) ); - }, - ], + return array_sum( array_column( $items, 'quantity' ) ); + }, ], - 'resolve' => function ( $source, array $args, AppContext $context, ResolveInfo $info ) { - $resolver = new Cart_Item_Connection_Resolver( $source, $args, $context, $info ); + 'productCount' => [ + 'type' => 'Int', + 'description' => __( 'Total number of different products in the cart', 'wp-graphql-woocommerce' ), + 'resolve' => function( $source ) { + if ( empty( $source['edges'] ) ) { + return 0; + } - return $resolver->get_connection(); - }, + return count( array_values( $source['edges'][0]['source']->get_cart() ) ); + }, + ], ], + 'resolve' => function ( $source, array $args, AppContext $context, ResolveInfo $info ) { + $resolver = new Cart_Item_Connection_Resolver( $source, $args, $context, $info ); + + return $resolver->get_connection(); + }, ], + ], + $other_connections + ); + } + + /** + * Registers Cart type + */ + public static function register_cart() { + register_graphql_object_type( + 'Cart', + [ + 'description' => __( 'The cart object', 'wp-graphql-woocommerce' ), + /** + * Allows for a decisive filtering of the cart fields. + * Note: Only use if deregisteration or renaming the field(s) has failed. + * + * @param array $fields Cart field definitions. + * @return array + */ + 'fields' => apply_filters( 'woographql_cart_field_definitions', self::get_cart_fields() ), + /** + * Allows for a decisive filtering of the cart connections. + * Note: Only use if deregisteration or renaming the connection(s) has failed. + * + * @param array $connections Cart connection definitions. + * @return array + */ + 'connections' => apply_filters( 'woographql_cart_connection_definitions', self::get_cart_connections() ), ] ); } diff --git a/includes/type/object/class-customer-type.php b/includes/type/object/class-customer-type.php index 9b19107f0..ccfddfcd1 100644 --- a/includes/type/object/class-customer-type.php +++ b/includes/type/object/class-customer-type.php @@ -22,6 +22,147 @@ */ class Customer_Type { + /** + * Returns the "Customer" type fields. + * + * @param array $other_fields Extra fields configs to be added or override the default field definitions. + * @return array + */ + public static function get_fields( $other_fields = [] ) { + return array_merge( + [ + 'id' => [ + 'type' => [ 'non_null' => 'ID' ], + 'description' => __( 'The globally unique identifier for the customer', 'wp-graphql-woocommerce' ), + ], + 'databaseId' => [ + 'type' => 'Int', + 'description' => __( 'The ID of the customer in the database', 'wp-graphql-woocommerce' ), + ], + 'isVatExempt' => [ + 'type' => 'Boolean', + 'description' => __( 'Is customer VAT exempt?', 'wp-graphql-woocommerce' ), + ], + 'hasCalculatedShipping' => [ + 'type' => 'Boolean', + 'description' => __( 'Has calculated shipping?', 'wp-graphql-woocommerce' ), + ], + 'calculatedShipping' => [ + 'type' => 'Boolean', + 'description' => __( 'Has customer calculated shipping?', 'wp-graphql-woocommerce' ), + ], + 'lastOrder' => [ + 'type' => 'Order', + 'description' => __( 'Gets the customers last order.', 'wp-graphql-woocommerce' ), + 'resolve' => function( $source, array $args, AppContext $context ) { + return Factory::resolve_crud_object( $source->last_order_id, $context ); + }, + ], + 'orderCount' => [ + 'type' => 'Int', + 'description' => __( 'Return the number of orders this customer has.', 'wp-graphql-woocommerce' ), + ], + 'totalSpent' => [ + 'type' => 'Float', + 'description' => __( 'Return how much money this customer has spent.', 'wp-graphql-woocommerce' ), + ], + 'username' => [ + 'type' => 'String', + 'description' => __( 'Return the customer\'s username.', 'wp-graphql-woocommerce' ), + ], + 'email' => [ + 'type' => 'String', + 'description' => __( 'Return the customer\'s email.', 'wp-graphql-woocommerce' ), + ], + 'firstName' => [ + 'type' => 'String', + 'description' => __( 'Return the customer\'s first name.', 'wp-graphql-woocommerce' ), + ], + 'lastName' => [ + 'type' => 'String', + 'description' => __( 'Return the customer\'s last name.', 'wp-graphql-woocommerce' ), + ], + 'displayName' => [ + 'type' => 'String', + 'description' => __( 'Return the customer\'s display name.', 'wp-graphql-woocommerce' ), + ], + 'role' => [ + 'type' => 'String', + 'description' => __( 'Return the customer\'s user role.', 'wp-graphql-woocommerce' ), + ], + 'date' => [ + 'type' => 'String', + 'description' => __( 'Return the date customer was created', 'wp-graphql-woocommerce' ), + ], + 'modified' => [ + 'type' => 'String', + 'description' => __( 'Return the date customer was last updated', 'wp-graphql-woocommerce' ), + ], + 'billing' => [ + 'type' => 'CustomerAddress', + 'description' => __( 'Return the date customer billing address properties', 'wp-graphql-woocommerce' ), + ], + 'shipping' => [ + 'type' => 'CustomerAddress', + 'description' => __( 'Return the date customer shipping address properties', 'wp-graphql-woocommerce' ), + ], + 'isPayingCustomer' => [ + 'type' => 'Boolean', + 'description' => __( 'Return the date customer was last updated', 'wp-graphql-woocommerce' ), + ], + 'sessionToken' => [ + 'type' => 'String', + 'description' => __( 'A JWT token that can be used in future requests to for WooCommerce session identification', 'wp-graphql-woocommerce' ), + 'resolve' => function( $source ) { + if ( \get_current_user_id() === $source->ID || 'guest' === $source->id ) { + return apply_filters( 'graphql_customer_session_token', \WC()->session->build_token() ); + } + return null; + }, + ], + + 'metaData' => Meta_Data_Type::get_metadata_field_definition(), + ], + $other_fields, + ); + } + + /** + * Returns the "Customer" type connections. + * + * @param array $other_connections Extra connections configs to be added or override the default connection definitions. + * @return array + */ + public static function get_connections( $other_connections = [] ) { + return array_merge( + [ + 'downloadableItems' => [ + 'toType' => 'DownloadableItem', + 'connectionArgs' => [ + 'active' => [ + 'type' => 'Boolean', + 'description' => __( 'Limit results to downloadable items that can be downloaded now.', 'wp-graphql-woocommerce' ), + ], + 'expired' => [ + 'type' => 'Boolean', + 'description' => __( 'Limit results to downloadable items that are expired.', 'wp-graphql-woocommerce' ), + ], + 'hasDownloadsRemaining' => [ + 'type' => 'Boolean', + 'description' => __( 'Limit results to downloadable items that have downloads remaining.', 'wp-graphql-woocommerce' ), + ], + ], + 'resolve' => function ( $source, array $args, AppContext $context, ResolveInfo $info ) { + $resolver = new Downloadable_Item_Connection_Resolver( $source, $args, $context, $info ); + + return $resolver->get_connection(); + }, + ], + ], + $other_connections + ); + } + /** * Registers Customer WPObject type and related fields. */ @@ -31,123 +172,22 @@ public static function register() { [ 'description' => __( 'A customer object', 'wp-graphql-woocommerce' ), 'interfaces' => [ 'Node' ], - 'fields' => [ - 'id' => [ - 'type' => [ 'non_null' => 'ID' ], - 'description' => __( 'The globally unique identifier for the customer', 'wp-graphql-woocommerce' ), - ], - 'databaseId' => [ - 'type' => 'Int', - 'description' => __( 'The ID of the customer in the database', 'wp-graphql-woocommerce' ), - ], - 'isVatExempt' => [ - 'type' => 'Boolean', - 'description' => __( 'Is customer VAT exempt?', 'wp-graphql-woocommerce' ), - ], - 'hasCalculatedShipping' => [ - 'type' => 'Boolean', - 'description' => __( 'Has calculated shipping?', 'wp-graphql-woocommerce' ), - ], - 'calculatedShipping' => [ - 'type' => 'Boolean', - 'description' => __( 'Has customer calculated shipping?', 'wp-graphql-woocommerce' ), - ], - 'lastOrder' => [ - 'type' => 'Order', - 'description' => __( 'Gets the customers last order.', 'wp-graphql-woocommerce' ), - 'resolve' => function( $source, array $args, AppContext $context ) { - return Factory::resolve_crud_object( $source->last_order_id, $context ); - }, - ], - 'orderCount' => [ - 'type' => 'Int', - 'description' => __( 'Return the number of orders this customer has.', 'wp-graphql-woocommerce' ), - ], - 'totalSpent' => [ - 'type' => 'Float', - 'description' => __( 'Return how much money this customer has spent.', 'wp-graphql-woocommerce' ), - ], - 'username' => [ - 'type' => 'String', - 'description' => __( 'Return the customer\'s username.', 'wp-graphql-woocommerce' ), - ], - 'email' => [ - 'type' => 'String', - 'description' => __( 'Return the customer\'s email.', 'wp-graphql-woocommerce' ), - ], - 'firstName' => [ - 'type' => 'String', - 'description' => __( 'Return the customer\'s first name.', 'wp-graphql-woocommerce' ), - ], - 'lastName' => [ - 'type' => 'String', - 'description' => __( 'Return the customer\'s last name.', 'wp-graphql-woocommerce' ), - ], - 'displayName' => [ - 'type' => 'String', - 'description' => __( 'Return the customer\'s display name.', 'wp-graphql-woocommerce' ), - ], - 'role' => [ - 'type' => 'String', - 'description' => __( 'Return the customer\'s user role.', 'wp-graphql-woocommerce' ), - ], - 'date' => [ - 'type' => 'String', - 'description' => __( 'Return the date customer was created', 'wp-graphql-woocommerce' ), - ], - 'modified' => [ - 'type' => 'String', - 'description' => __( 'Return the date customer was last updated', 'wp-graphql-woocommerce' ), - ], - 'billing' => [ - 'type' => 'CustomerAddress', - 'description' => __( 'Return the date customer billing address properties', 'wp-graphql-woocommerce' ), - ], - 'shipping' => [ - 'type' => 'CustomerAddress', - 'description' => __( 'Return the date customer shipping address properties', 'wp-graphql-woocommerce' ), - ], - 'isPayingCustomer' => [ - 'type' => 'Boolean', - 'description' => __( 'Return the date customer was last updated', 'wp-graphql-woocommerce' ), - ], - 'sessionToken' => [ - 'type' => 'String', - 'description' => __( 'A JWT token that can be used in future requests to for WooCommerce session identification', 'wp-graphql-woocommerce' ), - 'resolve' => function( $source ) { - if ( \get_current_user_id() === $source->ID || 'guest' === $source->id ) { - return apply_filters( 'graphql_customer_session_token', \WC()->session->build_token() ); - } - return null; - }, - ], - - 'metaData' => Meta_Data_Type::get_metadata_field_definition(), - ], - 'connections' => [ - 'downloadableItems' => [ - 'toType' => 'DownloadableItem', - 'connectionArgs' => [ - 'active' => [ - 'type' => 'Boolean', - 'description' => __( 'Limit results to downloadable items that can be downloaded now.', 'wp-graphql-woocommerce' ), - ], - 'expired' => [ - 'type' => 'Boolean', - 'description' => __( 'Limit results to downloadable items that are expired.', 'wp-graphql-woocommerce' ), - ], - 'hasDownloadsRemaining' => [ - 'type' => 'Boolean', - 'description' => __( 'Limit results to downloadable items that have downloads remaining.', 'wp-graphql-woocommerce' ), - ], - ], - 'resolve' => function ( $source, array $args, AppContext $context, ResolveInfo $info ) { - $resolver = new Downloadable_Item_Connection_Resolver( $source, $args, $context, $info ); - - return $resolver->get_connection(); - }, - ], - ], + /** + * Allows for a decisive filtering of the order fields. + * Note: Only use if deregisteration or renaming the field(s) has failed. + * + * @param array $fields Customer field definitions. + * @return array + */ + 'fields' => apply_filters( 'woographql_customer_field_definitions', self::get_fields() ), + /** + * Allows for a decisive filtering of the order connections. + * Note: Only use if deregisteration or renaming the connection(s) has failed. + * + * @param array $connections Customer connection definitions. + * @return array + */ + 'connections' => apply_filters( 'woographql_customer_connection_definitions', self::get_connections() ), ] ); diff --git a/includes/type/object/class-downloadable-item-type.php b/includes/type/object/class-downloadable-item-type.php index 4f6d73b1b..1da25131c 100644 --- a/includes/type/object/class-downloadable-item-type.php +++ b/includes/type/object/class-downloadable-item-type.php @@ -10,6 +10,7 @@ namespace WPGraphQL\WooCommerce\Type\WPObject; +use GraphQLRelay\Relay; use WPGraphQL\AppContext; use WPGraphQL\WooCommerce\Data\Factory; use WC_Product_Download; @@ -29,9 +30,16 @@ public static function register() { 'description' => __( 'A downloadable item', 'wp-graphql-woocommerce' ), 'interfaces' => [ 'Node' ], 'fields' => [ + 'id' => [ + 'type' => [ 'non_null' => 'ID' ], + 'description' => __( 'Downloadable item unique identifier', 'wp-graphql-woocommerce' ), + 'resolve' => function ( $source ) { + return ! empty( $source['download_id'] ) ? Relay::toGlobalId( 'download', $source['download_id'] ) : null; + }, + ], 'downloadId' => [ 'type' => [ 'non_null' => 'String' ], - 'description' => __( 'Downloadable item unique identifier', 'wp-graphql-woocommerce' ), + 'description' => __( 'Downloadable item ID.', 'wp-graphql-woocommerce' ), 'resolve' => function ( $source ) { return ! empty( $source['download_id'] ) ? $source['download_id'] : null; }, diff --git a/includes/type/object/class-order-item-type.php b/includes/type/object/class-order-item-type.php index 511f7a258..d09717ed0 100644 --- a/includes/type/object/class-order-item-type.php +++ b/includes/type/object/class-order-item-type.php @@ -309,6 +309,10 @@ public static function register() { private static function get_fields( $fields = [] ) { return array_merge( [ + 'id' => [ + 'type' => [ 'non_null' => 'ID' ], + 'description' => __( 'The ID of the order item in the database', 'wp-graphql-woocommerce' ), + ], 'databaseId' => [ 'type' => 'Int', 'description' => __( 'The ID of the order item in the database', 'wp-graphql-woocommerce' ), diff --git a/includes/type/object/class-order-type.php b/includes/type/object/class-order-type.php index 1d764b0c4..8a411dbee 100644 --- a/includes/type/object/class-order-type.php +++ b/includes/type/object/class-order-type.php @@ -22,21 +22,6 @@ * Class Order_Type */ class Order_Type { - /** - * Order Item connection resolver callback - * - * @param \WPGraphQL\Model\Order $source Source order. - * @param array $args Connection args. - * @param AppContext $context AppContext instance. - * @param ResolveInfo $info ResolveInfo instance. - * - * @return array - */ - public static function resolve_item_connection( $source, array $args, AppContext $context, ResolveInfo $info ) { - $resolver = new Order_Item_Connection_Resolver( $source, $args, $context, $info ); - - return $resolver->get_connection(); - } /** * Register Order type and queries to the WPGraphQL schema @@ -50,348 +35,404 @@ public static function register() { 'Node', 'NodeWithComments', ], - 'fields' => [ - 'id' => [ - 'type' => [ 'non_null' => 'ID' ], - 'description' => __( 'The globally unique identifier for the order', 'wp-graphql-woocommerce' ), - ], - 'databaseId' => [ - 'type' => 'Int', - 'description' => __( 'The ID of the order in the database', 'wp-graphql-woocommerce' ), - ], - 'orderKey' => [ - 'type' => 'String', - 'description' => __( 'Order key', 'wp-graphql-woocommerce' ), - ], - 'date' => [ - 'type' => 'String', - 'description' => __( 'Date order was created', 'wp-graphql-woocommerce' ), - ], - 'modified' => [ - 'type' => 'String', - 'description' => __( 'Date order was last updated', 'wp-graphql-woocommerce' ), - ], - 'currency' => [ - 'type' => 'String', - 'description' => __( 'Order currency', 'wp-graphql-woocommerce' ), - ], - 'paymentMethod' => [ - 'type' => 'String', - 'description' => __( 'Payment method', 'wp-graphql-woocommerce' ), - ], - 'paymentMethodTitle' => [ - 'type' => 'String', - 'description' => __( 'Payment method title', 'wp-graphql-woocommerce' ), - ], - 'transactionId' => [ - 'type' => 'String', - 'description' => __( 'Transaction ID', 'wp-graphql-woocommerce' ), - ], - 'customerIpAddress' => [ - 'type' => 'String', - 'description' => __( 'Customer IP Address', 'wp-graphql-woocommerce' ), - ], - 'customerUserAgent' => [ - 'type' => 'String', - 'description' => __( 'Customer User Agent', 'wp-graphql-woocommerce' ), - ], - 'createdVia' => [ - 'type' => 'String', - 'description' => __( 'How order was created', 'wp-graphql-woocommerce' ), - ], - 'dateCompleted' => [ - 'type' => 'String', - 'description' => __( 'Date order was completed', 'wp-graphql-woocommerce' ), - ], - 'datePaid' => [ - 'type' => 'String', - 'description' => __( 'Date order was paid', 'wp-graphql-woocommerce' ), - ], - 'discountTotal' => [ - 'type' => 'String', - 'description' => __( 'Discount total amount', 'wp-graphql-woocommerce' ), - 'args' => [ - 'format' => [ - 'type' => 'PricingFieldFormatEnum', - 'description' => __( 'Format of the price', 'wp-graphql-woocommerce' ), - ], + /** + * Allows for a decisive filtering of the order fields. + * Note: Only use if deregisteration or renaming the field(s) has failed. + * + * @param array $fields Order field definitions. + * @return array + */ + 'fields' => apply_filters( 'woographql_order_field_definitions', self::get_fields() ), + /** + * Allows for a decisive filtering of the order connections. + * Note: Only use if deregisteration or renaming the connection(s) has failed. + * + * @param array $connections Order connection definitions. + * @return array + */ + 'connections' => apply_filters( 'woographql_order_connection_definitions', self::get_connections() ), + ] + ); + } + + /** + * Returns the "Order" type fields. + * + * @param array $other_fields Extra fields configs to be added or override the default field definitions. + * @return array + */ + public static function get_fields( $other_fields = [] ) { + return array_merge( + [ + 'id' => [ + 'type' => [ 'non_null' => 'ID' ], + 'description' => __( 'The globally unique identifier for the order', 'wp-graphql-woocommerce' ), + ], + 'databaseId' => [ + 'type' => 'Int', + 'description' => __( 'The ID of the order in the database', 'wp-graphql-woocommerce' ), + ], + 'orderKey' => [ + 'type' => 'String', + 'description' => __( 'Order key', 'wp-graphql-woocommerce' ), + ], + 'date' => [ + 'type' => 'String', + 'description' => __( 'Date order was created', 'wp-graphql-woocommerce' ), + ], + 'modified' => [ + 'type' => 'String', + 'description' => __( 'Date order was last updated', 'wp-graphql-woocommerce' ), + ], + 'currency' => [ + 'type' => 'String', + 'description' => __( 'Order currency', 'wp-graphql-woocommerce' ), + ], + 'paymentMethod' => [ + 'type' => 'String', + 'description' => __( 'Payment method', 'wp-graphql-woocommerce' ), + ], + 'paymentMethodTitle' => [ + 'type' => 'String', + 'description' => __( 'Payment method title', 'wp-graphql-woocommerce' ), + ], + 'transactionId' => [ + 'type' => 'String', + 'description' => __( 'Transaction ID', 'wp-graphql-woocommerce' ), + ], + 'customerIpAddress' => [ + 'type' => 'String', + 'description' => __( 'Customer IP Address', 'wp-graphql-woocommerce' ), + ], + 'customerUserAgent' => [ + 'type' => 'String', + 'description' => __( 'Customer User Agent', 'wp-graphql-woocommerce' ), + ], + 'createdVia' => [ + 'type' => 'String', + 'description' => __( 'How order was created', 'wp-graphql-woocommerce' ), + ], + 'dateCompleted' => [ + 'type' => 'String', + 'description' => __( 'Date order was completed', 'wp-graphql-woocommerce' ), + ], + 'datePaid' => [ + 'type' => 'String', + 'description' => __( 'Date order was paid', 'wp-graphql-woocommerce' ), + ], + 'discountTotal' => [ + 'type' => 'String', + 'description' => __( 'Discount total amount', 'wp-graphql-woocommerce' ), + 'args' => [ + 'format' => [ + 'type' => 'PricingFieldFormatEnum', + 'description' => __( 'Format of the price', 'wp-graphql-woocommerce' ), ], - 'resolve' => function( $source, $args ) { - if ( isset( $args['format'] ) && 'raw' === $args['format'] ) { - // @codingStandardsIgnoreLine. - return $source->discountTotalRaw; - } else { - // @codingStandardsIgnoreLine. - return $source->discountTotal; - } - }, ], - 'discountTax' => [ - 'type' => 'String', - 'description' => __( 'Discount tax amount', 'wp-graphql-woocommerce' ), - 'args' => [ - 'format' => [ - 'type' => 'PricingFieldFormatEnum', - 'description' => __( 'Format of the price', 'wp-graphql-woocommerce' ), - ], + 'resolve' => function( $source, $args ) { + if ( isset( $args['format'] ) && 'raw' === $args['format'] ) { + // @codingStandardsIgnoreLine. + return $source->discountTotalRaw; + } else { + // @codingStandardsIgnoreLine. + return $source->discountTotal; + } + }, + ], + 'discountTax' => [ + 'type' => 'String', + 'description' => __( 'Discount tax amount', 'wp-graphql-woocommerce' ), + 'args' => [ + 'format' => [ + 'type' => 'PricingFieldFormatEnum', + 'description' => __( 'Format of the price', 'wp-graphql-woocommerce' ), ], - 'resolve' => function( $source, $args ) { - if ( isset( $args['format'] ) && 'raw' === $args['format'] ) { - // @codingStandardsIgnoreLine. - return $source->discountTaxRaw; - } else { - // @codingStandardsIgnoreLine. - return $source->discountTax; - } - }, ], - 'shippingTotal' => [ - 'type' => 'String', - 'description' => __( 'Shipping total amount', 'wp-graphql-woocommerce' ), - 'args' => [ - 'format' => [ - 'type' => 'PricingFieldFormatEnum', - 'description' => __( 'Format of the price', 'wp-graphql-woocommerce' ), - ], - ], - 'resolve' => function( $source, $args ) { - if ( isset( $args['format'] ) && 'raw' === $args['format'] ) { - // @codingStandardsIgnoreLine. - return $source->shippingTotalRaw; - } - + 'resolve' => function( $source, $args ) { + if ( isset( $args['format'] ) && 'raw' === $args['format'] ) { // @codingStandardsIgnoreLine. - return $source->shippingTotal; - }, - ], - 'shippingTax' => [ - 'type' => 'String', - 'description' => __( 'Shipping tax amount', 'wp-graphql-woocommerce' ), - 'args' => [ - 'format' => [ - 'type' => 'PricingFieldFormatEnum', - 'description' => __( 'Format of the price', 'wp-graphql-woocommerce' ), - ], - ], - 'resolve' => function( $source, $args ) { - if ( isset( $args['format'] ) && 'raw' === $args['format'] ) { - // @codingStandardsIgnoreLine. - return $source->shippingTaxRaw; - } - + return $source->discountTaxRaw; + } else { // @codingStandardsIgnoreLine. - return $source->shippingTax; - }, - ], - 'cartTax' => [ - 'type' => 'String', - 'description' => __( 'Cart tax amount', 'wp-graphql-woocommerce' ), - 'args' => [ - 'format' => [ - 'type' => 'PricingFieldFormatEnum', - 'description' => __( 'Format of the price', 'wp-graphql-woocommerce' ), - ], + return $source->discountTax; + } + }, + ], + 'shippingTotal' => [ + 'type' => 'String', + 'description' => __( 'Shipping total amount', 'wp-graphql-woocommerce' ), + 'args' => [ + 'format' => [ + 'type' => 'PricingFieldFormatEnum', + 'description' => __( 'Format of the price', 'wp-graphql-woocommerce' ), ], - 'resolve' => function( $source, $args ) { - if ( isset( $args['format'] ) && 'raw' === $args['format'] ) { - // @codingStandardsIgnoreLine. - return $source->cartTaxRaw; - } else { - // @codingStandardsIgnoreLine. - return $source->cartTax; - } - }, ], - 'total' => [ - 'type' => 'String', - 'description' => __( 'Order grand total', 'wp-graphql-woocommerce' ), - 'args' => [ - 'format' => [ - 'type' => 'PricingFieldFormatEnum', - 'description' => __( 'Format of the price', 'wp-graphql-woocommerce' ), - ], + 'resolve' => function( $source, $args ) { + if ( isset( $args['format'] ) && 'raw' === $args['format'] ) { + // @codingStandardsIgnoreLine. + return $source->shippingTotalRaw; + } + + // @codingStandardsIgnoreLine. + return $source->shippingTotal; + }, + ], + 'shippingTax' => [ + 'type' => 'String', + 'description' => __( 'Shipping tax amount', 'wp-graphql-woocommerce' ), + 'args' => [ + 'format' => [ + 'type' => 'PricingFieldFormatEnum', + 'description' => __( 'Format of the price', 'wp-graphql-woocommerce' ), ], - 'resolve' => function( $source, $args ) { - if ( isset( $args['format'] ) && 'raw' === $args['format'] ) { - // @codingStandardsIgnoreLine. - return $source->totalRaw; - } else { - return $source->total; - } - }, ], - 'totalTax' => [ - 'type' => 'String', - 'description' => __( 'Order taxes', 'wp-graphql-woocommerce' ), - 'args' => [ - 'format' => [ - 'type' => 'PricingFieldFormatEnum', - 'description' => __( 'Format of the price', 'wp-graphql-woocommerce' ), - ], + 'resolve' => function( $source, $args ) { + if ( isset( $args['format'] ) && 'raw' === $args['format'] ) { + // @codingStandardsIgnoreLine. + return $source->shippingTaxRaw; + } + + // @codingStandardsIgnoreLine. + return $source->shippingTax; + }, + ], + 'cartTax' => [ + 'type' => 'String', + 'description' => __( 'Cart tax amount', 'wp-graphql-woocommerce' ), + 'args' => [ + 'format' => [ + 'type' => 'PricingFieldFormatEnum', + 'description' => __( 'Format of the price', 'wp-graphql-woocommerce' ), ], - 'resolve' => function( $source, $args ) { - if ( isset( $args['format'] ) && 'raw' === $args['format'] ) { - // @codingStandardsIgnoreLine. - return $source->totalTaxRaw; - } else { - // @codingStandardsIgnoreLine. - return $source->totalTax; - } - }, ], - 'subtotal' => [ - 'type' => 'String', - 'description' => __( 'Order subtotal', 'wp-graphql-woocommerce' ), - 'args' => [ - 'format' => [ - 'type' => 'PricingFieldFormatEnum', - 'description' => __( 'Format of the price', 'wp-graphql-woocommerce' ), - ], + 'resolve' => function( $source, $args ) { + if ( isset( $args['format'] ) && 'raw' === $args['format'] ) { + // @codingStandardsIgnoreLine. + return $source->cartTaxRaw; + } else { + // @codingStandardsIgnoreLine. + return $source->cartTax; + } + }, + ], + 'total' => [ + 'type' => 'String', + 'description' => __( 'Order grand total', 'wp-graphql-woocommerce' ), + 'args' => [ + 'format' => [ + 'type' => 'PricingFieldFormatEnum', + 'description' => __( 'Format of the price', 'wp-graphql-woocommerce' ), ], - 'resolve' => function( $source, $args ) { - if ( isset( $args['format'] ) && 'raw' === $args['format'] ) { - // @codingStandardsIgnoreLine. - return $source->subtotalRaw; - } else { - return $source->subtotal; - } - }, - ], - 'orderNumber' => [ - 'type' => 'String', - 'description' => __( 'Order number', 'wp-graphql-woocommerce' ), - ], - 'orderVersion' => [ - 'type' => 'String', - 'description' => __( 'Order version', 'wp-graphql-woocommerce' ), - ], - 'pricesIncludeTax' => [ - 'type' => 'Boolean', - 'description' => __( 'Prices include taxes?', 'wp-graphql-woocommerce' ), - ], - 'cartHash' => [ - 'type' => 'String', - 'description' => __( 'Cart hash', 'wp-graphql-woocommerce' ), - ], - 'customerNote' => [ - 'type' => 'String', - 'description' => __( 'Customer note', 'wp-graphql-woocommerce' ), ], - 'isDownloadPermitted' => [ - 'type' => 'Boolean', - 'description' => __( 'Is product download is permitted', 'wp-graphql-woocommerce' ), - ], - 'billing' => [ - 'type' => 'CustomerAddress', - 'description' => __( 'Order billing properties', 'wp-graphql-woocommerce' ), - ], - 'shipping' => [ - 'type' => 'CustomerAddress', - 'description' => __( 'Order shipping properties', 'wp-graphql-woocommerce' ), - ], - 'status' => [ - 'type' => 'OrderStatusEnum', - 'description' => __( 'Order status', 'wp-graphql-woocommerce' ), + 'resolve' => function( $source, $args ) { + if ( isset( $args['format'] ) && 'raw' === $args['format'] ) { + // @codingStandardsIgnoreLine. + return $source->totalRaw; + } else { + return $source->total; + } + }, + ], + 'totalTax' => [ + 'type' => 'String', + 'description' => __( 'Order taxes', 'wp-graphql-woocommerce' ), + 'args' => [ + 'format' => [ + 'type' => 'PricingFieldFormatEnum', + 'description' => __( 'Format of the price', 'wp-graphql-woocommerce' ), + ], ], - 'parent' => [ - 'type' => 'Order', - 'description' => __( 'Parent order', 'wp-graphql-woocommerce' ), - 'resolve' => function( $order, array $args, AppContext $context ) { - return Factory::resolve_crud_object( $order->parent_id, $context ); - }, + 'resolve' => function( $source, $args ) { + if ( isset( $args['format'] ) && 'raw' === $args['format'] ) { + // @codingStandardsIgnoreLine. + return $source->totalTaxRaw; + } else { + // @codingStandardsIgnoreLine. + return $source->totalTax; + } + }, + ], + 'subtotal' => [ + 'type' => 'String', + 'description' => __( 'Order subtotal', 'wp-graphql-woocommerce' ), + 'args' => [ + 'format' => [ + 'type' => 'PricingFieldFormatEnum', + 'description' => __( 'Format of the price', 'wp-graphql-woocommerce' ), + ], ], - 'customer' => [ - 'type' => 'Customer', - 'description' => __( 'Order customer', 'wp-graphql-woocommerce' ), - 'resolve' => function( $order, array $args, AppContext $context ) { - if ( empty( $order->customer_id ) ) { - // Guest orders don't have an attached customer. - return null; - } + 'resolve' => function( $source, $args ) { + if ( isset( $args['format'] ) && 'raw' === $args['format'] ) { + // @codingStandardsIgnoreLine. + return $source->subtotalRaw; + } else { + return $source->subtotal; + } + }, + ], + 'orderNumber' => [ + 'type' => 'String', + 'description' => __( 'Order number', 'wp-graphql-woocommerce' ), + ], + 'orderVersion' => [ + 'type' => 'String', + 'description' => __( 'Order version', 'wp-graphql-woocommerce' ), + ], + 'pricesIncludeTax' => [ + 'type' => 'Boolean', + 'description' => __( 'Prices include taxes?', 'wp-graphql-woocommerce' ), + ], + 'cartHash' => [ + 'type' => 'String', + 'description' => __( 'Cart hash', 'wp-graphql-woocommerce' ), + ], + 'customerNote' => [ + 'type' => 'String', + 'description' => __( 'Customer note', 'wp-graphql-woocommerce' ), + ], + 'isDownloadPermitted' => [ + 'type' => 'Boolean', + 'description' => __( 'Is product download is permitted', 'wp-graphql-woocommerce' ), + ], + 'billing' => [ + 'type' => 'CustomerAddress', + 'description' => __( 'Order billing properties', 'wp-graphql-woocommerce' ), + ], + 'shipping' => [ + 'type' => 'CustomerAddress', + 'description' => __( 'Order shipping properties', 'wp-graphql-woocommerce' ), + ], + 'status' => [ + 'type' => 'OrderStatusEnum', + 'description' => __( 'Order status', 'wp-graphql-woocommerce' ), + ], + 'parent' => [ + 'type' => 'Order', + 'description' => __( 'Parent order', 'wp-graphql-woocommerce' ), + 'resolve' => function( $order, array $args, AppContext $context ) { + return Factory::resolve_crud_object( $order->parent_id, $context ); + }, + ], + 'customer' => [ + 'type' => 'Customer', + 'description' => __( 'Order customer', 'wp-graphql-woocommerce' ), + 'resolve' => function( $order, array $args, AppContext $context ) { + if ( empty( $order->customer_id ) ) { + // Guest orders don't have an attached customer. + return null; + } - return Factory::resolve_customer( $order->customer_id, $context ); - }, - ], - 'shippingAddressMapUrl' => [ - 'type' => 'String', - 'description' => __( 'Order customer', 'wp-graphql-woocommerce' ), - ], - 'hasBillingAddress' => [ - 'type' => 'Boolean', - 'description' => __( 'Order has a billing address?', 'wp-graphql-woocommerce' ), - ], - 'hasShippingAddress' => [ - 'type' => 'Boolean', - 'description' => __( 'Order has a shipping address?', 'wp-graphql-woocommerce' ), - ], - 'needsShippingAddress' => [ - 'type' => 'Boolean', - 'description' => __( 'If order needs shipping address', 'wp-graphql-woocommerce' ), - ], - 'hasDownloadableItem' => [ - 'type' => 'Boolean', - 'description' => __( 'If order contains a downloadable product', 'wp-graphql-woocommerce' ), - ], - 'needsPayment' => [ - 'type' => 'Boolean', - 'description' => __( 'If order needs payment', 'wp-graphql-woocommerce' ), - ], - 'needsProcessing' => [ - 'type' => 'Boolean', - 'description' => __( 'If order needs processing before it can be completed', 'wp-graphql-woocommerce' ), - ], - 'metaData' => Meta_Data_Type::get_metadata_field_definition(), + return Factory::resolve_customer( $order->customer_id, $context ); + }, ], - 'connections' => [ - 'taxLines' => [ - 'toType' => 'TaxLine', - 'connectionArgs' => [], - 'resolve' => [ __CLASS__, 'resolve_item_connection' ], - ], - 'feeLines' => [ - 'toType' => 'FeeLine', - 'connectionArgs' => [], - 'resolve' => [ __CLASS__, 'resolve_item_connection' ], - ], - 'shippingLines' => [ - 'toType' => 'ShippingLine', - 'connectionArgs' => [], - 'resolve' => [ __CLASS__, 'resolve_item_connection' ], - ], - 'couponLines' => [ - 'toType' => 'CouponLine', - 'connectionArgs' => [], - 'resolve' => [ __CLASS__, 'resolve_item_connection' ], - ], - 'lineItems' => [ - 'toType' => 'LineItem', - 'connectionArgs' => [], - 'resolve' => [ __CLASS__, 'resolve_item_connection' ], - ], - 'downloadableItems' => [ - 'toType' => 'DownloadableItem', - 'connectionArgs' => [ - 'active' => [ - 'type' => 'Boolean', - 'description' => __( 'Limit results to downloadable items that can be downloaded now.', 'wp-graphql-woocommerce' ), - ], - 'expired' => [ - 'type' => 'Boolean', - 'description' => __( 'Limit results to downloadable items that are expired.', 'wp-graphql-woocommerce' ), - ], - 'hasDownloadsRemaining' => [ - 'type' => 'Boolean', - 'description' => __( 'Limit results to downloadable items that have downloads remaining.', 'wp-graphql-woocommerce' ), - ], - ], - 'resolve' => function ( $source, array $args, AppContext $context, ResolveInfo $info ) { - $resolver = new Downloadable_Item_Connection_Resolver( $source, $args, $context, $info ); + 'shippingAddressMapUrl' => [ + 'type' => 'String', + 'description' => __( 'Order customer', 'wp-graphql-woocommerce' ), + ], + 'hasBillingAddress' => [ + 'type' => 'Boolean', + 'description' => __( 'Order has a billing address?', 'wp-graphql-woocommerce' ), + ], + 'hasShippingAddress' => [ + 'type' => 'Boolean', + 'description' => __( 'Order has a shipping address?', 'wp-graphql-woocommerce' ), + ], + 'needsShippingAddress' => [ + 'type' => 'Boolean', + 'description' => __( 'If order needs shipping address', 'wp-graphql-woocommerce' ), + ], + 'hasDownloadableItem' => [ + 'type' => 'Boolean', + 'description' => __( 'If order contains a downloadable product', 'wp-graphql-woocommerce' ), + ], + 'needsPayment' => [ + 'type' => 'Boolean', + 'description' => __( 'If order needs payment', 'wp-graphql-woocommerce' ), + ], + 'needsProcessing' => [ + 'type' => 'Boolean', + 'description' => __( 'If order needs processing before it can be completed', 'wp-graphql-woocommerce' ), + ], + 'metaData' => Meta_Data_Type::get_metadata_field_definition(), + ], + $other_fields + ); + } - return $resolver->get_connection(); - }, + /** + * Returns the "Order" type connections. + * + * @param array $other_connections Extra connections configs to be added or override the default connection definitions. + * @return array + */ + public static function get_connections( $other_connections = [] ) { + return array_merge( + [ + 'taxLines' => [ + 'toType' => 'TaxLine', + 'connectionArgs' => [], + 'resolve' => [ __CLASS__, 'resolve_item_connection' ], + ], + 'feeLines' => [ + 'toType' => 'FeeLine', + 'connectionArgs' => [], + 'resolve' => [ __CLASS__, 'resolve_item_connection' ], + ], + 'shippingLines' => [ + 'toType' => 'ShippingLine', + 'connectionArgs' => [], + 'resolve' => [ __CLASS__, 'resolve_item_connection' ], + ], + 'couponLines' => [ + 'toType' => 'CouponLine', + 'connectionArgs' => [], + 'resolve' => [ __CLASS__, 'resolve_item_connection' ], + ], + 'lineItems' => [ + 'toType' => 'LineItem', + 'connectionArgs' => [], + 'resolve' => [ __CLASS__, 'resolve_item_connection' ], + ], + 'downloadableItems' => [ + 'toType' => 'DownloadableItem', + 'connectionArgs' => [ + 'active' => [ + 'type' => 'Boolean', + 'description' => __( 'Limit results to downloadable items that can be downloaded now.', 'wp-graphql-woocommerce' ), + ], + 'expired' => [ + 'type' => 'Boolean', + 'description' => __( 'Limit results to downloadable items that are expired.', 'wp-graphql-woocommerce' ), + ], + 'hasDownloadsRemaining' => [ + 'type' => 'Boolean', + 'description' => __( 'Limit results to downloadable items that have downloads remaining.', 'wp-graphql-woocommerce' ), + ], ], + 'resolve' => function ( $source, array $args, AppContext $context, ResolveInfo $info ) { + $resolver = new Downloadable_Item_Connection_Resolver( $source, $args, $context, $info ); + + return $resolver->get_connection(); + }, ], - ] + ], + $other_connections ); } + + /** + * Order Item connection resolver callback + * + * @param \WPGraphQL\Model\Order $source Source order. + * @param array $args Connection args. + * @param AppContext $context AppContext instance. + * @param ResolveInfo $info ResolveInfo instance. + * + * @return array + */ + public static function resolve_item_connection( $source, array $args, AppContext $context, ResolveInfo $info ) { + $resolver = new Order_Item_Connection_Resolver( $source, $args, $context, $info ); + + return $resolver->get_connection(); + } } diff --git a/tests/_support/Helper/Wpunit.php b/tests/_support/Helper/Wpunit.php index 7a7ab2768..f6ea5cd9b 100644 --- a/tests/_support/Helper/Wpunit.php +++ b/tests/_support/Helper/Wpunit.php @@ -89,7 +89,7 @@ public function get_nodes( $ids, $crud ) { } public function clear_loader_cache( $loader_name ) { - $loader = \WPGraphQL::get_app_context()->getLoader( $loader_name ); + $loader = \WPGraphQL::get_app_context()->get_loader( $loader_name ); $loader->clearAll(); }