Skip to main content

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_themes scope (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

BlockTargetWhat it replaces
grid (marqo-results)static-collection, static-searchNative product grid
subcollections (marqo-subcollections)static-subcollections-featured-collection (simple layouts)Native subcollection carousels
featured (marqo-featured-collection)dynamic-featured-collection sectionsNative 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

FlagDescription
--blocks grid|subcollections|featured|both|allWhich block types to inject. both = grid + subcollections (default). all = grid + subcollections + featured.
--dry-runPreview 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:

  1. Reads the template JSON from the Shopify Asset API
  2. Classifies the main section type and determines eligible blocks
  3. Skips if main is already disabled (previously injected) or if the template type isn't supported
  4. Injects Marqo app blocks before main (grid/subcollections) or in place of native featured sections
  5. Disables the native section ("disabled": true)
  6. Groups consecutive featured collections into a single apps section to minimize section count
  7. Prunes pre-existing disabled sections if the 25-section Shopify limit would be exceeded
  8. Writes the modified template back via the Asset API
  9. Generates a timestamped report file

The script extracts settings from native dynamic-featured-collection sections:

Native settingMarqo block settingNotes
collectioncollectionCollection handle
titletitleHeading text (blank = no heading)
layoutlayoutslideshow or grid
product_countproduct_countClamped to max 24
cta_labelcta_labelCTA button text
cta_button_stylecta_button_styleprimary or secondary
cta_positionDefaults to bottom (centered black button below carousel)
header_alignmentDefaults to center
title_fallbackDefaults 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 settingMarqo settingNotes
headingtc_headingCard heading
pre_headingtc_pre_headingSmall text above heading
cta_labeltc_cta_labelCard button text
imagetc_imageBackground image (Shopify asset ref)
overlay_colortc_overlay_colorOverlay background color
overlay_opacitytc_overlay_opacity0–100
text_colortc_text_colorText color
text_alignmenttc_text_alignmente.g., center-center
horizontal_sizetc_horizontal_sizeColumn span (grid only)
vertical_sizetc_vertical_sizeRow 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:

  1. Go to Theme Customize on the target theme
  2. Click App embeds (grid icon at top of sidebar)
  3. Toggle Marqo Search on
  4. 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 apps section
  • Prunes pre-existing disabled sections

If it still exceeds 25, the template is logged as an error. Handle manually:

  1. Check how many disabled sections exist
  2. Remove additional disabled sections (including main if already disabled)
  3. 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:

  1. Backup uncollapse state and any custom settings from the old theme
  2. Clone the live theme in Shopify admin
  3. Enable Marqo app embed on the clone and save
  4. Compare old vs new theme templates to check for added/removed templates
  5. Run the inject script with --blocks all
  6. Re-apply uncollapse flags from backup
  7. Re-apply fallback collection settings
  8. 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-card JSON attribute must include the tc_* fields)
  • Check if tc_heading is blank (no title card shown)
  • Check if the title card block was disabled in 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

FilePurpose
scripts/ecom/inject_marqo_blocks.pyMain injection script
components/shopify/extensions/marqo-search-theme/blocks/marqo-results.liquidGrid block template
components/shopify/extensions/marqo-search-theme/blocks/marqo-subcollections.liquidSubcollections block template
components/shopify/extensions/marqo-search-theme/blocks/marqo-featured-collection.liquidFeatured collection block template
components/shopify/storefront_search/src/vue/FeaturedCollectionApp.tsFeatured collection Vue component
docs/design/featured-collections-app-block.mdArchitecture design doc