Skip to content

Commit

Permalink
fix: Fixed all product connection filtering regressions (#704)
Browse files Browse the repository at this point in the history
* fix: Fixed all product connection filtering regressions

* chore: WPCS compliance met

* fix: Unsupport syntax refactored
  • Loading branch information
kidunot89 committed Feb 2, 2023
1 parent 18e66cd commit de8cad3
Show file tree
Hide file tree
Showing 5 changed files with 198 additions and 159 deletions.
5 changes: 5 additions & 0 deletions includes/class-core-schema-filters.php
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,11 @@ public static function add_filters() {
10,
2
);

add_filter(
'graphql_wp_connection_type_config',
[ '\WPGraphQL\WooCommerce\Connection\Products', 'set_connection_config' ]
);
}

/**
Expand Down
85 changes: 63 additions & 22 deletions includes/connection/class-products.php
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,7 @@ function() {
'fromFieldName' => 'parent',
'description' => __( 'The parent of the node. The parent object can be of various types', 'wp-graphql-woocommerce' ),
'oneToOne' => true,
'queryClass' => '\WC_Product_Query',
'resolve' => function( $source, $args, AppContext $context, ResolveInfo $info ) {
if ( empty( $source->parent_id ) ) {
return null;
Expand All @@ -243,27 +244,6 @@ function() {
]
);

// Taxonomy To Product resolver.
$resolve_product_from_taxonomy = function( $source, array $args, AppContext $context, ResolveInfo $info ) {
add_filter( 'graphql_post_object_connection_args', [ __CLASS__, 'bypass_get_args_sanitization' ], 10, 3 );
$resolver = new PostObjectConnectionResolver( $source, $args, $context, $info, 'product' );
remove_filter( 'graphql_post_object_connection_args', [ __CLASS__, 'bypass_get_args_sanitization' ], 10, 3 );

$tax_query = [
[
// WPCS: slow query ok.
'taxonomy' => $source->taxonomyName, // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
'field' => 'term_id',
'terms' => $source->term_id,
],
];
$resolver->set_query_arg( 'tax_query', $tax_query );

$resolver = self::set_ordering_query_args( $resolver, $args );

return $resolver->get_connection();
};

// From WooCommerce product attributes.
$attributes = WP_GraphQL_WooCommerce::get_product_attribute_taxonomies();
foreach ( $attributes as $attribute ) {
Expand All @@ -275,7 +255,9 @@ function() {
'fromFieldName' => 'variations',
'resolve' => function( $source, array $args, AppContext $context, ResolveInfo $info ) {
global $wpdb;
add_filter( 'graphql_post_object_connection_args', [ __CLASS__, 'bypass_get_args_sanitization' ], 10, 3 );
$resolver = new PostObjectConnectionResolver( $source, $args, $context, $info, 'product_variation' );
remove_filter( 'graphql_post_object_connection_args', [ __CLASS__, 'bypass_get_args_sanitization' ], 10, 3 );

// phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
$attribute_meta_key = 'attribute_' . strtolower( preg_replace( '/([A-Z])/', '_$1', $source->taxonomyName ) );
Expand All @@ -291,8 +273,9 @@ function() {
)
);

$variation_ids = ! empty( $variation_ids ) ? $variation_ids : [ '0' ];

$resolver->set_query_arg( 'post__in', $variation_ids );
$resolver->set_query_arg( 'post_type', 'product_variation' );

$resolver = self::set_ordering_query_args( $resolver, $args );

Expand All @@ -304,6 +287,64 @@ function() {
}//end foreach
}

/**
* Returns the singular name of all registered taxonomies connected the products.
*
* @return array
*/
private static function get_product_connected_taxonomies() {
$taxonomies = [];
$allowed_taxonomies = \WPGraphQL::get_allowed_taxonomies( 'objects' );

foreach ( $allowed_taxonomies as $tax_object ) {
if ( ! in_array( 'product', $tax_object->object_type, true ) ) {
continue;
}

$taxonomies[] = ucfirst( $tax_object->graphql_single_name );
}

return $taxonomies;
}

