<?php | |
namespace App\GraphQL; | |
use WC_Bundled_Item_Data; | |
use WC_PB_DB; | |
use WPGraphQL\AppContext; | |
use WPGraphQL\WooCommerce\Data\Connection\Product_Connection_Resolver; | |
/** | |
* Register a GraphQL Connection between Product and BundleProduct in order to return the | |
* bundle items for a given Product Bundle | |
*/ | |
add_action( 'graphql_register_types', function () { | |
register_graphql_connection( [ | |
'fromType' => TYPE_BUNDLE_PRODUCT, | |
'toType' => 'Product', | |
'fromFieldName' => 'bundleItems', | |
'resolve' => function ( $source, $args, $context, $info ) { | |
$resolver = new Product_Connection_Resolver( $source, $args, $context, $info ); | |
return $resolver->get_connection(); | |
}, | |
'edgeFields' => [ | |
'quantityMin' => [ | |
'type' => 'Int', | |
'resolve' => function ( $source ) { | |
wp_send_json($source); | |
/* @var $bundledItem WC_Bundled_Item_Data */ | |
$bundledItem = $source['bundledItem']; | |
return $bundledItem->get_meta( 'quantity_min' ); | |
}, | |
], | |
'quantityMax' => [ | |
'type' => 'Int', | |
'resolve' => function ( $source ) { | |
/* @var $bundledItem WC_Bundled_Item_Data */ | |
$bundledItem = $source['bundledItem']; | |
return $bundledItem->get_meta( 'quantity_max' ); | |
}, | |
], | |
], | |
] ); | |
} ); | |
/** | |
* Short-circuit WP_Query to ensure we only query bundle items for a given post. Ideally | |
* would like to set query_args at the resolver level during the | |
* register_graphql_connection(), but query args don't take effect there. | |
* | |
* see https://github.com/wp-graphql/wp-graphql-woocommerce/issues/321 | |
*/ | |
add_filter( 'graphql_product_connection_query_args', function ( $query_args, $source, $args, $context, $info ) { | |
// Bail if this isn't a bundle | |
if ( 'bundle' !== $source->type ) { | |
return $query_args; | |
} | |
// Get the product id of the Product Bundle parent | |
$productId = $source->productId; | |
// Bail if we don't have a product id to run our query | |
if ( empty( $productId ) ) { | |
return $query_args; | |
} | |
global $wpdb; | |
/** | |
* Allow for LIMIT overwrites if greater than n is needed for a use-case | |
* | |
* @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. | |
*/ | |
$bundle_item_limit = apply_filters( 'graphql_product_bundle_item_connector_limit', 10, $source, $args, $context, $info ); | |
// Run our query - get me all of the post ids of the bundle items | |
$bundle_item_ids = $wpdb->get_results( $wpdb->prepare( " | |
SELECT | |
product_id | |
FROM | |
{$wpdb->prefix}woocommerce_bundled_items | |
WHERE | |
bundle_id = %d | |
LIMIT %d | |
", | |
intval( $productId ), | |
intval( $bundle_item_limit ) | |
) ); | |
// Extract IDs from query result with some wp_list_pluck magic and set post__in args | |
$query_args['post__in'] = wp_list_pluck( $bundle_item_ids, 'product_id' ); | |
return $query_args; | |
}, 10, 5 ); | |
/** | |
* Inject the WC_Bundled_Item_Data Class into the resolver so that fields can access | |
* edge data | |
*/ | |
add_filter( 'graphql_connection_edges', function ( $edges, $resolver ) { | |
$source = $resolver->getSource(); | |
// Bail if we don't have a source | |
if ( empty( $source ) ) { | |
return $edges; | |
} | |
// Bail if we don't have a type to check against | |
if ( empty( $source->type ) ) { | |
return $edges; | |
} | |
// Bail if our $source isn't a bundle | |
if ( 'bundle' !== $source->type ) { | |
return $edges; | |
} | |
// Get some info about the $resolver | |
$resolverInfo = $resolver->getInfo(); | |
// Bail if there isn't any info | |
if ( empty( $resolverInfo ) ) { | |
return $edges; | |
} | |
// Get the name of the field we are resolving | |
$fieldName = $resolverInfo->fieldName; | |
// Bail if there's nothing to check against | |
if ( empty( $fieldName ) ) { | |
return $edges; | |
} | |
// Bail if our field isn't bundleItems | |
if ( 'bundleItems' !== $fieldName ) { | |
return $edges; | |
} | |
$bundled_data_items = $resolver->getSource()->get_bundled_data_items(); | |
// Go through each edge, find the bundle item id, and set the bundleItem | |
foreach ( $edges as $key => $edge ) { | |
$raw_bundled_data_item = array_filter( $bundled_data_items, function ( WC_Bundled_Item_Data $item ) use ( $edge ) { | |
return $item->get_product_id() === $edge['node']->ID; | |
} ); | |
if ( empty( $raw_bundled_data_item ) ) { | |
$edges[ $key ]['bundledItem'] = []; | |
continue; | |
} | |
$bundled_data_item = array_values( $raw_bundled_data_item ); | |
// Expose the bundleItem so that the resolver can get edge data | |
$edges[ $key ]['bundledItem'] = WC_PB_DB::get_bundled_item( $bundled_data_item[0]->get_bundled_item_id() ); | |
} | |
return $edges; | |
}, 10, 2 ); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment