Companion to the September SEO re-audit (64/100), written for the developer joining the project. Every task below names the exact file or admin screen, verified against the live site and repo on 2–7 Sept. Read the safety rules first — this repo deploys to a live store serving 14 markets, and it has bitten people.
These are not conventions — each one exists because violating it caused a real production incident.
shopify theme push. It full-mirrors and has wiped a colleague's draft-theme edits with no undo. Always --only <file>, and never push settings_data.json or template JSON to a theme that has editor state.{% # %} comments need # on every line; theme check does NOT catch it). After any promotion, verify per-FILE: shopify theme pull the file and diff it against your commit.data-cookieconsent="ignore" (js-variables → theme.settings, jquery, vendor, theme.js, slick) must stay a complete set — a partial change reorders boot and once killed add-to-cart for every first-time EU visitor for a day (store CR −32%). Any change to script loading/order/consent attrs needs a fresh pre-consent EU pageview test.shopify theme dev silently rewrites uncommitted JSON settings edits — never ship settings/template JSON that sat in the working tree while dev ran. Also: sections/collection-*-schema.liquid keep vanishing and break theme dev; restore from commit 8158327.nb_free_gift_enabled); the EG app embed is disabled but the app stays installed as rollback insurance. NanoBag/, Theme without Code updates/, backups/ are reference copies — never edit. Desktop breakpoint is 992px, not the base theme's 1024.No theme code involved. All four are Shopify admin changes; the theme repo is untouched.
The six *-meta-catalog products (ads-feed-only) are back in sitemap_products_1.xml — the seo.hidden metafield got wiped somewhere. They're now sitemap-listed and robots-blocked, the worst combination.
seo.hidden = 1 (namespace seo, key hidden, integer)curl -A "Mozilla/5.0" "https://nanobag.com/sitemap_products_1.xml?..." → expect 7 product URLs, zero meta-catalogseo.hidden only removes them from the sitemap.In the sitemap today: /collections/eg-gift-app (internal gift plumbing), /collections/sellable-bags, /collections/nanobag-1, six placeholder style collections serving stock Shopify filler text, /pages/page (stale Winter Sale LP), and /pages/go-nanobag-eu (a 200 JS-redirect page with no <title> at all).
seo.hidden = 1 metafield on each collection/page. Alternative for the style collections (standard/xl/sling/micro/air/pack): write 2–3 real sentences each and keep them — they're plausible landers for style queries. Ask Shubham which way before doing it.sitemap_collections_1.xml / sitemap_pages_1.xmlOne description (shared by 8 products including the entire Meta ads feed) still sells the discontinued Mini and Air and contradicts the on-page comparison table on all six weights. The schema also leaks the internal name "Nanobag - US" as the ProductGroup name. One rewrite propagates everywhere at once: page, JSON-LD, ads feed, MCP catalog.
description no longer mentions Mini/Air; name is customer-facingPOST nanobag.com/api/mcp → search_catalog("reusable shopping bag") returns 10 products: all six meta-catalog products plus market duplicates — and omits the canonical reusable-shopping-bags entirely. Any AI shopping agent asking what Nanobag sells gets the ads-only catalog. seo.hidden does not filter MCP; Online Store channel publication does.
curl -X POST https://nanobag.com/api/mcp -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"search_catalog","arguments":{"query":"reusable shopping bag"}}}'Judge.me server-renders data-average-rating='4.84' / 708 reviews (note: single quotes — double-quote greps miss it), but no schema block on the site emits aggregateRating. Third audit in a row. This unlocks star ratings in product SERPs.
layout/theme.liquid (existing schema blocks live around lines 328–486 on the Shubham branch; re-check against main) reading Judge.me's synced metafields (product.metafields.reviews.rating.value / reviews.rating_count.value — verify they're populated before relying on them). Emit a Product node with aggregateRating using the same @id the native ProductGroup uses so Google merges them./products/reusable-shopping-bags — must show Product with rating, no errors. Curl the raw HTML too: grep -c aggregateRating → ≥1.Commit e12ee58 ("defer jquery+slick, drop Font Awesome, async slick.css, cap video poller" — touches layout/theme.liquid, sections/new-video-slideshow.liquid, snippets/modal-video.liquid) sits on the Shubham branch, never promoted. Live head still loads jquery.min.js and slick.js parser-blocking. Lighthouse mobile today: PDP 30/100, LCP 13.8s, TBT 10s.
e12ee58 onto a fresh branch off current origin/main — do not port files wholesale; the commit is 14 months of drift old, resolve conflicts against main's current file versions line by line.--only the 3 files), then: (a) fresh pre-consent EU pageview — variant picker, add-to-cart, and gallery must work before accepting cookies; (b) new-video-slideshow sections still initialize (that section historically needed parser-blocking jQuery — this is exactly the conflict to test); (c) after promotion, CLI-pull each of the 3 files and diff vs the commit (rule 3).qa-bot has a consent-guard check (QA_CONSENTCHECK=1) that watches this invariant — run it.{!= form_name !} H1 leak ThemeA literal Zipify template string ships as a real second <h1> on the PDP, homepage, and pages: <h1 class="zpa-crm-popup-title">{!= form_name !}</h1>. Source found: snippets/page-footer.zipifypages.liquid.
<template> tags, or if the Zipify CRM popup is confirmed dead, remove the render. Check first whether any live page actually uses the popup.curl -s https://nanobag.com/ | grep -c 'form_name' → 0, and the PDP drops to one <h1>*.zipifypages.liquid snippets are written by the Zipify Pages app — it may regenerate the file on its next publish. Note the change somewhere durable, and if Zipify is still actively used, prefer the <template> wrap (survives regeneration semantics better than deletion) and re-check after any Zipify publish.Google sees <h1>Standard Black</h1> on the money page. Root cause is deliberate code in sections/new-main-product.liquid:283: unless product.has_only_default_variant → h1_title = selected_or_first_available_variant.options | join ' '.
product.title; render the variant options in a non-heading element below it. But: the PDP variant shim rewrites this title client-side on variant change (the "XL-Duck" title behavior) and the <split-words> animation wrapper has its own NBSP-eating gotcha (shielded in commit 8663c98). Read the shim before changing the markup — the shim must keep targeting whatever element now carries the variant text.curl shows the product name in the H1/de-de/products/reusable-shopping-bags serves the byte-identical English title tag and meta description — product-level SEO fields were never translated (bodies and homepages are). Every non-English market competes in Google with an English snippet.
translationsRegister pattern — working examples in scripts/register-homepage-translations.mjs and scripts/register-pl-website.mjs (GraphQL Admin API, one-off Node scripts, npm only). Target the product resource's meta_title / meta_description translatable keys per locale.curl -A "Mozilla/5.0" https://nanobag.com/de-de/products/reusable-shopping-bags | grep '<title>' → German40 of 138 <img> on the PDP lack alt text. Part of the remainder is payment/review-widget SVGs — ignore those. The repo has a ready-made worklist: nanobag-alt-text-audit.html in the theme repo root covers the product gallery set. Alt lives on the images in Shopify admin, not in theme code.
How changes actually reach production here.
--only → Shubham reviews and QAs → single verified commit is cherry-picked to main → per-file CLI-pull verification. You never publish.NANOBAG-DOCS.md (repo root) is the status board + shiplog — dated entry in the same session it goes live.templates/*.context.<market>.json files are deliberate — never collapse or "clean up". Market context files override parent template content.