/**
* Ensures all connection the `Product` type have proper connection config upon registration.
*
* @param array $config Connection config.
* @return array
*/
public static function set_connection_config( $config ) {
$to_type = $config['toType'];
$from_type = $config['fromType'];
if ( 'Product' === $to_type ) {
$config['connectionArgs'] = self::get_connection_args();
$config['queryClass'] = '\WC_Product_Query';
}

$taxonomies = self::get_product_connected_taxonomies();
if ( 'Product' === $to_type && in_array( $from_type, $taxonomies, true ) ) {
$config['resolve'] = function( $source, array $args, AppContext $context, ResolveInfo $info ) {
add_filter( 'graphql_post_object_connection_args', [ __CLASS__, 'bypass_get_args_sanitization' ], 10, 3 );
$resolver = new PostObjectConnectionResolver( $source, $args, $context, $info, 'product' );
remove_filter( 'graphql_post_object_connection_args', [ __CLASS__, 'bypass_get_args_sanitization' ], 10, 3 );
$tax_query = [
[
'taxonomy' => $source->taxonomyName, // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
'terms' => [ $source->term_id ],
'field' => 'term_id',
'include_children' => false,
],
];
$resolver->set_query_arg( 'tax_query', $tax_query );

$resolver = self::set_ordering_query_args( $resolver, $args );

return $resolver->get_connection();
};
}
return $config;
}

/**
* Given an array of $args, this returns the connection config, merging the provided args
* with the defaults
Expand Down
38 changes: 23 additions & 15 deletions tests/_support/Factory/ProductVariationFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,26 @@ public function create_object( $args ) {

// Create variation.
$variation = new $variation_class();
$variation->set_props( $args );
if ( ! empty( $args['meta_data'] ) ) {
$variation->set_meta_data( $args['meta_data'] );
}
if ( ! empty( $args['attributes'] ) ) {
$variation->set_attributes( $args['attributes'] );
foreach ( $args as $field => $field_value ) {
if ( ! is_callable( [ $variation, "set_{$field}" ] ) ) {
throw new \Exception(
sprintf( '"%1$s" is not a valid %2$s product variation field.', $field, $variation->get_type() )
);
}

$variation->{"set_{$field}"}( $field_value );
}

// if ( ! empty( $args['meta_data'] ) ) {
// $variation->set_meta_data( $args['meta_data'] );
// unset( $args['meta_data'] );
// }
// if ( ! empty( $args['attributes'] ) ) {
// $variation->set_attributes( $args['attributes'] );
// unset( $args['attributes'] );
// }
// $variation->set_props( $args );

return $variation->save();
}

Expand All @@ -51,7 +63,7 @@ public function update_object( $object, $fields ) {
foreach ( $fields as $field => $field_value ) {
if ( ! is_callable( [ $object, "set_{$field}" ] ) ) {
throw new \Exception(
sprintf( '"%1$s" is not a valid %2$s product field.', $field, $object->get_type() )
sprintf( '"%1$s" is not a valid %2$s product variation field.', $field, $object->get_type() )
);
}

Expand All @@ -73,12 +85,14 @@ public function createSome( $product = null, $args = [] ) {
// Create variation stub data.
$variation_data = [
[
'parent_id' => $product,
'attributes' => [ 'pa_size' => 'small' ],
'image_id' => null,
'downloads' => [ $this->factory->product->createDownload() ],
'regular_price' => 10,
],
[
'parent_id' => $product,
'attributes' => [ 'pa_size' => 'medium' ],
'image_id' => $this->factory->post->create(
[
Expand All @@ -91,6 +105,7 @@ public function createSome( $product = null, $args = [] ) {
'regular_price' => 15,
],
[
'parent_id' => $product,
'attributes' => [ 'pa_size' => 'large' ],
'image_id' => null,
'downloads' => [],
Expand All @@ -101,14 +116,7 @@ public function createSome( $product = null, $args = [] ) {
$variations = [];
foreach ( $variation_data as $data ) {
$args = array_merge( $data, $args );
$variation = $this->create_and_get(
$args,
[
'parent_id' => $product,
'sku' => uniqid(),
'variation_class' => '\WC_Product_Variation',
]
);
$variation = $this->create_and_get( $args, [ 'variation_class' => '\WC_Product_Variation' ] );

$variations[] = $variation->get_id();
}
Expand Down
Loading

0 comments on commit de8cad3

Please sign in to comment.