Products and listings SDK reference
Product, collection, search, review, variant and recommendation views.
Import these public values from @upstorr/theme-sdk/v1. Do not import their internal source files.
buildThemeProductRecommendationsUrl
buildThemeProductRecommendationsUrl(input: ThemeProductRecommendationsInput): string
createThemeCollectionCardView
createThemeCollectionCardView<TCollection extends { id?: string | null; title?: string | null; handle?: string | null; url?: string | null; }>(input: { collectionSetting: unknown; closestCollection?: TCollection | null; title?: unknown; label?: unknown; link?: unknown; }): { readonly collection: TCollection | { id: string; handle: string; title: string; imageUrl: string | null; url: string | null; } | null; readonly title: string; readonly href: string; readonly isPlaceholder: boolean; }
createThemeCollectionCountView
createThemeCollectionCountView(value: unknown): { readonly visible: false; readonly count: 0; } | { readonly visible: true; readonly count: number; }
createThemeCollectionLinksView
createThemeCollectionLinksView<TCollection extends { id: string; title: string; handle: string; imageUrl?: string | null; products_count?: number | null; all_products_count?: number | null; }>(input: { collections: TCollection[]; activeCollection?: { id?: string | null; handle?: string | null; } | null; showCount: boolean; }): { readonly collections: TCollection[]; readonly initialActiveIndex: number; readonly locals: (collection: TCollection, index: number, activeCollectionId: string | null) => { current: boolean; loading: string | undefined; count: string | number; count_value: string | number; placeholder_name: string; index: number; }; }
createThemeCollectionListingView
createThemeCollectionListingView<TProduct>(collection: ThemeCollectionListing<TProduct> | null | undefined): { readonly products: TProduct[]; readonly isEmpty: boolean; readonly resetHref: string; readonly pagination: ThemePaginationView; readonly loadMore: ThemePaginationDirectionView; }
createThemeCollectionListView
createThemeCollectionListView<TCollection extends { id: string; title: string; handle: string; imageUrl?: string | null; }>(input: { sectionType: string; collectionListSetting: unknown; collections: TCollection[]; collectionsProvided: boolean; layout: unknown; columns: unknown; maxCollections: unknown; }): { readonly collections: TCollection[]; readonly selectedReferences: string[]; readonly limit: number; }
createThemeCustomerReviewsView
createThemeCustomerReviewsView<TReview extends ThemeReviewInput>(input: { productReviews?: ThemeReviewsInput<TReview> | null; reviewsCount: unknown; columns: unknown; initialReviews: unknown; reviewsPerClick: unknown; }): { readonly reviews: TReview[]; readonly columns: number; readonly initialReviews: number; readonly reviewsPerClick: number; readonly canShowMore: boolean; readonly loop: (index: number) => { index: number; index0: number; first: boolean; last: boolean; length: number; }; }
createThemeFiltersView
createThemeFiltersView(input: { search?: ThemeFilterSource | null; collection?: ThemeFilterSource | null; products?: ThemeListingProduct[]; resultsSize?: unknown; currentCurrency: string; showFilterLabel: boolean; }): ThemeFiltersView
createThemeGiftCardLineMetadata
createThemeGiftCardLineMetadata(input: ThemeGiftCardPurchaseInput): ThemeCartLineMetadata
createThemePaginationView
createThemePaginationView(input: { pagination?: ThemeListingPagination | null; total: number; hrefForPage: (page: number) => ThemeListingHref; }): ThemePaginationView
createThemeProductAvailabilityView
createThemeProductAvailabilityView(product: ThemeProductPurchaseProduct | null | undefined): { readonly available: boolean; }
createThemeProductBadgeView
createThemeProductBadgeView(product: ThemeProductPurchaseProduct, selectedVariant?: ThemeProductPurchaseVariant | null): { visible: boolean; kind: "sold-out" | "sale"; label: string; }
createThemeProductCartLineMetadata
createThemeProductCartLineMetadata(input: { isGiftCardProduct: boolean; giftCardPurchase: ThemeGiftCardPurchaseForm; customProperties: ThemeProductCustomPropertyCollection | null; }): ThemeCartLineMetadata | null
createThemeProductCustomProperties
createThemeProductCustomProperties(collection: ThemeProductCustomPropertyCollection | null): Record<string, string> | null
createThemeProductHotspotView
createThemeProductHotspotView(product: ThemeProductPurchaseProduct | null | undefined, currentCurrency: string): ThemeProductHotspotView
createThemeProductInformationView
createThemeProductInformationView<TVariant extends ThemeProductPurchaseVariant, TProduct extends ThemeProductPurchaseProduct<TVariant>>(input: { product: TProduct; selectedVariant?: TVariant | null; hasMediaBlock: boolean; hideUnselectedVariantMedia: boolean; recommendationProducts: TProduct[]; }): { readonly hasMedia: boolean; readonly mediaImages: string[]; readonly recommendations: { readonly performed: boolean; readonly products: TProduct[]; readonly products_count: number; }; }
createThemeProductInventoryView
createThemeProductInventoryView(product: ThemeProductPurchaseProduct | null | undefined, selectedVariant: ThemeProductPurchaseVariant | null | undefined, options: { threshold: unknown; showQuantity: boolean; }): { visible: boolean; productId: string; status: "in_stock" | "out_of_stock" | "low"; label: string; }
createThemeProductListButtonView
createThemeProductListButtonView(collection: { handle?: unknown; url?: unknown; products_count?: unknown; all_products_count?: unknown; products?: unknown[]; } | null | undefined, maxProducts: unknown): { readonly visible: boolean; readonly href: string; }
createThemeProductListView
createThemeProductListView<TProduct, TCollection extends { id: string; title: string; handle: string; products_count?: number | null; }>(input: { products: TProduct[]; maxProducts: unknown; collection?: TCollection | null; collectionSetting?: unknown; }): { readonly limit: number; readonly products: TProduct[]; readonly items: (TProduct | null)[]; readonly collection: { id: string; handle: string; title: string; products: TProduct[]; products_count: number; } | null; }
createThemeProductMetafieldsView
createThemeProductMetafieldsView(product: { metadata?: Record<string, unknown> | null; category?: { template?: unknown; } | null; }): { key: string; label: string; value: string; }[]
createThemeProductPriceView
createThemeProductPriceView(product: ThemeProductPurchaseProduct | null | undefined, selectedVariant: ThemeProductPurchaseVariant | null | undefined, options: { currencyCode: string; showCurrencyCode?: boolean; showSalePriceFirst?: boolean; }): ThemeProductPriceView
createThemeProductPurchaseVariants
createThemeProductPurchaseVariants<TVariant extends ThemeProductPurchaseVariant>(product: ThemeProductPurchaseProduct<TVariant>): TVariant[]
createThemeProductQuickAddView
createThemeProductQuickAddView<TVariant extends ThemeProductPurchaseVariant>(product: ThemeProductPurchaseProduct<TVariant> & { options?: Array<{ name?: string; values?: string[]; }>; }, variants: TVariant[], isPurchasable: boolean, isUpdating: boolean): { readonly mode: "add" | "choose"; readonly optionCount: number; readonly canAdd: boolean; readonly disabled: boolean; readonly addLabel: "Adding" | "Add"; readonly addAriaLabel: "Add"; readonly chooseLabel: "Choose"; readonly chooseAriaLabel: "Choose"; }
createThemeProductRatingView
createThemeProductRatingView(input: { reviewSummary?: ThemeReviewSummaryInput | null; starsStyle: string; showNumber: boolean; }): { readonly value: number; readonly scaleMax: 5; readonly stars: ThemeReviewStarView[]; readonly filledStars: number; readonly showNumber: boolean; readonly ratingLabel: string; readonly reviewCount: number; readonly reviewCountLabel: `${number} Reviews`; readonly ariaLabel: `${number} out of 5 stars`; } | null
createThemeProductRecommendationsContext
createThemeProductRecommendationsContext<TProduct>(products: TProduct[], performed: boolean): { readonly performed: boolean; readonly products: TProduct[]; readonly products_count: number; }
createThemeProductRecommendationsView
createThemeProductRecommendationsView<TProduct extends ThemeProductPurchaseProduct>(input: { products: TProduct[]; closestProduct: TProduct | null | undefined; productReference?: unknown; maxProducts: unknown; baseUrl: string; sectionId?: string; }): { readonly mode: "products" | "placeholders" | "skeletons"; readonly products: TProduct[]; readonly items: { key: string; kind: "product"; product: TProduct; index: number; resourceId: string; }[] | { key: string; kind: "placeholder" | "skeleton"; product: null; index: number; resourceId: string; }[]; readonly listItems: (TProduct | null)[]; readonly hasVisibleItems: boolean; readonly hasProductContext: boolean; readonly recommendations: { readonly performed: boolean; readonly products: TProduct[]; readonly products_count: number; }; readonly runtimeProps: { readonly 'data-url': string; readonly 'data-section-id': string | undefined; readonly 'data-product-id': string | undefined; readonly 'data-intent': string; readonly 'data-recommendations-performed': "true" | "false"; }; }
createThemeProductStickyBarView
createThemeProductStickyBarView(product: ThemeProductPurchaseProduct, selectedVariant: ThemeProductPurchaseVariant | null | undefined, canAddToCart: boolean): { readonly title: string; readonly image: string | null; readonly variantTitle: string; readonly canAddToCart: boolean; }
createThemeProductSwatchValues
createThemeProductSwatchValues<TVariant extends ThemeProductPurchaseVariant>(product: ThemeProductPurchaseProduct<TVariant>, showVariantImage: boolean): ThemeProductSwatchView[]
createThemeProductVariantPickerView
createThemeProductVariantPickerView<TVariant extends ThemeProductPurchaseVariant>(product: ThemeProductPurchaseProduct<TVariant> & { options?: Array<{ name?: string; values?: string[]; }>; }, variants: TVariant[], selectedVariantId: string): { visible: boolean; groups: { key: string; name: string; optionIndex: number; selectedValue: string; variantIdForValue: (value: string) => string | null; choices: { value: string; variant: TVariant | null; variantId: string | null; selected: boolean; disabled: boolean; }[]; }[]; }
createThemeQuickOrderListView
createThemeQuickOrderListView<TProduct extends ThemeProductPurchaseProduct>(input: { products: TProduct[]; variantsPerPage: unknown; showImage: boolean; showSku: boolean; }): { readonly items: { key: string; product: TProduct; title: string; href: string; image: string; sku: string; }[]; readonly limit: number; }
createThemeReviewBreakdownView
createThemeReviewBreakdownView<TReview extends ThemeReviewInput>(productReviews: ThemeReviewsInput<TReview> | null | undefined, showEmptyRows: boolean): { readonly visible: boolean; readonly totalReviews: number; readonly rows: { rating: number; count: number; percentage: number; }[]; }
createThemeReviewCardView
createThemeReviewCardView<TReview extends ThemeReviewInput>(review: TReview): { readonly review: TReview; readonly reviewerName: string; readonly dateLabel: string; readonly media: ({ type: "image"; src: string; } | { type: "video"; src: string; })[]; readonly stars: ThemeReviewStarView[]; }
createThemeReviewStars
createThemeReviewStars(value: unknown, scaleMax?: number, snapHalf?: boolean): ThemeReviewStarView[]
createThemeSearchInputView
createThemeSearchInputView(input: { query: unknown; resultsCount: unknown; searchUrl: string; noResultsTemplate: string; }): { readonly query: string; readonly showNoResults: boolean; readonly noResultsText: string; readonly resetHref: string; }
createThemeSearchListingView
createThemeSearchListingView<TProduct>(input: { products: TProduct[]; resultsCount: unknown; pagination?: ThemeListingPagination | null; currentUrl?: string | null; }): { readonly products: TProduct[]; readonly resultsCount: number; readonly isEmpty: boolean; readonly pagination: ThemePaginationView; readonly loadMore: ThemePaginationDirectionView; }
createThemeVariantSwatchView
createThemeVariantSwatchView(value: string, variant: ThemeProductPurchaseVariant | null | undefined, showVariantImage: boolean): { value: string; isVariantImage: boolean; }
formatThemeReviewDate
formatThemeReviewDate(value: unknown): string
getFirstThemeProductVariant
getFirstThemeProductVariant<TVariant extends ThemeProductPurchaseVariant>(product: ThemeProductPurchaseProduct<TVariant> | null | undefined): TVariant | null
getThemeProductImages
getThemeProductImages(product: ThemeProductPurchaseProduct | null | undefined): string[]
getThemeProductPageMediaImages
getThemeProductPageMediaImages<TVariant extends ThemeProductPurchaseVariant>(product: ThemeProductPurchaseProduct<TVariant>, selectedVariant?: TVariant | null, hideUnselectedVariantMedia?: boolean): string[]
getThemeProductRecommendationsProps
getThemeProductRecommendationsProps(input: ThemeProductRecommendationsInput): { readonly 'data-url': string; readonly 'data-section-id': string | undefined; readonly 'data-product-id': string | undefined; readonly 'data-intent': string; readonly 'data-recommendations-performed': "true" | "false"; }
getThemeProductVariantImage
getThemeProductVariantImage(variant: ThemeProductPurchaseVariant | null | undefined): string
getThemeProductVariantImages
getThemeProductVariantImages(variant: ThemeProductPurchaseVariant | null | undefined): string[]
getThemeProductVariantOptionValue
getThemeProductVariantOptionValue(variant: ThemeProductPurchaseVariant | null | undefined, optionName: string | undefined, optionIndex: number): string
getThemeProductVariants
getThemeProductVariants<TVariant extends ThemeProductPurchaseVariant>(product: ThemeProductPurchaseProduct<TVariant> | null | undefined): TVariant[]
hasThemeProductVariantChoices
hasThemeProductVariantChoices(product: ThemeProductPurchaseProduct | null | undefined): boolean
isThemeProductOnSale
isThemeProductOnSale(product: ThemeProductPurchaseProduct, selectedVariant?: ThemeProductPurchaseVariant | null): boolean
normalizeThemeProductPurchaseQuantity
normalizeThemeProductPurchaseQuantity(value: unknown): number
readThemeProductReference
readThemeProductReference(value: unknown): string
readThemeSearchRouteData
readThemeSearchRouteData<TProduct = unknown, TSortOption = unknown, TFilter = unknown, TPagination = unknown>(data: unknown): ThemeSearchRouteData<TProduct, TSortOption, TFilter, TPagination>
resolveThemeProductImageAspectRatio
resolveThemeProductImageAspectRatio(requestedRatio: unknown, product: ThemeProductPurchaseProduct | null | undefined): string
selectInitialThemeProductVariantId
selectInitialThemeProductVariantId<TVariant extends ThemeProductPurchaseVariant>(product: ThemeProductPurchaseProduct<TVariant>, variants: TVariant[]): string
THEME_DEFAULT_GIFT_CARD_PURCHASE
THEME_DEFAULT_GIFT_CARD_PURCHASE: ThemeGiftCardPurchaseForm
THEME_DEFAULT_SORT_OPTIONS
THEME_DEFAULT_SORT_OPTIONS: ThemeSortOptionInput[]
ThemeFilterInput
type ThemeFilterInput = {
type: 'boolean' | 'list' | 'price_range';
label: string;
param_name: string;
values?: ThemeFilterValueInput[];
active_values?: ThemeFilterValueInput[];
min_value?: { value?: number | null } | null;
max_value?: { value?: number | null } | null;
range_max?: number | null;
currency?: string | null;
url_to_remove?: string | null;
};
ThemeFiltersView
type ThemeFiltersView = {
productsCount: number;
productsCountLabel: string;
seeResultsLabel: string;
filters: ThemeFilterView[];
activePills: Array<{ key: string; label: string; href: string }>;
activeFilterCount: number;
currentSort: string;
sortOptions: ThemeSortOptionInput[];
defaultSort: string;
resultsUrl: string;
terms: string;
currency: string;
};
ThemeFilterValueInput
type ThemeFilterValueInput = {
value: string;
label: string;
count?: number;
active?: boolean;
url_to_remove?: string;
};
ThemeFilterValueView
type ThemeFilterValueView = ThemeFilterValueInput & {
active: boolean;
disabled: boolean;
};
ThemeFilterView
type ThemeFilterView = {
type: ThemeFilterInput['type'];
label: string;
paramName: string;
activeCount: number;
values: ThemeFilterValueView[];
price: null | {
minValue: number | null;
maxValue: number | null;
highestPrice: number;
highestPriceInput: string;
highestPriceLabel: string;
currency: string;
currencyLabel: string;
active: boolean;
};
};
ThemeGiftCardPurchaseForm
type ThemeGiftCardPurchaseForm = {
deliveryType: 'SELF' | 'RECIPIENT';
recipientEmail: string;
recipientName: string;
recipientMessage: string;
sendAt: string;
};
ThemeGiftCardPurchaseInput
type ThemeGiftCardPurchaseInput = {
deliveryType?: 'SELF' | 'RECIPIENT';
recipientEmail?: string | null;
recipientName?: string | null;
recipientMessage?: string | null;
sendAt?: string | null;
};
ThemeListingHref
type ThemeListingHref = string;
ThemePaginationDirectionView
type ThemePaginationDirectionView = {
available: boolean;
page: number;
href: ThemeListingHref;
};
ThemePaginationPartView
type ThemePaginationPartView = {
key: string;
kind: 'gap' | 'current' | 'link';
page: number | null;
label: string;
href: ThemeListingHref | null;
};
ThemePaginationView
type ThemePaginationView = {
currentPage: number;
totalPages: number;
visible: boolean;
previous: ThemePaginationDirectionView;
next: ThemePaginationDirectionView;
pages: ThemePaginationPartView[];
};
ThemeProductCustomPropertyCollection
type ThemeProductCustomPropertyCollection = {
controls: ThemeProductCustomPropertyControl[];
reportInvalid: () => void;
};
ThemeProductCustomPropertyControl
type ThemeProductCustomPropertyControl = {
name: string;
type: string;
value: string;
disabled: boolean;
checked: boolean;
valid: boolean;
};
ThemeProductHotspotView
type ThemeProductHotspotView = {
hasProduct: boolean;
title: string;
image: string | null;
priceLabel: string;
href: string;
soldOut: boolean;
};
ThemeProductPriceView
type ThemeProductPriceView = {
visible: boolean;
currency: string;
placeholderFormattedPrice: string;
showComparePrice: boolean;
regular: {
hidden: boolean;
formattedPrice: string;
};
sale: {
hidden: boolean;
items: Array<{
kind: 'regular' | 'sale';
assistiveLabel: string;
formattedPrice: string;
}>;
};
};
ThemeProductPurchaseProduct
type ThemeProductPurchaseProduct<TVariant extends ThemeProductPurchaseVariant = ThemeProductPurchaseVariant> = {
id: string;
name?: string | null;
title?: string | null;
handle?: string | null;
price?: number | null;
salePrice?: number | null;
inStock?: boolean;
totalStock?: number | null;
thumbnail?: string | null;
images?: string[] | null;
fulfillmentKind?: string | null;
currency?: string | null;
currencyCode?: string | null;
selectedVariantId?: string | null;
selectedVariant?: TVariant | null;
variants?: TVariant[];
productVariants?: TVariant[];
options?: Array<{ name?: string; values?: string[] }>;
metadata?: Record<string, unknown> | null;
[key: string]: unknown;
};
ThemeProductPurchaseVariant
type ThemeProductPurchaseVariant = {
id: string;
name?: string | null;
title?: string | null;
sku?: string | null;
price?: number | null;
salePrice?: number | null;
inStock?: boolean;
totalStock?: number | null;
thumbnail?: string | null;
image?: string | null;
imageUrl?: string | null;
featuredImage?: string | null;
featured_image?: string | null;
images?: string[] | null;
option1?: string | null;
option2?: string | null;
option3?: string | null;
options?: Record<string, string> | Array<{ name?: string; value?: string }>;
[key: string]: unknown;
};
ThemeProductRecommendationsInput
type ThemeProductRecommendationsInput = {
baseUrl?: string | null;
productId?: string | null;
sectionId?: string | null;
limit?: number | string | null;
intent?: string | null;
performed?: boolean;
};
ThemeProductSwatchView
type ThemeProductSwatchView = {
label: string;
value: string;
isVariantImage: boolean;
};
ThemeReviewInput
type ThemeReviewInput = {
id: string;
rating: number;
title?: string | null;
comment?: string | null;
reviewerName?: string | null;
images?: string[];
videos?: string[];
verified?: boolean | null;
adminResponse?: string | null;
createdAt?: string | null;
user?: { name?: string | null } | null;
};
ThemeReviewsInput
type ThemeReviewsInput<TReview extends ThemeReviewInput = ThemeReviewInput> = {
reviews: TReview[];
summary: ThemeReviewSummaryInput;
};
ThemeReviewStarView
type ThemeReviewStarView = {
key: number;
kind: 'full' | 'half' | 'empty';
fillPercent: number;
};
ThemeReviewSummaryInput
type ThemeReviewSummaryInput = {
totalReviews?: number | null;
averageRating?: number | null;
ratingBreakdown?: Array<{ rating: number; count: number }>;
};
ThemeSearchRouteData
type ThemeSearchRouteData<
TProduct = unknown,
TSortOption = unknown,
TFilter = unknown,
TPagination = unknown,
> = {
query: string;
products: TProduct[];
resultsCount: number;
emptyStateTitle: string;
pagination: TPagination | null;
sortBy: string;
defaultSortBy: string;
sortOptions: TSortOption[];
filters: TFilter[];
url: string;
currentUrl: string;
};
ThemeSortOptionInput
type ThemeSortOptionInput = { value: string; name: string };
useThemeProductPurchase
useThemeProductPurchase<TVariant extends ThemeProductPurchaseVariant, TProduct extends ThemeProductPurchaseProduct<TVariant>>(input: { product: TProduct; checkoutUrl: string; collectCustomProperties: (source: HTMLElement | null | undefined, productId: string) => ThemeProductCustomPropertyCollection | null; }): { product: TProduct; variants: TVariant[]; selectedVariant: TVariant | null; selectedVariantId: string; setSelectedVariantId: import("react").Dispatch<import("react").SetStateAction<string>>; quantity: number; setQuantity: (value: unknown) => void; quantityView: { minimum: number; maximum: number; canDecrease: boolean; decreaseValue: number; increaseValue: number; }; isGiftCardProduct: boolean; giftCardPurchase: ThemeGiftCardPurchaseForm; setGiftCardPurchase: import("react").Dispatch<import("react").SetStateAction<ThemeGiftCardPurchaseForm>>; isPurchasable: boolean; statusMessage: string | null; errorMessage: string | null; isUpdating: boolean; addToCartView: { canSubmit: boolean; disabled: boolean; label: string; productId: string; variantId: string; quantitySuffix: string; }; variantPicker: { visible: boolean; groups: { key: string; name: string; optionIndex: number; selectedValue: string; variantIdForValue: (value: string) => string | null; choices: { value: string; variant: TVariant | null; variantId: string | null; selected: boolean; disabled: boolean; }[]; }[]; }; quickAddView: { readonly mode: "add" | "choose"; readonly optionCount: number; readonly canAdd: boolean; readonly disabled: boolean; readonly addLabel: "Adding" | "Add"; readonly addAriaLabel: "Add"; readonly chooseLabel: "Choose"; readonly chooseAriaLabel: "Choose"; }; addToCart: (source?: HTMLElement | null) => Promise<void>; buyNow: (source?: HTMLElement | null) => Promise<void>; }