Recommendation Rules
Recommendation in Dino Discover is deliberately simple: each answer carries upvote weights against products or product variants; the engine sums every upvote a shopper accumulates and ranks the result.
That model is small enough to debug in your head, which is the point. When you need something fancier, the engine is a single PHP interface you can replace — but the default works well for catalogues with hundreds of products and a four-or-five-question quiz.
The Upvotes panel
Section titled “The Upvotes panel”Every answer in the Builder has an Upvotes panel on the right edge. It contains a small list of upvote rows:
- Target — a product or a product variant.
- Weight — a positive integer (usually 1).
Add a row, search for the product or variant, set the weight, save.
[SCREENSHOT: The Upvotes panel on a single-select answer with three product targets, each weighted 1.]
The recommendation engine, on a session-completion recommend call,
sums these per product across every answer the shopper picked. The
products are ranked by total upvotes, ties broken by stable product
order.
Worked example — three questions, three products
Section titled “Worked example — three questions, three products”Suppose your store sells three coffees: Bright, Bold, and Balanced. You build a three-question quiz:
| Question | Answer A | Answer B | Answer C |
|---|---|---|---|
| Roast preference | Light: +1 Bright | Medium: +1 Balanced | Dark: +1 Bold |
| Brewing method | Filter: +1 Bright, +1 Balanced | Espresso: +1 Bold, +1 Balanced | French press: +1 Bold |
| Strength | Easy: +1 Bright | Standard: +1 Balanced | Strong: +1 Bold |
A shopper picks Medium / Espresso / Standard. Their upvote totals become:
- Bright = 0
- Balanced = 1 + 1 + 1 = 3
- Bold = 0 + 1 + 0 = 1
The recommendation engine returns Balanced first, then Bold, then Bright.
That’s the entire model.
Weights
Section titled “Weights”Weight 1 is almost always the right value. You can set higher weights
on answers that strongly indicate a product, but the model is
addition-based — bigger weights compound across answers, so the maths
gets harder to reason about quickly. Two patterns that tend to work:
- Default to 1. Treat each upvote as one vote. The total ordering comes from how many votes a product accumulates, not from a few loud answers.
- Use 2 or 3 sparingly, to encode “this answer all but guarantees this product.” For example, an allergy question that says “fragrance-free only” should weight unscented products higher because every other product is now disqualified by reality.
Eligibility filters
Section titled “Eligibility filters”The default engine doesn’t just rank — it also filters. Before scoring, it drops products that:
- Are not purchasable in WooCommerce (out of stock, draft post, trashed).
- Are not visible on the storefront (catalogue visibility set to Hidden).
- Don’t match any variation gates the merchant configured (e.g. only variants in stock that match the answer’s variant target).
So if a product is upvoted by a shopper’s answers but is out of stock, it disappears from the result list — the rest of the ranking shifts up.
The final-result filter
Section titled “The final-result filter”After scoring and filtering, the engine returns a RecommendationSet
through the filter dino_discover_recommendation_results. Subscribers
can re-rank, suppress, or inject items at the last step. This is the
canonical extension point for storefront-side business rules — “always
promote products from the seasonal collection” or “never return more
than two products from the same category”.
See Hook Reference for the signature.
Tag-based shortcuts vs per-product upvotes
Section titled “Tag-based shortcuts vs per-product upvotes”You can upvote a product directly, or upvote a product variant. There is no first-class “upvote a tag” shortcut in the Beta — instead, the recommended workflow for tagged catalogues is:
- Tag your products.
- In the Builder, search by tag and select the products to upvote.
This keeps the upvote model concrete (each upvote points at a specific product) without forcing you to maintain a separate tagging convention.
For a worked filter that adds tag-style upvotes, see the
dino_discover_recommendation_results example in
Hook Reference.
Swapping the recommendation engine
Section titled “Swapping the recommendation engine”For agencies and developers who want a different ranking model — an embedding-based ranker, an LLM ranker, a hybrid — the engine sits behind a single PHP interface:
RecommendationEngineInterface::recommend( QuizContext $context, AnswerHistory $history): RecommendationSet;Implement the interface, return it from a class your container can
build, and use the dino_discover_recommendation_engine filter to
substitute it.
The storefront calls POST /storefront/sessions/{sid}/recommend. That
endpoint dispatches into whatever the filter resolves. Neither the
storefront bundle nor the REST contract changes when you swap engines.
See Engine Interfaces for the full contracts.
What’s next
Section titled “What’s next”- Question Builder — the upstream side of the same picture.
- Catalogue Coverage — proves that your rules can actually reach every product.
- Preview & Test — the preview tab to sanity-check what your rules return.
- Engine Interfaces — the developer contract for swapping the engine.