{"id":346192,"date":"2026-09-15T16:43:49","date_gmt":"2026-09-15T16:43:49","guid":{"rendered":"https:\/\/wordpress.org\/plugins\/seekmodo-search\/"},"modified":"2026-09-15T21:42:35","modified_gmt":"2026-09-15T21:42:35","slug":"seekmodo","status":"publish","type":"plugin","link":"https:\/\/nl-be.wordpress.org\/plugins\/seekmodo\/","author":7941541,"comment_status":"closed","ping_status":"closed","template":"","meta":{"version":"0.11.62","stable_tag":"0.11.62","tested":"7.1.1","requires":"6.2","requires_php":"8.0","requires_plugins":null,"header_name":"Seekmodo Search","header_author":"Numinix","header_description":"AI-powered search for WordPress (and WooCommerce product search, when active). Routes site search through the Seekmodo platform at mcp.seekmodo.com. Two activatable verticals: `content` (WP core) and `commerce` (WooCommerce). Optional drop-in typeahead dropdown UI (v0.4.0+). Native LIKE \/ Woo query stays permanently armed as a graceful fallback. Requires a Seekmodo account; every plan ships with a 14-day free trial.","assets_banners_color":"effafe","last_updated":"2026-09-15 21:42:35","external_support_url":"","external_repository_url":"","donate_link":"","header_plugin_uri":"https:\/\/seekmodo.com\/plugins\/wordpress","header_author_uri":"https:\/\/numinix.com","rating":5,"author_block_rating":0,"active_installs":0,"downloads":90,"num_ratings":2,"support_threads":0,"support_threads_resolved":0,"author_block_count":0,"sections":["description","installation","faq","changelog"],"tags":{"0.11.59":{"tag":"0.11.59","author":"numinix","date":"2026-09-15 16:43:36","revision":3697394},"0.11.60":{"tag":"0.11.60","author":"numinix","date":"2026-09-15 17:59:28","revision":3697505},"0.11.61":{"tag":"0.11.61","author":"numinix","date":"2026-09-15 18:29:27","revision":3697552},"0.11.62":{"tag":"0.11.62","author":"numinix","date":"2026-09-15 21:42:35","revision":3697724}},"upgrade_notice":{"0.11.60":"<ul>\n<li>New: search-suggestions dropdown is enabled by default (opt out in Settings or via filters).<\/li>\n<li>Fix: bulk index pushes no longer abort at the 2s search timeout \u2014 full reindexes report real counts.<\/li>\n<\/ul>","0.11.59":"<ul>\n<li>Security: All $_SERVER inputs are properly sanitized through ServerInput helper class per WordPress.org Plugin Review requirements.<\/li>\n<li>wordpress.org: GET \/images is read-only (no public mark_dirty post meta writes).<\/li>\n<\/ul>","0.11.58":"<ul>\n<li>wordpress.org: GET \/images is read-only (no public mark_dirty post meta writes).<\/li>\n<\/ul>","0.11.57":"<ul>\n<li>Commerce typeahead: when cloud\/Enhanced Native returns no rows, fall back to WooCommerce products (not blog posts).<\/li>\n<\/ul>","0.11.56":"<ul>\n<li>wordpress.org: uninstall.php no longer reads DOCUMENT_ROOT; runtime $_SERVER already via ServerInput since 0.11.52.<\/li>\n<\/ul>","0.11.54":"<ul>\n<li>Heal broken suggest thumbs: durable ProductImage URLs, \/images hydrate, commerce index cron.<\/li>\n<\/ul>","0.11.53":"<ul>\n<li>Recommendations hover stacking: overflow-y visible + raised z-index so theme card hovers are not clipped.<\/li>\n<\/ul>","0.11.52":"<ul>\n<li>wordpress.org review: sanitize\/validate $_SERVER (and related) inputs early via ServerInput helper.<\/li>\n<\/ul>","0.11.51":"<ul>\n<li>wordpress.org review: Tested up to in readme.txt only; ship Suggest\/Ask TS source; remove static ABSPATH .well-known writes; clear stale over_quota sticky mid-trial.<\/li>\n<\/ul>","0.11.50":"<ul>\n<li>wordpress.org review: drop source maps with CDN URLs from the package, JWKS via wp_remote_get only, nonce-gate cloud-suggest-denied, tighter inline-script \/ placeholder escaping.<\/li>\n<\/ul>","0.11.49":"<ul>\n<li>Plugin Check i18n: literal __() strings in SuggestLabels (no variable text\/domain).<\/li>\n<\/ul>","0.11.48":"<ul>\n<li>Fix: WooCommerce add-to-cart telemetry caps \u2014 15-minute product dedupe, 30 ATC\/session\/day, 120 ATC\/IP\/hour \u2014 stops scraper floods from inflating fleet-health funnels.<\/li>\n<\/ul>","0.11.41":"<ul>\n<li>Fix: Suggest paints thumbnail_url for content posts; hides price_range on content vertical.<\/li>\n<\/ul>","0.11.38":"<ul>\n<li>Fix: Multilingual Suggest dropdown no longer empties from mixed-locale \/v1\/suggest rows (serp filter_by lang + over-fetch + typeahead merge).<\/li>\n<\/ul>","0.11.37":"<ul>\n<li>Fix: Polylang language-switch SERP no longer empties when gateway cache ignores lang (localize IDs + per-lang fetch buckets).<\/li>\n<\/ul>","0.11.36":"<p>Suggest View all SERP links keep the active Polylang\/WPML language path prefix.<\/p>","0.11.35":"<p>Suggest chrome i18n: locale label packs + web-components 0.4.5 labels attribute support.<\/p>","0.11.34":"<p>WordPress.org review follow-ups: enqueue inline assets, sanitize shopper inputs, uploads subdirectory for shadow logs, no default site-root writes.<\/p>","0.11.22":"<p>Fixes Enhanced Native SERP order when themes force chronological sorting over relevance.<\/p>","0.11.21":"<p>Stronger Enhanced Native title-phrase ranking so exact titles beat long body matches.<\/p>","0.11.20":"<p>Improves Enhanced Native ranking: exact whole-word matches and adjacent title phrases outrank prefix\/partial noise (Lead vs Leaders).<\/p>","0.11.18":"<p>Fixes commerce-only storefronts: unscoped <code>\/?s=<\/code> searches now claim the commerce swap so search_event_id is stamped for click tracking.<\/p>","0.11.17":"<p>Fixes content SERP click tracking: search_event_id is stamped for <code>\/?s=<\/code> searches so clicks count again (POCO Marine fleet health).<\/p>","0.11.16":"<p>Fixes WooCommerce add-to-cart and purchase tracking: conversion hooks always register, flush with clicks instead of starving, and no longer drop decimal quantities.<\/p>","0.11.10":"<ul>\n<li>Stamp search_event_id on add_to_cart \/ purchase for LTR last-touch linkage.<\/li>\n<\/ul>","0.11.9":"<ul>\n<li>Shopper-context parity for typeahead + conversion events (session_id \/ ua \/ referer).<\/li>\n<\/ul>","0.11.8":"<p>Documents HMAC auth_fail \/ signature_mismatch soft-degrade: Gateway\\Client returns null so native WP\/Woo search keeps serving during secret drift.<\/p>","0.11.7":"<p>WordPress.org compliance: text domain seekmodo, no custom updater, branding off by default, privacy IP\/UA disclosure.<\/p>","0.11.6":"<p>WordPress.org submission readiness: vendored web-components bundle\n(no default CDN), complete uninstall cleanup, Tested up to 7.0,\nprivacy-policy guide text, Health widget restricted to admins.<\/p>","0.6.0":"<p>SM-606 Universal Suggest Widget. When the &quot;Enable connector typeahead\nUI&quot; master toggle is on, v0.6.0 swaps the legacy flat-row vanilla-JS\ndropdown for the new `` web component, which renders\nthe rich \/v1\/suggest envelope (recent + trending + keywords +\nproducts + categories + did-you-mean + &quot;View all N results&quot; CTA) and\nshares its UX with the BigCommerce \/ Zen Cart \/ AKS connectors.\nExisting sites can opt back into the legacy dropdown for one major-\nversion cycle via Settings \u2192 Seekmodo \u2192 &quot;Use legacy flat-row typeahead&quot;\nor the new <code>seekmodo_wp_suggest_legacy<\/code> option. Bundle adds a single\n~7 KB gzip JS asset under <code>assets\/suggest\/<\/code>. Adds a public\n    POST \/wp-json\/seekmodo\/v1\/browser-token route so long-running tabs\ncan refresh the gateway-direct token without a page reload.<\/p>","0.5.3":"<p>Two follow-ups from PM-303. Operator UX: <code>wp seekmodo index --full<\/code> now\ncovers BOTH verticals (content + commerce) by default and accepts a\nnew <code>--vertical=content|commerce|all<\/code> flag. Pre-0.5.3 it only ran the\ncontent indexer, forcing commerce-only operators to drop into\n    wp eval &#039;\\Numinix\\SeekmodoWordPress\\Commerce\\Indexer::reindexFull();&#039;.\nSafety: a stricter write-side host-lock gate (<code>DomainLock::canIndex()<\/code>)\nfails closed by default on non-prod hosts (<code>dev.*<\/code>, <code>staging.*<\/code>,\n    stage.*, <code>test.*<\/code>, <code>qa.*<\/code>, <code>preview.*<\/code>, <code>beta.*<\/code>, <code>preprod.*<\/code>,\n    sandbox.*) when the storefront-host lock is self-referential \u2014 the\nexact regression that put <code>dev.pocomarine.com<\/code> URLs into POCO&#039;s\nproduction Typesense index after the prod cutover. Read paths\n(typeahead, search swap) are unchanged. Operators with a legitimate\nnon-prod indexing setup (e.g. paired to a separate <code>*-dev<\/code> tenant)\nopt back in via:\n    add_filter(&#039;seekmodo_allow_nonprod_indexing&#039;, &#039;__return_true&#039;);\nin a mu-plugin. Mandatory upgrade for any tenant with a paired dev \/\nstaging WordPress install.<\/p>","0.5.2":"<p>Hotfix for the gateway-direct typeahead introduced in v0.5.0. The\nstorefront browser script was rendering an empty &quot;No results&quot; state\non commerce-vertical sites because the canonical commerce row from\n    \/v1\/typeahead (per <code>CONNECTOR_TYPEAHEAD_SPEC.md<\/code>) ships rows as\n    name \/ <code>url<\/code> \/ <code>image<\/code> \/ <code>in_stock<\/code>, while the renderer only knew\nthe legacy WP REST proxy shape (<code>title<\/code> \/ <code>permalink<\/code> \/ <code>image_url<\/code> \/\n    stock_status). The gateway-direct fast path therefore looked up\n    r.title on every row, found <code>undefined<\/code>, and skipped them all \u2014\nthe user saw &quot;No results&quot; for every keystroke even though the wire\nreturned 8 rows. Mandatory upgrade for any commerce-vertical install\nrunning v0.5.0 or v0.5.1.<\/p>","0.5.1":"<p>Self-healing cache flushes. The connector now detects on-disk version\nbumps on the very first request after any deploy (rsync, wp-cli, or\nWordPress&#039;s native upgrader) and fans out cache invalidations to WP\nRocket, LiteSpeed, W3 Total Cache, WP Super Cache, WP-Optimize,\nHummingbird, Cache Enabler, Pantheon, Kinsta, Cloudflare WP, plus\nOPCache and the WordPress object cache. Fixes the &quot;I deployed v0.5.0\nbut the site still loads v0.4.0&quot; class of regression on hosts with\nWP Rocket page + minify caching configured for 1 year. Mandatory\nupgrade if you have any page-cache plugin installed.<\/p>","0.5.0":"<p>Performance: typeahead now talks directly to the Seekmodo gateway from\nthe storefront browser, skipping the WordPress REST hop. Drops the\nper-keystroke latency from ~2 seconds (WordPress full-stack boot on\neach request) to ~80\u2013150 ms on heavy WooCommerce \/ Wordfence sites.\nAlso adds a 32-entry client-side LRU cache so backspace + retype\non a previously-fetched prefix renders instantly without a network\nround trip. Falls back to the WordPress REST endpoint automatically\non any gateway-direct failure (token expiry, gateway 5xx, breaker\nopen) \u2014 your search bar never breaks.<\/p>","0.4.0":"<p>New feature: drop-in typeahead dropdown UI. The connector now ships a\nvanilla-JS search-suggestions box that auto-binds to your theme&#039;s\n     \/ `` and renders gateway-\npowered results as you type, with vertical-aware row shapes (blog\nposts vs WooCommerce product cards). Default-OFF \u2014 flip it on from\nSettings \u2192 Seekmodo Search \u2192 Typeahead dropdown when you&#039;re ready,\nor leave it off if your theme already provides its own typeahead.\nOptional &quot;Powered by Seekmodo&quot; footer is opt-in (white-label by\ndefault).<\/p>","0.3.4":"<p>New feature: editorial post-type ranking priority. Search results\ncan now be bucket-sorted so that pages outrank blog posts (or any\nother order you specify) while textual relevance is preserved within\neach tier. No-op upgrade for sites that don&#039;t set the new option \u2014\ngateway-relevance order keeps flowing through untouched.<\/p>","0.3.3":"<p>Critical fix: the v0.3.2 pair-callback REST route was registered\nbehind <code>is_admin()<\/code> so it never appeared on the server-to-server\ncallback POST from seekmodo.com. Pairing was still impossible.\nv0.3.3 lifts the registration out of the admin-only block. Mandatory\nupgrade for anyone who hasn&#039;t paired yet.<\/p>","0.3.2":"<p>Critical fix: the &quot;Connect to Seekmodo&quot; pairing flow has been rebuilt\non the canonical install_token + signed-JWT protocol. v0.3.0 \/ v0.3.1\nsent legacy <code>nonce<\/code> \/ <code>return_to<\/code> query params that seekmodo.com\nrejects with &quot;This link is incomplete&quot; \u2014 pairing through the browser\nwas impossible. Superseded by v0.3.3 \u2014 install that one instead.<\/p>","0.3.1":"<p>Bug fix: the &quot;Connect to Seekmodo&quot; button silently redirected to the\nWP admin homepage instead of seekmodo.com (wp_safe_redirect() rejecting\nthe off-site host). Pairing was impossible without manual wp-cli\nfallback. Superseded by v0.3.2 \u2014 install that one instead.<\/p>","0.3.0":"<p>Commerce vertical realigned to the gateway&#039;s Typesense schema \u2014\nWooCommerce indexing now actually works (was 400&#039;ing every upsert).\nSchema-version auto-promotes a one-time full reindex on the\ncommerce side; content vertical is undisturbed. Ships the\nself-service &quot;Promote dev to production&quot; admin card so merchants\ncan flip their canonical from a dev site to production without an\noperator round-trip. Worth picking up before standing up your\nWooCommerce dev site.<\/p>","0.1.4":"<p>Adds WordPress.org Plugin Directory listing support: the <code>Update URI<\/code>\nheader now routes update checks to seekmodo.com so we can ship\nhot-fixes faster than the w.org SVN sync cadence. No upgrade work\nrequired; just update.<\/p>","0.1.3":"<p>Per-tenant &quot;Powered by Seekmodo&quot; branding toggle. Off by default;\nopt-in for partner sites.<\/p>","0.1.0":"<p>Initial public release.<\/p>"},"ratings":{"1":0,"2":0,"3":0,"4":0,"5":2},"assets_icons":{"icon-128x128.png":{"filename":"icon-128x128.png","revision":3697393,"resolution":"128x128","location":"assets","locale":"","width":128,"height":128},"icon-256x256.png":{"filename":"icon-256x256.png","revision":3697393,"resolution":"256x256","location":"assets","locale":"","width":256,"height":256}},"assets_banners":{"banner-1544x500.png":{"filename":"banner-1544x500.png","revision":3697393,"resolution":"1544x500","location":"assets","locale":"","width":1544,"height":500},"banner-772x250.png":{"filename":"banner-772x250.png","revision":3697393,"resolution":"772x250","location":"assets","locale":"","width":772,"height":250}},"assets_blueprints":{},"all_blocks":{"seekmodo\/chat":{"$schema":"https:\/\/schemas.wp.org\/trunk\/block.json","apiVersion":3,"name":"seekmodo\/chat","version":"0.1.0","title":"Seekmodo Chat","category":"widgets","icon":"format-chat","description":"Conversational AI shopping assistant. Supports policy\/shipping RAG when configured.","textdomain":"seekmodo-wordpress","supports":{"html":false,"align":["wide","full"]},"attributes":{"placeholder":{"type":"string","default":"Ask anything\u2026"},"intro":{"type":"string","default":""},"maxTurns":{"type":"number","default":12},"autoCitations":{"type":"boolean","default":false}},"editorScript":"seekmodo-block-chat-editor"},"seekmodo\/ask":{"$schema":"https:\/\/schemas.wp.org\/trunk\/block.json","apiVersion":3,"name":"seekmodo\/ask","version":"0.1.0","title":"Seekmodo Ask AI","category":"widgets","icon":"format-status","description":"Single-turn Ask AI Q&A over your indexed catalog and policies.","textdomain":"seekmodo-wordpress","supports":{"html":false,"align":["wide","full"]},"attributes":{"placeholder":{"type":"string","default":"Ask about products or policies\u2026"},"buttonLabel":{"type":"string","default":"Ask AI"}},"editorScript":"seekmodo-block-ask-editor"},"seekmodo\/search":{"$schema":"https:\/\/schemas.wp.org\/trunk\/block.json","apiVersion":3,"name":"seekmodo\/search","version":"0.1.0","title":"Seekmodo Search Box","category":"widgets","icon":"search","description":"AI-powered search input that emits seekmodo:search events. Pairs with <seekmodo-results> on the same page or links to a search-results URL.","textdomain":"seekmodo-wordpress","supports":{"html":false,"align":["wide","full"]},"attributes":{"placeholder":{"type":"string","default":"Search products"},"value":{"type":"string","default":""},"withTypeahead":{"type":"boolean","default":false},"submitOnEnter":{"type":"boolean","default":true}},"editorScript":"seekmodo-block-search-editor"},"seekmodo\/recommend":{"$schema":"https:\/\/schemas.wp.org\/trunk\/block.json","apiVersion":3,"name":"seekmodo\/recommend","version":"0.1.0","title":"Seekmodo Recommendations","category":"widgets","icon":"thumbs-up","description":"Renders a horizontal strip of related\/popular\/similar products. Backed by the Seekmodo recommendation algorithms.","textdomain":"seekmodo-wordpress","supports":{"html":false,"align":["wide","full"]},"attributes":{"algorithm":{"type":"string","default":"related"},"placement":{"type":"string","default":"pdp"},"sourceDocId":{"type":"string","default":""},"limit":{"type":"number","default":6}},"editorScript":"seekmodo-block-recommend-editor"},"seekmodo\/quiz":{"$schema":"https:\/\/schemas.wp.org\/trunk\/block.json","apiVersion":3,"name":"seekmodo\/quiz","version":"0.1.0","title":"Seekmodo Quiz","category":"widgets","icon":"list-view","description":"AI shopping quiz \/ product finder. Reads a quiz definition and surfaces a personalized result set.","textdomain":"seekmodo-wordpress","supports":{"html":false,"align":["wide","full"]},"attributes":{"quizId":{"type":"string","default":""},"quizSlug":{"type":"string","default":""},"definitionSrc":{"type":"string","default":""},"inlineDefinition":{"type":"string","default":""},"autoStart":{"type":"boolean","default":false}},"editorScript":"seekmodo-block-quiz-editor"}},"tagged_versions":["0.11.59","0.11.60","0.11.61","0.11.62"],"block_files":[],"assets_screenshots":{"screenshot-1.png":{"filename":"screenshot-1.png","revision":3697393,"resolution":"1","location":"assets","locale":"","width":1280,"height":800},"screenshot-2.png":{"filename":"screenshot-2.png","revision":3697393,"resolution":"2","location":"assets","locale":"","width":1280,"height":800},"screenshot-3.png":{"filename":"screenshot-3.png","revision":3697393,"resolution":"3","location":"assets","locale":"","width":1920,"height":1080}},"screenshots":{"1":"<strong>Settings \u2192 Seekmodo Search.<\/strong> Pair status, storefront-host lock\nindicator, Re-pair control, and Health (mode + circuit breaker).","2":"<strong>Settings \u2192 Health + indexable types.<\/strong> Mode \/ breaker readouts,\nindexable post-type selector, and search ranking priority.","3":"<strong>Storefront suggest widget.<\/strong> Gateway-ranked products, categories,\nand keyword suggestions for a live storefront search."}},"plugin_section":[262246],"plugin_tags":[220145,3226,944,3550,286],"plugin_category":[45],"plugin_contributors":[280917],"plugin_business_model":[],"class_list":["post-346192","plugin","type-plugin","status-publish","hentry","plugin_section-dashboard-widgets","plugin_tags-ai-search","plugin_tags-autocomplete","plugin_tags-search","plugin_tags-typeahead","plugin_tags-woocommerce","plugin_category-ecommerce","plugin_contributors-numinix","plugin_committers-numinix"],"banners":{"banner":"https:\/\/ps.w.org\/seekmodo\/assets\/banner-772x250.png?rev=3697393","banner_2x":"https:\/\/ps.w.org\/seekmodo\/assets\/banner-1544x500.png?rev=3697393","banner_rtl":false,"banner_2x_rtl":false},"icons":{"svg":false,"icon":"https:\/\/ps.w.org\/seekmodo\/assets\/icon-128x128.png?rev=3697393","icon_2x":"https:\/\/ps.w.org\/seekmodo\/assets\/icon-256x256.png?rev=3697393","generated":false},"screenshots":[{"src":"https:\/\/ps.w.org\/seekmodo\/assets\/screenshot-1.png?rev=3697393","caption":"<strong>Settings \u2192 Seekmodo Search.<\/strong> Pair status, storefront-host lock\nindicator, Re-pair control, and Health (mode + circuit breaker)."},{"src":"https:\/\/ps.w.org\/seekmodo\/assets\/screenshot-2.png?rev=3697393","caption":"<strong>Settings \u2192 Health + indexable types.<\/strong> Mode \/ breaker readouts,\nindexable post-type selector, and search ranking priority."},{"src":"https:\/\/ps.w.org\/seekmodo\/assets\/screenshot-3.png?rev=3697393","caption":"<strong>Storefront suggest widget.<\/strong> Gateway-ranked products, categories,\nand keyword suggestions for a live storefront search."}],"raw_content":"<!--section=description-->\n<p><strong>Seekmodo Search<\/strong> replaces the built-in WordPress site search (and the\nWooCommerce product search, when WooCommerce is active) with an AI-powered\nsearch experience served by the Seekmodo platform at mcp.seekmodo.com.\nOne plugin, two activatable verticals:<\/p>\n\n<ul>\n<li><strong>Content vertical<\/strong> \u2014 WordPress core search via <code>pre_get_posts<\/code> +\n  posts_pre_query. Auto-detects public Custom Post Types so blog posts,\npages, docs, and your custom CPTs all participate in the same ranked\nresult set.<\/li>\n<li><strong>Commerce vertical<\/strong> \u2014 WooCommerce product search via\n  woocommerce_product_query + <code>posts_search<\/code>. Indexes products plus\nvariations, stock state, price, SKU, and attributes. Auto-on when\nWooCommerce is detected; dormant otherwise.<\/li>\n<\/ul>\n\n<p>What you get:<\/p>\n\n<ul>\n<li>AI search out of the box \u2014 vector recall + commerce-aware reranking\non top of Typesense, with no relevance tuning required to start.<\/li>\n<li>Typo tolerance, partial-word matching, and prefix-matched typeahead\nvia a single REST endpoint your theme can hit from any autocomplete\nwidget.<\/li>\n<li>Click-through telemetry feeds a self-tuning learn-to-rank pipeline.\nRelevance gets better as your shoppers interact.<\/li>\n<li>Always-on safety net \u2014 every gateway-talking entry point falls\nthrough to native <code>WP_Query<\/code> (or <code>WC_Query<\/code> for products) inside the\nsame request when the platform is unreachable. Visitors never see an\nempty results page. A per-tenant circuit breaker prevents repeated\ntimeouts from compounding.<\/li>\n<li>Multi-environment safe \u2014 Seekmodo locks each tenant to a canonical\nstorefront host. Staging \/ dev clones are auto-detected and return\nno-op from every gateway entry, so your production index is never\npolluted by a non-production deploy.<\/li>\n<li>Settings tunable remotely \u2014 flip search mode, adjust ranking knobs,\nand toggle the \"Powered by Seekmodo\" badge from\n<a href=\"https:\/\/admin.seekmodo.com\">https:\/\/admin.seekmodo.com<\/a>; the connector picks the change up on\nthe next 5-min cadence.<\/li>\n<\/ul>\n\n<p><strong>External service dependency.<\/strong> Seekmodo Search is the WordPress\nconnector for the Seekmodo AI search platform. The platform is a\nhosted service operated by Numinix Technology Inc. at\n<a href=\"https:\/\/mcp.seekmodo.com\">https:\/\/mcp.seekmodo.com<\/a> and <a href=\"https:\/\/admin.seekmodo.com\">https:\/\/admin.seekmodo.com<\/a>. The\nplugin connects your site to a Seekmodo tenant via an HMAC-signed\npairing flow; once paired, the plugin sends indexable post \/ product\ndata to mcp.seekmodo.com and queries it for search results, typeahead\nsuggestions, and click telemetry.<\/p>\n\n<p><strong>Free trial.<\/strong> Every Seekmodo plan ships with a 14-day free trial at\n$0 \u2014 full features, unlimited searches, no card required upfront.\nCancel before day 14 and you pay nothing. After the trial, plans\nstart at $29\/month. Pricing details, including how the plan auto-sizes\nto your real traffic during the trial: <a href=\"https:\/\/seekmodo.com\/pricing\">https:\/\/seekmodo.com\/pricing<\/a>.<\/p>\n\n<p><strong>What happens if you stop paying.<\/strong> The plugin does not break your\nsite. If the gateway is unreachable, your subscription lapses, or\nyou simply uninstall the plugin, every search entry point falls back\nto native WordPress \/ WooCommerce search inside the same request. No\nwhite screens, no fatal errors, no broken search box.<\/p>\n\n<p><strong>Privacy + data handling.<\/strong>\n<a href=\"https:\/\/seekmodo.com\/legal\/privacy\">https:\/\/seekmodo.com\/legal\/privacy<\/a> lays out the full picture, but\nin short: searchable post \/ product content you choose to index is\nsent to mcp.seekmodo.com; visitor search queries and clicks are sent\nto mcp.seekmodo.com as telemetry; no personal data about your\nvisitors leaves your site unless you opt in to additional\nanalytics integrations from the Seekmodo admin. The plugin\nself-checks for stale indexes, configuration drift, and update\navailability \u2014 all such phone-home requests are vanilla HTTPS GETs\nthat carry no tenant ID and no site-identifying data; they're\nstatic-cacheable from our perspective.<\/p>\n\n<!--section=installation-->\n<p>Either:<\/p>\n\n<ol>\n<li>In WordPress admin, go to <strong>Plugins \u2192 Add New<\/strong> and search for\n\"Seekmodo\".<\/li>\n<li>Click <strong>Install Now<\/strong> on \"Seekmodo Search\", then <strong>Activate<\/strong>.<\/li>\n<\/ol>\n\n<p>Or upload manually:<\/p>\n\n<ol>\n<li>Download the latest zip from\n<a href=\"https:\/\/seekmodo.com\/plugins\/wordpress\">https:\/\/seekmodo.com\/plugins\/wordpress<\/a>.<\/li>\n<li>Upload via <strong>Plugins \u2192 Add New \u2192 Upload Plugin<\/strong> \u2192 choose the\nzip \u2192 <strong>Install Now<\/strong> \u2192 <strong>Activate<\/strong>.<\/li>\n<\/ol>\n\n<p>Then in either case:<\/p>\n\n<ol>\n<li>Go to <strong>Settings \u2192 Seekmodo Search \u2192 Connect to Seekmodo<\/strong>.<\/li>\n<li>Click <strong>Start free trial \/ sign in<\/strong> and approve the pairing on\nseekmodo.com.<\/li>\n<li>(Optional) Run <code>wp seekmodo index --full<\/code> to seed your tenant\nimmediately. (The plugin will otherwise reindex incrementally on\nits own.)<\/li>\n<li>Flip search mode from <code>shadow<\/code> to <code>active<\/code> in the connector\nsettings once you've spot-checked a few searches.<\/li>\n<\/ol>\n\n<p>Headless \/ CI install:<\/p>\n\n<pre><code>wp plugin install seekmodo --activate\nwp seekmodo connect --tenant=&lt;tenant_id&gt; --secret=&lt;shared_secret&gt;\nwp seekmodo index --full\nwp option update seekmodo_wp_mode shadow\n<\/code><\/pre>\n\n<!--section=faq-->\n<dl>\n<dt id=\"do%20i%20need%20a%20seekmodo%20account%3F\"><h3>Do I need a Seekmodo account?<\/h3><\/dt>\n<dd><p>Yes. Seekmodo Search is the WordPress connector for the Seekmodo\nhosted AI search platform; the plugin itself is free and GPLv2, but\nit needs a paired Seekmodo tenant to do its job. Every plan ships\nwith a 14-day free trial at $0 with full features and unlimited\nsearches. After the trial, plans start at $29\/month. Pricing details:\n<a href=\"https:\/\/seekmodo.com\/pricing\">https:\/\/seekmodo.com\/pricing<\/a>.<\/p><\/dd>\n<dt id=\"do%20i%20need%20woocommerce%3F\"><h3>Do I need WooCommerce?<\/h3><\/dt>\n<dd><p>No. The <strong>content vertical<\/strong> works on any WordPress site (posts,\npages, public custom post types). The <strong>commerce vertical<\/strong> activates\nautomatically when WooCommerce is detected, and idles otherwise.<\/p><\/dd>\n<dt id=\"what%20happens%20if%20the%20gateway%20is%20down%3F\"><h3>What happens if the gateway is down?<\/h3><\/dt>\n<dd><p>Every gateway-talking entry point falls through to native <code>WP_Query<\/code>\n(or <code>WC_Query<\/code> for products) inside the same request. Visitors never\nsee an empty results page. A per-tenant circuit breaker prevents\nrepeated timeouts from compounding, and Seekmodo health metrics\nauto-demote the connector back to native search if our gateway is\nunhealthy.<\/p><\/dd>\n<dt id=\"what%20happens%20if%20i%20stop%20paying%20%2F%20cancel%20my%20subscription%3F\"><h3>What happens if I stop paying \/ cancel my subscription?<\/h3><\/dt>\n<dd><p>Same as the previous answer. The plugin stays installed, the\ngateway-talking entry points start returning \"no results\" (since the\ntenant is gated), and every entry point falls back to native search\nin the same request. Your site keeps working; you just stop getting\nAI relevance. Re-pairing with a paid tenant restores full\nfunctionality.<\/p><\/dd>\n<dt id=\"will%20this%20work%20on%20a%20staging%20clone%3F\"><h3>Will this work on a staging clone?<\/h3><\/dt>\n<dd><p>Yes \u2014 Seekmodo locks each tenant to a canonical storefront host.\nStaging \/ dev hosts are auto-detected and return no-op from every\ngateway-talking entry point, so your production search index is never\noverwritten by a non-production deploy.<\/p><\/dd>\n<dt id=\"where%20are%20my%20credentials%20stored%3F\"><h3>Where are my credentials stored?<\/h3><\/dt>\n<dd><p>In <code>wp_options<\/code> (<code>seekmodo_wp_tenant_id<\/code>, <code>seekmodo_wp_shared_secret<\/code>).\n    wp seekmodo connect can be re-run any time to rotate the pair.<\/p><\/dd>\n<dt id=\"where%20does%20the%20plugin%20send%20data%3F\"><h3>Where does the plugin send data?<\/h3><\/dt>\n<dd><p>Indexable post \/ product content goes to <code>mcp.seekmodo.com<\/code> (the\ngateway). Visitor search queries and clicks go to <code>mcp.seekmodo.com<\/code>\nas telemetry. The update check (12 h cadence) goes to\n    seekmodo.com\/api\/plugins\/seekmodo. Configuration pull (5 min\ncadence) goes to <code>mcp.seekmodo.com\/v1\/tenant\/snapshot<\/code>. All\ngateway-bound requests carry an HMAC signature derived from the\npairing secret. Full details in\n<a href=\"https:\/\/seekmodo.com\/legal\/privacy\">https:\/\/seekmodo.com\/legal\/privacy<\/a>.<\/p><\/dd>\n<dt id=\"does%20the%20plugin%20support%20translations%3F\"><h3>Does the plugin support translations?<\/h3><\/dt>\n<dd><p>The admin UI is localised via the <code>seekmodo<\/code> text domain\nand <code>\/languages\/<\/code> directory. We ship English (<code>en_US<\/code>) as the source\nlocale; contributions for other locales are welcome.<\/p><\/dd>\n<dt id=\"how%20do%20i%20get%20help%3F\"><h3>How do I get help?<\/h3><\/dt>\n<dd><ul>\n<li>Support email: <a href=\"mailto:support@seekmodo.com\">&#115;&#117;&#112;&#112;o&#x72;&#x74;&#x40;&#x73;&#x65;&#x65;&#107;&#109;&#111;&#100;&#111;.&#x63;&#x6f;&#x6d;<\/a><\/li>\n<li>Docs: <a href=\"https:\/\/seekmodo.com\/docs\/wordpress\">https:\/\/seekmodo.com\/docs\/wordpress<\/a><\/li>\n<li>WordPress.org support forum (replies within ~1 business day during\nweekdays)<\/li>\n<\/ul><\/dd>\n<dt id=\"where%20is%20the%20human-readable%20source%20for%20the%20suggest%20javascript%3F\"><h3>Where is the human-readable source for the Suggest JavaScript?<\/h3><\/dt>\n<dd><p>The production Suggest bundle\n(<code>assets\/suggest\/seekmodo-suggest.global.js<\/code>) is a minified IIFE built\nfrom <code>@seekmodo\/web-components<\/code>. Readable TypeScript for that bundle\n(and for the Ask IIFE \/ full web-components ESM) ships inside the\nplugin at <code>assets\/suggest\/src\/<\/code>. See <code>assets\/suggest\/SOURCE.md<\/code> for\nthe entry \u2192 file map, rebuild steps (<code>npm install<\/code> + <code>npm run build<\/code>\nin the web-components package), and notes on the inlined SDK copy\nunder <code>assets\/suggest\/src\/vendor\/seekmodo-sdk\/<\/code>. Ask and full ESM\npointers: <code>assets\/ask\/SOURCE.md<\/code>, <code>assets\/web-components\/README.md<\/code>.<\/p><\/dd>\n\n<\/dl>\n\n<!--section=changelog-->\n<h4>0.11.62<\/h4>\n\n<ul>\n<li>Improvement: \"Build index now\" no longer runs the full rebuild inside the admin page load \u2014 it queues a resumable WP-Cron build that runs in bounded background slices, so large catalogs no longer hit proxy\/Cloudflare timeout error pages while PHP keeps working. The settings panel shows live progress, and wp-cli <code>wp seekmodo local_index build<\/code> remains synchronous for operators.<\/li>\n<\/ul>\n\n<h4>0.11.61<\/h4>\n\n<ul>\n<li>New: wordpress.org review prompts \u2014 a dismissible admin banner shown 14 days after pairing, a \"Rate it\" link in the Plugins table row, and a footer line on the Seekmodo settings page. \"No thanks\" dismisses permanently; \"Maybe later\" snoozes for 14 days.<\/li>\n<li>Chore: removed a stray internal debug file from the shipped package.<\/li>\n<\/ul>\n\n<h4>0.11.60<\/h4>\n\n<ul>\n<li>New: search-suggestions dropdown is now enabled by default on fresh installs and upgrades where the setting was never touched. Sites that previously turned it off keep it off; themes can still force-off via the seekmodo_enqueue_typeahead \/ seekmodo_enqueue_suggest filters.<\/li>\n<li>Fix: bulk index pushes (\/v1\/index) now use a 30s timeout instead of the shopper-facing 250ms-2s search cap. Large batches no longer abort client-side and report phantom \"failed\" counts while still importing server-side.<\/li>\n<\/ul>\n\n<h4>0.11.59<\/h4>\n\n<ul>\n<li>Security: All $_SERVER inputs are properly sanitized through ServerInput helper class per WordPress.org Plugin Review requirements (DOCUMENT_ROOT, HTTP_REFERER, REQUEST_METHOD, etc.). uninstall.php cleanup uses only ABSPATH and no longer reads $_SERVER directly.<\/li>\n<li>wordpress.org review: GET <code>\/seekmodo\/v1\/images<\/code> is intentional public read-only image hydrate; remove <code>mark_dirty<\/code> (no unauthenticated post meta writes). Dirty reindex remains via product-save hooks and gateway <code>pending_image_refresh_ids<\/code>.<\/li>\n<\/ul>\n\n<h4>0.11.58<\/h4>\n\n<ul>\n<li>wordpress.org review: GET <code>\/seekmodo\/v1\/images<\/code> is intentional public read-only image hydrate; remove <code>mark_dirty<\/code> (no unauthenticated post meta writes). Dirty reindex remains via product-save hooks and gateway <code>pending_image_refresh_ids<\/code>.<\/li>\n<\/ul>\n\n<h4>0.11.57<\/h4>\n\n<ul>\n<li>Fix: commerce typeahead falls back to WooCommerce products (not blog posts) when cloud\/Enhanced Native returns no rows; shared native-fallback filter keeps content rows for vertical=content.<\/li>\n<\/ul>\n\n<h4>0.11.56<\/h4>\n\n<ul>\n<li>wordpress.org review: remove remaining uninstall.php DOCUMENT_ROOT $_SERVER read (ABSPATH-only .well-known cleanup). Discovery\/runtime already use ServerInput since 0.11.52; cited WellKnownWriter\/ShopperContext\/McpDiscovery snippets were pre-0.11.52.<\/li>\n<\/ul>\n\n<h4>0.11.55<\/h4>\n\n<ul>\n<li>Fix: EventsQueue::ensureTable() on boot and before push() so click beacons are not silently dropped; Options::bustOptionsCache() after pairing\/mode so Redis alloptions cannot stay stale.<\/li>\n<\/ul>\n\n<h4>0.11.54<\/h4>\n\n<ul>\n<li>Broken suggest image heal: filesystem-aware ProductImage, REST <code>\/seekmodo\/v1\/images<\/code>, Suggest <code>images-hydrate-url<\/code>, schedule commerce index cron, drain gateway <code>pending_image_refresh_ids<\/code>.<\/li>\n<\/ul>\n\n<h4>0.11.52<\/h4>\n\n<ul>\n<li>wordpress.org review: sanitize\/validate <code>$_SERVER<\/code> (and related) inputs early via <code>ServerInput<\/code> helper; DOCUMENT_ROOT path guards; SearchSwap GET numeric casts sanitized.<\/li>\n<\/ul>\n\n<h4>0.11.51<\/h4>\n\n<ul>\n<li>wordpress.org review: <code>Tested up to<\/code> in readme.txt only; ship Suggest\/Ask TS under <code>assets\/suggest\/src\/<\/code>; remove static ABSPATH <code>.well-known<\/code> writes (PHP discovery only).<\/li>\n<li>Fix: clear stale PreferLocal <code>over_quota<\/code> sticky while trial is still active.<\/li>\n<\/ul>\n\n<h4>0.11.50<\/h4>\n\n<ul>\n<li>wordpress.org review: exclude\/remove .map files (no jsDelivr strings), JWKS fetch via wp_remote_get only, nonce on cloud-suggest-denied, JSON_HEX_* for Suggest inline config, wp_kses for recommendation placeholders.<\/li>\n<\/ul>\n\n<h4>0.11.49<\/h4>\n\n<ul>\n<li>Plugin Check i18n: SuggestLabels uses literal __() text\/domain (no variables).<\/li>\n<\/ul>\n\n<h4>0.11.46<\/h4>\n\n<ul>\n<li>Fix: sticky unpaid\/over-quota Suggest skips metered \/v1\/suggest (prefer-local) and still fills EN rows when img-ver is set.<\/li>\n<\/ul>\n\n<h4>0.11.45<\/h4>\n\n<ul>\n<li>Fix: unpaid\/over-quota Suggest fallback keeps the Seekmodo-styled suggest box (EN via typeahead-fallback-url) instead of switching to the plain TypeaheadUI product list.<\/li>\n<\/ul>\n\n<h4>0.11.44<\/h4>\n\n<ul>\n<li>Fix: homepage suggestions when Suggest JS is delayed\/blocked \u2014 autoboot on token-guard, typeahead skip while Suggest owns the input, watchdog flip to Enhanced Native typeahead.<\/li>\n<\/ul>\n\n<h4>0.11.41<\/h4>\n\n<ul>\n<li>Suggest: paint thumbnail_url for content posts; hide price_range on content vertical.<\/li>\n<\/ul>\n\n<h4>0.11.38<\/h4>\n\n<ul>\n<li>Fix: Multilingual Suggest sends serp_passthrough filter_by lang:=slug, over-fetches suggest limit to 48 for client i18n_filter, and keeps cloud products when typeahead returns only posts.<\/li>\n<\/ul>\n\n<h4>0.11.37<\/h4>\n\n<ul>\n<li>Fix: Polylang language-switch SERP no longer empties when gateway cache ignores lang (localize IDs + per-lang fetch buckets).<\/li>\n<\/ul>\n\n<h4>0.11.36<\/h4>\n\n<ul>\n<li>Fix: Suggest \"View all\" SERP href uses Polylang\/WPML language path prefix (e.g. \/fr\/?s={q}&amp;post_type=product).<\/li>\n<\/ul>\n\n<h4>0.11.35<\/h4>\n\n<ul>\n<li>Suggest chrome i18n: inject locale label packs into seekmodo-suggest (labels attr + SeekmodoSuggestLabels); vendor web-components 0.4.5 suggest bundle.<\/li>\n<\/ul>\n\n<h4>0.11.34<\/h4>\n\n<ul>\n<li>WordPress.org review follow-ups: enqueue Health\/ModeBadge CSS and beacon seid via wp_add_inline_*; sanitize shopper UA\/IP\/referer and search keywords; rest_url() for pairing callback; shadow logs under uploads\/seekmodo\/; remove load_plugin_textdomain; static .well-known writes opt-in; exclude release-signing-keys from release zip.<\/li>\n<\/ul>\n\n<h4>0.11.33<\/h4>\n\n<ul>\n<li>Plugin Check: remove HEREDOC\/NOWDOC from shipped PHP; Tested up to 7.1; release compliance gate.<\/li>\n<\/ul>\n\n<h4>0.11.22<\/h4>\n\n<ul>\n<li>Fix: Relevanssi-compat hydration re-applies post__in score order after get_posts so theme date sorting cannot reshuffle SERPs.<\/li>\n<\/ul>\n\n<h4>0.11.21<\/h4>\n\n<ul>\n<li>Improve: stronger ordered title-phrase boost so exact publication titles outrank long body TF matches.<\/li>\n<\/ul>\n\n<h4>0.11.20<\/h4>\n\n<ul>\n<li>Improve: Enhanced Native exact whole-word hits outrank prefix\/partial matches; unquoted multi-word queries boost adjacent ordered title\/excerpt phrases.<\/li>\n<\/ul>\n\n<h4>0.11.18<\/h4>\n\n<ul>\n<li>Fix: commerce-only tenants (<code>enabled_verticals=commerce<\/code>) now claim unscoped <code>\/?s=<\/code> \/ <code>post_type=any<\/code> main searches so search_event_id reaches the click beacon.<\/li>\n<\/ul>\n\n<h4>0.11.17<\/h4>\n\n<ul>\n<li>Fix: content SERP (<code>\/?s=<\/code> without post_type=product) now stamps search_event_id so click beacons are accepted; also supports Rank Math <code>\/search\/{q}\/<\/code> keyword detection.<\/li>\n<\/ul>\n\n<h4>0.11.16<\/h4>\n\n<ul>\n<li>Fix: WooCommerce add-to-cart and purchase events now register even when WooCommerce is not visible at plugins_loaded, flush in the same cron tick as clicks (instead of starving behind SERP click traffic), and no longer drop silent TypeErrors when quantity is a decimal.<\/li>\n<\/ul>\n\n<h4>0.11.15<\/h4>\n\n<ul>\n<li>Fix: the events-queue flush cron (clicks, add-to-cart \/ purchase conversions) never actually ran on any install. <code>wp_schedule_event()<\/code> was called with a recurrence name that was never registered via the <code>cron_schedules<\/code> filter, so WordPress silently refused to schedule it while searches kept working fine \u2014 the underlying cause of fleet monitoring flagging sites with real traffic but zero recorded clicks. Registering the plugin now also self-heals existing installs immediately (no need to deactivate\/reactivate).<\/li>\n<\/ul>\n\n<h4>0.11.14<\/h4>\n\n<ul>\n<li>Daily unpaid-recovery: the existing 5-minute tenant.snapshot pull now clears a stuck trial_expired \/ paused \/ closed sticky as soon as the gateway reports the account active again, so a resubscribe or trial extension restores cloud suggest within one pull instead of waiting out the 1-hour sticky TTL. An over_quota sticky is left to clear on its own (TTL or next successful search) since an active subscription can still be over this period's quota.<\/li>\n<\/ul>\n\n<h4>0.11.13<\/h4>\n\n<ul>\n<li>Search suggestions box now supports full CSS custom-property theming (accent color, header, CTA pill, row accent bar, rail background) so you can brand the dropdown to match your site without a child plugin. No visual changes if you don't set any of the new properties.<\/li>\n<\/ul>\n\n<h4>0.11.10<\/h4>\n\n<ul>\n<li>Stamp search_event_id on add_to_cart \/ purchase for LTR last-touch linkage.<\/li>\n<\/ul>\n\n<h4>0.11.9<\/h4>\n\n<ul>\n<li>Shopper-context parity for typeahead + conversion events (session_id \/ ua \/ referer).<\/li>\n<\/ul>\n\n<h4>0.11.8<\/h4>\n\n<ul>\n<li>Document HMAC auth_fail \/ signature_mismatch contract: Gateway\\Client returns null (native WP\/Woo fallback) during secret drift; optional WP_DEBUG log.<\/li>\n<\/ul>\n\n<h4>0.11.7<\/h4>\n\n<ul>\n<li>Text domain seekmodo; removed Update URI \/ WporgUpdateClient for Directory updates.<\/li>\n<li>Suggest branding defaults off; privacy guide mentions IP\/UA\/referer.<\/li>\n<li>Plugin Check ERROR cleanups (escaping, SQL prepare, ABSPATH, packaging excludes).<\/li>\n<\/ul>\n\n<h4>0.11.6<\/h4>\n\n<ul>\n<li>WordPress.org submission readiness: vendored full\n  @seekmodo\/web-components ESM under <code>assets\/web-components\/<\/code> (no\ndefault CDN load; override via <code>seekmodo_web_components_src<\/code>).<\/li>\n<li>Complete uninstall cleanup (options, local-index tables, crons,\ntransients).<\/li>\n<li><code>Tested up to: 7.0<\/code>. Health dashboard widget requires\n  manage_options. Suggested privacy-policy guide text added.<\/li>\n<li>Cart cascade ranks multi-line carts by <code>support_count<\/code> across up\nto 10 anchors.<\/li>\n<\/ul>\n\n<h4>0.11.5<\/h4>\n\n<ul>\n<li>PDP\/cart recommendation cascades (<code>pdp-cascade<\/code>, <code>cart<\/code>) via\n  \/wp-json\/seekmodo\/v1\/recommendations with cross-section de-dupe and\nin-cart <code>exclude_doc_ids<\/code>, matching the AKS cascade contract.<\/li>\n<li>Auto-injects placeholders on WooCommerce PDP\/cart templates and\nrefreshes after cart fragments; enqueues <code>@seekmodo\/web-components<\/code>\non those templates even without Gutenberg blocks.<\/li>\n<\/ul>\n\n<h4>0.11.4<\/h4>\n\n<ul>\n<li>Stop requiring REQUEST fingerprints for add_to_cart mirrors (theme\/custom AJAX was dropping all ATCs). Session-restore skip remains the spam guard.<\/li>\n<li>Also emit purchases on woocommerce_payment_complete (deduped) when thankyou never renders.<\/li>\n<\/ul>\n\n<h4>0.11.3<\/h4>\n\n<ul>\n<li>Events flush uses an 8s timeout and smaller batches (clicks first) so ATC attribution no longer wedges the queue.<\/li>\n<li>Skips cart-session restore add_to_cart mirrors; only intentional shopper adds are queued.<\/li>\n<li>Persists sm_seid cookie for SERP click attribution when footer beacon localization races.<\/li>\n<\/ul>\n\n<h4>0.11.2<\/h4>\n\n<ul>\n<li>Stamps per-shopper session_id + visitor IP\/UA on search and click events for bot-check and fleet linkage.<\/li>\n<li>Drops unlinked SERP beacon clicks (missing search_event_id) that were polluting LTR \/ fleet health.<\/li>\n<\/ul>\n\n<h4>0.8.9<\/h4>\n\n<ul>\n<li>Shared thumbnail resolver for content typeahead and indexing (featured\nimage, inline content image, seekmodo_thumbnail_url filter).<\/li>\n<\/ul>\n\n<h4>0.8.8<\/h4>\n\n<ul>\n<li>Content typeahead unions gateway hits with native WP rows and applies\npost-type priority so pages surface before posts (trek.ca parity with SERP).<\/li>\n<li>Suggest widget always merges the REST typeahead fallback when configured.<\/li>\n<\/ul>\n\n<h4>0.8.7<\/h4>\n\n<ul>\n<li>Fixes WooCommerce SERP showing product categories instead of ranked\ngateway products after the search swap.<\/li>\n<li>Suggest dropdown merges REST typeahead fallback when gateway suggest\nreturns no product rows (content sites like trek.ca).<\/li>\n<\/ul>\n\n<h4>0.8.6<\/h4>\n\n<ul>\n<li>Fixes WooCommerce SERP titles showing <code>Search results: \"\"<\/code> after the\ngateway search swap clears the query <code>s<\/code> var.<\/li>\n<\/ul>\n\n<h4>0.8.4<\/h4>\n\n<ul>\n<li>Fixes mobile split-rail draggable divider (both panels resize again).<\/li>\n<li>Refreshes the vendored <code>@seekmodo\/web-components<\/code> suggest bundle.<\/li>\n<\/ul>\n\n<h4>0.8.3<\/h4>\n\n<ul>\n<li>Typeahead product-row clicks thread <code>search_event_id<\/code> from <code>\/v1\/suggest<\/code>\nmeta for LTR click attribution.<\/li>\n<li>Refreshes the vendored <code>@seekmodo\/web-components<\/code> suggest bundle (split-rail\nmobile divider, native title tooltips, anchor performance fixes).<\/li>\n<\/ul>\n\n<h4>0.8.2<\/h4>\n\n<ul>\n<li>Fixes typeahead and search-swap click attribution (rank\/surface metadata).<\/li>\n<li>Refreshes suggest bundle with split-rail scroll and thumb scaling fixes.<\/li>\n<\/ul>\n\n<h4>0.8.1<\/h4>\n\n<ul>\n<li>CORS-block UX when gateway script loads or suggest fetches are blocked.<\/li>\n<li>Refreshes suggest bundle to v0.2.2.<\/li>\n<\/ul>\n\n<h4>0.8.0<\/h4>\n\n<ul>\n<li>Enhanced Native search layer (Tier 1 + Tier 2) for unpaired installs.<\/li>\n<\/ul>\n\n<h4>0.6.0<\/h4>\n\n<ul>\n<li><strong>SM-606 Universal Suggest Widget<\/strong>: when the operator-facing\n\"Enable connector typeahead UI\" toggle is on, v0.6.0 enqueues the\nnew <code>&lt;seekmodo-suggest&gt;<\/code> custom element (~7 KB gzip, lives at\n  assets\/suggest\/seekmodo-suggest.global.js) instead of the legacy\nflat-row dropdown. The web component renders the rich <code>\/v1\/suggest<\/code>\nenvelope from the gateway (WS-2): recent + trending + keywords +\nproducts + categories + did-you-mean + \"View all N results\" CTA,\nall from one server round-trip. UX is shared 1:1 with the\nBigCommerce \/ Zen Cart \/ AKS \/ WordPress connectors so a tenant\nwith multiple storefronts gets one suggestions UI everywhere.<\/li>\n<li><strong>Opt-out flag<\/strong>: new <code>seekmodo_wp_suggest_legacy<\/code> per-site option\n(Settings \u2192 Seekmodo \u2192 \"Use legacy flat-row typeahead instead of the\nuniversal suggest widget\") flips back to the v0.5.x dropdown for one\nmajor-version cycle. The two surfaces are mutually exclusive \u2014\n  Frontend\\TypeaheadUI::isEnabled() returns false when the flag is\noff, preventing double-attaching dropdowns to the same input.<\/li>\n<li><strong>Browser-token refresh<\/strong>: new public <code>POST \/wp-json\/seekmodo\/v1\/browser-token<\/code>\nroute returns <code>{token, expires_at, session_id}<\/code> so the in-bundle SDK\ncan refresh a 5-min JWT without a full page reload. Cached behind\nthe existing per-tenant transient in <code>Gateway\\BrowserToken<\/code> so a\nlong-running tab amounts to ~one mint per ~4 min regardless of how\nmany keystrokes the shopper triggers.<\/li>\n<li><strong>Customization surface (theme-side)<\/strong>:\n\n<ul>\n<li><code>seekmodo_suggest_selectors<\/code> \u2014 CSS-selector list the autoboot\nwalks (default <code>input[type=\"search\"]<\/code>, <code>input[name=\"s\"]<\/code>,\n   input[data-seekmodo-suggest], <code>input[data-seekmodo-typeahead]<\/code>).<\/li>\n<li><code>seekmodo_suggest_blocks<\/code> \u2014 CSV of blocks the widget should\nrender in order (default <code>recent,did_you_mean,keywords,trending,\nproducts,categories<\/code>). Drop any block by leaving it out.<\/li>\n<li><code>seekmodo_suggest_view_all_href<\/code> \u2014 URL template for the CTA.\nDefault <code>\/?s={q}<\/code> (or <code>\/?s={q}&amp;post_type=product<\/code> on Woo sites).<\/li>\n<li><code>seekmodo_suggest_extra_attrs<\/code> \u2014 assoc map of additional\nattributes (e.g. <code>min-length<\/code>, <code>debounce-ms<\/code>, <code>limit<\/code>,\n   cache-size, <code>lang<\/code>) forwarded to every spawned element.<\/li>\n<li><code>seekmodo_suggest_config<\/code> \u2014 last-resort filter on the localized\nJS config.<\/li>\n<li>Shadow-DOM CSS Custom Properties (<code>--seekmodo-suggest-bg<\/code>,\n   --seekmodo-suggest-row-hover, <code>--seekmodo-suggest-thumb-size<\/code>,\netc.) so child themes can theme the dropdown without forking\nits markup.<\/li>\n<li><code>&lt;slot name=\"recent|keywords|trending|products|categories|empty|\nheader|footer\"&gt;<\/code> lets a theme drop bespoke HTML inside an\nelement and override any one block's rendering wholesale.<\/li>\n<\/ul><\/li>\n<li><strong>Performance<\/strong>: matches the AKS-3801e baseline (sub-300 ms p95\ncold cache, &lt;16 ms warm-cache render) via the bundle's built-in\n150 ms keystroke debounce, AbortController cancel-on-next-keystroke,\n32-entry LRU cache, and single rAF-batched render. Skeleton loader\nmasks the first-render latency on a cold cache.<\/li>\n<\/ul>\n\n<p><h4>0.5.3<\/h4><\/p>\n\n<ul>\n<li><strong>Operator UX<\/strong>: <code>wp seekmodo index --full<\/code> now reindexes every\ngateway-enabled vertical for the tenant (content + commerce, in\nseries), and accepts a new <code>--vertical=content|commerce|all<\/code> flag\nfor surgical per-vertical reindexes. Pre-0.5.3 the command only\ninvoked <code>Content\/Indexer::reindexFull()<\/code>; commerce-only operators\n(and dual-vertical operators chasing a stale product index) had to\ndrop into <code>wp eval '\\Numinix\\SeekmodoWordPress\\Commerce\\Indexer::reindexFull();'<\/code>.\nVerticals the gateway hasn't enabled for this tenant \u2014 or whose\nruntime dependency is missing (e.g. WooCommerce inactive) \u2014 are\nskipped silently with an info-level log line; the command reports\nthe per-vertical totals separately so the operator can tell at a\nglance whether each vertical actually executed.<\/li>\n<li><strong>Safety<\/strong>: stricter write-side host-lock gate, exposed as\n  DomainLock::canIndex() and surfaced in <code>wp seekmodo health<\/code> \/\n  wp seekmodo diagnose as a new <code>can_index<\/code> row. Used by every\ngateway-mutating helper (<code>numinix_seekmodo_run_bulk_upsert<\/code>,\n  numinix_seekmodo_mirror_click) plus the cron-tick early-out in\nboth <code>Content\/Indexer::tick()<\/code> and <code>Commerce\/Indexer::tick()<\/code>.\nFailure modes the new gate catches that the looser\n  DomainLock::matches() did NOT:\n\n<ul>\n<li><strong>Self-referential lock on a non-prod host.<\/strong> <code>dev.example.com<\/code>\nseeds its <code>seekmodo_wp_storefront_host<\/code> to its own home_url() at\nactivation; <code>matches()<\/code> returns true (current==locked); pre-0.5.3\nindexer cron would happily push every product save to the prod\ntenant's Typesense collection, with <code>dev.example.com<\/code> URLs\npoisoning the customer-visible search results. Exact PM-303\nregression.<\/li>\n<li><strong>Unset lock on a non-prod host.<\/strong> A freshly-installed dev clone\nthat hasn't completed its first 5-min <code>tenant.snapshot<\/code> pull yet:\npre-0.5.3 <code>matches()<\/code> returned true (no lock \u2192 tentative allow).\n0.5.3 fails closed.<\/li>\n<\/ul><\/li>\n<li><strong>Safety<\/strong>: read paths (typeahead, search-swap, click-beacon\nenqueue) keep gating on <code>numinix_seekmodo_enabled()<\/code> so an\noperator smoke-testing search behavior on a staging clone still\ngets results \u2014 only writes are tightened.<\/li>\n<li><strong>Safety<\/strong>: two override filters, intentionally separated so a\nread-side bypass doesn't accidentally also unlock writes:\n\n<ul>\n<li><code>seekmodo_disable_storefront_host_lock<\/code> (existing, since v0.1.0)\n\u2014 read AND write; bypasses every check. Used by blue\/green CDN\nsetups where the request reaches WP under a different Host\nheader than the visitor sees.<\/li>\n<li><code>seekmodo_allow_nonprod_indexing<\/code> (NEW, v0.5.3) \u2014 write only;\nconsenting non-prod indexer for installs paired to a separate\n*-dev tenant. Defaults false.<\/li>\n<\/ul><\/li>\n<li><strong>Operator UX<\/strong>: <code>wp seekmodo health<\/code> now prints <code>current_host<\/code>,\n  locked_host, <code>host_lock_match<\/code>, <code>can_index<\/code>, and\n  looks_like_nonprod instead of the older single <code>host_lock_match<\/code>\nrow, so an operator chasing \"why isn't dev indexing?\" can see\nevery input the gate consults at a glance.<\/li>\n<\/ul>\n\n<p><h4>0.5.1<\/h4><\/p>\n\n<ul>\n<li><strong>Reliability<\/strong>: deploy-channel-agnostic version-bump detector. The\nconnector now compares the on-disk <code>SEEKMODO_WP_VERSION<\/code> constant\nto the last-seen value stored in <code>wp_options<\/code> on every request,\nand on a mismatch fans out cache invalidations to every page-cache\n\/ minify \/ object-cache \/ OPCache plugin we know about. Closes the\n\"I rsync'd v0.5.0 onto the server but visitors still load v0.4.0\"\nregression that surfaced on POCO after the v0.5.0 push: WP Rocket\nwas serving the cached v0.4.0 minified JS for 1 year because it\nonly invalidates on <code>upgrader_process_complete<\/code> (which rsync\ndeploys never fire).<\/li>\n<li><strong>Reliability<\/strong>: explicit OPCache reset on version bump. Hosts\nwith <code>opcache.validate_timestamps=0<\/code> (typical on shared hosting\nfor performance) silently kept executing the old PHP class\nbytecode after rsync. The reset is wrapped in a function-exists\nguard so PHP builds without OPCache compiled in stay safe.<\/li>\n<li><strong>Reliability<\/strong>: browser-token transient explicitly invalidated\non version bump so the next typeahead keystroke re-mints a token\nsigned against whatever the new gateway expects, instead of\ninheriting a payload-shape from the prior connector version.<\/li>\n<li><strong>Maintenance<\/strong>: fan-out is gated behind a one-shot atomic option\nwrite so two concurrent first-bump requests don't double-fire the\ncache flush. Hosts running bespoke cache infra can suppress the\nfan-out entirely with the new <code>seekmodo_skip_upgrade_flush<\/code>\nfilter, or extend it with extra do_action keys via\n  seekmodo_upgrade_flush_actions.<\/li>\n<li>No new operator-facing settings; mass-deployable as a no-op\nupdate on every connector site.<\/li>\n<\/ul>\n\n<p><h4>0.5.0<\/h4><\/p>\n\n<ul>\n<li><strong>Performance<\/strong>: typeahead now POSTs <code>mcp.seekmodo.com\/v1\/typeahead<\/code>\ndirectly from the storefront browser using a short-lived browser\ntoken minted server-side at page render. Skips the WordPress REST\nhop (and the ~1.5\u20132 s WordPress full-stack boot it pays on a heavy\nWooCommerce + Wordfence install) on every keystroke.\nPer-keystroke latency on POCO observed dropping from ~2,250 ms to\n~80\u2013150 ms.<\/li>\n<li><strong>Performance<\/strong>: 32-entry client-side LRU cache keyed on the\nnormalized <code>(vertical, max, q)<\/code> prefix. Backspace + retype on a\npreviously-fetched prefix renders synchronously from in-memory\ncache, no network round-trip. Cache size is operator-tunable via\nthe <code>seekmodo_typeahead_config<\/code> filter.<\/li>\n<li><strong>Performance<\/strong>: server-side <code>Cache-Control: public, s-maxage=30,\nmust-revalidate<\/code> + <code>Vary: X-Seekmodo-Tenant<\/code> on gateway typeahead\nresponses lets Cloudflare \/ Varnish absorb keystroke storms on\nhot prefixes without leaking rows across tenants.<\/li>\n<li><strong>Performance<\/strong>: per-FPM-process APCu micro-cache (10 s TTL) on\nthe gateway side defends Typesense from a hot prefix when the\nedge cache is cold.<\/li>\n<li><strong>Added<\/strong>: <code>seekmodo_typeahead_gateway_direct<\/code> filter. Defaults\n  true. Site can <code>__return_false<\/code> to force every typeahead call\nback to the WordPress REST endpoint \u2014 useful for incident-response\n\/ debugging without a connector update.<\/li>\n<li><strong>Added<\/strong>: <code>Gateway\/BrowserToken.php<\/code> \u2014 caches the per-tenant\nbrowser-token mint in a WordPress transient (refresh window\nhonored, hard-cap 240 s). The mint failure mode silently falls\nback to the REST hop, so the typeahead never breaks regardless\nof token availability.<\/li>\n<li><strong>Fixed<\/strong>: pre-existing regression where <code>Client::typeahead()<\/code>\nPOSTed <code>\/v1\/typeahead<\/code> against the gateway, the gateway returned\n  404 tool_not_found, and the connector fell back to a native\n  WP_Query LIKE search on every keystroke (~2.3 s on POCO,\n~1.1 s on Trek.ca). The new gateway-side <code>TypeaheadTool<\/code> (SM-602\non the platform side) is what makes the gateway-direct path\nreturn real Typesense rows in ~80 ms.<\/li>\n<\/ul>\n\n<h4>0.4.0<\/h4>\n\n<ul>\n<li><strong>Added<\/strong>: front-end typeahead dropdown UI. The connector now ships\n  assets\/typeahead\/seekmodo-typeahead.{js,css} plus\n  src\/Frontend\/TypeaheadUI.php \u2014 a vanilla-JS dropdown that\nauto-binds to common search inputs (<code>input[type=\"search\"]<\/code>,\n  input[name=\"s\"], <code>input[data-seekmodo-typeahead]<\/code>), debounces\ninput at 150ms, and renders rows from the existing\n  \/wp-json\/seekmodo\/v1\/typeahead REST endpoint. Two row shapes:\ncontent rows (title + post-type meta + excerpt + thumbnail) and\ncommerce rows (product card with price \/ sale \/ stock badges).<\/li>\n<li><strong>Added<\/strong>: optional \"Powered by Seekmodo\" footer in the dropdown,\ndriven by the existing <code>seekmodo_show_branding<\/code> filter +\n  OPT_SHOW_BRANDING option. Default OFF \u2014 partner sites flip it on\nvia the Settings page or have it pushed down by the gateway's\ntenant-snapshot config pull. White-label by default.<\/li>\n<li><strong>Added<\/strong>: per-site \"Enable typeahead\" + \"Show branding\" toggles\non Settings \u2192 Seekmodo Search \u2192 Typeahead dropdown. The enable\ntoggle defaults OFF so an upgrade on a site that already has its\nown theme-level typeahead (e.g. trek.ca's\n  inc\/seekmodo-search.php) doesn't double-render.<\/li>\n<li><strong>Added<\/strong>: <code>seekmodo_enqueue_typeahead<\/code>,\n  seekmodo_typeahead_selectors, and <code>seekmodo_typeahead_config<\/code>\nfilters so themes can suppress or customise the connector UI\nwithout forking the JS.<\/li>\n<li><strong>Compat<\/strong>: existing <code>assets\/typeahead\/seekmodo-beacon.js<\/code> click\nattribution picks up <code>data-seekmodo-id<\/code> \/ <code>data-seekmodo-pos<\/code> \/\n  data-seekmodo-surface=\"typeahead\" attributes the new dropdown\nemits \u2014 no second beacon, no separate REST endpoint, click-through\ndata flows through the same EventsQueue pipeline.<\/li>\n<\/ul>\n\n<h4>0.3.4<\/h4>\n\n<ul>\n<li><strong>Added<\/strong>: editorial post-type ranking priority. After the gateway\nscores results by textual relevance, hits whose post type appears\nearlier in the configured priority list are bucket-sorted to the\ntop. Within each tier the gateway's relevance order is preserved\n-- we don't re-score textual relevance, just bucket-sort by post\ntype. Configurable via the new <code>Search ranking priority<\/code> field on\nSettings \u2192 Seekmodo Search, or by setting the\n  seekmodo_wp_post_type_priority option directly. The\n  seekmodo_post_type_priority filter overrides for site-specific\nmu-plugins. Default is empty -- no re-rank, gateway order flows\nthrough untouched. Fixes the trek.ca complaint where blog posts\ndominated <code>?s=PPC<\/code> while the high-intent <code>\/services\/<\/code> pages got\nburied below the fold.<\/li>\n<\/ul>\n\n<h4>0.3.3<\/h4>\n\n<ul>\n<li><strong>Fixed<\/strong>: the v0.3.2 pair-callback REST route at\n  \/wp-json\/seekmodo\/v1\/connect\/callback was registered behind\n  Bootstrap::boot()'s <code>is_admin()<\/code> gate, so the route never\nappeared on the server-to-server POST from seekmodo.com (REST API\nrequests are not \"admin\" in WordPress's classification). The\nadmin-side Connect button worked, but the JWT callback POST\nsilently 404'd and pairing died at the last step. v0.3.3 lifts\n  ConnectFlow::register() out of the <code>is_admin()<\/code> block so the\n  rest_api_init hook always runs. The\n  admin_post_seekmodo_wp_connect hook stays registered globally\ntoo (harmless -- it only fires on <code>admin-post.php<\/code> hits).<\/li>\n<\/ul>\n\n<h4>0.3.2<\/h4>\n\n<ul>\n<li><p><strong>Fixed<\/strong>: the \"Connect to Seekmodo\" pairing flow has been\nrebuilt on the canonical <code>install_token<\/code> + signed-JWT protocol\n(the same protocol Seekmodo for Zen Cart has used since v1.0.x).\nv0.3.0 and v0.3.1 sent legacy <code>nonce<\/code> + <code>return_to<\/code> query params\nthat seekmodo.com rejects with \"This link is incomplete\" \u2014 the\nredirect-back side of that protocol was an aspirational design\nthat was never implemented on the seekmodo.com side. Pairing\nthrough the browser was impossible until this release.<\/p>\n\n<ul>\n<li><code>Admin\\ConnectFlow::initiate()<\/code> now mints a 32-hex\ninstall_token (10-min TTL) and sends\n?install_token=&amp;callback= to seekmodo.com\/connect.<\/li>\n<li>The new <code>Admin\\ConnectFlow::handleCallback()<\/code> is registered as a\npublic REST endpoint at\nwp-json\/seekmodo\/v1\/connect\/callback. seekmodo.com POSTs\n{token, install_token} to that URL with the\nX-Seekmodo-Install-Token header.<\/li>\n<li>The new <code>Connect\\Pairing<\/code> class verifies the EdDSA-signed JWT\nagainst <code>https:\/\/seekmodo.com\/.well-known\/jwks.json<\/code>, validates\nthe standard claims (iss\/aud\/exp\/install_token), and persists\ntenant_id + <code>shared_secret<\/code> + <code>mcp_url<\/code>.<\/li>\n<\/ul><\/li>\n<li><p><strong>Removed<\/strong>: <code>Gateway\\Client::verifyClaimToken()<\/code> and the matching\n  wp seekmodo connect --token=&lt;...&gt; CLI flag. They both round-tripped\nthrough a <code>\/v1\/connect\/verify<\/code> endpoint that the gateway never\nimplemented; users hitting that path were getting silent failures.\nThe CLI pair still works via <code>--tenant=<\/code> <code>--secret=<\/code> for\nheadless \/ CI installs.<\/p><\/li>\n<li><p><strong>Required<\/strong>: PHP <code>sodium<\/code> extension (ext-sodium) -- needed for the\nJWT signature verify. It's part of core PHP since 7.2 and shipped\non default cPanel\/EasyApache builds, but if it's not loaded the\npair-callback surfaces a cPanel-specific install hint\n(<code>yum install -y ea-php82-php-sodium<\/code>).<\/p><\/li>\n<\/ul>\n\n<h4>0.3.1<\/h4>\n\n<ul>\n<li><strong>Fixed<\/strong>: <code>Admin\\ConnectFlow::initiate()<\/code> called\n  wp_safe_redirect('https:\/\/seekmodo.com\/connect?...') without\nwhitelisting the connect host. WP's redirect validator silently\nrewrote the destination back to the site root, landing the\noperator on the WP admin homepage instead of the connect page \u2014\npairing was impossible via the browser flow. The <code>wp seekmodo\nconnect<\/code> CLI path was unaffected. Now registers a one-shot\n  allowed_redirect_hosts filter for the connect host (overridable\nvia the existing <code>seekmodo_connect_base_url<\/code> filter) for the\nduration of the redirect call only.<\/li>\n<\/ul>\n\n<h4>0.3.0<\/h4>\n\n<ul>\n<li><strong>Changed<\/strong>: Commerce vertical doc shape realigned to the gateway\nTypesense schema. <code>Commerce\\ProductFields::buildDoc()<\/code> now emits\ngateway-canonical field names \u2014 <code>name<\/code>, <code>url<\/code>, <code>in_stock<\/code> (bool),\n  category_id[], <code>category_breadcrumbs[]<\/code>, <code>image_url<\/code>,\n  description (combined excerpt + content_plain, HTML-stripped, 4\nKB cap), <code>last_indexed_at<\/code>, plus optional <code>on_sale<\/code>, <code>sale_price<\/code>,\n  currency. Removes pre-v0.3.0 WP-shaped names (<code>title<\/code>,\n  permalink, <code>stock_status<\/code> string, <code>regular_price<\/code>, <code>excerpt<\/code>,\n  content_plain, <code>attributes<\/code>, <code>variations[]<\/code>, <code>categories<\/code>,\n  post_type, <code>extra<\/code>) that the gateway's strict-schema Typesense\nwas rejecting on every upsert.<\/li>\n<li><strong>Changed<\/strong>: Commerce schema version split out from the content\nschema version so a commerce-only realignment doesn't trigger an\nunnecessary content-side full reindex. New\n  Options::OPT_COMMERCE_SCHEMA_VERSION (<code>commerce_schema_version<\/code>\nin wp_options) is consulted by <code>Commerce\\Indexer::tick()<\/code> and\ntriggers a one-shot full reindex on upgrade \u2014 same trick as the\nv0.1.1 content-side bump.<\/li>\n<li><strong>Added<\/strong>: Self-service \"Promote dev \u2192 production\" card on the\nSeekmodo Search settings page. Surfaces when the connector's\ncurrent host looks like a non-prod environment\n(<code>dev|staging|stage|test|qa|preview|sandbox<\/code>) and the canonical\nlock matches that host. One-click POST to the gateway's new\n  tenant.domain.promote MCP tool flips <code>locked_domain<\/code> to the\nselected production host. Within 5 min the dev plugin's next\n  tenant.snapshot pull sees the new lock and goes silent\n(DomainLock mismatch), so dev \/ staging mirrors stop polluting\nproduction search analytics automatically. Closes the operator\nround-trip the v0.2.x flow required.<\/li>\n<li><strong>Added<\/strong>: <code>Gateway\\Client::promoteCanonicalDomain()<\/code> thin HTTP\nhelper for the new tool. Same HMAC envelope as every other\ngateway call.<\/li>\n<li><strong>Added<\/strong>: Admin-app mirror \u2014 <code>tenant-settings-form.tsx<\/code> now shows\na \"Promote dev to production\" hint band + one-click action when\nthe tenant is locked to a non-prod host and a prod-looking\nconnector has authenticated. Pre-fills the locked-domain field\nwith the most-recently-seen prod host; operator clicks Save to\napply.<\/li>\n<\/ul>\n\n<h4>0.1.4<\/h4>\n\n<ul>\n<li><strong>Added<\/strong>: WordPress.org Plugin Directory submission readiness.\nPlugin header <code>Update URI: https:\/\/seekmodo.com\/plugins\/seekmodo<\/code>\n(WP 5.8+) routes update checks to our marketing-site endpoint, so\nthe plugin lists at <a href=\"https:\/\/wordpress.org\/plugins\/seekmodo\/\">https:\/\/wordpress.org\/plugins\/seekmodo\/<\/a> for\ninitial install + searchability while all subsequent\nversion-checks and zip downloads happen against seekmodo.com.<\/li>\n<li><strong>Added<\/strong>: <code>Numinix\\SeekmodoWordPress\\Updates\\WporgUpdateClient<\/code> \u2014\nhooks <code>update_plugins_seekmodo.com<\/code> (the filter key WP core\nsynthesises from our <code>Update URI<\/code> header) and the\n  plugins_api \u2192 plugin_information \"View details\" modal. Reads\nfrom <code>https:\/\/seekmodo.com\/api\/plugins\/seekmodo<\/code>, cached 12 h on\nsuccess and 5 min on failure. Endpoint is filterable via\n  seekmodo_wporg_update_endpoint for staging.<\/li>\n<li><strong>Changed<\/strong>: Plugin name shortened from \"Seekmodo Search for\nWordPress\" to \"Seekmodo Search\" (w.org plugin-review guideline:\nthe \"for WordPress\" suffix is discouraged when the plugin is\nlisted there).<\/li>\n<li><strong>Changed<\/strong>: Plugin description rewritten for w.org's plugin-card\npreview, with explicit SaaS-dependency disclosure and free-trial\nnote matching the Mailchimp \/ Algolia \/ Akismet pattern.<\/li>\n<li><strong>Changed<\/strong>: <code>Tested up to: 6.6<\/code> added to plugin header + readme so\nthe WP-admin compatibility filter and the w.org directory listing\nreflect the latest tested WordPress release.<\/li>\n<li><strong>Fixed<\/strong>: <code>tools\/build_release.py --auto-pr<\/code> now writes a manifest\nentry whose schema matches the live <code>platforms.zen_cart<\/code> entry\nexactly (<code>sha256<\/code> \/ <code>sig<\/code> \/ <code>sig_kid<\/code> \/ <code>signed_at<\/code> \/ <code>signed_with<\/code>\n\/ <code>released_at<\/code> \/ <code>release_notes_url<\/code>) instead of the orphan\n  sha256_url \/ <code>signature_url<\/code> \/ <code>released_at_utc<\/code> shape it\nproduced before. Also replaces a Unix-only\n  subprocess.check_output([\"date\", ...]) with portable\n  datetime.now(timezone.utc).<\/li>\n<\/ul>\n\n<h4>0.1.3<\/h4>\n\n<ul>\n<li>Add: per-tenant \"Powered by Seekmodo\" branding toggle. Off by default;\noperators turn it on from the admin.seekmodo.com tenant settings page\nfor partner \/ specific-deal sites. New helpers\n  numinix_seekmodo_show_branding() and <code>numinix_seekmodo_brand_url()<\/code>\nfor themes, with <code>seekmodo_show_branding<\/code> and <code>seekmodo_brand_url<\/code>\nfilters.<\/li>\n<\/ul>\n\n<h4>0.1.2<\/h4>\n\n<ul>\n<li>Fix: <code>AutoPromoter<\/code> substate FSM is now actually wired up. Previous\nversions never advanced the <code>active+shadow \u2192 active+enforce<\/code>\nsubstate, and the SearchSwaps consulted the headline mode instead\nof the effective mode, so <code>auto_promote=true<\/code> was decorative.\n  MODE=active now correctly bakes into enforce on healthy metrics\nand demotes back to shadow on a breach.<\/li>\n<li>Fix: <code>MODE=active<\/code> + <code>auto_promote=false<\/code> now correctly collapses\nto a hard enforce (operator opt-out of the safety hop).<\/li>\n<\/ul>\n\n<h4>0.1.1<\/h4>\n\n<ul>\n<li>Fix: Content indexer doc shape aligned with the gateway's strict\nTypesense <code>content<\/code> collection schema. Previous releases would\nhave 400'd on every <code>index.upsert<\/code>.<\/li>\n<li>Bumped <code>Options::SCHEMA_VERSION<\/code> to force a full reindex on\nupgrade.<\/li>\n<\/ul>\n\n<h4>0.1.0<\/h4>\n\n<ul>\n<li>Initial release. Sprints 0-5 shipped: content + commerce verticals,\nmode FSM with auto-promoter, shadow-mode diff logger, typeahead,\nclick beacon, events queue, health widget, signed-zip release\npipeline.<\/li>\n<\/ul>","raw_excerpt":"AI-powered search for WordPress and WooCommerce. Vector + keyword recall, commerce-aware reranking, native search permanently armed as a fallback.","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/nl-be.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/346192","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/nl-be.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin"}],"about":[{"href":"https:\/\/nl-be.wordpress.org\/plugins\/wp-json\/wp\/v2\/types\/plugin"}],"replies":[{"embeddable":true,"href":"https:\/\/nl-be.wordpress.org\/plugins\/wp-json\/wp\/v2\/comments?post=346192"}],"author":[{"embeddable":true,"href":"https:\/\/nl-be.wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/numinix"}],"wp:attachment":[{"href":"https:\/\/nl-be.wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=346192"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/nl-be.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=346192"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/nl-be.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=346192"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/nl-be.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=346192"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/nl-be.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=346192"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/nl-be.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=346192"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}