Hi,
I`m trying to rewrite function from Scripts Editor to Shopify Functions, the problem is I cannot query the property from line_item.properties with Graphql.
This is the code in Scripts Editor:
DiscountConfig = Struct.new(:block_id, :percentage, :message) do
def applicable?(line_item)
line_item.properties["_checkoutblocks"] == block_id
end
def apply_discount(line_item)
return unless applicable?(line_item)
discount_amount = line_item.line_price * percentage
new_price = line_item.line_price - discount_amount
line_item.change_line_price(new_price, message: message)
end
end
discount_configs = [
DiscountConfig.new("someID", 0.05, "Checkout offer 5% off"),
]
Input.cart.line_items.each do |line_item|
discount_configs.each { |config| config.apply_discount(line_item) }
end
Output.cart = Input.cart
I`m trying to get this property _checkoutblocks, but it returns null.
query RunInput {
shop {
metafield(
namespace: "discount-by-block-app-settings"
key: "discount-by-block-app"
) {
value
}
}
cart {
lines {
id
quantity
attribute(key: "_checkoutblocks") {
key
value
}
}
}
}
The query syntax looks correct, so the null return is most likely a timing issue rather than a GraphQL mistake.
Shopify discount functions execute early in the checkout pipeline — often before checkout UI extensions have had a chance to write anything to the cart lines. If the Checkout Blocks app sets the `_checkoutblocks` property through its checkout extension (which is the typical pattern for that app), that value simply won’t exist yet when your function’s input is evaluated.
A quick way to confirm this: swap `attribute(key: “_checkoutblocks”)` for `attributes { key value }` to see all attributes that are actually present at the time your function runs. If the list comes back empty or missing that key entirely, it’s a pipeline ordering problem, not a query issue.
If that’s the case, a few options worth exploring:
Check whether the Checkout Blocks app exposes its own discount function API or native integration. Since the original script relies on a property that Checkout Blocks itself manages, they may have a supported path for this specific use case that doesn’t require you to read that property externally.
If the property is being set on the cart *before* checkout (e.g. via the cart API or an add-to-cart event), make sure it’s being written as a line item attribute and not a cart-level attribute — those are different fields in the Functions input.
If you need the discount to be applied based on something that only exists during checkout UI interaction, a checkout UI extension applying the discount directly via `applyCartLinesChange` or using the Checkout Branding / validation extension might be a better architectural fit than a discount function.
The Shopify docs note that cart line attributes and line item properties are equivalent in concept, but that equivalence only holds when the properties were set before the function’s execution context. That’s the gap you’re likely hitting here.