Skip to content
291 changes: 186 additions & 105 deletions composer.lock

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions includes/class-core-schema-filters.php
Original file line number Diff line number Diff line change
Expand Up @@ -389,7 +389,7 @@ public static function inject_type_resolver( $type, $value ) {
* Resolves GraphQL type for provided product model.
*
* @param \WPGraphQL\WooCommerce\Model\Product $value Product model.
*
*
* @throws \GraphQL\Error\UserError Invalid product type requested.
*
* @return mixed
Expand Down Expand Up @@ -420,7 +420,7 @@ public static function resolve_product_type( $value ) {
* Resolves GraphQL type for provided product variation model.
*
* @param \WPGraphQL\WooCommerce\Model\Product $value Product model.
*
*
* @throws \GraphQL\Error\UserError Invalid product type requested.
*
* @return mixed
Expand Down
4 changes: 2 additions & 2 deletions includes/class-jwt-auth-schema-filters.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public static function get_auth_class() {
* Get the auth token for a user.
*
* @param \WP_User $user The user object.
*
*
* @throws \GraphQL\Error\UserError If the token cannot be retrieved.
*
* @return string|null
Expand Down Expand Up @@ -69,7 +69,7 @@ public static function get_auth_token( \WP_User $user ) {
* Get the refresh token for a user.
*
* @param \WP_User $user The user object.
*
*
* @throws \GraphQL\Error\UserError If the token cannot be retrieved.
*
* @return string|null
Expand Down
1 change: 1 addition & 0 deletions includes/class-type-registry.php
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ public function init() {
Type\WPInputObject\Collection_Stats_Query_Input::register();
Type\WPInputObject\Collection_Stats_Where_Args::register();
Type\WPInputObject\Product_Attribute_Filter_Input::register();
Type\WPInputObject\Product_Attribute_Query_Input::register();

/**
* Interfaces.
Expand Down
1 change: 1 addition & 0 deletions includes/class-wp-graphql-woocommerce.php
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,7 @@ private function includes() {
require $include_directory_path . 'type/input/class-collection-stats-query-input.php';
require $include_directory_path . 'type/input/class-collection-stats-where-args.php';
require $include_directory_path . 'type/input/class-product-attribute-filter-input.php';
require $include_directory_path . 'type/input/class-product-attribute-query-input.php';

// Include mutation type class files.
require $include_directory_path . 'mutation/class-cart-add-fee.php';
Expand Down
2 changes: 1 addition & 1 deletion includes/connection/class-customers.php
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ public static function map_input_fields_to_wp_query( $query_args, $where_args, $
* has been added to the UserConnectionResolver
*
* @param array $connection Resolved connection.
* @param \WPGraphQL\Data\Connection\AbstractConnectionResolver $resolver Resolver class.
* @param \WPGraphQL\Data\Connection\AbstractConnectionResolver $resolver Resolver class.
*
* @return array
*/
Expand Down
16 changes: 11 additions & 5 deletions includes/connection/class-products.php
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,7 @@ public static function get_connection_fields(): array {

/**
* Returns array of where args.
*
*
* @param array $extra_args Extra connection args.
*
* @return array
Expand Down Expand Up @@ -379,13 +379,19 @@ public static function get_connection_args( $extra_args = [] ): array {
'type' => 'Int',
'description' => __( 'Limit result set to products assigned a specific shipping class ID.', 'wp-graphql-woocommerce' ),
],
'attributes' => [
'type' => 'ProductAttributeQueryInput',
'description' => __( 'Limit result set to products with selected global attribute queries.', 'wp-graphql-woocommerce' ),
],
'attribute' => [
'type' => 'String',
'description' => __( 'Limit result set to products with a specific attribute. Use the taxonomy name/attribute slug.', 'wp-graphql-woocommerce' ),
'type' => 'String',
'description' => __( 'Limit result set to products with a specific global product attribute', 'wp-graphql-woocommerce' ),
'deprecationReason' => 'Use attributes instead.',
],
'attributeTerm' => [
'type' => 'String',
'description' => __( 'Limit result set to products with a specific attribute term ID (required an assigned attribute).', 'wp-graphql-woocommerce' ),
'type' => 'String',
'description' => __( 'Limit result set to products with a specific global product attribute term ID (required an assigned attribute).', 'wp-graphql-woocommerce' ),
'deprecationReason' => 'Use attributes instead.',
],
'stockStatus' => [
'type' => [ 'list_of' => 'StockStatusEnum' ],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ public function get_ids() {

/**
* Returns meta keys to be used for connection ordering.
*
*
* @param bool $is_numeric Return numeric meta keys. Defaults to "true".
*
* @return array
Expand Down
84 changes: 67 additions & 17 deletions includes/data/connection/class-product-connection-resolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@
/**
* Class Product_Connection_Resolver
*
* @deprecated v0.10.0
*
* @property \WPGraphQL\WooCommerce\Data\Loader\WC_CPT_Loader $loader
*/
class Product_Connection_Resolver extends AbstractConnectionResolver {
Expand Down Expand Up @@ -154,7 +152,6 @@ public function get_query_args() {
$query_args = array_merge( $query_args, $input_fields );
}


/**
* If the query contains search default the results to
*/
Expand Down Expand Up @@ -190,8 +187,6 @@ public function get_query_args() {

/**
* {@inheritDoc}
*
* @return \WP_Query
*/
public function get_query() {
// Run query and add product query filters.
Expand Down Expand Up @@ -224,7 +219,7 @@ public function product_query_post_clauses( $args, $wp_query ) {
/**
* Custom query used to filter products by price.
*
* @param array $args SQL clauses $args Query args.
* @param array $args SQL clauses.
* @param \WP_Query $wp_query WP_Query object.
*
* @return array
Expand Down Expand Up @@ -270,6 +265,7 @@ public function price_filter_post_clauses( $args, $wp_query ) {
*/
public function get_ids_from_query() {
$ids = $this->query->get_posts();
remove_filter( 'posts_clauses', [ $this, 'product_query_post_clauses' ], 10 );

// If we're going backwards, we need to reverse the array.
if ( ! empty( $this->args['last'] ) ) {
Expand All @@ -283,7 +279,7 @@ public function get_ids_from_query() {
* Returns meta keys to be used for connection ordering.
*
* @param bool $is_numeric Return numeric meta keys. Defaults to "true".
*
*
* @return array
*/
public function ordering_meta( $is_numeric = true ) {
Expand All @@ -297,11 +293,6 @@ public function ordering_meta( $is_numeric = true ) {
return apply_filters(
'woographql_product_connection_orderby_numeric_meta_keys',
[
'_price',
'_regular_price',
'_sale_price',
'_wc_rating_count',
'_wc_average_rating',
'_sale_price_dates_from',
'_sale_price_dates_to',
'total_sales',
Expand Down Expand Up @@ -456,6 +447,9 @@ public function sanitize_input_fields( array $where_args ) {

// Filter by attribute and term.
if ( ! empty( $where_args['attribute'] ) && ! empty( $where_args['attributeTerm'] ) ) {
graphql_debug(
__( 'The "attribute" and "attributeTerm" arguments have been deprecated. Please use the "attributes" argument instead.', 'wp-graphql-woocommerce' ),
);
if ( in_array( $where_args['attribute'], \wc_get_attribute_taxonomy_names(), true ) ) {
$tax_query[] = [
'taxonomy' => $where_args['attribute'],
Expand All @@ -465,6 +459,61 @@ public function sanitize_input_fields( array $where_args ) {
}
}

// Filter by attributes.
if ( ! empty( $where_args['attributes'] ) && ! empty( $where_args['attributes']['queries'] ) ) {
$attributes = $where_args['attributes']['queries'];
$att_queries = [];

foreach ( $attributes as $attribute ) {
if ( empty( $attribute['ids'] ) && empty( $attribute['terms'] ) ) {
continue;
}

if ( ! in_array( $attribute['taxonomy'], \wc_get_attribute_taxonomy_names(), true ) ) {
continue;
}

$operator = isset( $attribute['operator'] ) ? $attribute['operator'] : 'IN';

if ( ! empty( $attribute['terms'] ) ) {
foreach ( $attribute['terms'] as $term ) {
$att_queries[] = [
'taxonomy' => $attribute['taxonomy'],
'field' => 'slug',
'terms' => $term,
'operator' => $operator,
];
}
}

if ( ! empty( $attribute['ids'] ) ) {
foreach ( $attribute['ids'] as $id ) {
$att_queries[] = [
'taxonomy' => $attribute['taxonomy'],
'field' => 'term_id',
'terms' => $id,
'operator' => $operator,
];
}
}
}

if ( 1 < count( $att_queries ) ) {
$relation = ! empty( $where_args['attributes']['relation'] ) ? $where_args['attributes']['relation'] : 'AND';
if ( 'NOT_IN' === $relation ) {
graphql_debug( __( 'The "NOT_IN" relation is not supported for attributes. Please use "IN" or "AND" instead.', 'wp-graphql-woocommerce' ) );
$relation = 'IN';
}

$tax_query[] = array_merge(
[ 'relation' => $relation ],
$att_queries
);
} else {
$tax_query = array_merge( $tax_query, $att_queries );
}
}

if ( empty( $where_args['type'] ) && empty( $where_args['typeIn'] ) && ! empty( $where_args['supportedTypesOnly'] )
&& true === $where_args['supportedTypesOnly'] ) {
$supported_types = array_keys( WP_GraphQL_WooCommerce::get_enabled_product_types() );
Expand Down Expand Up @@ -552,7 +601,7 @@ public function sanitize_input_fields( array $where_args ) {
'terms' => $rating_terms,
];
}

// Process "taxonomyFilter".
$tax_filter_query = [];
if ( ! empty( $where_args['taxonomyFilter'] ) ) {
Expand Down Expand Up @@ -619,6 +668,9 @@ public function sanitize_input_fields( array $where_args ) {
'compare' => 'LIKE',
];
}
if ( ! empty( $where_args['minPrice'] ) ) {
$query_args['min_price'] = floatval( $where_args['minPrice'] );
}

if ( ! empty( $where_args['minPrice'] ) ) {
$query_args['min_price'] = floatval( $where_args['minPrice'] );
Expand Down Expand Up @@ -649,8 +701,6 @@ public function sanitize_input_fields( array $where_args ) {
$query_args[ $on_sale_key ] = $on_sale_ids;
}



/**
* {@inheritDoc}
*/
Expand Down Expand Up @@ -709,9 +759,9 @@ public function is_valid_offset( $offset ) {

/**
* Adds meta query to the query args.
*
*
* @param array $value Meta query.
*
*
* @return \WPGraphQL\WooCommerce\Data\Connection\Product_Connection_Resolver
*/
public function add_meta_query( $value ) {
Expand Down
6 changes: 3 additions & 3 deletions includes/data/loader/class-wc-cpt-loader.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ class WC_CPT_Loader extends AbstractDataLoader {
* @param boolean $fatal Throw if no model found.
*
* @throws \GraphQL\Error\UserError - throws if no corresponding Model is registered to the post-type.
*
*
* @return \WPGraphQL\Model\Model|null
*/
public static function resolve_model( $post_type, $id, $fatal = true ) {
Expand All @@ -52,7 +52,7 @@ public static function resolve_model( $post_type, $id, $fatal = true ) {
/**
* If a model is registered to the post-type, we can return an instance of that model
* with the post ID passed in.
*
*
* @var \WPGraphQL\Model\Model
*/
return new $model( $id );
Expand Down Expand Up @@ -153,7 +153,7 @@ static function ( $split, \WP_Query $query ) {

/**
* {@inheritDoc}
*
*
* @return \WPGraphQL\Model\Model|null
*/
protected function get_model( $entry, $key ) {
Expand Down
2 changes: 1 addition & 1 deletion includes/type/enum/class-products-orderby-enum.php
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ protected static function values() {
'description' => __( 'Order by product popularity', 'wp-graphql-woocommerce' ),
],
'REVIEW_COUNT' => [
'value' => '_wc_rating_count',
'value' => 'popularity',
'description' => __( 'Order by number of reviews on product', 'wp-graphql-woocommerce' ),
],
'RATING' => [
Expand Down
2 changes: 1 addition & 1 deletion includes/type/input/class-collection-stats-query-input.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public static function register() {
'description' => __( 'Product Taxonomy', 'wp-graphql-woocommerce' ),
],
'relation' => [
'type' => [ 'non_null' => 'RelationEnum' ],
'type' => 'RelationEnum',
'description' => __( 'Taxonomy relation to query', 'wp-graphql-woocommerce' ),
],
],
Expand Down
4 changes: 2 additions & 2 deletions includes/type/input/class-collection-stats-where-args.php
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,8 @@ public static function register() {
'description' => __( 'Limit result set to products assigned to a specific group of tag IDs.', 'wp-graphql-woocommerce' ),
],
'attributes' => [
'type' => [ 'list_of' => 'ProductAttributeFilterInput' ],
'description' => __( 'Limit result set to products with a specific attribute. Use the taxonomy name/attribute slug.', 'wp-graphql-woocommerce' ),
'type' => 'ProductAttributeQueryInput',
'description' => __( 'Limit result set to products with selected global attribute queries.', 'wp-graphql-woocommerce' ),
],
'stockStatus' => [
'type' => [ 'list_of' => 'StockStatusEnum' ],
Expand Down
38 changes: 38 additions & 0 deletions includes/type/input/class-product-attribute-query-input.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<?php
/**
* WPInputObjectType - ProductAttributeQueryInput
*
* @package WPGraphQL\WooCommerce\Type\WPInputObject
* @since TBD
*/

namespace WPGraphQL\WooCommerce\Type\WPInputObject;

/**
* Class Product_Attribute_Query_Input
*/
class Product_Attribute_Query_Input {
/**
* Registers type
*
* @return void
*/
public static function register() {
register_graphql_input_type(
'ProductAttributeQueryInput',
[
'description' => __( 'Product filter', 'wp-graphql-woocommerce' ),
'fields' => [
'queries' => [
'type' => [ 'list_of' => 'ProductAttributeFilterInput' ],
'description' => __( 'Limit result set to products with selected global attributes.', 'wp-graphql-woocommerce' ),
],
'relation' => [
'type' => 'AttributeOperatorEnum',
'description' => __( 'The logical relationship between attributes when filtering across multiple at once.', 'wp-graphql-woocommerce' ),
],
],
]
);
}
}
2 changes: 1 addition & 1 deletion includes/type/interface/class-downloadable-product.php
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?php
/**
* Defines the "DownloadableProduct" interface.
*
*
* @package WPGraphQL\WooCommerce\Type\WPInterface
* @since 0.17.0
*/
Expand Down
2 changes: 1 addition & 1 deletion includes/type/interface/class-inventoried-product.php
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?php
/**
* Defines the "InventoriedProduct" interface.
*
*
* @package WPGraphQL\WooCommerce\Type\WPInterface
* @since 0.17.0
*/
Expand Down
Loading