Magnolia 5.3 reached end of life on June 30, 2017. This branch is no longer supported, see End-of-life policy.
The Shop module offers basic e-commerce functionality for Magnolia. The module provides a flexible data structure and a set of classes for handling the data. You define the look and behavior of the shop. The module includes templates and components that adhere to the pop theme. Magnolia partner fastforward started the Shop module and developed the first version in collaboration with Magnolia International Ltd.
Features:
You can view the sample shop in Pages > /demo-features/modules/sample-shop
.
The Shop module is not part of the Magnolia bundle. Download the Shop bundle from our Nexus repository and install the following jars:
magnolia-module-shop
magnolia-module-ocm
: saves the shopping cart bean and cart items to JCR nodes, distributes order numbers, and configures what to save.jackrabbit-ocm
Shop is a Community Edition module. It is typically not installed.
The Shop module is configured at Configuration > /modules/shop
.
Node name | Value |
---|---|
modules | |
shop | |
apps | |
dialogs | |
fieldTypes | |
templates |
The Magnolia OCM module is used to save the shopping cart bean and cart items to nodes, to distribute order numbers (order number is the name of the cart node), and to configure what to save. It implements the shopping cart functionality and is configured at Configuration > /modules/ocm
. Here's the configuration for the of the defaultShoppingCart
.
Node name | Value |
---|---|
modules | |
ocm | |
pages | |
config | |
classDescriptors | |
defaultShoppingCart | |
fieldDescriptors | |
beanDescriptors | |
collectionDescriptors | |
class | org.apache.jackrabbit.ocm.mapper.model.ClassDescriptor |
className | info.magnolia.module.shop.beans.DefaultShoppingCartImpl |
jcrType | mgnl:contentNode |
nextBeanId | 176 |
parentJcrType | mgnl:folder |
defaultShoppingCartItem | |
defaultShoppingCartOption |
All shop related items except product categories are managed in apps. Product categories are created automatically for each page based on the Product Category template.
The Manage Shops group contains apps that allow you manage items for all shops in once place. Create new shops in All shops.
When you create a shop, a dedicated app group is created automatically for that shop. This allows you to manage permissions for each shop. Here's the app launcher menu for the Sample Shop.
The module creates four workspaces:
shops
: stores configuration for all shopsshopProducts
: stores the product details for all shops.shopSuppliers
: stores the supplier details for all shops.shoppingCarts
: stores shopping carts for all shops.To create a new shop, go to Manage Shops > All Shops and click Add Shop. The module also ships with a sample shop that you can customize to your liking.
When you save the new shop, Magnolia creates dedicated app group for quick access to the shop.
Parent nodes for the various configuration options are created automatically. You can add as many tax and price categories, currencies, countries and shipping options as necessary by selecting the parent item and adding relevant sub items. The configured options are assigned on a product-by-product basis when adding products.
Fields:
The default classes and cart session variable are auto filled. Do not change these unless you have a customized implementation.
DefaultPriceCategoryManagerImpl
is the default implementation of the PriceCategoryManager
interface and is used get the default price category for a selected shop.DefaultShoppingCartImpl
is the default implementation of the ShoppingCart
interface. It is registered in the ocm
module configuration (above). The implementation includes order, billing and shipping addresses, and allows only one cart item per product (i.e. when adding the same product multiple times, the quantity of the cart item will be increased).Value added tax (VAT) is levied at different rates on different products. It is calculated as a percentage of the net price. You can create several tax categories such as normal goods at 7.6%, reduced at 2.4% and so on. Tax is added to the price at checkout. The amount of tax applied to a particular product depends on the price category the product belongs to.
Fields:
001-Books
. The ID can contain letters, numbers and special characters with certain exceptions.Books
.7.6
into this box. The number format is Double where period is a decimal point.The Shop module supports multiple currencies. This is useful for large shops with a global customer base and shops that are located near a two-country border.
While it is possible to configure multiple currencies, only one currency is used at a time. Customers cannot switch between currencies in the default implementation; all products are priced in the currency defined in the default price category.
Fields:
USD
, EUR
or CHF
. It is displayed to editors when they edit product details.$
, €
or CHF
. It is displayed to customers next to the product price in the shop.###,###.00
. The corresponding convention for Swiss Francs is 1'234.55 (###'###.00
) and for euros 1.234,56 (###.###,00
).Price category defines the currency in which a product is sold and whether tax should be applied.
Fields:
Tax-free Swiss franc
.Once your price categories are set up, launch the All shops app and select the default currency in the Systems tab.
DefaultPriceCategoryManagerImp
l is the default implementation of the PriceCategoryManager
interface and allows to display one price category at a time. To sell the same product in different currencies and tax scenarios, for example, you need to write a custom price category class that allows switching between price categories. Suppose you sell the same product in two different currencies: euros and Swiss francs. Customers who pay euros come from the euro area where your shop is located so they need to pay value-added tax (VAT). Swiss franc customers come from across the border in Switzerland so no tax is levied on their purchases. You need two price categories: Standard selling price and Tax-free Swiss franc. You also need to allow customers to choose the currency in which they wish to pay for products.
You can set up different shipping options for different countries.
Shipping options are currently not used by the default shopping cart implementation.
Fields:
Define the countries you ship to.
Countries are currently not used by the default shopping cart implementation.
Fields:
You can add product suppliers in Manage shops > All suppliers or the dedicated Suppliers app for the shop. Editors select suppliers for each product when adding products. Supplier details are stored in the shopSuppliers
workspace. The Supplier, Address and Logo tabs include fields for complete supplier details.
Supplier content is currently not rendered on the product category and detail pages, but you can customize the components to render it.
The module includes page templates to display a shop on your site. A shop has its own navigation. For this reason, all pages except the shop home and category pages should be hidden from standard navigation in the page properties dialogs. The page templates are configured in Configuration > /modules/shop/templates/pages
.
At minimum, a shop requires these pages:
Page | Template | Description |
---|---|---|
<shop name> | Shop Home | Shop home page. When you add a page based on the Shop Home template the system creates a basic shop structure automatically. In the page properties dialog you can select the relevant shop. |
| Product Category | One page for each product category. |
| Product Detail | A single page. Renders details of all products |
| Shop Search Result | A single page. Renders product search results. |
| Shop Keyword Search Result | A single page. Renders keyword search results. Keywords are set when adding products and rendered in the extras tag cloud component. |
| Shopping Cart | Adds a shopping cart. |
| Checkout Form | Step one of the checkout process. Includes a shipping address form. |
| Shop Form Step | Step two of the checkout process. Includes a billing address form. |
| Confirm Order Form Step | Step three of the checkout process. Allows user to confirm order and address information. |
| Confirmation Page | Confirms order and provides an order number. |
Categories organize the products sold in the shop. A book shop might have categories such as Travel, Gardening and Audiobooks. The Travel category might split further into Europe, Latin America and Middle East. The purpose of categories is to help customers browse the shop and find products they are interested in. Each category is a page in the shop site hierarchy. Make sure your category taxonomy is logical. It makes finding products quicker.
Product categories are created automatically for each page based on the Product Category template. The product category page structure determines the navigational structure in the shop. The module automatically creates a list of categories in the Products app for selection when editors add products. Here's the page structure for our T Shirt shop example.
This is what the shop navigation looks like to the visitor:
The Shop module uses the Categories app to assign keywords to products. You can select keywords as you add products. The extras tag cloud component that is autogenerated on the Product Category template renders links for all keywords assigned to products within the product category. When clicked, products that have the keyword are displayed.
Products are the items sold in the shop: books in a book shop, songs in a music shop and so on.
Add products in the Products app. The Product Detail template renders products on pages. You can organize products into folders to match your categories or any other suitable structure, for example by supplier. The structure has no bearing on functionality.
The Product dialog contains all the necessary fields for your products. All shop configuration options such as price categories, shipping options and countries, and suppliers can be linked to individual products.
Product details:
978-1613820773
for A Tale of Two Cities by Charles Dickens. The ID can also match a product ID in an external warehousing system if you import products into Magnolia. Use IDs that make sense for your products. The ID is not displayed to customers in the shop by default.Categories and keywords:
Pricing:
Weight and size:
The product looks like this on the category page:
And like this on the detail page:
You can also edit products directly on Web pages in the page editor. Click the Edit Product link on a category page to open the dialog in the Products app.
Product options are variations within one product such as sizes or colors. For example, if you sell the same shirt in different sizes and colors create variants such as S, M, L, XL, red, white, yellow etc. Different options can be created for each product.
The options are displayed in dropdowns on the product category and detail pages.
The Shopping Cart component is autogenerated in the extras area on product category and detail pages. The component allows users to add products to the cart. You can make the component available on any template.
The View Shopping Cart link opens the Shopping Cart page that is based on the Shopping Cart template. Prices of all units are totaled and VAT is added if applicable. In the cart the customer can add and remove units of a product using the plus ( + ), minus ( - ) and delete buttons.
Checkout is a three-step form that asks the customer to provide a shipping address, billing address and confirmation. Once the order is successfully submitted, the customer is given an order number.
You can configure the form on the shipping address page (Checkout Form template) to send emails to the user and a shop administrator. Here's a Freemarker example you can use to render product and cart details in the confirmation email. See Form module and Form component for more.
Thank you for your order: Your order number is: ${cartId} [#list cart.getCartItems() as product] Product Name: ${product.productTitle} Quantity: ${product.quantity} Unit Price: ${product.unitPrice?string("0.00")} Total: ${product.itemTotal?string("0.00")} [/#list] Subtotal: ${cart.grossTotalExclTax?string("0.00")} Vat: ${cart.itemTaxTotal?string("0.00")} Total: ${cart.grossTotalInclTax?string("0.00")}
Full details of the order are stored in the Shopping Carts app. The order number matches the shopping cart node name.
The default SaveAndConfirmFormProcessor
class converts the order JavaBean object to nodes and properties using Jackrabbit's Object Content Manager (OCM) framework. This functionality is provided by the Magnolia OCM module which is required. You can export the order to a third party warehouse or ERP system by writing a custom shopping cart processor.
Use the Shop Product Teaser component to showcase products. The component is available in main area on the shop home page and in extras area on other appropriate shop templates. The purpose of a teaser is to promote the product and invite the customer to find out more.
The shop module functionality is available in the STK. It is a good example of how to extend the STK to provide additional functionality.
Templates are made available in STK > Site Definitions /default/templates/availability/templates
.
Node name | Value |
---|---|
default | |
templates | |
prototype | |
availability | |
templates | |
stkHome | |
... | |
shopHome | |
id | shop:pages/shopHome |
shopProductCategory | |
... |
Page templates are configured at Configuration > /modules/shop/templates/pages
. They are STK templates and define only modifications to the template prototype.
category
: feature
. This is relevant to their availability within the page hierarchy. See Categories and subcategories for more.class
: STKPage
. See Page template properties for more.renderType
: stk
. (STKRenderer
).shopHome
, are assigned:modelClass
: ShopSingletonParagraphTemplateModel
that extends STKPageModel
to add shopping cart functionality.bodyID
: shop
. This is relevant to CSS styling. See Themes (below) and Body classes and ids for more.Here's the template definition of the shopProductCategory
template.
Node name | Value |
---|---|
modules | |
shop | |
templates | |
pages | |
shopProductCategory | |
navigation | |
areas | |
bodyID | shop |
category | feature |
class | info.magnolia.module.templatingkit.templates.pages.STKPage |
dialog | standard-templating-kit:pages/section/stkSectionProperties |
i18nBasename | info.magnolia.module.shop.messages |
modelClass | info.magnolia.module.shop.templates.ShopSingletonParagraphTemplateModel |
renderType | stk |
subcategory | product-category |
title | templates.shopProductCategory.title |
visible | true |
The shop home template is essentially a section template.
Properties:
bodyID
: section
.dialog
: shop:pages/shopSectionProperties
(see below).modelClass
: ShopHomeParagraphTemplateModel
that extends STKPageModel
to generate the basic shop page structure automatically. The structure includes one product category, product detail, product search result, keyword search result and checkout form pages. Here's the code snippet that achieves this.createShopPage(content, "sample-category", "shop:pages/shopProductCategory"); createShopPage(content, "product-detail", "shop:pages/shopProductDetail"); createShopPage(content, "product-search-result", "shop:pages/shopProductSearchResult"); createShopPage(content, "keyword-search-result", "shop:pages/shopProductKeywordResult"); Node shoppingCart = createShopPage(content, "shopping-cart", "shop:pages/shopShoppingCart"); Node checkout = createShopPage(shoppingCart, "check-out", "shop:pages/shopCheckoutForm"); createShopPage(shoppingCart, "confirmation", "shop:pages/shopConfirmationPage"); createShopPage(checkout, "form-step", "shop:pages/shopFormStep"); createShopPage(checkout, "confirm-order", "shop:pages/shopFormStepConfirmOrder");
The shopSectionProperties
dialog is configured at Configuration > /modules/shop/dialogs/shopSectionProperties
. The configuration adds a Shop tab to the standard properties dialog that allows for the selection on the appropriate shop.
The page templates (except shopHome
) use the autogeneration feature in the same way as STK feature templates. Functionality is provided by components that are autogenerated on the page template. Here's the configuration for content
area in the shopShoppingCart
template.
Node name | Value |
---|---|
shopShoppingCart | |
areas | |
intro | |
main | |
areas | |
content | |
autogeneration | |
content | |
singleton | |
nodeType | mgnl:component |
templateId | shop:components/features/shopShoppingCart |
generatorClass | info.magnolia.rendering.generator.CopyGenerator |
enabled | true |
type | single |
Component templates are configured at Configuration > /modules/shop/templates/components
.
The names of the feature component definitions correspond with the names of the templates they are used on, for example the shopShoppingCart
template autogenerates the shopShoppingCart
component in content
area. Here's the definition of the shopProductDetail
component.
Node name | Value |
---|---|
components | |
features | |
shopProductDetail | |
parameters | |
divClass | teaser |
divIDPrefix | |
headingLevel | h2 |
description | - |
dialog | shop:shopProductList |
i18nBasename | info.magnolia.module.shop.messages |
modelClass | info.magnolia.module.shop.paragraphs.ShopParagraphModel |
renderType | stk |
templateScript | /shop/paragraphs/features/productDetails.ftl |
title | paragraphs.features.shopProductDetail.title |
The shopForm
component, autogenerated on the shopCheckoutForm
template, is a standard Magnolia multistep form customized for shop functionality. See the /demo-features/modules/sample-shop/shopping-cart
page for the default form settings and email code. Configure valid SMTP settings to test the form.
formProcessors
: There are three custom form processors that are not enabled by default:SaveAndConfirmFormProcessor
saves the shopping cart into the Shop module using OCM.SendShopOrderEmailProcessor
is the default processor to send an email including the order details to customers.SendShopConfirmationEmailProcessor
is the default processor to send an email including the order details to shop administrators.modelClass
: ShopFormModel
ensures that the ShopStartStepFormEngine
is in use. The engine checks the shopping cart for a form token. This allows users to continue browsing without losing checkout out form data.Node name | Value |
---|---|
components | |
features | |
shopForm | |
formProcessors | |
saveAndConfirmOrder | |
class | info.magnolia.module.shop.processors.SaveAndConfirmFormProcessor |
enabled | true |
sendContactEmail | |
class | info.magnolia.module.shop.processors.SendShopOrderEmailProcessor |
enabled | true |
sendConfirmationEmail | |
class | info.magnolia.module.shop.processors.SendShopConfirmationEmailProcessor |
enabled | |
trackMail | true |
parameters | |
areas | |
fieldSets | |
availableComponents | |
formGroupFields | |
id | form:components/formGroupFields |
enabled | true |
templateScript | /form/generic/listArea.ftl |
type | list |
class | info.magnolia.module.form.templates.components.FormParagraph |
description | form description |
dialog | form:form |
i18nBasename | info.magnolia.module.shop.messages |
modelClass | info.magnolia.module.shop.paragraphs.ShopFormModel |
renderType | freemarker |
templateScript | /shop/paragraphs/features/shopForm.ftl |
title | Form |
Here's the shopForm.ftl
script that renders the component
[#assign shoppingCart = model.getShoppingCart()] [#if (!shoppingCart?has_content || shoppingCart.getCartItemsCount() == 0) && !cmsfn.isEditMode() ] <p>${i18n['shoppingcart.empty']}</p> [#else] [#include "/form/components/form.ftl"] [/#if]
The module includes four custom teaser components.
shopExtrasProduct
and shopProductTeaser
are demonstrated above in Teasing products.extras
area is enabled.shopExtrasCart
adds the shopping cart.shopExtrasTagCloud
renders a list of keywords and product count.
shopExtrasProductSearch
allows a user to search for products.Node name | Value |
---|---|
components | |
extras | |
shopExtrasProduct | |
shopExtrasCart | |
shopExtrasTagCloud | |
shopExtrasProductSearch | |
teasers | |
shopProductTeaser |
The module adds CSS styles and theme images to the default pop
theme in the STK.
The shop.css
sheet is referenced In STK > Themes /pop/cssFiles/shop
.
Node name | Value |
---|---|
pop | |
cssFiles | |
styles | |
shop | |
farFutureCaching | true |
link | /resources/templating-kit/themes/pop/css/shop.css |
media | screen, projection |
ie6 |
You can access the resources in STK > Resources at /templating-kit/themes/pop/css/shop.css
and /images/shop
.
The module installs the shop-user-base
role and grants the superuser
role full access to all shop workspaces. The shop-user-base
role is not assigned to any user by default. The role allows a user to view content in the Setup, Products and Shopping carts apps, and in the components on pages.
Access control lists:
Workspace | Permission | Scope | Path |
---|---|---|---|
Shops | Read only | Selected and sub nodes | / |
ShopProducts | Read only | Selected and sub nodes | / |
ShoppingCarts | Read only | Selected and sub nodes | / |
Public users need write permission to the shoppingCarts
workspace and read permission to the other workspaces. To allow public users to view the content of the shop pages and use the cart, create a new role on the public instance with the following permissions and assign it to the anonymous
user in Security > Public Users.
Access control lists:
Workspace | Permission | Scope | Path |
---|---|---|---|
Shops | Read only | Selected and sub nodes | / |
ShopProducts | Read only | Selected and sub nodes | / |
ShopCarts | Read/Write | Selected and sub nodes | / |
If you assign the shop-user-base
role to editors they can add and edit shop teaser components. To grant permissions to add and edit products in the Products app, and work in the Shopping carts, Shop suppliers and Systems apps, create and assign a new role with one or more of the following permissions.
Access control lists:
Workspace | Permission | Scope | Path |
---|---|---|---|
Shops | Read/Write | Selected and sub nodes | / |
ShopProducts | Read/Write | Selected and sub nodes | / |
ShoppingCarts | Read/Write | Selected and sub nodes | / |
ShoppingSuppliers | Read/Write | Selected and sub nodes | / |
These permissions allow the user access the general and dedicated shop apps but you can limit this by configuration.
You can control access to apps in the app and app launcher configurations. See App permissions for more information.
The following example configuration at Configuration > /modules/ui-admincentral/config/appLauncherLayout/sampleShop
limits access to the Sample shop menu in the app launcher to users assigned the superuser
and sample-shop-administrator
role.
Node name | Value |
---|---|
modules | |
ui-admincentral | |
config | |
appLauncherLayout | |
groups | |
edit | |
sampleShop | |
apps | |
permissions | |
roles | |
superuser | superuser |
administrator | sample-shop-administrator |
The following example configuration at Configuration > /modules/shop/apps/shops
limits access to the Manage shops > All shops app to users assigned the superuser
role.
Node name | Value |
---|---|
modules | |
shop | |
apps | |
shop | |
shops | |
subapps | |
permissions | |
roles | |
superuser | superuser |
The Shop module does not have payment processing. Connection to a payment gateway is a customization task for the implementer. It can be achieved by:
The easiest way to connect to an external product repository is to import the data into the All products or dedicated products app adhering to the data structure the Shop module uses to store products. This requires a custom import handler. The import mechanism can be scheduled so the data will be automatically updated.