Shopify Collection Blocks — Injection Workflow
Guide for programmatically inserting Marqo app blocks into Shopify collection templates using the inject script. Covers the full workflow from fresh theme to production-ready, including edge cases and reclone procedures.
Prerequisites
- Shopify access token with
write_themesscope (from the Marqo app's stored session) - Theme ID (from the Shopify admin URL:
themes/<ID>/editor) - Marqo app embed enabled and saved on the target theme (the script auto-detects the extension UUID from this)
Block Types
| Block | Target | What it replaces |
|---|---|---|
grid (marqo-results) | static-collection, static-search | Native product grid |
subcollections (marqo-subcollections) | static-subcollections-featured-collection (simple layouts) | Native subcollection carousels |
featured (marqo-featured-collection) | dynamic-featured-collection sections | Native featured collection carousels/grids |
Quick Start
# Dry run — see what would change without modifying anything
python3 scripts/ecom/inject_marqo_blocks.py \
--shop <store>.myshopify.com \
--theme-id <THEME_ID> \
--token <ACCESS_TOKEN> \
--blocks all \
--exclude collection.found-muji.json \
--dry-run
# Run for real
python3 scripts/ecom/inject_marqo_blocks.py \
--shop <store>.myshopify.com \
--theme-id <THEME_ID> \
--token <ACCESS_TOKEN> \
--blocks all \
--exclude collection.found-muji.json
Script Options
| Flag | Description |
|---|---|
--blocks grid|subcollections|featured|both|all | Which block types to inject. both = grid + subcollections (default). all = grid + subcollections + featured. |
--dry-run | Preview changes without writing to the theme |
--template <name> | Only process a single template (e.g., collection.aroma.json) |
--exclude <names...> | Skip specific templates (e.g., collection.found-muji.json) |
What the Script Does
For each eligible template:
- Reads the template JSON from the Shopify Asset API
- Classifies the
mainsection type and determines eligible blocks - Skips if main is already disabled (previously injected) or if the template type isn't supported
- Injects Marqo app blocks before
main(grid/subcollections) or in place of native featured sections - Disables the native section (
"disabled": true) - Groups consecutive featured collections into a single
appssection to minimize section count - Prunes pre-existing disabled sections if the 25-section Shopify limit would be exceeded
- Writes the modified template back via the Asset API
- Generates a timestamped report file
Featured Collection Settings Mapping
The script extracts settings from native dynamic-featured-collection sections:
| Native setting | Marqo block setting | Notes |
|---|---|---|
collection | collection | Collection handle |
title | title | Heading text (blank = no heading) |
layout | layout | slideshow or grid |
product_count | product_count | Clamped to max 24 |
cta_label | cta_label | CTA button text |
cta_button_style | cta_button_style | primary or secondary |
| — | cta_position | Defaults to bottom (centered black button below carousel) |
| — | header_alignment | Defaults to center |
| — | title_fallback | Defaults to false (blank heading = no heading) |
Title Card Extraction
If a native section has a title_card inner block that is not disabled:
| Native block setting | Marqo setting | Notes |
|---|---|---|
heading | tc_heading | Card heading |
pre_heading | tc_pre_heading | Small text above heading |
cta_label | tc_cta_label | Card button text |
image | tc_image | Background image (Shopify asset ref) |
overlay_color | tc_overlay_color | Overlay background color |
overlay_opacity | tc_overlay_opacity | 0–100 |
text_color | tc_text_color | Text color |
text_alignment | tc_text_alignment | e.g., center-center |
horizontal_size | tc_horizontal_size | Column span (grid only) |
vertical_size | tc_vertical_size | Row span (grid only) |
Disabled title card blocks (hidden in the theme editor) are skipped — the component shows a centered heading instead.
Full Workflow
1. Backup Existing State
Before any changes, save the current settings and any manually-set overrides:
# Save uncollapse state (if re-applying to a recloned theme)
python3 -c "
# See the uncollapse backup script in the Muji integration doc
"
# Save admin UI settings (settings_data.json)
# Use the Shopify Asset API to read config/settings_data.json
2. Enable App Embed
In the Shopify theme editor:
- Go to Theme Customize on the target theme
- Click App embeds (grid icon at top of sidebar)
- Toggle Marqo Search on
- Save (the script will fail if this isn't saved)
3. Dry Run
Always dry run first:
python3 scripts/ecom/inject_marqo_blocks.py \
--shop <store>.myshopify.com \
--theme-id <THEME_ID> \
--token <ACCESS_TOKEN> \
--blocks all \
--dry-run
Check the report for:
- Expected number of injections
- Any errors (section limits, validation)
- Templates being skipped and why
[HAS CUSTOM CSS]flags on featured sections
4. Test on a Single Template
python3 scripts/ecom/inject_marqo_blocks.py \
--shop <store>.myshopify.com \
--theme-id <THEME_ID> \
--token <ACCESS_TOKEN> \
--blocks featured \
--template collection.aroma.json
Verify in the theme editor preview that the block renders correctly.
5. Full Run
python3 scripts/ecom/inject_marqo_blocks.py \
--shop <store>.myshopify.com \
--theme-id <THEME_ID> \
--token <ACCESS_TOKEN> \
--blocks all \
--exclude collection.found-muji.json
6. Post-Injection Steps
Re-apply uncollapse flags
If migrating from an old theme with uncollapse: true on specific blocks:
# Read the saved uncollapse state, find matching blocks on the new theme
# by template name + collection handle, set uncollapse=True, push back
See the Muji integration doc for the full script.
Set fallback collection (if applicable)
For stores with market-based inventory filtering:
# For each marqo-results block on collection pages (not search),
# set fallback_collection and fallback_message in block settings
7. Handle Edge Cases
25-section limit
The script automatically:
- Groups consecutive featured collections into one
appssection - Prunes pre-existing disabled sections
If it still exceeds 25, the template is logged as an error. Handle manually:
- Check how many disabled sections exist
- Remove additional disabled sections (including
mainif already disabled) - Inject the featured blocks manually
Editorial layouts
Templates with >1 dynamic-featured-collection sections (non-main) are classified as "editorial" and skipped by the subcollections logic. Featured blocks are still injected independently.
The tableware template on Muji CA has 6+ featured sections and is skipped entirely — handle manually if needed.
Extension UUID
The Marqo app extension UUID differs per store. The script auto-detects it from config/settings_data.json. If the app embed isn't enabled, the script exits with an error.
Reclone Workflow
When a merchant deploys a new theme version and you need to re-apply Marqo:
- Backup uncollapse state and any custom settings from the old theme
- Clone the live theme in Shopify admin
- Enable Marqo app embed on the clone and save
- Compare old vs new theme templates to check for added/removed templates
- Run the inject script with
--blocks all - Re-apply uncollapse flags from backup
- Re-apply fallback collection settings
- Verify on preview before publishing
# Compare templates between themes
python3 -c "
# Get template keys from both themes via Asset API
# Report added/removed/common
"
Troubleshooting
"Marqo app embed not found"
The app embed isn't enabled or wasn't saved. Go to theme editor > App embeds > enable Marqo Search > Save.
Blocks appear in JSON but not in theme editor
The extension UUID in the block type doesn't match the store's app installation. The script auto-detects the UUID — if you're writing blocks manually, check config/settings_data.json for the correct UUID.
"Setting X must be a valid number"
Native theme stores some range values as strings. The script casts tc_horizontal_size and tc_vertical_size to int(). If you encounter other validation errors, check the Liquid schema types.
"sections: must have a maximum of 25"
Template has too many sections. The script prunes disabled sections automatically, but some templates are too packed. Handle manually by removing additional disabled sections.
Title card not rendering
- Check if the Liquid extension is deployed (the
data-title-cardJSON attribute must include thetc_*fields) - Check if
tc_headingis blank (no title card shown) - Check if the title card block was
disabledin the native theme (skipped by script)
Products showing but title card height wrong
The title card uses ResizeObserver to match sibling product card height. On slow connections, there can be a brief flash at the CSS min-height before syncing. This is a known cosmetic issue.
Key Files
| File | Purpose |
|---|---|
scripts/ecom/inject_marqo_blocks.py | Main injection script |
components/shopify/extensions/marqo-search-theme/blocks/marqo-results.liquid | Grid block template |
components/shopify/extensions/marqo-search-theme/blocks/marqo-subcollections.liquid | Subcollections block template |
components/shopify/extensions/marqo-search-theme/blocks/marqo-featured-collection.liquid | Featured collection block template |
components/shopify/storefront_search/src/vue/FeaturedCollectionApp.ts | Featured collection Vue component |
docs/design/featured-collections-app-block.md | Architecture design doc |