Search by

magenxcommerce / module-catalog-graph-ql-batch

magenxcommerce

Removes per-product database lookups from Magento's GraphQL product lists: pre-loads catalog rule and tier prices once per product collection, and resolves ProductInterface.rating_summary and review_count with one query per list.

Package info

github.com/magenxcommerce/module-catalog-graph-ql-batch

Type:magento2-module

pkg:composer/magenxcommerce/module-catalog-graph-ql-batch

Statistics

Installs: 0

Dependents: 1

Suggesters: 0

Stars: 1

Open Issues: 0

v1.0.0 2026-10-08 10:45 UTC

This package is auto-updated.

Last update: 2026-10-24 21:32:31 UTC


README

Built with AI assistance. This module is built with significant use of Claude Code, under active human review and guidance. It is open source and in active development. AI assistance does not lower the engineering bar: every change must meet the same correctness, security, documentation and maintainability requirements as any other contribution.

No warranty. We are not responsible for any incompatibility. By installing this software, you accept responsibility for its security, upgrades, patches and monitoring.

Removes per-product database lookups from Magento's GraphQL product lists. There is no schema change for the storefront and no configuration: enable the module and grids and linked-product lists run fewer queries.

Why

Profiling GetProductLinkedProducts (a PDP's related, upsell and frequently-bought-together lists, about 24 products) showed these core paths running once per product:

Field Core path Per product
price_range CatalogRulePrice::getValue() → Rule::getRulePrice() (the GraphQL product collection never joins catalogrule_product_price) 1 query
price_range TierPrice::getStoredTierPrices() → tier_price backend afterLoad() (the collection never calls addTierPriceData()) 1 query
rating_summary Magento\ReviewGraphQl\...\RatingSummary: Summary::load($productId) 1 query
review_count Magento\ReviewGraphQl\...\ReviewCount: Review::getTotalReviews($productId) 1 query

What it does

  • Plugin\PreloadProductPrices (graphql area, after CatalogGraphQl\...\Product\CollectionPostProcessor::process()): when a price field (price_range, price, price_tiers, deal) is selected, it loads tier prices for the whole collection (addTierPriceData()) and catalog rule prices with one catalogrule_product_price query, and sets them on each product. The pricing classes then read them from the model instead of querying. This post-processor runs for both GraphQL product loaders: the products query and the related/upsell/cross-sell lists.
  • rating_summary / review_count are re-declared in schema.graphqls with batch resolvers (Model\Resolver\Product\*): one query per product list for each, through Model\ReviewStatsProvider.

The values are the same as core's. The pre-load uses the same inputs as the per-product paths (current store and website, the store's local date, the customer session's group), and the review queries use the same tables and filters (review_entity_summary by store; approved reviews in review + review_store). If the price pre-load fails, it logs a warning and the pricing classes fall back to their own per-product lookups.

Not covered: configurable products still resolve their lowest-priced child per product (LowestPriceOptionsProvider), logged-in customers' rule prices are still recomputed per product by CatalogRuleGraphQl's UpdateCatalogRulePrice plugin, and stock_status is unchanged.

Install

composer require magenxcommerce/module-catalog-graph-ql-batch
bin/magento module:enable Magenx_CatalogGraphQlBatch
bin/magento setup:upgrade && bin/magento setup:di:compile

Verify

bin/magento dev:query-log:enable --include-all-queries=true --query-time-threshold=0 --include-call-stack=false
: > var/debug/db.log
# run one GetProductLinkedProducts (or a category grid) request
grep -oE 'FROM `[a-z0-9_]+`' var/debug/db.log | sort | uniq -c | sort -rn | head -20
bin/magento dev:query-log:disable

catalogrule_product_price, catalog_product_entity_tier_price, review_entity_summary and review should appear once per product list, not once per product. Compare a few price_range, rating_summary and review_count values with the module disabled.