{"product_id":"2026-09-27","title":"[Horizon] Scoping storefront search to the articles of one specific blog when a store has several blogs","description":"\u003cp\u003eShopify storefront search can be narrowed to articles with \u003ccode\u003e\/search?q=keyword\u0026amp;type=article\u003c\/code\u003e, but \u003cstrong\u003eit always spans every blog in the store, and there is no parameter to limit it to one blog\u003c\/strong\u003e. If your store runs more than one blog, articles from the other blogs end up in the results. This TIPS shows how to scope the search to a single blog without changing a single vendor file.\u003c\/p\u003e\n\n\u003cp\u003e\u003cimg alt=\"A search form on the blog page and a scoped results page\" src=\"https:\/\/cdn.shopify.com\/s\/files\/1\/0733\/0381\/8491\/files\/2026-09-27_1_en.png?v=1790491927\" class=\"zoomable-image\" style=\"max-width:100%;height:auto;\"\u003e\u003c\/p\u003e\n\n\u003cp\u003eA search form on the blog page, and a results page that lists only the articles of that blog. With several blogs, each one can have its own search.\u003c\/p\u003e\n\n\u003cp\u003e\u003cstrong style=\"color:#e0301e;\"\u003e[Relation to earlier TIPS]\u003c\/strong\u003e The earlier \u003ca href=\"\/en-us\/products\/2025-06-08\"\u003earticle search for Dawn blogs\u003c\/a\u003e carried the caveat \"for stores with only one blog\" precisely because of this limitation. This is its sequel, usable on stores with several blogs. The approach is close to \u003ca href=\"\/en-us\/products\/2024-02-06\"\u003esearching only the FAQ pages\u003c\/a\u003e: the filter is based on the URL.\u003c\/p\u003e\n\n\u003ch3\u003eWhat happens with the regular search\u003c\/h3\u003e\n\n\u003cp\u003eEven with \u003ccode\u003etype=article\u003c\/code\u003e, Shopify returns articles from every blog in the store. Below is a search for \"Horizon\" on a store that runs a News blog and a Journal blog; the three results in the red box belong to the Journal blog.\u003c\/p\u003e\n\n\u003cp\u003e\u003cimg alt=\"Storefront search spans every blog\" src=\"https:\/\/cdn.shopify.com\/s\/files\/1\/0733\/0381\/8491\/files\/2026-09-27_2_en.png?v=1790491927\" class=\"zoomable-image\" style=\"max-width:100%;height:auto;\"\u003e\u003c\/p\u003e\n\n\u003ch3\u003eHow it works (three pieces)\u003c\/h3\u003e\n\n\u003cp\u003e\u003cimg alt=\"Let Shopify search, then filter the results\" src=\"https:\/\/cdn.shopify.com\/s\/files\/1\/0733\/0381\/8491\/files\/2026-09-27_3_en.png?v=1790491927\" class=\"zoomable-image\" style=\"max-width:100%;height:auto;\"\u003e\u003c\/p\u003e\n\n\u003cp\u003e\u003cstrong\u003e1. An alternate template (\u003ccode\u003e?view=\u003c\/code\u003e) for the results page\u003c\/strong\u003e\u003cbr\u003e\nWhen a URL carries a \u003ccode\u003eview\u003c\/code\u003e parameter, Shopify renders \u003ccode\u003etemplates\/search.{name}.json\u003c\/code\u003e. The regular \u003ccode\u003e\/search\u003c\/code\u003e keeps working exactly as before while you add a dedicated results page for the blog.\u003c\/p\u003e\n\n\u003cp\u003e\u003cstrong\u003e2. Filter by the article URL\u003c\/strong\u003e\u003cbr\u003e\nLet Shopify run the search, then walk through \u003ccode\u003esearch.results\u003c\/code\u003e and drop every article that does not belong to the target blog. The URL is the reliable signal: an article of the target blog always contains \u003ccode\u003e\/blogs\/\u0026lt;blog handle\u0026gt;\/\u003c\/code\u003e.\u003c\/p\u003e\n\n\u003cp\u003e\u003cstrong\u003e3. Ship both parts as theme blocks\u003c\/strong\u003e\u003cbr\u003e\nThe entry form and the results list are separate theme blocks. Neither occupies a section of its own, and both are placed from \"Add block\" in the theme editor. The form passes \u003ccode\u003etype=article\u003c\/code\u003e and \u003ccode\u003eview={name}\u003c\/code\u003e as hidden fields, so the visitor only types a keyword.\u003c\/p\u003e\n\n\u003ch3\u003eFiles\u003c\/h3\u003e\n\n\u003cp\u003eThree new files, no existing file is modified.\u003c\/p\u003e\n\n\u003cp\u003e\u003cimg alt=\"Three new files in the theme code editor\" src=\"https:\/\/cdn.shopify.com\/s\/files\/1\/0733\/0381\/8491\/files\/2026-09-27_4_en_18305fc9-6791-4bcc-bde5-259f883e1eb1.png?v=1790491927\" class=\"zoomable-image\" style=\"max-width:100%;height:auto;\"\u003e\u003c\/p\u003e\n\n\u003cul\u003e\n\u003cli\u003e\u003ccode\u003eblocks\/blog-search-form.liquid\u003c\/code\u003e (new) — the search form placed on the blog page\u003c\/li\u003e\n\u003cli\u003e\u003ccode\u003eblocks\/blog-search-results.liquid\u003c\/code\u003e (new) — the results page: form plus the filtered article list\u003c\/li\u003e\n\u003cli\u003e\u003ccode\u003etemplates\/search.blog-search.json\u003c\/code\u003e (new) — the results page template, carrying that second block inside Horizon's stock \"section\"\u003c\/li\u003e\n\u003c\/ul\u003e\n\n\u003cp\u003e\u003ccode\u003esections\/main-blog.liquid\u003c\/code\u003e is not touched: you simply add the block from the theme editor. Do not hand-edit \u003ccode\u003etemplates\/blog.json\u003c\/code\u003e either — the theme editor rewrites it.\u003c\/p\u003e\n\n\u003cp\u003e\u003ccode\u003etemplates\/search.blog-search.json\u003c\/code\u003e only declares \"place one of Horizon's stock sections and put the results block inside it\". Settings you leave out fall back to their defaults, so that is enough.\u003c\/p\u003e\n\n\u003cp\u003e\u003cstrong style=\"color:#e0301e;\"\u003eDo not prefix the block filename with \u003ccode\u003e_\u003c\/code\u003e.\u003c\/strong\u003e A leading \u003ccode\u003e_\u003c\/code\u003e makes the block unavailable on the blog page and forces a vendor file edit.\u003c\/p\u003e\n\n\u003ch3\u003eSetting it up in the theme editor\u003c\/h3\u003e\n\n\u003cp\u003eBoth screens are built from \"Add block\". The results page, however, \u003cstrong\u003edoes not appear in the theme editor's page picker\u003c\/strong\u003e: there is only one \"Search\" entry, and alternate templates are not listed. You reach it by building the URL yourself.\u003c\/p\u003e\n\n\u003cp\u003e\u003cstrong style=\"color:#e0301e;\"\u003e1. Place the search form on the blog page\u003c\/strong\u003e\u003c\/p\u003e\n\n\u003cp\u003eOpen Online Store → Themes → Customize, then pick the blog from the page selector. In the sidebar, under Template, use \u003cstrong\u003eAdd block\u003c\/strong\u003e below \"Blog posts\" → category \"Forms\" → \u003cstrong\u003eBlog search form\u003c\/strong\u003e.\u003cbr\u003e\nSet \u003ccode\u003eDestination template view name\u003c\/code\u003e to \u003ccode\u003eblog-search\u003c\/code\u003e and save.\u003c\/p\u003e\n\n\u003cp\u003e\u003cimg alt=\"Step 1 — place the search form on the blog page\" src=\"https:\/\/cdn.shopify.com\/s\/files\/1\/0733\/0381\/8491\/files\/2026-09-27_5_en.png?v=1790491927\" class=\"zoomable-image\" style=\"max-width:100%;height:auto;\"\u003e\u003c\/p\u003e\n\n\u003cp\u003e\u003cstrong style=\"color:#e0301e;\"\u003e2. Open the results page by URL\u003c\/strong\u003e\u003c\/p\u003e\n\n\u003cp\u003eThe editor URL you are on looks like this:\u003c\/p\u003e\n\n\u003cp\u003e\u003ccode\u003ehttps:\/\/admin.shopify.com\/store\/\u003cstrong\u003e{store}\u003c\/strong\u003e\/themes\/\u003cstrong\u003e{theme id}\u003c\/strong\u003e\/editor?previewPath=...\u003c\/code\u003e\u003c\/p\u003e\n\n\u003cp\u003eKeep everything up to \u003ccode\u003e\/editor\u003c\/code\u003e and replace what follows \u003ccode\u003e?\u003c\/code\u003e with:\u003c\/p\u003e\n\n\u003cp\u003e\u003ccode\u003e?previewPath=%2Fsearch%3Fq%3Dtest%26type%3Darticle%26view%3Dblog-search\u003c\/code\u003e\u003c\/p\u003e\n\n\u003cp\u003eThat is the URL-encoded form of \u003ccode\u003e\/search?q=test\u0026amp;type=article\u0026amp;view=blog-search\u003c\/code\u003e. Put a keyword that actually returns results in \u003ccode\u003eq\u003c\/code\u003e so you can see the list. The \u003ccode\u003eview\u003c\/code\u003e value has to match the filename of \u003ccode\u003etemplates\/search.{name}.json\u003c\/code\u003e.\u003c\/p\u003e\n\n\u003cp\u003e\u003cstrong\u003eEnter your store handle and theme ID to get the exact URL.\u003c\/strong\u003e Both are readable from the editor URL you are on: \u003ccode\u003e...\/store\/\u003cstrong\u003ehere\u003c\/strong\u003e\/themes\/\u003cstrong\u003ehere\u003c\/strong\u003e\/editor...\u003c\/code\u003e\u003c\/p\u003e\n\n\u003cdiv class=\"bs-urlgen\" style=\"border:1px solid #dcdfe3;border-radius:10px;padding:18px;margin:18px 0;background:#f7f8fa;\"\u003e\n\u003cdiv style=\"display:flex;gap:14px;flex-wrap:wrap;margin-bottom:14px;\"\u003e\n\u003clabel style=\"font-size:13px;font-weight:700;\"\u003eStore handle (before .myshopify.com)\u003cbr\u003e\u003cinput class=\"bs-shop\" type=\"text\" value=\"your-store\" style=\"margin-top:4px;padding:7px 10px;border:1px solid #c9ced4;border-radius:6px;font:inherit;font-size:14px;min-width:220px;\"\u003e\u003c\/label\u003e\n\u003clabel style=\"font-size:13px;font-weight:700;\"\u003eTheme ID\u003cbr\u003e\u003cinput class=\"bs-theme\" type=\"text\" value=\"000000000\" style=\"margin-top:4px;padding:7px 10px;border:1px solid #c9ced4;border-radius:6px;font:inherit;font-size:14px;min-width:160px;\"\u003e\u003c\/label\u003e\n\u003clabel style=\"font-size:13px;font-weight:700;\"\u003eView name\u003cbr\u003e\u003cinput class=\"bs-view\" type=\"text\" value=\"blog-search\" style=\"margin-top:4px;padding:7px 10px;border:1px solid #c9ced4;border-radius:6px;font:inherit;font-size:14px;min-width:160px;\"\u003e\u003c\/label\u003e\n\u003c\/div\u003e\n\u003ctextarea class=\"bs-out\" readonly rows=\"3\" style=\"width:100%;padding:10px;border:1px solid #c9ced4;border-radius:6px;font-family:SFMono-Regular,Menlo,monospace;font-size:13px;line-height:1.6;background:#fff;resize:vertical;\"\u003e\u003c\/textarea\u003e\n\u003cbutton class=\"bs-copy\" type=\"button\" style=\"margin-top:10px;padding:8px 18px;border:0;border-radius:999px;background:#1a1a1a;color:#fff;font:inherit;font-size:14px;font-weight:700;cursor:pointer;\"\u003eCopy URL\u003c\/button\u003e\n\u003cspan class=\"bs-msg\" style=\"margin-left:10px;font-size:13px;color:#2e7d32;\"\u003e\u003c\/span\u003e\n\u003c\/div\u003e\n\u003cscript\u003e\n(function(){\n  var roots = document.querySelectorAll('.bs-urlgen');\n  Array.prototype.forEach.call(roots, function(r){\n    if (r.dataset.ready) return;\n    r.dataset.ready = '1';\n    var shop = r.querySelector('.bs-shop'), theme = r.querySelector('.bs-theme'),\n        view = r.querySelector('.bs-view'), out = r.querySelector('.bs-out'),\n        btn = r.querySelector('.bs-copy'), msg = r.querySelector('.bs-msg');\n    function build(){\n      var p = '\/search?q=test\u0026type=article\u0026view=' + (view.value || 'blog-search');\n      out.value = 'https:\/\/admin.shopify.com\/store\/' + (shop.value || 'your-store')\n        + '\/themes\/' + (theme.value || '000000000')\n        + '\/editor?previewPath=' + encodeURIComponent(p);\n    }\n    [shop, theme, view].forEach(function(i){ i.addEventListener('input', build); });\n    btn.addEventListener('click', function(){\n      out.select(); out.setSelectionRange(0, 99999);\n      var ok = false;\n      try { ok = document.execCommand('copy'); } catch (e) {}\n      if (!ok \u0026\u0026 navigator.clipboard) { navigator.clipboard.writeText(out.value); ok = true; }\n      msg.textContent = ok ? 'Copied' : '';\n      setTimeout(function(){ msg.textContent = ''; }, 2000);\n    });\n    build();\n  });\n})();\n\u003c\/script\u003e\n\n\u003cp\u003eIf it opened correctly, the template name at the top left of the editor reads \u003cstrong\u003esearch.blog-search\u003c\/strong\u003e. If it still says \"Search\", you are on the default search template.\u003c\/p\u003e\n\n\u003cp\u003e\u003cstrong style=\"color:#e0301e;\"\u003e3. Place the block on the results page\u003c\/strong\u003e\u003c\/p\u003e\n\n\u003cp\u003eIn the sidebar, under Template, use \u003cstrong\u003eAdd block\u003c\/strong\u003e below \"Section\" → category \"Forms\" → \u003cstrong\u003eBlog search results\u003c\/strong\u003e. Pick the target blog in \u003ccode\u003eSearch target blog\u003c\/code\u003e, set \u003ccode\u003eItems fetched per page\u003c\/code\u003e, and save. \u003cstrong\u003eThere is no view name to enter here\u003c\/strong\u003e — it is derived from the template the block sits on.\u003c\/p\u003e\n\n\u003cp\u003e\u003cimg alt=\"Step 2 — open the results page by URL and add the results block\" src=\"https:\/\/cdn.shopify.com\/s\/files\/1\/0733\/0381\/8491\/files\/2026-09-27_6_en.png?v=1790491927\" class=\"zoomable-image\" style=\"max-width:100%;height:auto;\"\u003e\u003c\/p\u003e\n\n\u003cp\u003e\u003cstrong style=\"color:#e0301e;\"\u003e[Careful] A typo in the view name fails silently.\u003c\/strong\u003e An unknown \u003ccode\u003eview\u003c\/code\u003e raises no error; Shopify simply renders the default \u003ccode\u003etemplates\/search.json\u003c\/code\u003e, i.e. the ordinary search results. Check that the name matches in both places: the form block and the template filename.\u003c\/p\u003e\n\n\u003ch3\u003eRunning more than one blog\u003c\/h3\u003e\n\n\u003cp\u003e\u003cstrong\u003eEach blog needs two templates.\u003c\/strong\u003e Not just the results one — \u003cstrong\u003ethe blog page has to be split as well\u003c\/strong\u003e. The view name is stored as a form block setting inside \u003ccode\u003etemplates\/blog.json\u003c\/code\u003e, so if several blogs share that file they all send the same view name and every search lands on the same blog's results.\u003c\/p\u003e\n\n\u003cp\u003eTo add another blog:\u003c\/p\u003e\n\n\u003col\u003e\n\u003cli\u003eCreate \u003ccode\u003etemplates\/blog.{name}.json\u003c\/code\u003e and \u003cstrong\u003eassign it as the theme template in the blog's settings\u003c\/strong\u003e (Content → Blog posts → Manage blogs → the blog)\u003c\/li\u003e\n\u003cli\u003eOpen that blog page in the theme editor, add the form block and set \u003ccode\u003eDestination template view name\u003c\/code\u003e to the new name\u003c\/li\u003e\n\u003cli\u003eCreate \u003ccode\u003etemplates\/search.{name}.json\u003c\/code\u003e under the same name (a copy of the existing one is fine)\u003c\/li\u003e\n\u003cli\u003eOpen it with the step 2 URL (swapping \u003ccode\u003eview\u003c\/code\u003e for the new name) and set the results block's \u003ccode\u003eSearch target blog\u003c\/code\u003e to the new blog\u003c\/li\u003e\n\u003c\/ol\u003e\n\n\u003cp\u003eOnly template JSON multiplies; the two files under \u003ccode\u003eblocks\/\u003c\/code\u003e are shared by every blog.\u003c\/p\u003e\n\n\u003cp\u003e\u003cimg alt=\"One results template per blog\" src=\"https:\/\/cdn.shopify.com\/s\/files\/1\/0733\/0381\/8491\/files\/2026-09-27_7_en.png?v=1790491928\" class=\"zoomable-image\" style=\"max-width:100%;height:auto;\"\u003e\u003c\/p\u003e\n\n\u003ch3\u003eCaveat: pagination is calculated before the filter\u003c\/h3\u003e\n\n\u003cp\u003e\u003cstrong\u003eThe number of pages is decided by the cross-blog hit count that Shopify returns, and the other blogs' articles are removed afterwards.\u003c\/strong\u003e As a result, a page can hold fewer items than the configured amount. If the other blogs' articles happen to cluster on the last page, that page can even come out empty.\u003c\/p\u003e\n\n\u003cp\u003eMeasured example (a store with 1,672 articles in the target blog and 46 in other blogs, searching for \"Flow\"):\u003c\/p\u003e\n\n\u003cul\u003e\n\u003cli\u003eHits returned by Shopify: 171\u003c\/li\u003e\n\u003cli\u003eShown as target-blog articles: 156\u003c\/li\u003e\n\u003cli\u003eRemoved as other-blog articles: 15\u003c\/li\u003e\n\u003cli\u003eItems per page: 20, 20, 20, 20, 20, 20, 20, 16, 0\u003c\/li\u003e\n\u003c\/ul\u003e\n\n\u003cp\u003e\u003cstrong\u003eMitigation:\u003c\/strong\u003e raise the \u003ccode\u003e{% paginate %}\u003c\/code\u003e amount (the ceiling is 250; anything larger is rounded down to 250). Fewer pages means fewer empty or unusually short ones. Around 50 works well in practice and is exposed as a block setting.\u003c\/p\u003e\n\n\u003cp\u003e\u003cimg alt=\"The page count is decided before the filter runs\" src=\"https:\/\/cdn.shopify.com\/s\/files\/1\/0733\/0381\/8491\/files\/2026-09-27_8_en.png?v=1790491927\" class=\"zoomable-image\" style=\"max-width:100%;height:auto;\"\u003e\u003c\/p\u003e\n\n\u003cp\u003e\u003cstrong style=\"color:#e0301e;\"\u003eWhat not to do:\u003c\/strong\u003e never \"fetch 50 and render only the first 20\". Items 21 and beyond would then appear on no page at all, and results would silently go missing. Render the whole filtered set.\u003c\/p\u003e\n\n\u003ch3\u003eNotes\u003c\/h3\u003e\n\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eWhy \u003ccode\u003eview\u003c\/code\u003e and not a custom parameter\u003c\/strong\u003e: Liquid cannot read arbitrary query parameters. The \u003ccode\u003erequest\u003c\/code\u003e object only exposes \u003ccode\u003edesign_mode\u003c\/code\u003e, \u003ccode\u003evisual_preview_mode\u003c\/code\u003e, \u003ccode\u003epage_type\u003c\/code\u003e, \u003ccode\u003ehost\u003c\/code\u003e, \u003ccode\u003eorigin\u003c\/code\u003e, \u003ccode\u003epath\u003c\/code\u003e and \u003ccode\u003elocale\u003c\/code\u003e — no query string. Sending something like \u003ccode\u003e\/search?blog=news\u003c\/code\u003e would leave nothing on the Liquid side to read it, so the dispatch goes through \u003ccode\u003eview\u003c\/code\u003e, which Shopify itself consumes to pick the template\u003c\/li\u003e\n\u003cli\u003eThe search covers article body, title and tags. If you store values such as year and month in tags, those become searchable too\u003c\/li\u003e\n\u003cli\u003eThe filters of Shopify's Search \u0026amp; Discovery app are for products only and do not apply to blog articles\u003c\/li\u003e\n\u003cli\u003eThe form on the results page can be hidden through a setting. It is shown by default so visitors can search again from the results\u003c\/li\u003e\n\u003c\/ul\u003e\n\n\u003ch3\u003eSample code\u003c\/h3\u003e\n\n\u003cp\u003eThe full source of all three files is included with your purchase.\u003c\/p\u003e\n","brand":"STORE DOJO","offers":[{"title":"Default Title","offer_id":50529036271867,"sku":null,"price":0.0,"currency_code":"USD","in_stock":true}],"thumbnail_url":"\/\/cdn.shopify.com\/s\/files\/1\/0733\/0381\/8491\/files\/2026-09-27.png?v=1790433056","url":"https:\/\/store-dojo.com\/en-us\/products\/2026-09-27","provider":"STORE DOJO","version":"1.0","type":"link"}