Skip to content

Commit

Permalink
fix: WPGraphQL v1.24.x support added
Browse files Browse the repository at this point in the history
  • Loading branch information
kidunot89 committed May 7, 2024
1 parent eac4d41 commit 22331ee
Show file tree
Hide file tree
Showing 22 changed files with 1,379 additions and 227 deletions.
2 changes: 1 addition & 1 deletion bin/_lib.sh
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ install_local_test_library() {
codeception/module-asserts:* \
codeception/module-rest:* \
codeception/util-universalframework:^1.0 \
wp-graphql/wp-graphql-testcase:^2.3 \
wp-graphql/wp-graphql-testcase \
stripe/stripe-php \
fakerphp/faker

Expand Down
291 changes: 186 additions & 105 deletions composer.lock

Large diffs are not rendered by default.

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
14 changes: 10 additions & 4 deletions includes/connection/class-products.php
Original file line number Diff line number Diff line change
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' => 'ProductAttributeEnum',
'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
148 changes: 99 additions & 49 deletions includes/data/connection/class-product-connection-resolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,9 @@ public function get_query_args() {
*/
$query_args['post_type'] = $this->post_type;


/**
* Set WC Query
* Set the wc_query to product_query
*/
$query_args['wc_query'] = 'product_query';

Expand Down Expand Up @@ -161,8 +162,7 @@ public function get_query_args() {
* Don't order search results by title (causes funky issues with cursors)
*/
$query_args['search_orderby_title'] = false;
$query_args['orderby'] = 'date';
$query_args['order'] = isset( $last ) ? 'ASC' : 'DESC';
$query_args = array_merge( $query_args, \WC()->query->get_catalog_ordering_args( 'relevance', isset( $last ) ? 'ASC' : 'DESC' ) );
}

/**
Expand Down Expand Up @@ -213,8 +213,7 @@ public function get_query_args() {
}//end if

if ( empty( $query_args['orderby'] ) ) {
$query_args['orderby'] = 'date';
$query_args['order'] = isset( $last ) ? 'ASC' : 'DESC';
$query_args = array_merge( $query_args, \WC()->query->get_catalog_ordering_args( 'menu_order', isset( $last ) ? 'ASC' : 'DESC' ) );
}

/**
Expand All @@ -241,64 +240,52 @@ public function get_query_args() {
* @return \WC_Query
*/
public function get_query() {
// Run query and remove hook.
\codecept_debug( $this->query_args );
$query = new \WP_Query( $this->query_args );
\WC()->query->product_query( $query );
return $query;

// Run query and add product query filters.
$wp_query = new \WP_Query();
$wp_query->query_vars = wp_parse_args( $this->query_args );
add_filter( 'posts_clauses', array( $this, 'product_query_post_clauses' ), 10, 2 );

return $wp_query;

Check failure on line 249 in includes/data/connection/class-product-connection-resolver.php

View workflow job for this annotation

GitHub Actions / Testing WooGraphQL code quality w/ PHPStan

Method WPGraphQL\WooCommerce\Data\Connection\Product_Connection_Resolver::get_query() should return WC_Query but returns WP_Query.
}

/**
* Add extra clauses to the product query.
* Filter the product query and apply WC's custom clauses.
*
* @param array $args The query clauses.
* @param \WP_Query $wp_query The WP_Query object.
*
* @param array $args Product query clauses.
* @param WP_Query $wp_query The current product query.
* @return array The updated product query clauses array.
* @return array
*/
public function product_query_post_clauses( $args, $wp_query ) {
if ( 'product_query' !== $wp_query->get( 'wc_query' ) ) {
return $args;
}

$args = $this->price_filter_post_clauses( $args, $wp_query );

Check failure on line 265 in includes/data/connection/class-product-connection-resolver.php

View workflow job for this annotation

GitHub Actions / Testing WooGraphQL code quality w/ PHPStan

Parameter #2 $wp_query of method WPGraphQL\WooCommerce\Data\Connection\Product_Connection_Resolver::price_filter_post_clauses() expects WPGraphQL\WooCommerce\Data\Connection\WP_Query, WP_Query given.
$args = $this->filterer->filter_by_attribute_post_clauses( $args, $wp_query, \WC_Query::get_layered_nav_chosen_attributes() );
$args = $this->filterer->filter_by_attribute_post_clauses( $args, $wp_query, [] );

Check failure on line 266 in includes/data/connection/class-product-connection-resolver.php

View workflow job for this annotation

GitHub Actions / Testing WooGraphQL code quality w/ PHPStan

Call to method filter_by_attribute_post_clauses() on an unknown class Automattic\WooCommerce\Internal\ProductAttributesLookup\Filterer.

return $args;
}

/**
* Join wc_product_meta_lookup to posts if not already joined.
*
* @param string $sql SQL join.
* @return string
*/
private function append_product_sorting_table_join( $sql ) {
global $wpdb;

if ( ! strstr( $sql, 'wc_product_meta_lookup' ) ) {
$sql .= " LEFT JOIN {$wpdb->wc_product_meta_lookup} wc_product_meta_lookup ON $wpdb->posts.ID = wc_product_meta_lookup.product_id ";
}
return $sql;
}

/**
* Custom query used to filter products by price.
*
* @since 3.6.0
*
* @param array $args Query args.
* @param WP_Query $wp_query WP_Query object.
* @param array $args Query args.
* @param WP_Query $wp_query WP_Query object.
*
* @return array
*/
public function price_filter_post_clauses( $args, $wp_query ) {

Check failure on line 279 in includes/data/connection/class-product-connection-resolver.php

View workflow job for this annotation

GitHub Actions / Testing WooGraphQL code quality w/ PHPStan

Parameter $wp_query of method WPGraphQL\WooCommerce\Data\Connection\Product_Connection_Resolver::price_filter_post_clauses() has invalid type WPGraphQL\WooCommerce\Data\Connection\WP_Query.
global $wpdb;
if ( 'product_query' !== $wp_query->get('wc_query') ) {
return $args;
}

$current_max_price = $wp_query->get( 'max_price' );
$current_min_price = $wp_query->get( 'min_price' );
$min_price = $wp_query->get( 'min_price' );

Check failure on line 282 in includes/data/connection/class-product-connection-resolver.php

View workflow job for this annotation

GitHub Actions / Testing WooGraphQL code quality w/ PHPStan

Call to method get() on an unknown class WPGraphQL\WooCommerce\Data\Connection\WP_Query.
$max_price = $wp_query->get( 'max_price' );

Check failure on line 283 in includes/data/connection/class-product-connection-resolver.php

View workflow job for this annotation

GitHub Actions / Testing WooGraphQL code quality w/ PHPStan

Call to method get() on an unknown class WPGraphQL\WooCommerce\Data\Connection\WP_Query.

if ( ! $current_max_price && ! $current_min_price ) {
return $args;
}
// phpcs:disable WordPress.Security.NonceVerification.Recommended
$current_min_price = $min_price ?: 0;
$current_max_price = $max_price ?: PHP_INT_MAX;
// phpcs:enable WordPress.Security.NonceVerification.Recommended

/**
* Adjust if the store taxes are not displayed how they are stored.
Expand All @@ -313,8 +300,10 @@ public function price_filter_post_clauses( $args, $wp_query ) {
$current_max_price -= \WC_Tax::get_tax_total( \WC_Tax::calc_inclusive_tax( $current_max_price, $tax_rates ) );
}
}

$args['join'] = $this->append_product_sorting_table_join( $args['join'] );

$args['join'] .= ! strstr( $args['join'], 'wc_product_meta_lookup' )
? " LEFT JOIN {$wpdb->wc_product_meta_lookup} wc_product_meta_lookup ON $wpdb->posts.ID = wc_product_meta_lookup.product_id "
: '';
$args['where'] .= $wpdb->prepare(
' AND NOT (%f<wc_product_meta_lookup.min_price OR %f>wc_product_meta_lookup.max_price ) ',
$current_max_price,
Expand All @@ -328,6 +317,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', array( $this, 'product_query_post_clauses' ), 10, 2 );

// If we're going backwards, we need to reverse the array.
if ( ! empty( $this->args['last'] ) ) {
Expand Down Expand Up @@ -381,18 +371,20 @@ public function sanitize_input_fields( array $where_args ) {
'maxPrice' => 'max_price',
'stockStatus' => 'stock_status',
'status' => 'post_status',
'include' => 'include',
'exclude' => 'exclude',
'parent' => 'parent',
'parentIn' => 'parent_in',
'include' => 'post__in',
'exclude' => 'post__not_in',
'parent' => 'post_parent',
'parentIn' => 'post_parent__in',
'parentNotIn' => 'post_parent__not_in',
'search' => 'search',
]
);

if ( ! empty( $where_args['orderby'] ) ) {
$default_order = isset( $this->args['last'] ) ? 'ASC' : 'DESC';
$orderby_input = current( $where_args['orderby'] );

$orderby = $orderby_input['field'];
$default_order = isset( $this->args['last'] ) ? 'ASC' : 'DESC';
$order = ! empty( $orderby_input['order'] ) ? $orderby_input['order'] : $default_order;
$query_args = array_merge( $query_args, \WC()->query->get_catalog_ordering_args( $orderby, $order ) );
}
Expand Down Expand Up @@ -508,6 +500,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 @@ -517,6 +512,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[] = [
'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
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' ),
],
],
]
);
}
}
Loading

0 comments on commit 22331ee

Please sign in to comment.