Skip to content

Hook Reference

Dino Discover exposes a few dozen named hooks in 0.1.0 — a mix of filters (used to substitute behaviour) and actions (fired at observability points). This page covers the load-bearing ones grouped by purpose. For an exhaustive callsite-by-callsite enumeration the authoritative answer is always grep:

Terminal window
grep -rn 'apply_filters\|do_action' includes/ | grep dino_discover_

For the architectural picture of how these hooks fit into the systems map, see Architecture.

The four filters that replace engine implementations site-wide. Each expects an instance of the corresponding interface as the return value.

FilterReplacesDefault
dino_discover_question_engineQuestionEngineInterfaceRulesQuestionEngine
dino_discover_recommendation_engineRecommendationEngineInterfaceUpvoteRecommendationEngine
dino_discover_coverage_engineCoverageEngineInterfaceCoverageCalculator
dino_discover_statistics_engineStatisticsInterfacePointEstimateStatistics
add_filter( 'dino_discover_recommendation_engine', function( $default ) {
return new \MyAgency\EmbeddingRecommendationEngine();
} );

Each filter runs at container-bind time, so it’s called once per request lifecycle, not per call.

Filters that run on engine output. Cheaper than swapping the whole engine when you only want to tweak the result.

Fires every time the question engine returns a next-node decision. Lets you override the routing per call.

  • File: includes/Engine/RulesQuestionEngine.php:497
  • Args: (NextNodeDecision $decision, AnswerHistory $history, QuizContext $context)
  • Returns: the (possibly-modified) NextNodeDecision.

The last word on the recommendation. Re-rank, suppress, or inject items here.

  • File: includes/Engine/UpvoteRecommendationEngine.php:156
  • Args: (RecommendationSet $set, QuizContext $context, AnswerHistory $history)
  • Returns: the (possibly-modified) RecommendationSet.
add_filter( 'dino_discover_recommendation_results', function( $set ) {
// Drop any product tagged 'discontinued'.
$items = array_filter( $set->items(), function( $item ) {
return ! has_term( 'discontinued', 'product_tag', $item->product_id() );
} );
return $set->with_items( array_values( $items ) );
}, 10 );

Observability points fired at key moments. Subscribe to integrate with external systems.

Fires after a successful publish, after the snapshot row is written and dd_quizzes.published_snapshot_id is flipped.

  • File: includes/Snapshot/Snapshotter.php:341
  • Args: (int $quiz_id, int $snapshot_id)

Use it to invalidate caches, notify Slack, kick off a CDN purge.

Fires after a snapshot is restored to draft (the inverse of publish).

  • File: includes/Snapshot/Snapshotter.php:392
  • Args: (int $quiz_id, int $snapshot_id)

Fires server-side when a new session row is created (the start of a shopper’s run through a quiz).

  • File: includes/API/StorefrontController.php (create_session)
  • Args: (int $session_id, array $payload)

Fires once per answer_given event after the row lands in dd_events_scratch.

  • File: includes/API/StorefrontController.php (events ingest)
  • Args: (int $session_id, array $event_payload)

Fires once per quiz_completed event.

  • File: includes/API/StorefrontController.php (events ingest)
  • Args: (int $session_id, array $event_payload)

Fires once per quiz_abandoned event.

  • File: includes/API/StorefrontController.php (events ingest)
  • Args: (int $session_id, array $event_payload)

Fires once per recommendation_clicked event.

  • File: includes/API/StorefrontController.php (events ingest)
  • Args: (int $session_id, array $event_payload)

Fires after a lead row is inserted, before any integration push is queued.

  • File: includes/API/StorefrontController.php:641
  • Args: (int $lead_id, int $session_id, string $email)

Note: the email passed here is the plaintext email submitted by the shopper. The row in dd_leads stores both the plaintext email column (for CSV export and outbound integrations) and an HMAC-SHA256 email_hash column (for dedupe lookups).

Fires after the AttributionLinker attributes a completed WooCommerce order back to a quiz session within the attribution window.

  • File: includes/Engine/Analytics/AttributionLinker.php:239
  • Args: (int $order_id, array $payload) where $payload carries session_id, quiz_id, snapshot_id, variant_id, product_id, revenue_cents (all ints).

Fires every time the admin draft-preview tab loads. The default listener (DraftPreviewAuditLogger) writes an audit entry to the WP error log.

  • File: includes/Storefront/DraftPreviewPage.php:204
  • Args: (array $payload) — keys include result, user_id, ip, quiz_id, quiz_slug, timestamp, plus optional reason and route discriminator.

