Shopify theme compatibility
Sellerlane implements a deliberately bounded Shopify Online Store 2.0 theme surface. Inside that boundary, compatibility means that the documented syntax, limits, URL shape, validation, and buyer-visible result are enforced and tested. Outside it, Sellerlane rejects or hides the feature instead of accepting a configuration that cannot work.
This page is the normative theme compatibility contract. It was last reconciled with Shopify’s public theme documentation and theme changelog on 14 July 2026. The broader commerce boundary is documented separately in Commerce compatibility and scope.
Compatibility status at a glance
| Surface | Status | Exact boundary |
|---|---|---|
| Online Store 2.0 theme structure | Compatible | Layout, JSON templates, sections, section groups, theme blocks, snippets, config, locales, and assets |
| Liquid parsing | Compatible, fail closed | Unknown, malformed, unclosed, deprecated, or unsupported constructs fail validation |
| JSON templates and section groups | Compatible | Strict schema, order, section/block limits, nesting, and static group references |
| Liquid objects, filters, and tags | Compatible where documented | The Sellerlane reference is the allowlist; undocumented Shopify entries are not implied |
| Dynamic sources | Compatible for documented section/block setting types | Typed picker, exact resource/closest scope, metafields, metaobjects, list projection, and save/runtime validation; no app or Markets sources |
{% form %} | Compatible plus typed extensions | Ten portable forms and eight sellerlane_ forms; passwordless accounts and typed product data |
| Pagination | Compatible | Maximum page size 250 and maximum reachable item 25,000; pageable list settings receive independent hashed parameters |
| Storefront filtering | Compatible for configured product and variant metafields | Shopify parameter grammar, taxonomy category IDs, caps, page reset, and large-result suppression; standard product attributes remain unavailable |
| Localized storefront URLs | Compatible for languages | Primary locale has no prefix; every published non-primary locale has a lowercase prefix |
| Section Rendering API | Compatible | Cart and direct rendering return section HTML and the CSS required by the returned render tree |
| Standard storefront events/actions | Compatible | Current shopify:* browser contract with Sellerlane-owned implementation and aliases |
| Theme assets and CSS subsetting | Compatible | Stable ?v= versioning, immutable live caching, draft no-store, render-tree CSS only |
| Theme editor preview | Compatible runtime, Sellerlane editor UI | Signed/revocable preview session; draft isolation; normal cart and checkout rules |
| Shopify apps and app blocks | Unavailable | No app runtime, app embeds, app blocks, or app-provided settings |
| Markets and selling plans | Unavailable | Language localization only; one store currency; no subscriptions |
| B2B wholesale | Typed Sellerlane extension | shop.b2b_enabled, customer.b2b?, customer.purchasing_personally?, order.b2b, contextual catalog pricing, and the built-in account purchase-identity switcher; Shopify’s company/company_location Liquid objects are not implied |
| Deprecated Liquid | Unavailable | Deprecated Shopify tags and filters are intentionally not supported |
Theme files and validation
A normal Sellerlane storefront theme uses:
layout/theme.liquidtemplates/*.jsonsections/*.liquidsections/*.jsonblocks/*.liquidsnippets/*.liquidconfig/settings_schema.jsonconfig/settings_data.jsonlocales/*.jsonassets/*Normal page templates are JSON so they remain editable as ordered sections.
templates/robots.txt.liquid is the supported Liquid-template exception. A
save, ZIP import, preview validation, or publish is rejected when a path,
extension, JSON shape, Liquid program, schema, reference, or resource limit is
invalid. Validation does not defer a known compiler error until a buyer opens
the page.
The {% section 'name' %} and {% sections 'group' %} references are static:
the name must be a quoted literal. Dynamic file lookup is rejected because it
cannot be validated or safely included in the compiled manifest.
Enforced theme limits
| Resource | Limit |
|---|---|
| Theme name | 50 Unicode characters |
| Files in a theme | 100,000 |
| JSON templates | 1,000 |
| Section groups | 20 |
| Sections in one template or group | 25 |
| Blocks in one section | 50 |
| Effective blocks in one 25-section template/group | 1,250 |
| Nested theme-block depth | 8 |
Files in blocks/ | 300 |
| Ordinary Liquid/code file | 256 KiB |
| JSON template | 512 KiB |
| Section-group JSON | 512 KiB |
settings_schema.json | 512 KiB |
settings_data.json | 1.5 MiB |
| One locale file | 1.5 MiB |
| Non-asset theme source in total | 250 MiB |
| Imported ZIP, compressed | 50 MiB |
| Imported ZIP expansion safety ceiling | 1 GiB |
| One Sellerlane-hosted theme asset | 20 MiB |
| Direct inline file transport | 5 MiB; larger allowed files use signed upload transport |
The 20 MiB asset and 1 GiB ZIP-expansion ceilings are Sellerlane operational security limits. They do not weaken the compatible Liquid or theme structure.
Liquid compiler and runtime
Sellerlane parses Liquid strictly at the theme boundary and again at runtime as a defense in depth. The public Liquid tags, filters, and objects pages are the supported allowlists. Use the storefront filtering guide for query grammar and the data-boundary guide for the buyer-visible Drop and privacy contract.
Important behavior includes:
{% render %}uses an isolated variable scope and supports documented named arguments andfor/withforms.{% section %}renders one statically named section;{% sections %}renders one statically named section group.{% schema %},{% stylesheet %}, and{% javascript %}are file-aware and validated for their legal locations and multiplicity.{% style %}can evaluate Liquid inline.{% stylesheet %}and{% javascript %}cannot contain Liquid and are collected once per source file.article_list,color_palette, andstandard_event_dataare available on the current supported surface.- An unknown tag/filter, malformed expression, unclosed block, invalid schema, or deprecated construct is an error. Sellerlane does not silently echo or ignore it.
- A storefront Liquid render has a 2-second wall-clock budget. Exceeding it terminates the render and returns an error rather than consuming an unbounded buyer request.
This follows Shopify’s stricter Liquid direction without claiming that the two engines are proprietary implementation equivalents. Portability is defined by the documented program result.
Dynamic-source contract
Section and block settings support dynamic sources for text, richtext,
inline_richtext, url, color, image_picker, video, singular
product/collection/page/article/metaobject resources, and their documented list
forms. article_list remains a valid setting type but is not a dynamic-source
target. blog is a Sellerlane-only direct-resource extension and does not imply
a persisted blog_reference metafield type. Global theme settings are not
connectable because they have no stable page or closest.* scope.
The seller backend owns draft persistence and metafield/metaobject definitions.
The buyer preview owns the actual template, section, block, and closest.*
runtime scope graph. The editor sends that snapshot-pinned graph back to the
buyer datasource endpoint, and the seller independently validates the persisted
expression on save. See Dynamic sources for
the exact grammar, compatibility matrix, examples, limits, stale-scope behavior,
and backend ownership model.
Pagination contract
Use {% paginate collection.products by 24 %} around a pageable collection.
Sellerlane enforces the current Shopify storefront limits:
| Rule | Behavior |
|---|---|
Maximum by value | 250 |
| Maximum reachable item | 25,000 |
| Invalid/non-positive page | Normalized to page 1 |
| Page beyond the reachable range | Clamped to the last reachable page |
| Pageable theme-setting lists | Each receives a deterministic hashed page_param |
| Links and anchors | Existing safe query parameters are retained; only that paginator’s page parameter changes |
The independent hashed parameter prevents multiple pageable theme-setting
lists from changing pages together. Ordinary resource lists use the documented
page parameter; place independent resource paginators in separate sections and
refresh them with the Section Rendering API when they must page independently.
Pagination is implemented for collection products, blog articles, article
comments, pages, customer orders, customer addresses, rewards, and the
documented pageable variant surface. A product exposes at most 250 variants,
and a paginated variant page is also capped at 250. variants_count reports
the full supported count.
Form tag contract
The Liquid form tag reference is the
complete field-level contract and includes native and Ajax examples. Supported
forms are:
| Portable form type | Sellerlane behavior |
|---|---|
product | Adds a canonical product variant plus typed modifiers and product-type details |
cart | Updates quantities and note |
contact | Sends a contact enquiry |
customer | Subscribes an email address to marketing; it does not create an account |
customer_login | Starts passwordless email or phone OTP sign-in |
create_customer | Starts passwordless enrollment |
customer_address | Creates or updates an authenticated customer’s address |
localization | Switches to a published language |
new_comment | Submits a blog comment with moderation/spam rules |
storefront_password | Unlocks a password-protected storefront, not a customer account |
Sellerlane also provides sellerlane_otp_verify,
sellerlane_cart_change, sellerlane_cart_offer,
sellerlane_customer_logout, sellerlane_customer_contact,
sellerlane_customer_profile, sellerlane_quote_request, and
sellerlane_stock_notification.
Most portable forms use native POST/redirect/GET behavior. Two Sellerlane
extensions are JSON-only today: sellerlane_customer_logout, whose script must
follow the returned redirect_to, and sellerlane_customer_contact, which only
starts the add-contact workflow. Contact verification is a separate JSON POST
to /account/contacts/verify. Native cart-change and cart-offer redirects record
form state under the base cart and product types rather than the namespaced
extension types.
The canonical OTP flow keeps the identifier out of the URL by using an opaque
challenge ID. The legacy challenge-less error path can still put identifier
in the query string, so new themes should not use it. For ordinary contact
forms, the server requires a valid email and at least one nonempty field; an
HTML required attribute on contact[body] is not an independent server-side
body requirement.
A form owns its action, method, encoding, CSRF input, locale prefix, trusted
resource selectors, and safe return_to. return_to accepts back or a
same-store relative path; external and protocol-relative redirects are rejected.
All form resource IDs are reloaded in the current store before a mutation.
Product data is typed
The product form sends the selected variant in id and can send:
sellerlane[modifiers][MODIFIER_ID][values][],text,number,date, orfile_key;sellerlane[event][slot_start_utc],slot_end_utc, and an allowed host;- typed gift-card recipient data;
- typed digital-delivery data; and
- typed bundle-child selections.
Required modifiers, allowed values, selection counts, text/number/date/file
constraints, price changes, inventory effects, event capacity, host rules, and
product-type rules are all revalidated by the cart service. HTML required
improves the buyer experience; it is never the only enforcement boundary.
Arbitrary Shopify properties[...] are not persisted.
Product view/select and cart-change telemetry is emitted through the standard event contract. It is not trusted as form authority and does not replace the typed product payload.
Storefront filtering and tags
Collection and search themes should render collection.filters or
search.filters and submit a normal GET form. Filter URLs use Shopify’s
public parameter grammar:
| Source | Query parameter | Value contract |
|---|---|---|
| Availability | filter.v.availability | Available/unavailable value supplied by the filter object |
| Price minimum | filter.v.price.gte | Decimal amount in the storefront currency’s major unit |
| Price maximum | filter.v.price.lte | Decimal amount in the storefront currency’s major unit |
| Product tag | filter.p.tag | Merchant tag text, preserving its stored display value |
| Product type | filter.p.product_type | Merchant product type text |
| Vendor | filter.p.vendor | Merchant vendor text |
| Product category | filter.p.t.category | Exact Shopify taxonomy/category ID; __ joins a selected category subtree list |
| Variant option | filter.v.option.OPTION_NAME | Option value; the option suffix is derived from the trusted filter definition |
| Product metafield | filter.p.m.NAMESPACE.KEY | Value allowed by the published filter definition |
| Variant metafield | filter.v.m.NAMESPACE.KEY | Value allowed by the published variant-owner filter definition; matching stays within one variant |
| Standard product attribute | filter.v.t.shopify.KEY | Not emitted or supported; a nonempty trusted manifest excludes it, while manifestless compatibility parsing can treat it as an ordinary variant-option key |
| Sellerlane product kind | filter.p.sellerlane_product_kind | Typed Sellerlane extension for physical, digital, event, gift-card, and related kinds |
filter.p.product_type means the merchant’s product type. It is not repurposed
for Sellerlane’s internal product-kind taxonomy. The explicit
filter.p.sellerlane_product_kind extension keeps portable and platform-specific
semantics separate.
Filter combination and limits
- Repeating values for a configured filter uses the operator in its trusted
definition. Without a manifest, compatibility parsing also accepts the
internal
.allsuffix asAND; themes must not emit that suffix. Different filter sources combine withAND. - Price bounds form one range and use the active currency exponent. A value of
10means ten currency units, including for zero- and three-decimal currencies. - Applying, removing, or clearing a filter resets the relevant pagination parameter so a previously deep page cannot create an empty filtered view.
- Each filter set, and each returned manifest, contains at most 25 filter
definitions. One buyer request accepts at most 30 distinct normalized
filter keys, 50 discrete values per key, and 500 discrete filter
values in total. Repeated values share one key, and
.gte/.lteprice bounds count as one range key. These separate configuration and request limits prevent ambiguous or unbounded queries. Admin configuration prevents duplicate source definitions and uses stable order/caps for legacy rows. - Collection facets are suppressed above 5,000 products. Search facets are suppressed above 100,000 matching results. Product results still render; only the filter UI is unavailable for that result set.
- Public metafield parameters are accepted only when they map to a trusted, enabled filter definition for that store. Internal definition IDs and forged namespace/key parameters are not forwarded.
- Tags remain merchant data. The runtime does not slugify, lowercase, or replace the display value exposed by the tag/filter objects.
Localized URLs
Sellerlane supports published storefront languages without Shopify Markets. The store’s primary locale always uses the bare URL. Every published non-primary locale uses a lowercase locale prefix:
Primary English: /products/examplePublished Hindi: /hi/products/examplePublished English-IN: /en-in/products/exampleThe locale code is canonicalized as a language tag for Liquid data, while the
URL segment is lowercase. Product, collection, page, blog, article, search,
filter, pagination, form-action, and routes URLs retain the active published
prefix. Canonical and alternate-language links use the same mapping.
POST /localization accepts locale_code (with locale and language_code
as compatible aliases), requires a published locale, and redirects safely:
- changing to the primary locale removes an existing published prefix;
- changing to a non-primary locale replaces or adds its prefix;
- path, query, and fragment are retained;
- external, protocol-relative, unknown, and unpublished locale targets are rejected; and
- an unknown locale-looking path prefix returns 404 instead of serving the primary language under a false URL.
Country/catalog and currency switching are intentionally unavailable. See Locales and translation for file fallback and schema-string behavior.
Save, compile, publish, and render
Sellerlane does not reinterpret every live theme file from mutable seller data on each buyer request. The publish path is:
-
Validate paths, sizes, JSON, Liquid syntax, schema, references, and theme limits.
-
Compile the complete immutable version and derive its SHA-256 manifest.
-
Upload compiled bundles beneath the private versioned prefix
_compiled/themes/v1/STORE_ID/THEME_ID/VERSION_ID/. -
Upload the manifest last; its presence is the commit marker.
-
Promote the validated version to live. Buyer requests load the persisted compiled artifact and verify the manifest/hash instead of compiling mutable source at request time.
If compile or persistence fails, publish fails closed and the existing live version remains authoritative. A controlled legacy read/backfill path can migrate an older version, but production does not silently serve a half-written compiled bundle.
Compiled-artifact rollout policy
Buyer and Seller must use the same THEME_COMPILED_ARTIFACTS value. The three
states are deliberately operational, not theme-facing feature flags:
| Value | Behaviour |
|---|---|
off | Validate the live source, but do not require a durable compiled manifest. Use only for local development or the initial deployment step. |
backfill | Validate the exact live snapshot and strictly compile any older version that has no artifact. Bundles are written first and the manifest commit marker last; activation or rollback stops if that marker is still missing. |
strict | Never compile lazily. A missing, non-strict, malformed, or unverifiable compiled artifact blocks activation or rollback until that version is republished. |
Every persisted manifest records strict compiler provenance. Runtime fallback output is never eligible for persistence, including during backfill. Compilation also bounds source reads, transforms, writes, embedded block counts, and bytes so a large but valid theme cannot create unbounded release work.
Roll out in this order: deploy the strict-capable Buyer first, deploy Seller with
both services set to backfill, warm or idempotently republish every existing
live version, and then switch both services to strict. Do not set Seller to
strict before Buyer, and do not leave the two services on different policies.
At runtime the page context supplies live catalog/customer/cart data to the compiled theme. This preserves dynamic commerce while moving parse, schema, reference, and source-collection work out of the hot path.
Assets and CSS subsetting
Theme assets use stable content/version URLs with a ?v= parameter. A live
asset is immutable-cacheable; an editor/draft asset is no-store. Themes must
not add timestamps or random bare query strings for cache busting.
{% stylesheet %} content is collected by the rendered file tree. A full page
ships only the CSS for sections, blocks, and snippets actually rendered. A
Section Rendering API response prepends the required subset as:
<style data-section-stylesheet> /* CSS required by this returned fragment */</style>That makes a section swapped into an existing page visually complete even when its stylesheet was not present in the initial document. Collected JavaScript is deduplicated by source file; theme code should still make component setup idempotent when replacing DOM.
Section rendering and cart updates
Cart add/change/update/clear and direct section-rendering requests can ask for
one or several section IDs. The response returns a map of section ID to HTML.
The platform renders each requested section against the requested safe
same-store sections_url (or the referring page), not against untrusted page
state.
The mutation happens once. The returned cart and sections describe the post-mutation state; a theme does not need to submit the same edit a second time. Replace the targeted wrappers, preserve focus where possible, and rely on the response’s section stylesheet block for newly introduced CSS. See Cart AJAX API.
Bulk cart operations are atomic and accept at most 250 lines. A mixed update can add, update, remove, change the note, and update discount codes as one server transaction. A validation failure does not leave a partially changed cart.
Standard storefront events and actions
Sellerlane installs the current standard action API under both
window.Shopify and window.Sellerlane; both names point to the same
Sellerlane-owned functions. The Shopify namespace is retained because imported
themes legitimately call the portable contract. Internal implementation names
remain Sellerlane names.
Supported event names are:
shopify:product:viewshopify:product:selectshopify:cart:viewshopify:cart:errorshopify:cart:lines-updateshopify:cart:note-updateshopify:cart:discount-updateshopify:search:updateshopify:collection:viewshopify:collection:updateThe default theme emits the product-selection event when the selected variant
changes; cart events after successful lines/note/discount actions; and
collection/search update events after facet navigation. The
standard_event_data: 'view' filter supplies canonical product, collection, or
cart view payloads for the s-view-event component.
Action results expose cart.lines.nodes; browser events expose a flat
cart.lines array, matching the current public contract. getCart reuses an
in-flight request. configure is one-shot, requires an event target, and
flushes pending events. Validation userErrors resolve as action results and do
not emit cart:error; thrown transport/runtime errors reject and emit it.
Sellerlane’s first-party analytics events are separate from this portability bus. A standard event can drive theme coordination without automatically granting a pixel consent or changing server-authoritative cart data.
Preview and editor sessions
A draft preview begins with a short-lived signed token that contains the store, theme/version, and intended preview origin. The buyer service validates the signature, claims, expiry, revocation state, store/version relationship, and origin. It then establishes the preview session and removes the bootstrap token from the visible URL by redirecting to the clean page URL.
Preview responses are isolated from live caching and carry a restrictive CSP. The editor may navigate among page types and locales, but a preview never gains permission to read another store or unpublished version.
Editor interaction surface
The Sellerlane editor is behaviorally compatible for the declared section/block workflow; its React/Chakra UI is not claimed to be a pixel-identical Shopify admin clone.
| Editor behavior | Sellerlane contract |
|---|---|
| Current page/template | Top picker shows the active template/resource and updates after an approved preview navigation |
| Sidebar rows | Section/block icon or representative image thumbnail, nesting, lock/visibility state, and selection highlight |
| Canvas inspection | Blue hover/selection overlay maps the exact runtime section and nested block back to the left tree/right inspector |
| Add from canvas | Overlay + opens the same section/block picker at the exact adjacent position |
| Picker previews | Section presets request a real draft section render when available |
| Add/reorder/duplicate/delete | Supported within schema, parent, depth, and count limits |
| Hide/show | Preserves the instance/settings but excludes it from preview rendering |
| Removed sections | Reversible Removed sections panel until forgotten/saved as documented |
| Copy/paste blocks | Supported for compatible destinations, including allowed nested parents |
| Undo/redo | Buttons and keyboard shortcuts; up to 80 in-memory states with rapid-setting edits merged |
| Restore last session | Best-effort local-browser snapshot, scoped to store/theme/template and offered only against the same saved base revision |
| Inline text editing | Supported only when canvas text maps unambiguously to one text or inline_richtext setting |
| Preview failure | Existing DOM is retained and the exact failed section/reason is surfaced |
| Default theme content | Dedicated form editor for storefront locales/*.json; schema locale files remain code-edited |
See Using the visual editor and Edit default theme content for the merchant workflow and recovery details.
Cart operations in preview call the normal buyer cart service and therefore must satisfy inventory, modifier, CSRF, and checkout rules. Preview is not a test-order emulator and does not bypass payments. For end-to-end order testing, use an isolated test store/payment configuration so the test does not alter a merchant’s production commerce state.
Cookies, CSRF, consent, pixels, and analytics
Cookie definitions and attributes are centralized so their purpose, lifetime,
Secure, HttpOnly, SameSite, path, domain, and deletion behavior can be
audited in one place. Cookies are divided by purpose:
| Purpose | Policy |
|---|---|
| Cart, checkout, authentication, CSRF, storefront password, preview | Strictly necessary; set only for their documented workflow |
| Preferences/localization | Used for the buyer-requested experience and kept separate from advertising |
| Analytics | Written or activated only after the applicable analytics consent |
| Marketing/pixel identifiers | Written or activated only after marketing consent |
Global Privacy Control is treated as a marketing opt-out. Revoking consent stops future non-essential dispatch and clears Sellerlane-managed non-essential identifiers. A third-party pixel is not injected merely because it is configured; it must also pass consent, channel, event allowlist, CSP, and payload policy.
Every state-changing same-origin buyer route uses the centralized CSRF boundary:
a signed readable CSRF cookie/token pair, x-csrf-token or _csrf echo, and
Origin/Referer/fetch-metadata checks. Login/OTP, preview, analytics-context,
visitor, cart, and pixel tokens have distinct purpose-specific claims and are
not interchangeable.
Cloudflare location headers are accepted only from the trusted edge path, normalized, range-checked, and reduced to the fields the analytics model is allowed to retain. A buyer-supplied country, latitude, or longitude header is not trusted as edge geolocation.
S3, R2, and public asset policy
The storage bucket is not the public security boundary. Both S3 and R2 remain private with public-access prevention enabled; the application or edge Worker decides which object classes can be served.
| Object class | Storage/access policy |
|---|---|
Published theme assets from assets/ | Public only through the allowlisted versioned storefront/CDN route; immutable live caching |
| Merchant media intentionally published to buyers | Public only through the media Worker/CDN route with normalized keys, content types, range handling, and the configured CORS policy |
| Public font library | Public through the font route; cross-origin font CORS only |
| Draft theme assets | Preview-authorized route; no-store; not generally public |
| Theme source, config, locales, templates, sections, snippets | Private; never exposed as raw bucket objects |
_compiled/themes/v1/* | Private application artifact; CloudFront/viewer access must be denied |
| Product-modifier uploads, digital files, exports, private documents | Authenticated or short-lived signed access only |
| Sitemap snapshots | Private S3 application data; served by the buyer origin after domain rewrite |
Do not attach an R2 development domain or a whole-bucket custom domain to the
production bucket. The Worker allowlist, not the presence of an assets/
folder name alone, controls public delivery. Likewise, S3 Block Public Access
stays enabled and the CDN must explicitly deny /_compiled/*.
Sitemap, domains, and SEO
The sitemap is generated as a bounded snapshot and stored privately in S3. It is
not a public R2 object. On GET /sitemap.xml, the buyer service applies the
current canonical public origin so one store can serve the correct URLs on its
active custom domain without rebuilding the logical sitemap for every domain
request.
SEO routes such as robots.txt, sitemap, canonical tags, and alternate-language
links are served only for an accepted store origin. The storefront also:
- emits one canonical URL for the active public domain and normalized path;
- emits hreflang links only for published locales and their real localized equivalents;
- avoids indexing preview, editor, checkout/session, and error state URLs;
- preserves locale in product, collection, article, page, pagination, and filter links;
- uses structured product/site data derived from canonical server data; and
- prevents query-only filter/sort/pagination state from becoming competing canonical pages.
Current Shopify changelog coverage
The compatibility review includes these current public theme changes:
| Shopify change | Sellerlane status |
|---|---|
| Stricter Liquid syntax validation | Implemented at save/import/publish and runtime |
article_list setting | Implemented |
Standardized asset URL ?v= parameters | Implemented |
| Automatic stylesheet subsetting | Implemented for full pages and section fragments |
Storefront agents.md, llms.txt, and llms-full.txt discovery | Implemented |
color_palette setting | Implemented |
| Standard storefront events and actions | Implemented |
| App-block maximum increase | Not applicable because apps/app blocks are intentionally unavailable |
Upstream references: Shopify theme changelog, theme architecture limits, Liquid form tag, storefront filtering, pagination limits, stylesheet subsetting, and standard events/actions.
Deliberate differences and open work
Do not describe these as strict parity:
- standard product attribute filters (
filter.v.t.shopify.*) because the enabled taxonomy attribute identity and custom-value Metaobject GID mapping are not persisted yet; - metaobject
system.urlcurrently normalizes a fallback URL even when the definition lacks the online-store capability; the corresponding page route still refuses to render, so themes must link it only for web-enabled types; - Shopify apps, app blocks, app embeds, and app checkout extensions;
- Shopify Markets country/catalog/currency switching;
- Shopify’s B2B Liquid surface —
company/company_locationobjects and Markets-based contextual pricing fields. Sellerlane B2B wholesale (companies, locations, negotiated catalogs, terms) exists as a typed extension whose Liquid contract is documented on theshop,customer,order,product, andvariantobject pages; - password-based customer account activation/recovery/reset forms;
- selling plans/subscriptions;
- arbitrary cart
attributes[...]and lineproperties[...]persistence; - deprecated Shopify Liquid tags/filters;
- full RFC 9421/Web Bot Auth crawler signatures (Sellerlane currently has a store-scoped token-hash v1 contract); and
- Shopify-proprietary network, fraud, Shop, or payment signals.
Sellerlane’s typed modifiers, event bookings, digital delivery, gift cards, bundles, quote requests, stock alerts, OTP accounts, loyalty, B2B wholesale, and other namespaced features are Sellerlane extensions. They can exceed Shopify core in product breadth without making a Shopify-portability claim.
Store-wide password access, home-page SEO/social metadata, spam protection, crawler tokens, locale behavior, and pixel navigation are documented in Online store preferences.
Release and operations checklist
Before declaring a theme-runtime release ready:
-
Run strict validation against the default theme and malformed fixtures.
-
Run buyer typecheck, build, production dependency audit, and the full buyer test suite.
-
Run seller targeted theme/filter/cart tests and the full Go suite.
-
Build the marketing documentation and verify internal links.
-
Typecheck and dry-run the R2 Worker for the production environment.
-
Verify S3 Block Public Access, compiled-prefix application permissions, and CDN denial for
/_compiled/*. -
Verify the R2 Worker/custom-domain migration and restricted CORS policy before removing a legacy public endpoint.
-
Exercise publish, rollback, preview revocation, localized navigation, cart mutation, section replacement, consent changes, sitemap custom-domain rewrite, and filter/pagination reset in a staging store.
The code test gate proves application behavior. IAM, bucket public-access, CloudFront, R2 custom-domain, Worker deployment, and CORS changes must also be applied and verified in the live cloud account; repository policy files alone do not change deployed infrastructure.