workarea 3.4.16 → 3.4.17
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +81 -0
- metadata +10 -579
- data/docs/Gemfile +0 -8
- data/docs/Gemfile.lock +0 -130
- data/docs/bin/middleman +0 -29
- data/docs/config.rb +0 -87
- data/docs/config.ru +0 -7
- data/docs/data/articles.yml +0 -157
- data/docs/package.json +0 -15
- data/docs/source/404.html.erb +0 -13
- data/docs/source/articles/access-routes-in-javascript.html.md +0 -33
- data/docs/source/articles/add-a-content-area.html.md +0 -169
- data/docs/source/articles/add-a-content-block-type.html.md +0 -334
- data/docs/source/articles/add-a-report.html.md +0 -202
- data/docs/source/articles/add-css-through-the-admin-ui.html.md +0 -30
- data/docs/source/articles/add-javascript-through-a-manifest.html.md +0 -367
- data/docs/source/articles/add-javascript-through-a-view.html.md +0 -80
- data/docs/source/articles/add-javascript-through-the-admin-ui.html.md +0 -30
- data/docs/source/articles/add-metrics.html.md +0 -58
- data/docs/source/articles/add-or-replace-a-pricing-calculator.html.md +0 -150
- data/docs/source/articles/add-remove-or-change-a-mongoid-validation.html.md +0 -147
- data/docs/source/articles/add-remove-or-change-a-product-template.html.md +0 -142
- data/docs/source/articles/add-remove-sort-and-group-storefront-search-filters.html.md +0 -483
- data/docs/source/articles/add-stylesheets-through-a-manifest.html.md +0 -276
- data/docs/source/articles/add-system-content.html.md +0 -138
- data/docs/source/articles/analytics-overview.html.md +0 -51
- data/docs/source/articles/analyze-storefront-search-results.html.md +0 -261
- data/docs/source/articles/api-overview.html.md +0 -35
- data/docs/source/articles/appending.html.md +0 -506
- data/docs/source/articles/application-document.html.md +0 -88
- data/docs/source/articles/automated-javascript-testing.html.md +0 -162
- data/docs/source/articles/b2b-overview.html.md +0 -64
- data/docs/source/articles/browser-and-device-support.html.md +0 -47
- data/docs/source/articles/change-product-placeholder-image.html.md +0 -39
- data/docs/source/articles/change-storefront-search-results.html.md +0 -283
- data/docs/source/articles/change-the-storefront-product-pricing-ui.html.md +0 -348
- data/docs/source/articles/change-the-storefront-search-filters-ui.html.md +0 -103
- data/docs/source/articles/checkout.html.md +0 -479
- data/docs/source/articles/commerce-model.html.md +0 -164
- data/docs/source/articles/configuration-for-hosting.html.md +0 -106
- data/docs/source/articles/configuration.html.md +0 -406
- data/docs/source/articles/configure-a-payment-gateway.html.md +0 -58
- data/docs/source/articles/configure-asset-storage.html.md +0 -29
- data/docs/source/articles/configure-asset-types.html.md +0 -18
- data/docs/source/articles/configure-contact-form-subjects-list.html.md +0 -24
- data/docs/source/articles/configure-imageoptim.html.md +0 -23
- data/docs/source/articles/configure-locales.html.md +0 -45
- data/docs/source/articles/configure-logins-and-authentication.html.md +0 -42
- data/docs/source/articles/configure-low-inventory-threshold.html.md +0 -26
- data/docs/source/articles/configure-product-image-sizes-and-processing.html.md +0 -28
- data/docs/source/articles/content.html.md +0 -554
- data/docs/source/articles/contentable.html.md +0 -41
- data/docs/source/articles/contribute-code.html.md +0 -69
- data/docs/source/articles/contribute-documentation.html.md +0 -60
- data/docs/source/articles/create-a-custom-discount.html.md +0 -234
- data/docs/source/articles/create-a-new-app.html.md +0 -131
- data/docs/source/articles/create-a-plugin.html.md +0 -19
- data/docs/source/articles/create-a-style-guide.html.md +0 -71
- data/docs/source/articles/create-a-theme.html.md +0 -134
- data/docs/source/articles/css-architectural-overview.html.md +0 -89
- data/docs/source/articles/customize-a-helper.html.md +0 -91
- data/docs/source/articles/decoration.html.md +0 -415
- data/docs/source/articles/define-and-configure-inventory-policies.html.md +0 -107
- data/docs/source/articles/documentation-style-guide.html.md +0 -48
- data/docs/source/articles/documentation.html.md +0 -54
- data/docs/source/articles/domain-modeling.html.md +0 -82
- data/docs/source/articles/error-pages.html.md.erb +0 -95
- data/docs/source/articles/extension-overview.html.md +0 -152
- data/docs/source/articles/favicon-support.html.md +0 -112
- data/docs/source/articles/feature-spec-helper-stylesheet.html.md +0 -25
- data/docs/source/articles/featurejs-and-feature-spec-helper.html.md +0 -20
- data/docs/source/articles/help-and-support.html.md +0 -34
- data/docs/source/articles/html-fragment-caching.html.md +0 -46
- data/docs/source/articles/http-caching.html.md +0 -43
- data/docs/source/articles/i18n.html.md +0 -35
- data/docs/source/articles/images-flow.html.md +0 -10
- data/docs/source/articles/index-storefront-search-documents.html.md +0 -104
- data/docs/source/articles/infrastructure.html.md +0 -46
- data/docs/source/articles/installing.html.md +0 -61
- data/docs/source/articles/integrate-a-payment-gateway.html.md +0 -124
- data/docs/source/articles/integrate-a-web-analytics-provider.html.md +0 -35
- data/docs/source/articles/integrate-an-inventory-management-system.html.md +0 -88
- data/docs/source/articles/integrating-with-other-software.html.md +0 -59
- data/docs/source/articles/inventory.html.md +0 -352
- data/docs/source/articles/javascript-coding-standards.html.md +0 -30
- data/docs/source/articles/javascript-modules.html.md +0 -174
- data/docs/source/articles/javascript-overview.html.md +0 -62
- data/docs/source/articles/javascript-reference-documentation.html.md +0 -51
- data/docs/source/articles/javascript-templates.html.md +0 -52
- data/docs/source/articles/low-level-caching.html.md +0 -25
- data/docs/source/articles/maintain-a-plugin.html.md +0 -12
- data/docs/source/articles/maintenance-policy.html.md +0 -79
- data/docs/source/articles/navigable.html.md +0 -51
- data/docs/source/articles/navigating-the-code.html.md +0 -149
- data/docs/source/articles/navigation.html.md +0 -386
- data/docs/source/articles/order-life-cycle.html.md +0 -546
- data/docs/source/articles/order-pricing.html.md +0 -389
- data/docs/source/articles/orders-and-items.html.md +0 -210
- data/docs/source/articles/orders.html.md +0 -66
- data/docs/source/articles/overriding.html.md +0 -155
- data/docs/source/articles/overview.html.md +0 -43
- data/docs/source/articles/plugins-overview.html.md +0 -12
- data/docs/source/articles/prerequisites-and-dependencies.html.md +0 -202
- data/docs/source/articles/products.html.md.erb +0 -1270
- data/docs/source/articles/progressive-web-application-support.html.md +0 -148
- data/docs/source/articles/rails-asset-manifests.html.md +0 -33
- data/docs/source/articles/rails-asset-view-helpers.html.md +0 -25
- data/docs/source/articles/reading-data.html.md +0 -10
- data/docs/source/articles/releasable.html.md +0 -37
- data/docs/source/articles/report-a-bug.html.md +0 -75
- data/docs/source/articles/ruby-coding-standards.html.md +0 -10
- data/docs/source/articles/run-sidekiq-in-a-local-environment.html.md +0 -40
- data/docs/source/articles/searching.html.md +0 -1005
- data/docs/source/articles/security-policy.html.md +0 -42
- data/docs/source/articles/seeds.html.md +0 -345
- data/docs/source/articles/shipping.html.md +0 -756
- data/docs/source/articles/sort-and-exclude-product-options.html.md +0 -47
- data/docs/source/articles/storefront-search-features.html.md +0 -568
- data/docs/source/articles/storefront-searches.html.md +0 -126
- data/docs/source/articles/style-guides.html.md +0 -21
- data/docs/source/articles/stylesheet-coding-standards.html.md +0 -24
- data/docs/source/articles/stylesheets-overview.html.md +0 -67
- data/docs/source/articles/swappable-list-data-structure.html.md +0 -81
- data/docs/source/articles/system-emails.html.md +0 -102
- data/docs/source/articles/taggable.html.md +0 -8
- data/docs/source/articles/test-a-credit-card-transaction.html.md +0 -16
- data/docs/source/articles/test-if-a-plugin-is-installed.html.md +0 -34
- data/docs/source/articles/testing.html.md +0 -914
- data/docs/source/articles/themes-overview.html.md +0 -155
- data/docs/source/articles/translate-administrable-content.html.md +0 -14
- data/docs/source/articles/translate-javascript-content.html.md +0 -16
- data/docs/source/articles/translate-or-customize-message-content.html.md +0 -29
- data/docs/source/articles/translate-or-customize-static-content.html.md +0 -30
- data/docs/source/articles/use-an-existing-workarea-app.html.md +0 -108
- data/docs/source/articles/view-models.html.md +0 -509
- data/docs/source/articles/views.html.md +0 -14
- data/docs/source/articles/workers.html.md +0 -613
- data/docs/source/articles/writing-data.html.md +0 -10
- data/docs/source/cli.html.md +0 -163
- data/docs/source/favicon.ico +0 -0
- data/docs/source/images/3-variants-1-option.png +0 -0
- data/docs/source/images/3-variants-3-options.png +0 -0
- data/docs/source/images/3-years-primary-image.png +0 -0
- data/docs/source/images/404-storefront-error-page.png +0 -0
- data/docs/source/images/404-system-content-admin.png +0 -0
- data/docs/source/images/404.jpg +0 -0
- data/docs/source/images/5-years-primary-image.png +0 -0
- data/docs/source/images/activity-dashboard.png +0 -0
- data/docs/source/images/activity-for-object.png +0 -0
- data/docs/source/images/activity-ui.png +0 -0
- data/docs/source/images/adding-captioned-image-block-custom-icon.png +0 -0
- data/docs/source/images/adding-captioned-image-block-default-icon.png +0 -0
- data/docs/source/images/admin-alerts-ui.png +0 -0
- data/docs/source/images/admin-category-range-filters.png +0 -0
- data/docs/source/images/admin-for-3-column-hero.png +0 -0
- data/docs/source/images/admin-help-index.png +0 -0
- data/docs/source/images/admin-help-ui.png +0 -0
- data/docs/source/images/admin-javascript.png +0 -0
- data/docs/source/images/admin-notification-for-deactivated-discount.png +0 -0
- data/docs/source/images/admin-notifications-ui.png +0 -0
- data/docs/source/images/admin-product-show-page.png +0 -0
- data/docs/source/images/admin-products-index-page.png +0 -0
- data/docs/source/images/admin-range-filters.png +0 -0
- data/docs/source/images/admin-style-guides-navigation.png +0 -0
- data/docs/source/images/after-re-seeding.png +0 -0
- data/docs/source/images/after-seeding-localhost-3000.png +0 -0
- data/docs/source/images/after-seeding.png +0 -0
- data/docs/source/images/arrow.svg +0 -1
- data/docs/source/images/arrow_white.svg +0 -1
- data/docs/source/images/aws-resource-map.png +0 -0
- data/docs/source/images/backordered-until-output-on-inventory-sku-card.png +0 -0
- data/docs/source/images/before-seeding-localhost-3000.png +0 -0
- data/docs/source/images/before-seeding.png +0 -0
- data/docs/source/images/browsing-workarea-versions-on-the-web.png +0 -0
- data/docs/source/images/bulk-asset-upload-on-assets-index-page.png +0 -0
- data/docs/source/images/bulk-asset-upload-while-editing-content.png +0 -0
- data/docs/source/images/bundle-show-workarea-core.png +0 -0
- data/docs/source/images/bundle-show-workarea.png +0 -0
- data/docs/source/images/calendar-for-backordered-until-field.png +0 -0
- data/docs/source/images/captioned-image-block-in-storefront.png +0 -0
- data/docs/source/images/captioned-image-content-block-storefront-component-style-guide.png +0 -0
- data/docs/source/images/cart-system-content-in-admin.png +0 -0
- data/docs/source/images/cart-system-content-in-storefront.png +0 -0
- data/docs/source/images/checkout-addresses-guest.png +0 -0
- data/docs/source/images/checkout-addresses-user.png +0 -0
- data/docs/source/images/checkout-confirmation.png +0 -0
- data/docs/source/images/checkout-flow-0.png +0 -0
- data/docs/source/images/checkout-flow-1.png +0 -0
- data/docs/source/images/checkout-flow-2.png +0 -0
- data/docs/source/images/checkout-flow-3.png +0 -0
- data/docs/source/images/checkout-flow-4.png +0 -0
- data/docs/source/images/checkout-payment-guest.png +0 -0
- data/docs/source/images/checkout-payment-user.png +0 -0
- data/docs/source/images/checkout-shipping.png +0 -0
- data/docs/source/images/color-picker-component-admin-style-guide.png +0 -0
- data/docs/source/images/color-picker-component-on-content-editing-screen.png +0 -0
- data/docs/source/images/commerce-model-carts-orders.png +0 -0
- data/docs/source/images/commerce-model-order-pricing.png +0 -0
- data/docs/source/images/commerce-model.png +0 -0
- data/docs/source/images/configuring-an-index-pattern-in-kibana.png +0 -0
- data/docs/source/images/content-block-presets.png +0 -0
- data/docs/source/images/content-search-customization.png +0 -0
- data/docs/source/images/country-with-region-data-in-address-form.png +0 -0
- data/docs/source/images/country-without-region-data-in-address-form.png +0 -0
- data/docs/source/images/create-content-block-preset-ui.png +0 -0
- data/docs/source/images/credit-card-icons.png +0 -0
- data/docs/source/images/css-added-through-admin.png +0 -0
- data/docs/source/images/css-admin-ui.png +0 -0
- data/docs/source/images/current-configuration-shown-in-admin-settings.png +0 -0
- data/docs/source/images/customer-impersonation-in-admin.png +0 -0
- data/docs/source/images/customer-impersonation-in-store-front.png +0 -0
- data/docs/source/images/date-filter-same-day.png +0 -0
- data/docs/source/images/developer-toolbar-in-store-front.png +0 -0
- data/docs/source/images/discounts-sorted-by-most-redeemed.png +0 -0
- data/docs/source/images/edit-help-article.png +0 -0
- data/docs/source/images/editing-content-for-search-customization.png +0 -0
- data/docs/source/images/editing-dynamic-captioned-image-block.png +0 -0
- data/docs/source/images/editing-product-fields-in-the-admin.png +0 -0
- data/docs/source/images/editing-search-system-content.png +0 -0
- data/docs/source/images/editing-static-captioned-image-block-custom-icon.png +0 -0
- data/docs/source/images/editing-static-captioned-image-block-default-icon.png +0 -0
- data/docs/source/images/external.svg +0 -1
- data/docs/source/images/favicon_16.png +0 -0
- data/docs/source/images/favicon_180.png +0 -0
- data/docs/source/images/favicon_32.png +0 -0
- data/docs/source/images/filters-all.png +0 -0
- data/docs/source/images/filters-control.png +0 -0
- data/docs/source/images/filters-custom.png +0 -0
- data/docs/source/images/filters-groups.png +0 -0
- data/docs/source/images/filters-material.png +0 -0
- data/docs/source/images/filters-omitted.png +0 -0
- data/docs/source/images/filters-pinned.png +0 -0
- data/docs/source/images/filters-range.png +0 -0
- data/docs/source/images/filters-sorted.png +0 -0
- data/docs/source/images/filters-wrapping-to-second-line-in-admin.png +0 -0
- data/docs/source/images/generic-product-template-images-no-options-selected.png +0 -0
- data/docs/source/images/generic-product-template-images-options-selected.png +0 -0
- data/docs/source/images/generic-template.png +0 -0
- data/docs/source/images/hosting.svg +0 -1
- data/docs/source/images/image-group-content-block-in-storefront.png +0 -0
- data/docs/source/images/images.svg +0 -1
- data/docs/source/images/import-export-screenshot.png +0 -0
- data/docs/source/images/invalid-display.png +0 -0
- data/docs/source/images/itcss.png +0 -0
- data/docs/source/images/kibana-dev-tools-console.png +0 -0
- data/docs/source/images/layout-content-admin-with-2-areas.png +0 -0
- data/docs/source/images/layout-content-admin-with-3-areas.png +0 -0
- data/docs/source/images/link-to-search-system-content.png +0 -0
- data/docs/source/images/logo.svg +0 -1
- data/docs/source/images/menu.svg +0 -2
- data/docs/source/images/mongo-replica-set.svg +0 -1
- data/docs/source/images/multi-column-hero-blocks.png +0 -0
- data/docs/source/images/option-selects-product-template-images-options-selected.png +0 -0
- data/docs/source/images/option-selects-template.png +0 -0
- data/docs/source/images/option-thumbnails-template.png +0 -0
- data/docs/source/images/order-item-total-price-diagram.png +0 -0
- data/docs/source/images/order-pricing-cart-example.png +0 -0
- data/docs/source/images/order-pricing-example-adjustments.png +0 -0
- data/docs/source/images/order-pricing-example-totals.png +0 -0
- data/docs/source/images/order-pricing-placed-order-example.png +0 -0
- data/docs/source/images/order-shipping-total-diagram.png +0 -0
- data/docs/source/images/order-show-with-multiple-tenders.png +0 -0
- data/docs/source/images/order-subtotal-price-diagram.png +0 -0
- data/docs/source/images/order-tax-total-diagram.png +0 -0
- data/docs/source/images/order-total-price-diagram.png +0 -0
- data/docs/source/images/order-total-value-diagram.png +0 -0
- data/docs/source/images/orders-dashboard-links.png +0 -0
- data/docs/source/images/oval.svg +0 -1
- data/docs/source/images/payment-icon-storefront-style-guide.png +0 -0
- data/docs/source/images/people-dashboard-links.png +0 -0
- data/docs/source/images/price-adjustments-diagram.png +0 -0
- data/docs/source/images/price-display-no-options.png +0 -0
- data/docs/source/images/price-display-options-selected.png +0 -0
- data/docs/source/images/pricing-calculators-diagram.png +0 -0
- data/docs/source/images/product-list-content-block-admin.png +0 -0
- data/docs/source/images/product-list-content-block-in-store-front.png +0 -0
- data/docs/source/images/promo-products-excluded-autocomplete-results-after.png +0 -0
- data/docs/source/images/promo-products-excluded-featured-category-results-after.png +0 -0
- data/docs/source/images/promo-products-excluded-recommendations-results-after.png +0 -0
- data/docs/source/images/promo-products-excluded-search-category-results-after.png +0 -0
- data/docs/source/images/promo-products-excluded-search-results-after.png +0 -0
- data/docs/source/images/promo-products-included-autocomplete-results-before.png +0 -0
- data/docs/source/images/promo-products-included-featured-category-results-before.png +0 -0
- data/docs/source/images/promo-products-included-recommendations-results-before.png +0 -0
- data/docs/source/images/promo-products-included-search-category-results-before.png +0 -0
- data/docs/source/images/promo-products-included-search-results-before.png +0 -0
- data/docs/source/images/rails-version-constraint.png +0 -0
- data/docs/source/images/re-enable-discount.png +0 -0
- data/docs/source/images/reading-data.svg +0 -1
- data/docs/source/images/readme-hero.png +0 -0
- data/docs/source/images/redesigned-customized-sort-for-search-results.png +0 -0
- data/docs/source/images/reviews-summary-above-share-buttons.png +0 -0
- data/docs/source/images/reviews-summary-below-product-name.png +0 -0
- data/docs/source/images/reviews-summary-below-share-buttons.png +0 -0
- data/docs/source/images/reviews-summary-removed.png +0 -0
- data/docs/source/images/rsa-fingerprint-for-stash.png +0 -0
- data/docs/source/images/ruby-version-constraint.png +0 -0
- data/docs/source/images/script-tag-added-through-admin.png +0 -0
- data/docs/source/images/search-analysis-admin-alternate-rendering.png +0 -0
- data/docs/source/images/search-analysis-admin.png +0 -0
- data/docs/source/images/search-quality-report.png +0 -0
- data/docs/source/images/search.svg +0 -1
- data/docs/source/images/searching-for-cart-system-content-in-admin.png +0 -0
- data/docs/source/images/searching-for-layout-system-content-in-admin.png +0 -0
- data/docs/source/images/seeded-admin.png +0 -0
- data/docs/source/images/seeds-from-plugins.png +0 -0
- data/docs/source/images/seo-metadata-automation-ui.png +0 -0
- data/docs/source/images/show-password-button.png +0 -0
- data/docs/source/images/storefront-autocomplete.png +0 -0
- data/docs/source/images/storefront-category-summary-content-block.png +0 -0
- data/docs/source/images/storefront-category.png +0 -0
- data/docs/source/images/storefront-product-after-overriding.png +0 -0
- data/docs/source/images/storefront-product-before-overriding.png +0 -0
- data/docs/source/images/storefront-product-browse-page.png +0 -0
- data/docs/source/images/storefront-product-recommendations.png +0 -0
- data/docs/source/images/storefront-product-show-page.png +0 -0
- data/docs/source/images/storefront-requests-and-search-requests.png +0 -0
- data/docs/source/images/storefront-search-request-handling.png +0 -0
- data/docs/source/images/storefront-search-response-creation.png +0 -0
- data/docs/source/images/storefront-search.png +0 -0
- data/docs/source/images/storefront-style-guides-navigation.png +0 -0
- data/docs/source/images/styles.css +0 -3
- data/docs/source/images/tax-categories-ui.png +0 -0
- data/docs/source/images/tax-rates-ui.png +0 -0
- data/docs/source/images/unpurchasable-product.png +0 -0
- data/docs/source/images/url-redirects-filtering.png +0 -0
- data/docs/source/images/utility-nav-area-in-admin.png +0 -0
- data/docs/source/images/utility-nav-area-in-storefront.png +0 -0
- data/docs/source/images/validation-message-in-storefront.png +0 -0
- data/docs/source/images/view-model-interface.png +0 -0
- data/docs/source/images/viewing-workarea-version-in-source.png +0 -0
- data/docs/source/images/workarea.svg +0 -1
- data/docs/source/images/worst-performing-searches-on-results-customization-page.png +0 -0
- data/docs/source/images/writing-data.svg +0 -1
- data/docs/source/index.html.erb +0 -166
- data/docs/source/javascripts/jquery.js +0 -2
- data/docs/source/javascripts/lunr.js +0 -7
- data/docs/source/javascripts/site.js +0 -299
- data/docs/source/javascripts/vendor/highlight.pack.js +0 -2
- data/docs/source/layouts/article.erb +0 -106
- data/docs/source/layouts/bare.erb +0 -46
- data/docs/source/layouts/layout.erb +0 -43
- data/docs/source/release-notes/workarea-3-0-0.html.md +0 -146
- data/docs/source/release-notes/workarea-3-0-1.html.md +0 -161
- data/docs/source/release-notes/workarea-3-0-10.html.md +0 -39
- data/docs/source/release-notes/workarea-3-0-11.html.md +0 -277
- data/docs/source/release-notes/workarea-3-0-12.html.md +0 -14
- data/docs/source/release-notes/workarea-3-0-13.html.md +0 -153
- data/docs/source/release-notes/workarea-3-0-14.html.md +0 -93
- data/docs/source/release-notes/workarea-3-0-15.html.md +0 -107
- data/docs/source/release-notes/workarea-3-0-16.html.md +0 -36
- data/docs/source/release-notes/workarea-3-0-17.html.md +0 -141
- data/docs/source/release-notes/workarea-3-0-18.html.md +0 -123
- data/docs/source/release-notes/workarea-3-0-19.html.md +0 -160
- data/docs/source/release-notes/workarea-3-0-2.html.md +0 -222
- data/docs/source/release-notes/workarea-3-0-20.html.md +0 -95
- data/docs/source/release-notes/workarea-3-0-21.html.md +0 -168
- data/docs/source/release-notes/workarea-3-0-22.html.md +0 -268
- data/docs/source/release-notes/workarea-3-0-23.html.md +0 -173
- data/docs/source/release-notes/workarea-3-0-24.html.md +0 -19
- data/docs/source/release-notes/workarea-3-0-25.html.md +0 -26
- data/docs/source/release-notes/workarea-3-0-26.html.md +0 -199
- data/docs/source/release-notes/workarea-3-0-27.html.md +0 -113
- data/docs/source/release-notes/workarea-3-0-28.html.md +0 -39
- data/docs/source/release-notes/workarea-3-0-29.html.md +0 -73
- data/docs/source/release-notes/workarea-3-0-3.html.md +0 -35
- data/docs/source/release-notes/workarea-3-0-30.html.md +0 -186
- data/docs/source/release-notes/workarea-3-0-31.html.md +0 -125
- data/docs/source/release-notes/workarea-3-0-32.html.md +0 -73
- data/docs/source/release-notes/workarea-3-0-33.html.md +0 -137
- data/docs/source/release-notes/workarea-3-0-34.html.md +0 -203
- data/docs/source/release-notes/workarea-3-0-35.html.md +0 -205
- data/docs/source/release-notes/workarea-3-0-36.html.md +0 -105
- data/docs/source/release-notes/workarea-3-0-37.html.md +0 -144
- data/docs/source/release-notes/workarea-3-0-38.html.md +0 -73
- data/docs/source/release-notes/workarea-3-0-39.html.md +0 -77
- data/docs/source/release-notes/workarea-3-0-4.html.md +0 -14
- data/docs/source/release-notes/workarea-3-0-40.html.md +0 -130
- data/docs/source/release-notes/workarea-3-0-41.html.md +0 -70
- data/docs/source/release-notes/workarea-3-0-42.html.md +0 -52
- data/docs/source/release-notes/workarea-3-0-43.html.md +0 -72
- data/docs/source/release-notes/workarea-3-0-44.html.md +0 -93
- data/docs/source/release-notes/workarea-3-0-45.html.md +0 -61
- data/docs/source/release-notes/workarea-3-0-46.html.md +0 -171
- data/docs/source/release-notes/workarea-3-0-47.html.md +0 -130
- data/docs/source/release-notes/workarea-3-0-48.html.md +0 -160
- data/docs/source/release-notes/workarea-3-0-49.html.md +0 -28
- data/docs/source/release-notes/workarea-3-0-5.html.md +0 -225
- data/docs/source/release-notes/workarea-3-0-50.html.md +0 -74
- data/docs/source/release-notes/workarea-3-0-51.html.md +0 -61
- data/docs/source/release-notes/workarea-3-0-52.html.md +0 -76
- data/docs/source/release-notes/workarea-3-0-53.html.md +0 -126
- data/docs/source/release-notes/workarea-3-0-54.html.md +0 -112
- data/docs/source/release-notes/workarea-3-0-55.html.md +0 -105
- data/docs/source/release-notes/workarea-3-0-56.html.md +0 -56
- data/docs/source/release-notes/workarea-3-0-57.html.md +0 -82
- data/docs/source/release-notes/workarea-3-0-58.html.md +0 -153
- data/docs/source/release-notes/workarea-3-0-59.html.md +0 -78
- data/docs/source/release-notes/workarea-3-0-6.html.md +0 -165
- data/docs/source/release-notes/workarea-3-0-60.html.md +0 -43
- data/docs/source/release-notes/workarea-3-0-61.html.md +0 -46
- data/docs/source/release-notes/workarea-3-0-62.html.md +0 -23
- data/docs/source/release-notes/workarea-3-0-63.html.md +0 -25
- data/docs/source/release-notes/workarea-3-0-64.html.md +0 -25
- data/docs/source/release-notes/workarea-3-0-65.html.md +0 -37
- data/docs/source/release-notes/workarea-3-0-7.html.md +0 -207
- data/docs/source/release-notes/workarea-3-0-8.html.md +0 -337
- data/docs/source/release-notes/workarea-3-0-9.html.md +0 -196
- data/docs/source/release-notes/workarea-3-1-0.html.md +0 -414
- data/docs/source/release-notes/workarea-3-1-1.html.md +0 -139
- data/docs/source/release-notes/workarea-3-1-10.html.md +0 -19
- data/docs/source/release-notes/workarea-3-1-11.html.md +0 -27
- data/docs/source/release-notes/workarea-3-1-12.html.md +0 -216
- data/docs/source/release-notes/workarea-3-1-13.html.md +0 -113
- data/docs/source/release-notes/workarea-3-1-14.html.md +0 -39
- data/docs/source/release-notes/workarea-3-1-15.html.md +0 -107
- data/docs/source/release-notes/workarea-3-1-16.html.md +0 -188
- data/docs/source/release-notes/workarea-3-1-17.html.md +0 -141
- data/docs/source/release-notes/workarea-3-1-18.html.md +0 -73
- data/docs/source/release-notes/workarea-3-1-19.html.md +0 -137
- data/docs/source/release-notes/workarea-3-1-2.html.md +0 -55
- data/docs/source/release-notes/workarea-3-1-20.html.md +0 -203
- data/docs/source/release-notes/workarea-3-1-21.html.md +0 -205
- data/docs/source/release-notes/workarea-3-1-22.html.md +0 -121
- data/docs/source/release-notes/workarea-3-1-23.html.md +0 -144
- data/docs/source/release-notes/workarea-3-1-24.html.md +0 -94
- data/docs/source/release-notes/workarea-3-1-25.html.md +0 -77
- data/docs/source/release-notes/workarea-3-1-26.html.md +0 -130
- data/docs/source/release-notes/workarea-3-1-27.html.md +0 -70
- data/docs/source/release-notes/workarea-3-1-28.html.md +0 -52
- data/docs/source/release-notes/workarea-3-1-29.html.md +0 -44
- data/docs/source/release-notes/workarea-3-1-3.html.md +0 -185
- data/docs/source/release-notes/workarea-3-1-30.html.md +0 -72
- data/docs/source/release-notes/workarea-3-1-31.html.md +0 -93
- data/docs/source/release-notes/workarea-3-1-32.html.md +0 -61
- data/docs/source/release-notes/workarea-3-1-33.html.md +0 -171
- data/docs/source/release-notes/workarea-3-1-34.html.md +0 -130
- data/docs/source/release-notes/workarea-3-1-35.html.md +0 -179
- data/docs/source/release-notes/workarea-3-1-36.html.md +0 -28
- data/docs/source/release-notes/workarea-3-1-37.html.md +0 -74
- data/docs/source/release-notes/workarea-3-1-38.html.md +0 -61
- data/docs/source/release-notes/workarea-3-1-39.html.md +0 -96
- data/docs/source/release-notes/workarea-3-1-4.html.md +0 -148
- data/docs/source/release-notes/workarea-3-1-40.html.md +0 -126
- data/docs/source/release-notes/workarea-3-1-41.html.md +0 -128
- data/docs/source/release-notes/workarea-3-1-42.html.md +0 -105
- data/docs/source/release-notes/workarea-3-1-43.html.md +0 -37
- data/docs/source/release-notes/workarea-3-1-44.html.md +0 -82
- data/docs/source/release-notes/workarea-3-1-45.html.md +0 -153
- data/docs/source/release-notes/workarea-3-1-46.html.md +0 -91
- data/docs/source/release-notes/workarea-3-1-47.html.md +0 -65
- data/docs/source/release-notes/workarea-3-1-48.html.md +0 -46
- data/docs/source/release-notes/workarea-3-1-49.html.md +0 -23
- data/docs/source/release-notes/workarea-3-1-5.html.md +0 -169
- data/docs/source/release-notes/workarea-3-1-50.html.md +0 -42
- data/docs/source/release-notes/workarea-3-1-51.html.md +0 -25
- data/docs/source/release-notes/workarea-3-1-52.html.md +0 -57
- data/docs/source/release-notes/workarea-3-1-6.html.md +0 -117
- data/docs/source/release-notes/workarea-3-1-7.html.md +0 -176
- data/docs/source/release-notes/workarea-3-1-8.html.md +0 -283
- data/docs/source/release-notes/workarea-3-1-9.html.md +0 -212
- data/docs/source/release-notes/workarea-3-2-0.html.md +0 -1705
- data/docs/source/release-notes/workarea-3-2-1.html.md +0 -216
- data/docs/source/release-notes/workarea-3-2-10.html.md +0 -237
- data/docs/source/release-notes/workarea-3-2-11.html.md +0 -121
- data/docs/source/release-notes/workarea-3-2-12.html.md +0 -145
- data/docs/source/release-notes/workarea-3-2-13.html.md +0 -138
- data/docs/source/release-notes/workarea-3-2-14.html.md +0 -77
- data/docs/source/release-notes/workarea-3-2-15.html.md +0 -130
- data/docs/source/release-notes/workarea-3-2-16.html.md +0 -111
- data/docs/source/release-notes/workarea-3-2-17.html.md +0 -52
- data/docs/source/release-notes/workarea-3-2-18.html.md +0 -44
- data/docs/source/release-notes/workarea-3-2-19.html.md +0 -72
- data/docs/source/release-notes/workarea-3-2-2.html.md +0 -145
- data/docs/source/release-notes/workarea-3-2-20.html.md +0 -93
- data/docs/source/release-notes/workarea-3-2-21.html.md +0 -61
- data/docs/source/release-notes/workarea-3-2-22.html.md +0 -154
- data/docs/source/release-notes/workarea-3-2-23.html.md +0 -130
- data/docs/source/release-notes/workarea-3-2-24.html.md +0 -200
- data/docs/source/release-notes/workarea-3-2-25.html.md +0 -28
- data/docs/source/release-notes/workarea-3-2-26.html.md +0 -94
- data/docs/source/release-notes/workarea-3-2-27.html.md +0 -61
- data/docs/source/release-notes/workarea-3-2-28.html.md +0 -96
- data/docs/source/release-notes/workarea-3-2-29.html.md +0 -126
- data/docs/source/release-notes/workarea-3-2-30.html.md +0 -112
- data/docs/source/release-notes/workarea-3-2-31.html.md +0 -105
- data/docs/source/release-notes/workarea-3-2-32.html.md +0 -56
- data/docs/source/release-notes/workarea-3-2-33.html.md +0 -82
- data/docs/source/release-notes/workarea-3-2-34.html.md +0 -153
- data/docs/source/release-notes/workarea-3-2-35.html.md +0 -91
- data/docs/source/release-notes/workarea-3-2-36.html.md +0 -118
- data/docs/source/release-notes/workarea-3-2-37.html.md +0 -46
- data/docs/source/release-notes/workarea-3-2-38.html.md +0 -23
- data/docs/source/release-notes/workarea-3-2-39.html.md +0 -42
- data/docs/source/release-notes/workarea-3-2-4.html.md +0 -109
- data/docs/source/release-notes/workarea-3-2-40.html.md +0 -25
- data/docs/source/release-notes/workarea-3-2-41.html.md +0 -90
- data/docs/source/release-notes/workarea-3-2-5.html.md +0 -186
- data/docs/source/release-notes/workarea-3-2-6.html.md +0 -173
- data/docs/source/release-notes/workarea-3-2-7.html.md +0 -89
- data/docs/source/release-notes/workarea-3-2-8.html.md +0 -137
- data/docs/source/release-notes/workarea-3-2-9.html.md +0 -219
- data/docs/source/release-notes/workarea-3-3-0.html.md +0 -1272
- data/docs/source/release-notes/workarea-3-3-1.html.md +0 -324
- data/docs/source/release-notes/workarea-3-3-10.html.md +0 -69
- data/docs/source/release-notes/workarea-3-3-11.html.md +0 -72
- data/docs/source/release-notes/workarea-3-3-12.html.md +0 -136
- data/docs/source/release-notes/workarea-3-3-13.html.md +0 -61
- data/docs/source/release-notes/workarea-3-3-14.html.md +0 -196
- data/docs/source/release-notes/workarea-3-3-15.html.md +0 -167
- data/docs/source/release-notes/workarea-3-3-16.html.md +0 -234
- data/docs/source/release-notes/workarea-3-3-17.html.md +0 -82
- data/docs/source/release-notes/workarea-3-3-18.html.md +0 -165
- data/docs/source/release-notes/workarea-3-3-19.html.md +0 -106
- data/docs/source/release-notes/workarea-3-3-2.html.md +0 -72
- data/docs/source/release-notes/workarea-3-3-20.html.md +0 -116
- data/docs/source/release-notes/workarea-3-3-21.html.md +0 -228
- data/docs/source/release-notes/workarea-3-3-22.html.md +0 -125
- data/docs/source/release-notes/workarea-3-3-23.html.md +0 -154
- data/docs/source/release-notes/workarea-3-3-24.html.md +0 -70
- data/docs/source/release-notes/workarea-3-3-25.html.md +0 -114
- data/docs/source/release-notes/workarea-3-3-26.html.md +0 -260
- data/docs/source/release-notes/workarea-3-3-27.html.md +0 -138
- data/docs/source/release-notes/workarea-3-3-28.html.md +0 -147
- data/docs/source/release-notes/workarea-3-3-29.html.md +0 -63
- data/docs/source/release-notes/workarea-3-3-3.html.md +0 -153
- data/docs/source/release-notes/workarea-3-3-30.html.md +0 -102
- data/docs/source/release-notes/workarea-3-3-31.html.md +0 -57
- data/docs/source/release-notes/workarea-3-3-32.html.md +0 -44
- data/docs/source/release-notes/workarea-3-3-33.html.md +0 -114
- data/docs/source/release-notes/workarea-3-3-34.html.md +0 -29
- data/docs/source/release-notes/workarea-3-3-4.html.md +0 -332
- data/docs/source/release-notes/workarea-3-3-5.html.md +0 -242
- data/docs/source/release-notes/workarea-3-3-6.html.md +0 -100
- data/docs/source/release-notes/workarea-3-3-7.html.md +0 -148
- data/docs/source/release-notes/workarea-3-3-8.html.md +0 -163
- data/docs/source/release-notes/workarea-3-3-9.html.md +0 -93
- data/docs/source/release-notes/workarea-3-4-0.html.md +0 -580
- data/docs/source/release-notes/workarea-3-4-1.html.md +0 -150
- data/docs/source/release-notes/workarea-3-4-10.html.md +0 -72
- data/docs/source/release-notes/workarea-3-4-11.html.md +0 -60
- data/docs/source/release-notes/workarea-3-4-12.html.md +0 -155
- data/docs/source/release-notes/workarea-3-4-15.html.md +0 -100
- data/docs/source/release-notes/workarea-3-4-16.html.md +0 -88
- data/docs/source/release-notes/workarea-3-4-2.html.md +0 -188
- data/docs/source/release-notes/workarea-3-4-3.html.md +0 -136
- data/docs/source/release-notes/workarea-3-4-4.html.md +0 -114
- data/docs/source/release-notes/workarea-3-4-5.html.md +0 -275
- data/docs/source/release-notes/workarea-3-4-6.html.md +0 -169
- data/docs/source/release-notes/workarea-3-4-7.html.md +0 -162
- data/docs/source/release-notes/workarea-3-4-8.html.md +0 -95
- data/docs/source/release-notes/workarea-3-4-9.html.md +0 -135
- data/docs/source/release-notes.html.md +0 -261
- data/docs/source/search.html.erb +0 -34
- data/docs/source/shared/_header.erb +0 -61
- data/docs/source/shared/_svgs.erb +0 -17
- data/docs/source/style_guide/index.html.erb +0 -382
- data/docs/source/stylesheets/_base.scss +0 -125
- data/docs/source/stylesheets/_components.scss +0 -669
- data/docs/source/stylesheets/_helpers.scss +0 -10
- data/docs/source/stylesheets/_opinions.scss +0 -42
- data/docs/source/stylesheets/_settings.scss +0 -56
- data/docs/source/stylesheets/_typography.scss +0 -119
- data/docs/source/stylesheets/site.css.scss +0 -14
- data/docs/source/stylesheets/vendor/_avalanche.scss +0 -328
- data/docs/source/stylesheets/vendor/_normalize.scss +0 -341
- data/docs/source/stylesheets/vendor/highlight/_tomorrow_night_blue.scss +0 -75
- data/docs/source/upgrade-guides/workarea-3-4-0.html.md +0 -152
- data/docs/source/upgrade-guides.html.md +0 -18
- data/docs/workarea_renderer.rb +0 -8
- data/docs/yarn.lock +0 -2522
@@ -1,1270 +0,0 @@
|
|
1
|
-
---
|
2
|
-
title: Products
|
3
|
-
excerpt: A Workarea application presents a retailer’s catalog to consumers and promotes the sale of those items. Products are representations of the goods and services the retailer is presenting for sale. This guide further explains “product” as a concept with
|
4
|
-
---
|
5
|
-
|
6
|
-
# Products
|
7
|
-
|
8
|
-
A Workarea application presents a retailer’s catalog to consumers and promotes the sale of those items. <dfn>Products</dfn> are representations of the goods and services the retailer is presenting for sale. This guide further explains “product” as a concept within the Workarea platform.
|
9
|
-
|
10
|
-
A retailer’s catalog is modeled within the Workarea `Catalog` as products and variants (which each have details) and catalog product images. Additional records exist outside the `Catalog` module to represent the inventory, pricing, and shipping details for each item.
|
11
|
-
|
12
|
-
Presenting a product requires wrapping the catalog product document in an appropriate view model, which creates a view of the product suitable for either consumers shopping in the Storefront or administrators managing the catalog in the Admin.
|
13
|
-
|
14
|
-
Admins manage products, variants, and product images through the Admin web interface and data files. Developers have additional access to command line and programmatic interfaces. Regardless of interface, product management is affected by various application and document states.
|
15
|
-
|
16
|
-
Admins also manage the placement of products within the Storefront, optimizing what products consumers see while browsing. The systems that facilitate these optimizations rely on additional product representations of which developers should be aware. Additionally, each presented product is affected by various browsing states.
|
17
|
-
|
18
|
-
After narrowing to specific products, consumers view the details of each product, which presents options the consumer can use to reduce the product to a specific item. The display of the options and other product data are determined by the product template and several states related to showing a product.
|
19
|
-
|
20
|
-
## Modeling the Retailer’s Catalog
|
21
|
-
|
22
|
-
Each retailer maintains a <dfn>catalog</dfn>, a list of items for sale. These items are often _goods_ with physical inventory, but may also include intangible items such as digital downloads and warranties, and _services_, such as units of repair time or tech support. Regardless of type, the retailer maintains records for each item, such as its description and details, pricing, inventory, location within a warehouse, and shipping weight and dimensions. These records are often managed across many systems, such as point of sale, inventory, accounting, warehouse/fulfillment, and mail order catalog. To manage each item across systems, the retailer identifies each item with a <dfn>SKU</dfn>: an id internal to the retailer and unique across all the retailer’s systems.
|
23
|
-
|
24
|
-
The Workarea platform is similarly divided into multiple subsystems, many of which keep their own records for the retailer’s merchandise. These records are related by SKU, allowing multiple representations of the same item to be joined when needed.
|
25
|
-
|
26
|
-
### Catalog Products & Variants
|
27
|
-
|
28
|
-
Within the `Workarea::Catalog` namespace are `Product` and `Variant` [application documents](application-document.html). A <dfn>catalog product</dfn> represents a group of related but varying items for sale. Each catalog product embeds a collection of <dfn>variants</dfn>, each of which represents a distinct item for sale within that product.
|
29
|
-
|
30
|
-
Catalogs are generally organized in this fashion: with groups of products sharing some information (such as a name and description) while varying on other details (such as color and size). <sup><a id="note-1-context" href="#notes">[1]</a></sup>
|
31
|
-
|
32
|
-
Grouping items facilitates the usual shopping flow: first reduce the catalog to a product of interest (such as a cotton t-shirt), and then further reduce that product to a particular item to be purchased (for example, the _large_, _blue_ cotton t-shirt). The first part of this flow is known as _browsing_, where consumers shop _by product_. The second part is known as _showing_ or _product detail page_, where consumers see _options_, which allow easy comparison of a specific product’s variants. <sup><a id="note-2-context" href="#notes">[2]</a></sup> Grouping into products also benefits the retailer, allowing them to share data across items, attach discounts to groups of similar items, and view analytics by these groupings.
|
33
|
-
|
34
|
-
A product names and describes a group of items and stores the data that all the items in the group share. The only required field is `name`. Print a product as a document to get an overview of the catalog product interface.
|
35
|
-
|
36
|
-
```ruby
|
37
|
-
pp Workarea::Catalog::Product.find_by(name: 'Tropical Drink Mix').as_document
|
38
|
-
# {"_id"=>"5A74109BFA",
|
39
|
-
# "tags"=>[],
|
40
|
-
# "active"=>{"en"=>true},
|
41
|
-
# "subscribed_user_ids"=>[],
|
42
|
-
# "details"=>{"en"=>{"Ingredients"=>["Pure Cane Sugar", "Natural Flavor"]}},
|
43
|
-
# "filters"=>{"en"=>{}},
|
44
|
-
# "template"=>"generic",
|
45
|
-
# "purchasable"=>true,
|
46
|
-
# "name"=>{"en"=>"Tropical Drink Mix"},
|
47
|
-
# "digital"=>false,
|
48
|
-
# "slug"=>"tropical-drink-mix",
|
49
|
-
# "updated_at"=>2018-05-31 15:15:28 UTC,
|
50
|
-
# "created_at"=>2018-05-31 15:15:28 UTC,
|
51
|
-
# "variants"=>
|
52
|
-
# [{"_id"=>BSON::ObjectId('5b101190eefbfe0cb1018da8'),
|
53
|
-
# "active"=>{"en"=>true},
|
54
|
-
# "details"=>{"en"=>{}},
|
55
|
-
# "sku"=>"mango-hurricane-mix",
|
56
|
-
# "name"=>{"en"=>"Mango Hurricane"},
|
57
|
-
# "position"=>0},
|
58
|
-
# {"_id"=>BSON::ObjectId('5b101190eefbfe0cb1018da9'),
|
59
|
-
# "active"=>{"en"=>true},
|
60
|
-
# "details"=>{"en"=>{}},
|
61
|
-
# "sku"=>"coconut-cyclone-mix",
|
62
|
-
# "name"=>{"en"=>"Coconut Cyclone"},
|
63
|
-
# "position"=>1},
|
64
|
-
# {"_id"=>BSON::ObjectId('5b101190eefbfe0cb1018daa'),
|
65
|
-
# "active"=>{"en"=>true},
|
66
|
-
# "details"=>{"en"=>{}},
|
67
|
-
# "sku"=>"pineapple-typhoon-mix",
|
68
|
-
# "name"=>{"en"=>"Pineapple Typhoon"},
|
69
|
-
# "position"=>2}],
|
70
|
-
# "last_indexed_at"=>2018-05-31 15:15:28 UTC}
|
71
|
-
```
|
72
|
-
|
73
|
-
Notice above that several of the fields are internationalized; their values are keyed by locale.
|
74
|
-
|
75
|
-
Also observe the embedded collection of variants. Each variant represents a distinct variation of the product, giving it a name/id (through the `id`, `sku`, and `name` fields), description (through details), and an administrable position relative to its siblings.
|
76
|
-
|
77
|
-
You must provide the `sku` value when creating a variant, since this is a retailer-supplied ID that Workarea cannot generate. The variant’s SKU relates the variant to other models representing the same item within Workarea, and to other representations of the same item across other systems managed by the retailer.
|
78
|
-
|
79
|
-
Note that product and variant implement some of the same interface. One example of this is `active`, which both models inherit from `Workarea::Releasable`. Another example is the details interface, covered next.
|
80
|
-
|
81
|
-
### Details
|
82
|
-
|
83
|
-
Product and variant both inherit from `Workarea::Details` and therefore implement the same <dfn>details</dfn> interface. Details are administrable attributes of a product and its variants, which are displayed to consumers within the Storefront.
|
84
|
-
|
85
|
-
A product and each of its variants stores a `details` hash, where the keys are typically strings and the values are collections of non-blank, scalar values (again, often strings). These are flexible data structures that serve platform-defined and application-defined purposes.
|
86
|
-
|
87
|
-
The items that make up a product share some details and vary on others. Store the shared details on the product. Store on each variant the details that distinguish that variant from its siblings. Many examples of this follow.
|
88
|
-
|
89
|
-
Note that a variant’s SKU effectively encodes its details, by providing an ID which maps to a particular “configuration” of the product. This encoding may be observable in the ID itself. For example, the SKU _TSHIRT-BLACK-SMALL_ clearly identifies a particular product (_T-Shirt_) and particular variant details (a color, _black_, and a size, _small_).
|
90
|
-
|
91
|
-
Details on the _product_ are used for search text and implementation-specific use cases (perhaps a product template which enumerates the details when showing the product). Details on the _variant_ are used to create the product options which are presented to the consumer when showing the product. <sup><a id="note-3-context" href="#notes">[3]</a></sup>
|
92
|
-
|
93
|
-
The following examples demonstrate the process of mapping catalog data to products and variants. Each example provides a possible solution and some commentary.
|
94
|
-
|
95
|
-
The first example is presented in Table 1 and Listing 1.
|
96
|
-
|
97
|
-
<caption>
|
98
|
-
<p>Table 1</p>
|
99
|
-
<p>A subset of catalog data for keyed padlocks.</p>
|
100
|
-
</caption>
|
101
|
-
|
102
|
-
| SKU | Weather Resistance | Shackle Locking | Shackle Material | Shackle Length | Shackle Diameter |
|
103
|
-
| --- | --- | --- | --- | --- | --- |
|
104
|
-
| KEYPAD-S-1-14 | Covered | Dual ball bearing | Steel | 1" | 1/4" |
|
105
|
-
| KEYPAD-S-1-12 | Covered | Dual ball bearing | Steel | 1" | 1/2" |
|
106
|
-
| KEYPAD-S-2-14 | Covered | Dual ball bearing | Steel | 2" | 1/4" |
|
107
|
-
| KEYPAD-S-2-12 | Covered | Dual ball bearing | Steel | 2" | 1/2" |
|
108
|
-
| KEYPAD-B-1-14 | Covered | Dual ball bearing | Brass | 1" | 1/4" |
|
109
|
-
| KEYPAD-B-1-12 | Covered | Dual ball bearing | Brass | 1" | 1/2" |
|
110
|
-
| KEYPAD-B-2-14 | Covered | Dual ball bearing | Brass | 2" | 1/4" |
|
111
|
-
| KEYPAD-B-2-12 | Covered | Dual ball bearing | Brass | 2" | 1/2" |
|
112
|
-
|
113
|
-
<!-- <figure id="listing-1">
|
114
|
-
<figcaption>
|
115
|
-
<p>Listing 1</p>
|
116
|
-
<p>Creating a “Keyed Padlock” product (with variants) in Workarea from the data in <a href="#table-1">Table 1</a>. This represents one possible solution.</p>
|
117
|
-
</figcaption> -->
|
118
|
-
|
119
|
-
Listing 1
|
120
|
-
Creating a “Keyed Padlock” product (with variants) in Workarea from the data in <a href="#table-1">Table 1</a>. This represents one possible solution.
|
121
|
-
|
122
|
-
```ruby
|
123
|
-
name: 'Keyed Padlock',
|
124
|
-
details: {
|
125
|
-
'Weather Resistance' => ['Covered'],
|
126
|
-
'Shackle Locking' => ['Dual ball bearing']
|
127
|
-
},
|
128
|
-
variants: [
|
129
|
-
{
|
130
|
-
sku: 'KEYPAD-S-1-14',
|
131
|
-
details: {
|
132
|
-
'Shackle Material' => ['Steel'],
|
133
|
-
'Shackle Length' => ['1"'],
|
134
|
-
'Shackle Diameter' => ['1/4"']
|
135
|
-
}
|
136
|
-
},
|
137
|
-
{
|
138
|
-
sku: 'KEYPAD-S-1-12',
|
139
|
-
details: {
|
140
|
-
'Shackle Material' => ['Steel'],
|
141
|
-
'Shackle Length' => ['1"'],
|
142
|
-
'Shackle Diameter' => ['1/2"']
|
143
|
-
}
|
144
|
-
},
|
145
|
-
{
|
146
|
-
sku: 'KEYPAD-S-2-14',
|
147
|
-
details: {
|
148
|
-
'Shackle Material' => ['Steel'],
|
149
|
-
'Shackle Length' => ['2"'],
|
150
|
-
'Shackle Diameter' => ['1/4"']
|
151
|
-
}
|
152
|
-
},
|
153
|
-
{
|
154
|
-
sku: 'KEYPAD-S-2-12',
|
155
|
-
details: {
|
156
|
-
'Shackle Material' => ['Steel'],
|
157
|
-
'Shackle Length' => ['2"'],
|
158
|
-
'Shackle Diameter' => ['1/2"']
|
159
|
-
}
|
160
|
-
},
|
161
|
-
{
|
162
|
-
sku: 'KEYPAD-B-1-14',
|
163
|
-
details: {
|
164
|
-
'Shackle Material' => ['Brass'],
|
165
|
-
'Shackle Length' => ['1"'],
|
166
|
-
'Shackle Diameter' => ['1/4"']
|
167
|
-
|
168
|
-
}
|
169
|
-
|
170
|
-
},
|
171
|
-
{
|
172
|
-
sku: 'KEYPAD-B-1-12',
|
173
|
-
details: {
|
174
|
-
'Shackle Material' => ['Brass'],
|
175
|
-
'Shackle Length' => ['1"'],
|
176
|
-
'Shackle Diameter' => ['1/2"']
|
177
|
-
|
178
|
-
}
|
179
|
-
|
180
|
-
},
|
181
|
-
{
|
182
|
-
sku: 'KEYPAD-B-2-14',
|
183
|
-
details: {
|
184
|
-
'Shackle Material' => ['Brass'],
|
185
|
-
'Shackle Length' => ['2"'],
|
186
|
-
'Shackle Diameter' => ['1/4"']
|
187
|
-
}
|
188
|
-
},
|
189
|
-
{
|
190
|
-
sku: 'KEYPAD-B-2-12',
|
191
|
-
details: {
|
192
|
-
'Shackle Material' => ['Brass'],
|
193
|
-
'Shackle Length' => ['2"'],
|
194
|
-
'Shackle Diameter' => ['1/2"']
|
195
|
-
}
|
196
|
-
}
|
197
|
-
]
|
198
|
-
)
|
199
|
-
```
|
200
|
-
<!-- </figure> -->
|
201
|
-
|
202
|
-
Note the following about the example presented in Table 1 and Listing 1:
|
203
|
-
|
204
|
-
- The values for _Weather Resistance_ and _Shackle Locking_ are consistent across all items and are therefore stored on the product.
|
205
|
-
- The items vary by _Shackle Material_, _Shackle Length_, and _Shackle Diameter_, so those details are stored on the variants.
|
206
|
-
- The data uses English language and measurements. Since the `details` field is internationalized. You could store different values (such as metric units) using a different locale.
|
207
|
-
|
208
|
-
Table 2 and Listing 2 provide another example.
|
209
|
-
|
210
|
-
<caption>
|
211
|
-
<p>Table 2</p>
|
212
|
-
<p>A subset of catalog data for fitted baseball caps.</p>
|
213
|
-
</caption>
|
214
|
-
|
215
|
-
| SKU | Fitting Type | Materials | Color | Size |
|
216
|
-
| --- | --- | --- | --- | --- |
|
217
|
-
| BALLCAP-BLACK-S | Elastic | Cotton/Polyester | Black/White | Small |
|
218
|
-
| BALLCAP-BLACK-M | Elastic | Cotton/Polyester | Black/White | Medium |
|
219
|
-
| BALLCAP-BLACK-L | Elastic | Cotton/Polyester | Black/White | Large |
|
220
|
-
| BALLCAP-BLUE-S | Elastic | Cotton/Polyester | Blue/White | Small |
|
221
|
-
| BALLCAP-BLUE-M | Elastic | Cotton/Polyester | Blue/White | Medium |
|
222
|
-
| BALLCAP-BLUE-L | Elastic | Cotton/Polyester | Blue/White | Large |
|
223
|
-
| BALLCAP-RWB-S | Elastic | Cotton/Polyester | Red/White/Blue | Small |
|
224
|
-
| BALLCAP-RWB-M | Elastic | Cotton/Polyester | Red/White/Blue | Medium |
|
225
|
-
| BALLCAP-RWB-L | Elastic | Cotton/Polyester | Red/White/Blue | Large |
|
226
|
-
|
227
|
-
<!-- <figure id="listing-2">
|
228
|
-
<figcaption>
|
229
|
-
<p>Listing 2</p>
|
230
|
-
<p>Creating a “Fitted Baseball Cap” product (with variants) in Workarea from the data in <a href="#table-2">Table 2</a>. This represents one possible solution.</p>
|
231
|
-
</figcaption> -->
|
232
|
-
|
233
|
-
Listing 2
|
234
|
-
Creating a “Fitted Baseball Cap” product (with variants) in Workarea from the data in <a href="#table-2">Table 2</a>. This represents one possible solution.
|
235
|
-
|
236
|
-
```ruby
|
237
|
-
Workarea::Catalog::Product.create(
|
238
|
-
name: 'Fitted Baseball Cap',
|
239
|
-
details: {
|
240
|
-
'Fitting Type' => ['Elastic'],
|
241
|
-
'Materials' => ['Cotton', 'Polyester']
|
242
|
-
},
|
243
|
-
variants: [
|
244
|
-
{
|
245
|
-
sku: 'BALLCAP-BLACK-S',
|
246
|
-
details: {
|
247
|
-
'Color' => ['Black/White'],
|
248
|
-
'Size' => ['Small']
|
249
|
-
}
|
250
|
-
},
|
251
|
-
{
|
252
|
-
sku: 'BALLCAP-BLACK-M',
|
253
|
-
details: {
|
254
|
-
'Color' => ['Black/White'],
|
255
|
-
'Size' => ['Medium']
|
256
|
-
}
|
257
|
-
},
|
258
|
-
{
|
259
|
-
sku: 'BALLCAP-BLACK-L',
|
260
|
-
details: {
|
261
|
-
'Color' => ['Black/White'],
|
262
|
-
'Size' => ['Large']
|
263
|
-
}
|
264
|
-
},
|
265
|
-
{
|
266
|
-
sku: 'BALLCAP-BLUE-S',
|
267
|
-
details: {
|
268
|
-
'Color' => ['Blue/White'],
|
269
|
-
'Size' => ['Small']
|
270
|
-
}
|
271
|
-
},
|
272
|
-
{
|
273
|
-
sku: 'BALLCAP-BLUE-M',
|
274
|
-
details: {
|
275
|
-
'Color' => ['Blue/White'],
|
276
|
-
'Size' => ['Medium']
|
277
|
-
}
|
278
|
-
},
|
279
|
-
{
|
280
|
-
sku: 'BALLCAP-BLUE-L',
|
281
|
-
details: {
|
282
|
-
'Color' => ['Blue/White'],
|
283
|
-
'Size' => ['Large']
|
284
|
-
}
|
285
|
-
},
|
286
|
-
{
|
287
|
-
sku: 'BALLCAP-RWB-S',
|
288
|
-
details: {
|
289
|
-
'Color' => ['Red/White/Blue'],
|
290
|
-
'Size' => ['Small']
|
291
|
-
}
|
292
|
-
},
|
293
|
-
{
|
294
|
-
sku: 'BALLCAP-RWB-M',
|
295
|
-
details: {
|
296
|
-
'Color' => ['Red/White/Blue'],
|
297
|
-
'Size' => ['Medium']
|
298
|
-
}
|
299
|
-
},
|
300
|
-
{
|
301
|
-
sku: 'BALLCAP-RWB-L',
|
302
|
-
details: {
|
303
|
-
'Color' => ['Red/White/Blue'],
|
304
|
-
'Size' => ['Large']
|
305
|
-
}
|
306
|
-
}
|
307
|
-
]
|
308
|
-
)
|
309
|
-
```
|
310
|
-
<!-- </figure> -->
|
311
|
-
|
312
|
-
Note the following regarding the example presented in Table 2 and Listing 2:
|
313
|
-
|
314
|
-
- _Materials_ are stored (on the product) as multiple values so they can be enumerated for display or other purposes.
|
315
|
-
- _Color_ is stored (on each variant) as a single value because the retailer would like to present each combined color value to consumers as a single product option. This retailer is using <cite>Workarea Swatches</cite> to represent each combined color with a multi-color image. <sup><a id="note-4-context" href="#notes">[4]</a></sup>
|
316
|
-
|
317
|
-
Now see Table 3 and Listing 3 for a third example.
|
318
|
-
|
319
|
-
<caption>
|
320
|
-
<p>Table 3</p>
|
321
|
-
<p>A subset of catalog data for extended service plans (warranties).</p>
|
322
|
-
</caption>
|
323
|
-
|
324
|
-
| SKU | Duration |
|
325
|
-
| --- | --- |
|
326
|
-
| B45678 | 3 years |
|
327
|
-
| A57893 | 5 years |
|
328
|
-
|
329
|
-
<!--
|
330
|
-
<figure id="listing-3">
|
331
|
-
<figcaption>
|
332
|
-
<p>Listing 3</p>
|
333
|
-
<p>Creating an “Extended Service Plan” product (with variants) in Workarea from the data in <a href="#table-3">Table 3</a>. This represents one possible solution.</p>
|
334
|
-
</figcaption>
|
335
|
-
-->
|
336
|
-
|
337
|
-
Listing 3
|
338
|
-
Creating an “Extended Service Plan” product (with variants) in Workarea from the data in <a href="#table-3">Table 3</a>. This represents one possible solution.
|
339
|
-
|
340
|
-
```ruby
|
341
|
-
Workarea::Catalog::Product.create(
|
342
|
-
name: 'Extended Service Plan',
|
343
|
-
variants: [
|
344
|
-
{
|
345
|
-
sku: 'B45678',
|
346
|
-
details: {
|
347
|
-
'Duration' => ['3 years']
|
348
|
-
}
|
349
|
-
},
|
350
|
-
{
|
351
|
-
sku: 'A57893',
|
352
|
-
details: {
|
353
|
-
'Duration' => ['5 years']
|
354
|
-
}
|
355
|
-
}
|
356
|
-
]
|
357
|
-
)
|
358
|
-
```
|
359
|
-
<!-- </figure> -->
|
360
|
-
|
361
|
-
Notice in the 3rd example the SKUs aren’t as user-friendly as they were in the previous examples. However, SKUs are assigned by the retailer and should not be modified. Despite their cryptic appearance, they effectively encode the details of the variant by providing a unique ID that all relevant parties (retailer, Workarea, fulfillment system, etc) can decode.
|
362
|
-
|
363
|
-
Also note the details in the 3rd example have only one value. In such a case, the retailer may prefer to assign a name to the variant and forgo the use of variant details. See Table 4 and Listing 4 for an example that fits this description.
|
364
|
-
|
365
|
-
<caption>
|
366
|
-
<p>Table 4</p>
|
367
|
-
<p>A subset of catalog data for tropical drink mixes.</p>
|
368
|
-
</caption>
|
369
|
-
|
370
|
-
| SKU | Ingredients |
|
371
|
-
| --- | --- |
|
372
|
-
| mango-hurricane-mix | Pure Cane Sugar, Natural Flavor |
|
373
|
-
| coconut-cyclone-mix | Pure Cane Sugar, Natural Flavor |
|
374
|
-
| pineapple-typhoon-mix | Pure Cane Sugar, Natural Flavor |
|
375
|
-
|
376
|
-
<!--
|
377
|
-
<figure id="listing-4">
|
378
|
-
<figcaption>
|
379
|
-
<p>Listing 4</p>
|
380
|
-
<p>Creating a “Tropical Drink Mix” product (with variants) in Workarea from the data in <a href="#table-4">Table 4</a>. This represents one possible solution.</p>
|
381
|
-
</figcaption>
|
382
|
-
-->
|
383
|
-
|
384
|
-
Listing 4
|
385
|
-
Creating a “Tropical Drink Mix” product (with variants) in Workarea from the data in <a href="#table-4">Table 4</a>. This represents one possible solution.
|
386
|
-
|
387
|
-
```ruby
|
388
|
-
Workarea::Catalog::Product.create(
|
389
|
-
name: 'Tropical Drink Mix',
|
390
|
-
details: {
|
391
|
-
'Ingredients' => ['Pure Cane Sugar', 'Natural Flavor']
|
392
|
-
},
|
393
|
-
variants: [
|
394
|
-
{
|
395
|
-
sku: 'mango-hurricane-mix',
|
396
|
-
name: 'Mango Hurricane'
|
397
|
-
},
|
398
|
-
{
|
399
|
-
sku: 'coconut-cyclone-mix',
|
400
|
-
name: 'Coconut Cyclone'
|
401
|
-
},
|
402
|
-
{
|
403
|
-
sku: 'pineapple-typhoon-mix',
|
404
|
-
name: 'Pineapple Typhoon'
|
405
|
-
}
|
406
|
-
]
|
407
|
-
)
|
408
|
-
```
|
409
|
-
<!-- </figure> -->
|
410
|
-
|
411
|
-
As mentioned above, this final example assigns a name to each variant. These names may display to the consumer when showing the product.
|
412
|
-
|
413
|
-
Review all the examples above and observe how some of them store details on _only the product_, _only the variants_, or _both the product and the variants_. Remember! A product and its embedded variants each store their own details hash, so consider which object to write to or query from when operating on details.
|
414
|
-
|
415
|
-
```ruby
|
416
|
-
catalog_product =
|
417
|
-
Workarea::Catalog::Product.find_by(name: 'Fitted Baseball Cap')
|
418
|
-
|
419
|
-
catalog_product.details
|
420
|
-
# => {"Fitting Type"=>["Elastic"], "Materials"=>["Cotton", "Polyester"]}
|
421
|
-
|
422
|
-
catalog_product.variants.first.details
|
423
|
-
# => {"Color"=>["Black/White"], "Size"=>["Small"]}
|
424
|
-
|
425
|
-
catalog_product.variants.second.details
|
426
|
-
# => {"Color"=>["Black/White"], "Size"=>["Medium"]}
|
427
|
-
```
|
428
|
-
|
429
|
-
Finally, products and variants implement instance methods for fetching and testing details.
|
430
|
-
|
431
|
-
```ruby
|
432
|
-
puts Workarea::Details.instance_methods(false).sort
|
433
|
-
# fetch_detail
|
434
|
-
# has_detail?
|
435
|
-
# matches_detail?
|
436
|
-
# matches_details?
|
437
|
-
# update_details
|
438
|
-
```
|
439
|
-
|
440
|
-
### Catalog Product Images
|
441
|
-
|
442
|
-
In addition to variants, each catalog product embeds a collection of product images. Each product image is a document of type `Catalog::ProductImage` and has an attachment (an image file). Product images are [Dragonfly models](http://markevans.github.io/dragonfly/models) and implement that interface. A product image also has a `position` field for administrating display order, and an `option` field to associate the image with a product option.
|
443
|
-
|
444
|
-
The following examples use the “Extended Service Plan” product created in Listing 3 for demonstration. This product represents intangible goods that have no product photography, however, you can still use generated images to improve the shopping experience.
|
445
|
-
|
446
|
-
First, generate some image files. Admittedly, these images are not pretty, but they demonstrate the concepts sufficiently.
|
447
|
-
|
448
|
-
```bash
|
449
|
-
$ convert \
|
450
|
-
> -background lightblue \
|
451
|
-
> -fill blue \
|
452
|
-
> -font Helvetica \
|
453
|
-
> -size 400x600 \
|
454
|
-
> -pointsize 72 \
|
455
|
-
> -gravity center \
|
456
|
-
> 'label:3 Years' \
|
457
|
-
> 3_years.jpg
|
458
|
-
|
459
|
-
$ convert \
|
460
|
-
> -background blue \
|
461
|
-
> -fill lightblue \
|
462
|
-
> -font Helvetica \
|
463
|
-
> -size 400x600 \
|
464
|
-
> -pointsize 72 \
|
465
|
-
> -gravity center \
|
466
|
-
> 'label:5 Years' \
|
467
|
-
> 5_years.jpg
|
468
|
-
$
|
469
|
-
```
|
470
|
-
|
471
|
-
Next, create some product images within the product from those files, and explore the product image interface.
|
472
|
-
|
473
|
-
```ruby
|
474
|
-
catalog_product =
|
475
|
-
Workarea::Catalog::Product.find_by(name: 'Extended Service Plan')
|
476
|
-
|
477
|
-
catalog_product.images.create(
|
478
|
-
image: File.new('3_years.jpg'),
|
479
|
-
option: '3_years'
|
480
|
-
)
|
481
|
-
catalog_product.images.create(
|
482
|
-
image: File.new('5_years.jpg'),
|
483
|
-
option: '5_years'
|
484
|
-
)
|
485
|
-
|
486
|
-
catalog_product.images.count
|
487
|
-
# => 2
|
488
|
-
|
489
|
-
product_image = catalog_product.images.first
|
490
|
-
|
491
|
-
product_image.class
|
492
|
-
# => Workarea::Catalog::ProductImage
|
493
|
-
|
494
|
-
product_image.name
|
495
|
-
# => "3_years.jpg"
|
496
|
-
|
497
|
-
product_image.option
|
498
|
-
# => "3_years"
|
499
|
-
|
500
|
-
product_image.position
|
501
|
-
# => 0
|
502
|
-
|
503
|
-
product_image.format
|
504
|
-
# => "jpeg"
|
505
|
-
|
506
|
-
product_image.width
|
507
|
-
# => 400
|
508
|
-
|
509
|
-
product_image.height
|
510
|
-
# => 600
|
511
|
-
```
|
512
|
-
|
513
|
-
Product images are neither releasable nor are any of their fields internationalized. Therefore, application state does not affect product images.
|
514
|
-
|
515
|
-
Notably, product images are stored on the _product_, not the variants. You can associate each image with a product option. Administration of the `position` and `option` fields therefore affects the presentation of a product (also see Primary Image). <sup><a id="note-5-context" href="#notes">[5]</a></sup>
|
516
|
-
|
517
|
-
Finally, there is also a `Catalog::ProductPlaceholderImage`, which is used when presenting a product that has no embedded images. A product placeholder image implements the same interface as a product image, but there is only a single instance of the product placeholder image, accessible as `Catalog::ProductPlaceholderImage.cached`. <sup><a id="note-6-context" href="#notes">[6]</a></sup>
|
518
|
-
|
519
|
-
### Inventory, Pricing & Shipping SKUs
|
520
|
-
|
521
|
-
Beyond the Workarea `Catalog` module, several other Workarea subsystems store records representing the items of the retailer’s catalog. These additional models are outside the scope of this guide, however, the following examples briefly demonstrate the relationships of these models.
|
522
|
-
|
523
|
-
- `Workarea::Inventory` stores an `Inventory::Sku` for each item
|
524
|
-
- `Workarea::Pricing` stores a `Pricing::Sku` for each item
|
525
|
-
- `Workarea::Shipping` stores a `Shipping::Sku` for each item
|
526
|
-
- These models are related to each other and to the models of the `Catalog` by the retailer-provided SKU
|
527
|
-
|
528
|
-
For example: given a SKU, find the pricing, inventory, shipping, and product that match the SKU:
|
529
|
-
|
530
|
-
```ruby
|
531
|
-
sku = 'BALLCAP-BLUE-M'
|
532
|
-
pricing_sku = Workarea::Pricing::Sku.find(sku)
|
533
|
-
inventory_sku = Workarea::Inventory::Sku.find(sku)
|
534
|
-
shipping_sku = Workarea::Shipping::Sku.find(sku)
|
535
|
-
catalog_product = Workarea::Catalog::Product.find_by_sku(sku)
|
536
|
-
```
|
537
|
-
|
538
|
-
Notice the different method used to query for the product. This is because the SKU values are stored on the embedded variants, not the product itself.
|
539
|
-
|
540
|
-
As another example: given a catalog product ID, find the variants, SKUs, inventory collection, pricing collection, and shipping SKUs that correlate with the product:
|
541
|
-
|
542
|
-
```ruby
|
543
|
-
catalog_product_id = 'ABC123'
|
544
|
-
catalog_product = Workarea::Product.find(catalog_product_id)
|
545
|
-
variants = catalog_product.variants
|
546
|
-
skus = catalog_product.skus
|
547
|
-
inventory_collection = Workarea::Inventory::Collection.new(skus)
|
548
|
-
pricing_collection = Workarea::Pricing::Collection.new(skus)
|
549
|
-
shipping_skus = Workarea::Shipping::Sku.in(id: skus).to_a
|
550
|
-
```
|
551
|
-
|
552
|
-
There are also some additional models that represent products for use within the search, recommendations, and analytics subsystems, which are related by product ID. These will be explored further in an update to this guide.
|
553
|
-
|
554
|
-
## Presenting a Product
|
555
|
-
|
556
|
-
Workarea Storefront presents the retailer’s catalog to consumers using _products_ and does so in a variety of places:
|
557
|
-
|
558
|
-
- On dedicated product pages (product detail/show pages)
|
559
|
-
- Within search results and categories (product browse pages)
|
560
|
-
- As recommendations
|
561
|
-
- Within content
|
562
|
-
|
563
|
-
<figure id="figure-1">
|
564
|
-
<figcaption>
|
565
|
-
<p>Figure 1</p>
|
566
|
-
<p>A product detail page (show page) in the Storefront</p>
|
567
|
-
</figcaption>
|
568
|
-
<p><%= image_tag "images/storefront-product-show-page.png", alt: "Storefront product show page" %></p>
|
569
|
-
</figure>
|
570
|
-
|
571
|
-
<figure id="figure-2">
|
572
|
-
<figcaption>
|
573
|
-
<p>Figure 2</p>
|
574
|
-
<p>A category page (browse page) in the Storefront</p>
|
575
|
-
</figcaption>
|
576
|
-
<p><%= image_tag "images/storefront-product-browse-page.png", alt: "Storefront product browse page" %></p>
|
577
|
-
</figure>
|
578
|
-
|
579
|
-
Underlying each of the presented products is a `Catalog::Product` document.
|
580
|
-
|
581
|
-
Admin users with catalog access can additionally view the same catalog product through the Admin. In fact, like the Storefront, the Admin presents products in a variety of places:
|
582
|
-
|
583
|
-
- On dedicated product management pages
|
584
|
-
- Within search results and index pages
|
585
|
-
- Within dashboards
|
586
|
-
- Within the “featured products” UI
|
587
|
-
|
588
|
-
<figure id="figure-3">
|
589
|
-
<figcaption>
|
590
|
-
<p>Figure 3</p>
|
591
|
-
<p>A product show page in the Admin</p>
|
592
|
-
</figcaption>
|
593
|
-
<p><%= image_tag "images/admin-product-show-page.png", alt: "Admin product show page" %></p>
|
594
|
-
</figure>
|
595
|
-
|
596
|
-
<figure id="figure-4">
|
597
|
-
<figcaption>
|
598
|
-
<p>Figure 4</p>
|
599
|
-
<p>A products index page in the Admin</p>
|
600
|
-
</figcaption>
|
601
|
-
<p><%= image_tag "images/admin-products-index-page.png", alt: "Admin products index page" %></p>
|
602
|
-
</figure>
|
603
|
-
|
604
|
-
And like the Storefront, underlying each displayed product is a catalog product document.
|
605
|
-
|
606
|
-
However, in figures 1, 2, 3, and 4, you can see the presentations of the products include data from outside the catalog product document. To display a product, a controller wraps a catalog product document in an appropriate [view model](view-models.html) which is responsible for presenting the document within a particular context (e.g. Storefront or Admin). The view model extends the model with additional presentation logic, and joins the model with the other models needed to create the representation of the product the user within that context is expecting to see.
|
607
|
-
|
608
|
-
To demonstrate, consider the differing views of a product for consumers and administrators.
|
609
|
-
|
610
|
-
### Consumers’ View of the Catalog Product
|
611
|
-
|
612
|
-
Throughout the Storefront, each catalog product is wrapped in an instance of `Storefront::ProductViewModel` for presentation. <sup><a id="note-7-context" href="#notes">[7]</a></sup> The Storefront product view model is responsible for creating the view of the product a consumer is expecting to see in the Storefront while shopping. This view includes details beyond the catalog product, such as inventory, pricing, navigation, and recommendations (see Figure 1). The view model extends the existing interface of the catalog product and augments the interface with additional presentation logic and additional data joined from other models.
|
613
|
-
|
614
|
-
<!-- <figure id="listing-5">
|
615
|
-
<figcaption>
|
616
|
-
<p>Listing 5</p>
|
617
|
-
<p>The Storefront view model extends the catalog product interface</p>
|
618
|
-
</figcaption>
|
619
|
-
-->
|
620
|
-
|
621
|
-
Listing 5
|
622
|
-
The Storefront view model extends the catalog product interface
|
623
|
-
|
624
|
-
```ruby
|
625
|
-
changes_to_the_product_interface =
|
626
|
-
Workarea::Storefront::ProductViewModel.instance_methods(false) &
|
627
|
-
Workarea::Catalog::Product.instance_methods
|
628
|
-
|
629
|
-
puts changes_to_the_product_interface.sort
|
630
|
-
# browser_title
|
631
|
-
# cache_key
|
632
|
-
# images
|
633
|
-
# meta_description
|
634
|
-
# purchasable?
|
635
|
-
# variants
|
636
|
-
|
637
|
-
additions_to_the_product_interface =
|
638
|
-
Workarea::Storefront::ProductViewModel.instance_methods(false) -
|
639
|
-
Workarea::Catalog::Product.instance_methods
|
640
|
-
|
641
|
-
puts additions_to_the_product_interface.sort
|
642
|
-
# breadcrumbs
|
643
|
-
# browse_link_options
|
644
|
-
# catalog_id
|
645
|
-
# current_sku
|
646
|
-
# current_variant
|
647
|
-
# default_category
|
648
|
-
# has_prices?
|
649
|
-
# inventory
|
650
|
-
# inventory_purchasable?
|
651
|
-
# inventory_status
|
652
|
-
# on_sale?
|
653
|
-
# one_price?
|
654
|
-
# original_max_price
|
655
|
-
# original_min_price
|
656
|
-
# pricing
|
657
|
-
# primary_image
|
658
|
-
# recommendations
|
659
|
-
# sell_max_price
|
660
|
-
# sell_min_price
|
661
|
-
# show_original_range?
|
662
|
-
# show_sell_range?
|
663
|
-
# sku_options</code></pre>
|
664
|
-
```
|
665
|
-
<!-- </figure> -->
|
666
|
-
|
667
|
-
Listing 5 demonstrates how the product interface is modified when presenting a product in the Storefront, such as:
|
668
|
-
|
669
|
-
- `purchasable?` is redefined to consider pricing and inventory
|
670
|
-
- `variants` is modified to include only those variants that are active and have displayable inventory
|
671
|
-
- `browser_title` and `meta_description` are changed to fall back to `name` and `description` when blank
|
672
|
-
- `primary_image` encapsulates the logic for determining which image should represent the product when displaying it
|
673
|
-
- `breadcrumbs` join the catalog product with its position within the navigation taxonomy
|
674
|
-
- `recommendations` join the catalog product with its recommendations
|
675
|
-
- Various methods related to inventory and pricing join the catalog product with those subsystems
|
676
|
-
|
677
|
-
In all cases, the changes to the interface reflect the context of a consumer shopping the Storefront and present a product which aligns with the consumer’s expectations of the “product” concept.
|
678
|
-
|
679
|
-
### Administrators’ View of the Catalog Product
|
680
|
-
|
681
|
-
Throughout the Admin, each catalog product is wrapped in an instance of `Admin::ProductViewModel` for presentation. This view model similarly extends and augments the catalog product interface, but for a different context: administrators responsible for managing the catalog and store.
|
682
|
-
|
683
|
-
<!-- <figure id="listing-6">
|
684
|
-
<figcaption>
|
685
|
-
<p>Listing 6</p>
|
686
|
-
<p>The Admin view model extends the catalog product interface</p>
|
687
|
-
</figcaption> -->
|
688
|
-
|
689
|
-
Listing 6
|
690
|
-
The Admin view model extends the catalog product interface
|
691
|
-
|
692
|
-
```ruby
|
693
|
-
changes_to_the_product_interface =
|
694
|
-
Workarea::Admin::ProductViewModel.instance_methods(false) &
|
695
|
-
Workarea::Catalog::Product.instance_methods
|
696
|
-
|
697
|
-
puts changes_to_the_product_interface.sort
|
698
|
-
# categories
|
699
|
-
|
700
|
-
additions_to_the_product_interface =
|
701
|
-
Workarea::Admin::ProductViewModel.instance_methods(false) -
|
702
|
-
Workarea::Catalog::Product.instance_methods
|
703
|
-
|
704
|
-
puts additions_to_the_product_interface.sort
|
705
|
-
# analytics
|
706
|
-
# available_inventory
|
707
|
-
# categorization
|
708
|
-
# content
|
709
|
-
# customization_options
|
710
|
-
# default_category
|
711
|
-
# displayable?
|
712
|
-
# featured_categories
|
713
|
-
# has_prices?
|
714
|
-
# ignore_inventory?
|
715
|
-
# images_by_option
|
716
|
-
# inventory
|
717
|
-
# on_sale?
|
718
|
-
# one_price?
|
719
|
-
# options
|
720
|
-
# original_max_price
|
721
|
-
# original_min_price
|
722
|
-
# pricing
|
723
|
-
# pricing?
|
724
|
-
# primary_image
|
725
|
-
# rules_categories
|
726
|
-
# sales
|
727
|
-
# sell_max_price
|
728
|
-
# sell_min_price
|
729
|
-
# show_original_range?
|
730
|
-
# show_sell_range?
|
731
|
-
# storefront_recommendations
|
732
|
-
# storefront_view_model
|
733
|
-
# templates
|
734
|
-
# timeline
|
735
|
-
# variant_sell_price</code></pre>
|
736
|
-
```
|
737
|
-
<!-- </figure> -->
|
738
|
-
|
739
|
-
Listing 6 demonstrates the changes to the product interface that make the product suitable for presentation within the Admin. For instance:
|
740
|
-
|
741
|
-
- `analytics` provides analytics data to present insights to the retailer
|
742
|
-
- `categories` changes to a more sophisticated query that includes the categories that match the product according to product rules, and additional methods related to product categorization are added
|
743
|
-
- Methods such as `customization_options` and `templates` are used to present menus for product administration
|
744
|
-
- Remarkably, `storefront_view_model` and `timeline` each return an additional view model wrapping the same catalog product
|
745
|
-
|
746
|
-
In all of these examples, the changes reflect the needs of an administrator rather than a consumer.
|
747
|
-
|
748
|
-
Admins can toggle between these differing views of the same product using links in the Admin toolbar (in the Storefront) and the “View on Storefront” link (in the Admin).
|
749
|
-
|
750
|
-
## Managing Products, Variants & Product Images
|
751
|
-
|
752
|
-
The Admin view of the product, introduced above, is the primary means for admins to manage catalog products, variants, and product images within Workarea. Workarea 3.3 also introduces data files, allowing admins to import and export data from JSON and CSV files for integration with another system or software application. Developers have additional access to programmatic interfaces with which they can extend the platform, and a command line interface for executing developer-only tasks, such as running seeds.
|
753
|
-
|
754
|
-
### Admin Web Interface
|
755
|
-
|
756
|
-
Admin users with catalog access can manage products, variants, and product images through the Admin web interface. At a glance, this interface provides the ability to:
|
757
|
-
|
758
|
-
- Search, browse, and show existing products
|
759
|
-
- From a product show page:
|
760
|
-
- Edit the product’s fields
|
761
|
-
- Access the product’s embedded collections:
|
762
|
-
- Create, edit, delete, and re-order images
|
763
|
-
- Credit, edit, delete, and re-order variants
|
764
|
-
- Manage the recommendations settings for the product
|
765
|
-
- Manage the product’s categorization
|
766
|
-
- Access a timeline of past and upcoming activity on the product
|
767
|
-
- Access comments about the product from other admins or write your own comments
|
768
|
-
- View insights based on Workarea analytics
|
769
|
-
- Create a new product based on the current product (copy product)
|
770
|
-
- From the products index page:
|
771
|
-
- Search, sort, filter, and select to refine results for further action
|
772
|
-
- Edit each selection sequentially, bulk edit, or bulk delete
|
773
|
-
- Import or export
|
774
|
-
- Create a new product
|
775
|
-
|
776
|
-
Refer to figures 3, 4, and 5.
|
777
|
-
|
778
|
-
<figure id="figure-5">
|
779
|
-
<figcaption>
|
780
|
-
<p>Figure 5</p>
|
781
|
-
<p>Editing product fields in the Admin</p>
|
782
|
-
</figcaption>
|
783
|
-
<p><%= image_tag "images/editing-product-fields-in-the-admin.png", alt: "Editing product fields in the Admin" %></p>
|
784
|
-
</figure>
|
785
|
-
|
786
|
-
Since products and variants are releasable, edits may publish immediately or in the future (with a release).
|
787
|
-
|
788
|
-
Creating new products and copying products use multi-step workflows because both actions affect multiple models: the product, its embedded collections (variants and images), and the product’s categorization and navigation.
|
789
|
-
|
790
|
-
Plugins and applications extend this interface, so your application may include additional features not listed above.
|
791
|
-
|
792
|
-
### Data Files
|
793
|
-
|
794
|
-
Workarea 3.3 introduces importing from and exporting to data files (JSON and CSV). Imports/exports are accessible through the Admin, so administrators can use this feature to integrate Workarea with another software system (for example, importing catalog data exported from a warehouse, inventory, or POS system) or to view/edit Workarea data in another software application (such as a spreadsheet). Improvements to this feature are planned, such as a plugin to allow scheduling of imports and exports. A future guide will cover this feature in detail for developers.
|
795
|
-
|
796
|
-
### Command Line & Programmatic Interfaces
|
797
|
-
|
798
|
-
Since developers are typically super admins, they can use all the features of the Admin web interface.
|
799
|
-
|
800
|
-
However, they can also complete developer-only tasks related to product management through a command line interface. These tasks require shell access to the particular environment and include:
|
801
|
-
|
802
|
-
- [Seeding](seeds.html#seeding)
|
803
|
-
- Running repetitive actions with Rails _tasks_
|
804
|
-
- Running one-off actions non-interactively with Rails _runner_
|
805
|
-
- Running one-off actions interactively with Rails _console_
|
806
|
-
|
807
|
-
Developers also have access to application and platform source code (through gems and git repositories), allowing platform extensions that facilitate product management. Examples of this are:
|
808
|
-
|
809
|
-
- Extending existing or adding new products [seeds](seeds.html) (See `Workarea::ProductsSeeds`)
|
810
|
-
- Using existing [test factories](testing.html#factories) within your own [tests](testing.html#writing-new-tests) and [test decorators](testing.html#writing-test-decorators) and extending test factories as needed (See `Workarea::Factories::Catalog`)
|
811
|
-
- Extending existing or adding new [workers](workers.html) to manage products according to a schedule or in response to events
|
812
|
-
|
813
|
-
Finally, the <cite>Workarea API</cite> plugin provides a JSON over HTTP interface which allows management of products, variants, and product images. This allows for management of these models programmatically over the network. For example, another service can “push” product data to Workarea according to a schedule or events within the other system.
|
814
|
-
|
815
|
-
### Product State
|
816
|
-
|
817
|
-
Regardless of interface, be aware of application and document states affecting a given product.
|
818
|
-
|
819
|
-
The current Rails environment (and current _site_ if using <cite>Workarea Multi Site</cite>) determine the database to which the MongoDB driver is connected. Therefore the entire catalog products collection will vary on these states.
|
820
|
-
|
821
|
-
Furthermore, the current release and current locale may affect the field values of each product. All field values may vary by release (except for `slug`, which is explicitly not releasable), and the values of internationalized fields may vary by locale.
|
822
|
-
|
823
|
-
It’s also important to understand how administrable fields affect the state of a product when presenting it to consumers in the Storefront. Administration of `active` (products and variants), `purchasable`, `template`, `position` (variants and images), and the administration and availability of inventory and pricing have various effects on products presented in the Storefront (see Product State While Browsing for browsing examples; product showing examples will be included in a future update).
|
824
|
-
|
825
|
-
## Merchandising & Browsing the Storefront
|
826
|
-
|
827
|
-
Beyond managing the products, administrators need to organize them within the store. Although consumers can navigate to products directly by their slugs (see [Navigable](navigable.html)), this has limited application outside of social media and email marketing. Consumers depend on the store to lead them to the merchandise they are looking for.
|
828
|
-
|
829
|
-
Admins leverage this by managing the shopping experience in a way that entices consumers to buy. This process is called <dfn>merchandising</dfn> and involves a combination of automation (search, recommendations, analytics) and administration (navigation, content, pages, categories, search results customizations, recommendations settings, pricing, discounts). Administrators can manage what products are presented to consumers, along with where, when, and how.
|
830
|
-
|
831
|
-
### Presenting Results
|
832
|
-
|
833
|
-
As a result of merchandising, consumers experience products in a variety of places in the Storefront, such as:
|
834
|
-
|
835
|
-
- Full page browsing results like categories and search results
|
836
|
-
- Autocomplete results for quick search as you type navigation
|
837
|
-
- Content within layouts, navigation menus, content pages, system pages, categories, search results
|
838
|
-
- Recommendations within layouts, detail pages, carts, emails, and content
|
839
|
-
|
840
|
-
Many of these instances are displaying the products returned as the “results” of one or more API calls to Workarea subsystems, such as analytics, recommendations, and search. API calls of this sort each return an ordered collection of catalog product documents or document IDs (so the documents can be subsequently fetched from MongoDB) for a given query or other criteria. For example, the results could be products:
|
841
|
-
|
842
|
-
- matching a consumer's search query, possibly customized by an administrator
|
843
|
-
- matching a category, based on product rules and/or featured products
|
844
|
-
- recommended based on what's in the consumer's cart
|
845
|
-
- identified as top sellers or trending, based on analytics
|
846
|
-
|
847
|
-
In each case, the products that make up the results are each wrapped in an appropriate product view model and presented to the consumer, as described above in Presenting a Product.
|
848
|
-
|
849
|
-
Similar processes present products to administrators in the Admin within a variety of browsing contexts (search results, jump-to menu, index pages, dashboards).
|
850
|
-
|
851
|
-
### Additional Product Representations
|
852
|
-
|
853
|
-
To produce the product results described above, some Workarea subsystems maintain their own representations of each catalog product. These additional models and their uses are not covered here in detail but are introduced to provide a complete picture of the “product” concept. Just as each item of the retailer's catalog is modeled across subsystems, so is each catalog product.
|
854
|
-
|
855
|
-
#### Analytics Products
|
856
|
-
|
857
|
-
Workarea's analytics module stores an <dfn>analytics product</dfn> (see `Analytics::Product`) in MongoDB for each catalog product. Analytics products collectively provide the necessary data for product scores and aggregations, such as top sellers, most popular, and average selling price.
|
858
|
-
|
859
|
-
#### Recommendations Settings
|
860
|
-
|
861
|
-
The Workarea recommendations subsystem stores <dfn>recommendations settings</dfn> (see `Recommendations::Settings`) in MongoDB for each catalog product. Recommendations settings allow for administration of product recommendations, such as manually assigned recommendations, and the priority of sources used to provide automated recommendations.
|
862
|
-
|
863
|
-
#### Search Products
|
864
|
-
|
865
|
-
To facilitate real-time [search](searching.html), Workarea stores multiple search documents in Elasticsearch for each catalog product. Unlike analytics products and recommendations settings, search product documents are derived directly from the corresponding catalog product documents. [Search models](searching.html#search-models_9) such as `Search::Admin::CatalogProduct` and `Search::Storefront::Product` transform catalog product documents, joining fields within and across models as necessary, producing representations of the products suitable for real-time, full-text search (including matching, filtering, and sorting).
|
866
|
-
|
867
|
-
The various representations of a product are related by catalog product ID. The following example demonstrates these relationships.
|
868
|
-
|
869
|
-
```ruby
|
870
|
-
catalog_product_id = "02B81A9D07"
|
871
|
-
|
872
|
-
catalog_product =
|
873
|
-
Workarea::Catalog::Product.find(catalog_product_id)
|
874
|
-
|
875
|
-
analytics_product =
|
876
|
-
Workarea::Analytics::Product.find(catalog_product_id)
|
877
|
-
|
878
|
-
recommendations_settings =
|
879
|
-
Workarea::Recommendations::Settings.find(catalog_product_id)
|
880
|
-
|
881
|
-
search_products =
|
882
|
-
Workarea.elasticsearch.search(
|
883
|
-
index: '',
|
884
|
-
body: {
|
885
|
-
query: {
|
886
|
-
match: {
|
887
|
-
'_id' => "product-#{product_id}"
|
888
|
-
}
|
889
|
-
}
|
890
|
-
})['hits']['hits']
|
891
|
-
```
|
892
|
-
|
893
|
-
In the example above, `search_products` returns a collection because there are multiple search products for each catalog product (one for each Elasticsearch index; the exact number depends on several factors, such as the number of configured locales and which plugins are installed). Also note the search product IDs are prepended with `"product-"`. Each Elasticsearch index contains documents derived from various Mongoid document types, so the prefix is necessary to ensure uniqueness.
|
894
|
-
|
895
|
-
Remember, the product representations described in this section are used to determine _which_ products to show to consumers, but they aren't used to _display_ the products. That responsibility belongs to the catalog product documents (and view models).
|
896
|
-
|
897
|
-
### Product State While Browsing
|
898
|
-
|
899
|
-
As consumers browse the Storefront, the display of products is affected by various application and document states. The current Rails environment, the current locale, and the current site (if multi site) affect which Mongo database and Elasticsearch indexes are queried for products. Furthermore, the state of each Mongo document is affected by current locale and current release (release is applicable only when previewing the Storefront as an admin).
|
900
|
-
|
901
|
-
#### Product Inclusion
|
902
|
-
|
903
|
-
Each of the merchandising subsystems introduced above has its own logic to determine which products are returned for a given query or criteria. In all cases, _inactive products are excluded from results_; that is, they aren't displayed to consumers in the Storefront. A product's activeness is administrable; the product and each of its variants has an `active` field. The value of this field varies by release and locale, so each combination of those application states may produce a different value for `active`. Furthermore, a product is considered active only if one or more of its embedded variants are also active.
|
904
|
-
|
905
|
-
```ruby
|
906
|
-
product =
|
907
|
-
Workarea::Catalog::Product.create(name: 'Keyed Padlock')
|
908
|
-
|
909
|
-
variant =
|
910
|
-
product.variants.create(sku: 'KEYPAD-S-1-14')
|
911
|
-
|
912
|
-
variant.active?
|
913
|
-
# => true
|
914
|
-
|
915
|
-
product.active?
|
916
|
-
# => true
|
917
|
-
|
918
|
-
variant.update_attributes(active: false)
|
919
|
-
|
920
|
-
variant.active?
|
921
|
-
# => false
|
922
|
-
|
923
|
-
product.active?
|
924
|
-
# => false
|
925
|
-
```
|
926
|
-
|
927
|
-
#### Field Inclusion & Values
|
928
|
-
|
929
|
-
For each product that _is_ displayed, a view model and several partials and UI components are responsible for presenting the product. For example, the following ingredients may go into displaying a product in a browsing context within the Storefront:
|
930
|
-
|
931
|
-
- `Workarea::Storefront::ProductViewModel`
|
932
|
-
- _workarea/storefront/products/\_summary.html.haml_
|
933
|
-
- _workarea/storefront/products/\_pricing.html.haml_
|
934
|
-
- _workarea/storefront/products/\_price.html.haml_
|
935
|
-
- `.product-summary`
|
936
|
-
- `.product-prices`
|
937
|
-
|
938
|
-
Each of these is involved in determining which fields are included/excluded and how they are arranged.
|
939
|
-
|
940
|
-
Furthermore, the value of each field is subject to the current locale and current release (if present). The locale affects all internationalized fields, while the release affects nearly all fields.
|
941
|
-
|
942
|
-
#### Primary Image
|
943
|
-
|
944
|
-
Lastly, the image used to represent the product while browsing—the product's primary image—is determined by logic in the view model used to present the product. The behavior may be affected by plugins and extensions, but the default logic is to use the _first_ image, according to the administrable `position` of each image.
|
945
|
-
|
946
|
-
The following example re-uses the product and images created in Catalog Product Images.
|
947
|
-
|
948
|
-
```ruby
|
949
|
-
# the product has 2 images
|
950
|
-
catalog_product.images.map(&:name)
|
951
|
-
# => ["3_years.jpg", "5_years.jpg"]
|
952
|
-
|
953
|
-
# the "3_years" image is positioned first
|
954
|
-
catalog_product.images.map(&:position)
|
955
|
-
# => [0, 1]
|
956
|
-
|
957
|
-
# initialize a Storefront view model
|
958
|
-
storefront_product =
|
959
|
-
Workarea::Storefront::ProductViewModel.wrap(catalog_product)
|
960
|
-
|
961
|
-
# the "3_years" image is the primary image
|
962
|
-
storefront_product.primary_image.name
|
963
|
-
# => "3_years.jpg"
|
964
|
-
```
|
965
|
-
|
966
|
-
![](images/3-years-primary-image.png)
|
967
|
-
|
968
|
-
```ruby
|
969
|
-
# swap the image positions
|
970
|
-
catalog_product.images.first.update_attributes(position: 1)
|
971
|
-
catalog_product.images.second.update_attributes(position: 0)
|
972
|
-
catalog_product.images.map(&:position)
|
973
|
-
# => [1, 0]
|
974
|
-
|
975
|
-
# re-initialize the view model to simulate a new request
|
976
|
-
# (primary_image is cached for the duration of each request)
|
977
|
-
storefront_product =
|
978
|
-
Workarea::Storefront::ProductViewModel.wrap(catalog_product)
|
979
|
-
|
980
|
-
# now "5_years" is the primary image
|
981
|
-
storefront_product.primary_image.name
|
982
|
-
# => "5_years.jpg"
|
983
|
-
```
|
984
|
-
|
985
|
-
![](images/5-years-primary-image.png)
|
986
|
-
|
987
|
-
If the product has no images, the placeholder image is used.
|
988
|
-
|
989
|
-
```ruby
|
990
|
-
new_storefront_product =
|
991
|
-
Workarea::Storefront::ProductViewModel
|
992
|
-
.wrap(Workarea::Catalog::Product.new)
|
993
|
-
|
994
|
-
new_storefront_product.primary_image.name
|
995
|
-
# => "product_placeholder.jpg"
|
996
|
-
```
|
997
|
-
|
998
|
-
## Showing Products
|
999
|
-
|
1000
|
-
After browsing to narrow the catalog to a specific product, the _show_, or _detail_, page presents the product to the consumer with additional details: more images, larger images, a full description, recommendations, etc. Refer to Figure 1 for an example. The product show view presents the product's options, allowing the consumer to reduce the product to a specific item for purchase.
|
1001
|
-
|
1002
|
-
### Product Options
|
1003
|
-
|
1004
|
-
Conceptually, <dfn>product options</dfn> are the distinct values from which a consumer may choose to reduce a product (a group of items) to a specific item (identified by its SKU) for purchase. The options are derived from the collective details of the product's variants, after flattening each member's values. Concretely, in code and UI, the term "options" may refer to several different data structures and UI abstractions, but in each instance, the usage is generally aligned with the concept of product options just described.
|
1005
|
-
|
1006
|
-
Options (for example: Blue, Red, Large, Small) are typically grouped by name or key (for example: Color, Size) and presented as a multi-dimensional matrix, where the intersections represent the uniquely identifiable items that make up the product. To make this concrete, review the Keyed Padlock product introduced above. That product's variants collectively have 6 unique values, organized into 3 groupings.
|
1007
|
-
|
1008
|
-
```ruby
|
1009
|
-
option_groupings =
|
1010
|
-
keyed_padlock.variants.map(&:details).map(&:keys).flatten.uniq.sort
|
1011
|
-
options =
|
1012
|
-
keyed_padlock.variants.map(&:details).map(&:values).flatten.uniq.sort
|
1013
|
-
|
1014
|
-
option_groupings.count
|
1015
|
-
# => 3
|
1016
|
-
|
1017
|
-
puts option_groupings
|
1018
|
-
# Shackle Diameter
|
1019
|
-
# Shackle Length
|
1020
|
-
# Shackle Material
|
1021
|
-
|
1022
|
-
options.count
|
1023
|
-
# => 6
|
1024
|
-
|
1025
|
-
puts options
|
1026
|
-
# 1"
|
1027
|
-
# 1/2"
|
1028
|
-
# 1/4"
|
1029
|
-
# 2"
|
1030
|
-
# Brass
|
1031
|
-
# Steel
|
1032
|
-
```
|
1033
|
-
|
1034
|
-
How these options are presented to consumers varies by template (templates are covered next). The following image shows the product displayed using the option selects template.
|
1035
|
-
|
1036
|
-
![](images/option-selects-template.png)
|
1037
|
-
|
1038
|
-
Since the data is well designed and managed to this point, selecting a value from each of the 3 selects matches exactly 1 variant within the product. The SKU of that variant is used to identify the item to be purchased if the consumer adds to cart.
|
1039
|
-
|
1040
|
-
### Product Templates
|
1041
|
-
|
1042
|
-
Each product has an administrable template which is managed by admins and controls the presentation of the product in the Storefront. Specifically, each template is a combination of a view model and partial used to display the product in the Storefront.
|
1043
|
-
|
1044
|
-
Workarea (since v3.3) includes 3 templates: Generic, Option Selects, and Option Thumbnails. However, your application may include more templates, since plugins and applications can add their own templates (see [Add, Remove, or Change a Product Template](add-remove-or-change-a-product-template.html)).
|
1045
|
-
|
1046
|
-
The following snippets provide some examples of how to find which plugins are available to your application and how to find the relevant code for the templates. These examples are for an application with several plugins installed and its own custom "Pre Owned" template.
|
1047
|
-
|
1048
|
-
List the templates offered for each product within the Admin:
|
1049
|
-
|
1050
|
-
```ruby
|
1051
|
-
puts Workarea.config.product_templates.sort
|
1052
|
-
# gift_card
|
1053
|
-
# option_selects
|
1054
|
-
# option_thumbnails
|
1055
|
-
# pre_owned
|
1056
|
-
# swatches
|
1057
|
-
# test_product
|
1058
|
-
```
|
1059
|
-
|
1060
|
-
From the shell, list all product template view model and partial source code files that exist within your application and the specific version of the platform and plugins you are running. You can also do this search from your editor if that is preferrable.
|
1061
|
-
|
1062
|
-
```bash
|
1063
|
-
$ find . $(bundle show --paths) -type f -path '*app*view*workarea*storefront*product*templates*' | grep -o -e 'workarea-.*$' -e '^\..*$' | sort
|
1064
|
-
./app/view_models/workarea/storefront/product_templates/pre_owned_view_model.rb
|
1065
|
-
./app/views/workarea/storefront/products/templates/_pre_owned.html.haml
|
1066
|
-
workarea-gift_cards-3.4.0/app/view_models/workarea/storefront/product_templates/gift_card_view_model.rb
|
1067
|
-
workarea-gift_cards-3.4.0/app/views/workarea/storefront/products/templates/_gift_card.html.haml
|
1068
|
-
workarea-storefront-3.3.2/app/view_models/workarea/storefront/product_templates/option_selects_view_model.rb
|
1069
|
-
workarea-storefront-3.3.2/app/view_models/workarea/storefront/product_templates/option_thumbnails_view_model.rb
|
1070
|
-
workarea-storefront-3.3.2/app/view_models/workarea/storefront/product_templates/test_product_view_model.rb
|
1071
|
-
workarea-storefront-3.3.2/app/views/workarea/storefront/products/templates/_generic.html.haml
|
1072
|
-
workarea-storefront-3.3.2/app/views/workarea/storefront/products/templates/_option_selects.html.haml
|
1073
|
-
workarea-storefront-3.3.2/app/views/workarea/storefront/products/templates/_option_thumbnails.html.haml
|
1074
|
-
workarea-storefront-3.3.2/app/views/workarea/storefront/products/templates/_test.html.haml
|
1075
|
-
workarea-swatches-1.0.1/app/view_models/workarea/storefront/product_templates/swatches_view_model.rb
|
1076
|
-
workarea-swatches-1.0.1/app/views/workarea/storefront/products/templates/_swatches.html.haml
|
1077
|
-
```
|
1078
|
-
|
1079
|
-
The Generic template uses the default Storefront view model, while other templates use a more specialized view model that inherits from the default Storefront product view model (for example, Option Selects uses `Storefront::ProductTemplates::OptionSelectsViewModel`).
|
1080
|
-
|
1081
|
-
### Product State While Showing
|
1082
|
-
|
1083
|
-
Within the Storefront, several states affect the display of a product when showing.
|
1084
|
-
|
1085
|
-
#### Product Display
|
1086
|
-
|
1087
|
-
Whether a product displays at all is affected by its activeness. Consumers cannot view inactive products. Navigating to an inactive product (e.g. from an email or bookmarked URL) results in `InvalidDisplay` (404 response).
|
1088
|
-
|
1089
|
-
![](images/invalid-display.png)
|
1090
|
-
|
1091
|
-
Admins can view inactive products in the Storefront.
|
1092
|
-
|
1093
|
-
For a product to be considered active, it's `active` field must be `true` and it must have at least one active variant. Remember that the active field's value varies by locale (since Workarea 3.3).
|
1094
|
-
|
1095
|
-
#### Field Inclusion & Values
|
1096
|
-
|
1097
|
-
When showing a product in the Storefront, the product's template affects which fields are included/excluded, their current values, and how they are presented (the overall layout/design for the product).
|
1098
|
-
|
1099
|
-
For each product that _is_ displayed, a view model and several partials and UI components are responsible for presenting the product. For example, the following ingredients may go into displaying a product in a product detail context within the Storefront:
|
1100
|
-
|
1101
|
-
- `Workarea::Storefront::ProductViewModel`
|
1102
|
-
- _workarea/storefront/products/show.html.haml_
|
1103
|
-
- _workarea/storefront/products/templates/\_generic.html.haml_
|
1104
|
-
- _workarea/storefront/products/\_pricing.html.haml_
|
1105
|
-
- _workarea/storefront/products/\_price.html.haml_
|
1106
|
-
- `.product-detail-container`
|
1107
|
-
- `.product-details`
|
1108
|
-
- `.product-prices`
|
1109
|
-
|
1110
|
-
Each of these is involved in determining which fields are included/excluded and how they are arranged.
|
1111
|
-
|
1112
|
-
Furthermore, the value of each field is subject to the current locale and current release (if present). The locale affects all internationalized fields, while the release affects nearly all fields.
|
1113
|
-
|
1114
|
-
#### Inclusion of Options
|
1115
|
-
|
1116
|
-
Since a product's options are derived from its variants' details, _which options_ are included is determined in part by _which variants_ are included. The Storefront product view model redefines the catalog product's `variants` collection to include only those variants that are active and have displayable inventory (the concept of displayable inventory is outside the scope of this guide). Therefore, variants that are inactive or whose inventory is not displayable are not considered when creating the options for the product.
|
1117
|
-
|
1118
|
-
The following examples demonstrates how the product's variants collection and options are modified when presented for display in the Storefront.
|
1119
|
-
|
1120
|
-
```ruby
|
1121
|
-
# find the 'Tropical Drink Mix' product'
|
1122
|
-
model = Workarea::Catalog::Product.find_by(name: 'Tropical Drink Mix')
|
1123
|
-
# wrap it in a Storefront view model
|
1124
|
-
view_model = Workarea::Storefront::ProductViewModel.wrap(model)
|
1125
|
-
|
1126
|
-
# The variants count is the same at this point
|
1127
|
-
model.variants.count
|
1128
|
-
# => 3
|
1129
|
-
view_model.variants.count
|
1130
|
-
# => 3
|
1131
|
-
```
|
1132
|
-
|
1133
|
-
The product therefore has 3 variants and 3 options:
|
1134
|
-
|
1135
|
-
![](images/3-variants-3-options.png)
|
1136
|
-
|
1137
|
-
```ruby
|
1138
|
-
# set one of the variants to inactive
|
1139
|
-
model.variants.second.update_attributes!(active: false)
|
1140
|
-
# the model still has 3 variants
|
1141
|
-
model.variants.count
|
1142
|
-
# => 3
|
1143
|
-
|
1144
|
-
# re-create the view model (to bust cache)
|
1145
|
-
view_model = Workarea::Storefront::ProductViewModel.wrap(model)
|
1146
|
-
# the Storefront view of the product has only 2 variants
|
1147
|
-
view_model.variants.count
|
1148
|
-
# => 2
|
1149
|
-
|
1150
|
-
# choose another variant and make the corresponding
|
1151
|
-
# inventory undisplayable
|
1152
|
-
model.variants.last.tap do |variant|
|
1153
|
-
Workarea::Inventory::Sku
|
1154
|
-
.find(variant.sku)
|
1155
|
-
.update_attributes!(policy: 'standard', available: '0')
|
1156
|
-
end
|
1157
|
-
model.variants.count
|
1158
|
-
# => 3
|
1159
|
-
|
1160
|
-
# now the Storefront view of the product contains only a single variant
|
1161
|
-
view_model = Workarea::Storefront::ProductViewModel.wrap(model)
|
1162
|
-
view_model.variants.count
|
1163
|
-
# => 1
|
1164
|
-
```
|
1165
|
-
|
1166
|
-
Now the product has 3 variants, but only 1 option, so the option select menu is removed in the Storefront:
|
1167
|
-
|
1168
|
-
![](images/3-variants-1-option.png)
|
1169
|
-
|
1170
|
-
#### Presentation of Options
|
1171
|
-
|
1172
|
-
You saw above an image of the Keyed Padlock product displayed using the Option Selects template, where the options (for example Steel, Brass, 1", 2") are grouped by key (Shackle Material, Shackle Length). In contrast to this, the Generic template groups options by variant, essentially converting the matrix of options into a flat list of items.
|
1173
|
-
|
1174
|
-
```ruby
|
1175
|
-
# change the 'Keyed Padlock' product to the generic template
|
1176
|
-
keyed_padlock =
|
1177
|
-
Workarea::Catalog::Product.find_by(name: 'Keyed Padlock')
|
1178
|
-
keyed_padlock
|
1179
|
-
.update_attributes!(template: 'generic')
|
1180
|
-
```
|
1181
|
-
|
1182
|
-
The Keyed Padlock displayed with the Generic template:
|
1183
|
-
|
1184
|
-
![](images/generic-template.png)
|
1185
|
-
|
1186
|
-
The Option Thumbnails template groups options by details key, like the Option Selects template. But it uses a different UI to present the options, which includes a thumbnail image representing the option, when available.
|
1187
|
-
|
1188
|
-
```ruby
|
1189
|
-
# change the 'Extended Service Plan' product
|
1190
|
-
# to the option thumbnails template
|
1191
|
-
extended_service_plan =
|
1192
|
-
Workarea::Catalog::Product.find_by(name: 'Extended Service Plan')
|
1193
|
-
extended_service_plan
|
1194
|
-
.update_attributes!(template: 'option_thumbnails')
|
1195
|
-
```
|
1196
|
-
|
1197
|
-
An example of Option Thumbnails:
|
1198
|
-
|
1199
|
-
![](images/option-thumbnails-template.png)
|
1200
|
-
|
1201
|
-
#### Tracking Option State
|
1202
|
-
|
1203
|
-
As a consumer selects options in the Storefront, the UI updates asynchronously. The state of the option selections is stored as params in the URL.
|
1204
|
-
|
1205
|
-
The generic template prefers the `sku` param (e.g. `sku=KEYPAD-S-1-12`, while the other templates prefer params that match specific options (e.g. `Color=Blue,Size=Large`). However, either type of param is respected by all templates. Requesting a product with these URL params will attempt to restore the indicated option state.
|
1206
|
-
|
1207
|
-
#### Presentation of Product Images, Pricing & Inventory
|
1208
|
-
|
1209
|
-
Which images are shown and which image is selected depends on the product template and which options are selected. Remember that each image may be associated with a product option.
|
1210
|
-
|
1211
|
-
The generic template always displays all the product images. The following examples use the Extended Service Plan product from above, shown below using the generic template.
|
1212
|
-
|
1213
|
-
![](images/generic-product-template-images-no-options-selected.png)
|
1214
|
-
|
1215
|
-
When options are selected, the generic template will try to find images matching those options and will select the first such image. In the following screenshot, the "5 years" option is selected, so the image corresponding to that option is selected.
|
1216
|
-
|
1217
|
-
![](images/generic-product-template-images-options-selected.png)
|
1218
|
-
|
1219
|
-
Product templates other than generic will show _only_ the images which match the selected options. The screenshot below changes the template to Option Selects. The image matching the selected "5 years" option is selected, and is the only image displayed. The other image does not match this option and is hidden.
|
1220
|
-
|
1221
|
-
![](images/option-selects-product-template-images-options-selected.png)
|
1222
|
-
|
1223
|
-
When no options are selected in this type of template, only the images that match the options of the product's primary image will be displayed (since Workarea 3.3.2).
|
1224
|
-
|
1225
|
-
The selection of options also affects the display of pricing and inventory. The specifics of pricing and inventory are out of scope for this guide, but notice in the following examples how the selection of options affects the display of pricing and inventory. Once enough options are selected to identify a specific item, the item's SKU is used to look up specific pricing and inventory information. Without a specific SKU, the information is generalized (price ranges) or omitted (inventory).
|
1226
|
-
|
1227
|
-
once the options match a specific sku, we know the exact price for the given sku and quantity
|
1228
|
-
|
1229
|
-
The following example contains price ranges and no inventory status because a specific item has not been selected:
|
1230
|
-
|
1231
|
-
![](images/price-display-no-options.png)
|
1232
|
-
|
1233
|
-
In the next example a specific item is selected, so distinct pricing and inventory information is shown:
|
1234
|
-
|
1235
|
-
![](images/price-display-options-selected.png)
|
1236
|
-
|
1237
|
-
#### Product Purchasability
|
1238
|
-
|
1239
|
-
For a product to be purchasable, it must have at least 1 active variant, the inventory related to that variant's SKU must be purchasable, and the pricing related to the variant's SKU must have an active price. When these conditions are not met, the product is displayed, but consumers cannot purchase any of its items:
|
1240
|
-
|
1241
|
-
![](images/unpurchasable-product.png)
|
1242
|
-
|
1243
|
-
## Summary
|
1244
|
-
|
1245
|
-
- Workarea groups related buy varying items into catalog products, where the shared details are stored on the product, and the details on which the items vary are stored on embedded variants
|
1246
|
-
- Each variant stores a SKU, a retailer-provided ID which encodes the variant’s distinct details and identifies the item throughout the Workarea system and across other systems
|
1247
|
-
- Products also embed images, each of which may be associated with a particular product option (for example, the color _indigo_)
|
1248
|
-
- Workarea’s inventory, pricing, and shipping subsystems store additional records for each item; records are related by SKU
|
1249
|
-
- View models “wrap” catalog products, extending the product interface for presentation within a particular context (such as Admin or Storefront); this involves joining the catalog product with related models
|
1250
|
-
- Administrators manage products and related models through the Admin web interface and data files, which allow import from and export to other software systems or applications
|
1251
|
-
- Developers can additionally manage the catalog through a command line interface, through extension of the Ruby interface, and using the JSON/HTTP interface provided by the Workarea API plugin
|
1252
|
-
- Merchandising is a combination of automation and administration which determines the placement of products within the Storefront and entices consumers to buy
|
1253
|
-
- A variety of application and document states affect the presentation of products to consumers in the Storefront
|
1254
|
-
- A Storefront product show page presents the product details and options to consumers, so they can narrow the product to a specific item for purchase
|
1255
|
-
|
1256
|
-
## Notes
|
1257
|
-
|
1258
|
-
[1] If you’re working with a catalog that isn’t organized this way, storing exactly one variant per product may be preferable.
|
1259
|
-
|
1260
|
-
[2] Upcoming additions to this guide will explicitly define and explain the concept of options, and further explore product browsing and showing.
|
1261
|
-
|
1262
|
-
[3] Templates and options will be covered in a future update to this guide.
|
1263
|
-
|
1264
|
-
[4] However, you may want to store the colors as separate values for the product’s filters. Filters will be covered in a forthcoming guide on searching products.
|
1265
|
-
|
1266
|
-
[5] Upcoming additions to this guide will provide additional examples of this in the context of showing products in the Storefront.
|
1267
|
-
|
1268
|
-
[6] You can change the image file used for the product placeholder image. A forthcoming guide on extending product images will provide step-by-step instructions.
|
1269
|
-
|
1270
|
-
[7] A future section on templates will cover additional product view models in the Storefront.
|