Fires when a {token} in a template can’t be resolved.

  • File: includes/Engine/TokenResolver.php:242
  • Args: (string $token, string $template)

dino_discover_question_engine_removed_answer_fallback

Section titled “dino_discover_question_engine_removed_answer_fallback”

Fires when the question engine encounters an answer that’s been removed from the snapshot since the session started — the snapshot-aware recovery path.

  • File: includes/Engine/RulesQuestionEngine.php:124
  • Args: (int $current_id, array $answer_ids)

Fires when a target tag/category expansion exceeds the per-target product cap.

  • File: includes/Engine/Cache/TargetExpansionCache.php:141
  • Args: (int $id, int $total, string $type)

Override the admin capability gate.

  • File: includes/Support/Cap.php:29
  • Default: 'manage_dino_discover'
  • Args: (string $capability)

The roles to grant the admin capability to at activation.

  • File: includes/Activator.php:247
  • Default: [ 'administrator', 'shop_manager' ]
  • Args: (array $roles)

Swap the implementation of CartAdderInterface used by the bulk-add endpoint and per-card add-to-cart.

  • File: includes/Plugin.php:437
  • Default: WooCartAdder

Register a custom question type. The filter is called by the QuestionType\Registry at boot.

  • File: includes/Engine/QuestionType/Registry.php:62
  • Args: (array $descriptors) — append your descriptor to the array and return it.

Register a custom Connect-tab integration.

  • File: includes/Integrations/Registry.php

Site-wide Klaviyo API key for environments that source secrets from outside wp_options.

  • File: includes/Integrations/Klaviyo/KlaviyoPusher.php:619

Same pattern for Mailchimp.

  • File: includes/Integrations/Mailchimp/MailchimpPusher.php:629

Tune the per-route rate limit. Default is 60 requests/minute.

  • File: includes/API/RateLimiter.php:79

Override how the client IP is derived. Useful behind a CDN that sets CF-Connecting-IP, X-Forwarded-For, etc.

  • File: includes/API/RateLimiter.php:158

Override the attribution window (default 30 days; clamped to 0–365).

  • File: includes/Engine/Analytics/AttributionLinker.php:184

Customise the list of metrics treated as rate-style for confidence interval computation.

  • File: includes/Engine/Statistics/PointEstimateStatistics.php:192

Override the resolved template path before the loader requires it. The default loader looks up theme overrides, falls back to plugin templates; this filter is the last hop.

  • File: includes/Storefront/TemplateLoader.php (constant FILTER_TEMPLATE_PATH)

Both actions fire from templates/quiz-results.php around the results panel render. Use them to inject markup before or after the panel without overriding the template.

Fires immediately before the results panel renders.

  • File: templates/quiz-results.php:53
  • Args: (array $args)

Fires immediately after the results panel renders.

  • File: templates/quiz-results.php:131
  • Args: (array $args)

For agencies that want to host their own docs or customise the in-product help links:

FilterOverrides
dino_discover_docs_base_urlThe docs base URL for in-app links.
dino_discover_docs_urlThe Onboarding tips link.
dino_discover_methodology_urlThe analytics-methodology link.
FilterOverrides
dino_discover_licence_urlThe licence server URL.
dino_discover_licence_serverThe licence server implementation (LicenceServerInterface).

What’s documented in v1 but not yet emitted

Section titled “What’s documented in v1 but not yet emitted”
  • The per-quiz _for_quiz variants of the engine filters (e.g. dino_discover_recommendation_engine_for_quiz) are named in the design doc, but no callsite exists in includes/ today; only the global single-arg filters fire.
  • dino_discover_question_seen and dino_discover_recommendation_shown are documented as scratch-only telemetry events (per the LIFECYCLE_ACTIONS docblock in StorefrontController) — they are valid event_type values but intentionally do not surface as actions in 0.1.0.

Note that dino_discover_quiz_started, dino_discover_question_answered, dino_discover_quiz_completed, dino_discover_quiz_abandoned, dino_discover_recommendation_clicked, dino_discover_lead_captured, dino_discover_order_attributed, dino_discover_before_results, and dino_discover_after_results do fire in 0.1.0 — see the sections above for callsites.

The authoritative answer to “is hook X emitted” is grep:

Terminal window
grep -rn 'dino_discover_X' includes/

The result will show every apply_filters and do_action call site for the hook in the current build.