Many websites offer some kind of overview, maybe an image gallery or a list of downloadable files, or specific articles.
Many websites offer some kind of overview, maybe an image gallery or a list of downloadable files, or specific articles.
Overviews are meant to filter content by some criterion to help website visitors quickly find what they are looking for. So, in contrast to the result of a full-text search, an overview limits itself to items of a specific type: news articles, contact persons, and the like – or products.
In this tutorial, which is based on the Scrivito Example App, we are going to define a Product
object class and a simple overview widget for visitors to browse the list of products. If you want something more advanced, check out the fully fledged blog included in the example app.
For you to benefit the most from this tutorial, basic knowledge of how Scrivito’s content classes work and how they integrate with React is required.
To represent a product in Scrivito in a useful way, we need to collect its data relevant to visitors as well as internal processes like placing an order: a title and a description, a tag list (for assigning it to categories), an image and an order code. We could think of several other useful properties (availability, popularity, associated items, ...), but we’d like to keep it simple for now.
In case you’re asking yourself why we’re not considering creating a ProductWidget
but have chosen to use CMS objects: This is because we want each product to be unique, meaning that all references to a product must yield the same data. Thus, we need a single CMS object for each of them. Of course, nothing speaks against creating a ProductWidget
for placing a particular product object on any page. But that’s not what we’re after here.
Let’s define the Product
object class, the data model we will be working with in the overview widget: Just create a folder named Product
in “src/Objs”, and place the following two files into it:
The Product
object class above declares the properties (attributes) to be available for each of its instances. The editing configuration below is for making these attributes editable in each Product
’s properties and in the Content Browser (see below for how to make Product
objects accessible in the Content Browser).
Note that we are using hideInSelectionDialogs: true
in the above configuration since we don’t want Product
to show up in the page type selection dialog when creating a page.
To enable editors to create Product
objects via the Content Browser, we need to add a filter to its configuration in “src/config/scrivitoContentBrowser.js”. There are two places where the Product
class needs to be added, the defaultFilters
function and the FILTER_PRESENTATIONS
constant.
After that, you can select the filter in the Content Browser, click the plus icon to add a Product
item, and edit its properties on the right hand side.
You’ve probably noticed that the Product
class above isn’t complemented with a React component for rendering its instances. Since we need to render them from within the ProductListWidget
(we’re going to define further down), we’ve placed the component into a dedicated file in the “src/Components” directory, “ProductView.js”:
The above component renders a Product
instance as columns of a Bootstrap row. In the Bootstrap grid layout, a row consists of exactly 12 equally sized sections that can be combined to form up to 12 columns. As you can see from the CSS classes we used, the Product
view generates three columns with 2 + 7 + 3 = 12 sections.
We are connecting this functional component to Scrivito using Scrivito.connect
to ensure that all product data has been loaded before the component renders it.
One never knows where an overview of some kind may become useful in the future, at a later stage of the website. Thus, it’s a good idea to provide the overview as a widget (instead of a page type) that editors may then place on the pages they choose.
Next to the above-mentioned advantages of using CMS objects for maintaining data objects (e.g. products, like here), there’s another truly beneficial aspect to this approach: You can use Scrivito’s search functionality to restrict the contents of your overview to exactly the kind of items you want it to include. In our case of a ProductListWidget
, we simply collect all CMS objects of the Product
class. We’ve placed the code in the “src/Widgets/ProductListWidget” folder:
The ProductListWidget
class is equipped with just one attribute, bgColor
, for setting the background color of the list elements.
As mentioned, in the component, the Product
instances to display are determined using a search. Afterwards, the search result is converted to array elements ([...products]
) that are then rendered using the ProductView
component, which has been defined earlier.
To find all Product
instances, our component uses:
There’s no call to Scrivito.
Obj.where
in this statement, so why is this a search? The answer is simple if you recognize that Scrivito.getClass()
returns an object class. All CMS object classes are subclasses of the Obj
class to which the Obj
search methods all()
and where()
can be applied to find all or, respectively, a subset of instances of the given class.
The result of the all()
and where()
methods of object classes is an ObjSearch
. Basically, an ObjSearch
is a search query result that can be narrowed down or ordered by applying and()
, andNot()
, or, respectively, order()
to it. If, for example, we wanted to find only those Product
instances to which a specific tag has been assigned, we could use the following query:
With Scrivito, it’s easy to find content by specific properties (e.g. the object class) and have the result set displayed as what we called an “overview”. You can render the items in page views or in widgets, depending on the use case: If you want to enable editors to place the overview on any kind of page, provide them with a widget like the ProductListWidget
above. In all other cases, a dedicated result page is the means of choice.
The searches Scrivito lets you perform using Obj.all()
and Obj.where()
return an ObjSearch
that supports refinements and fetching the results in chunks, starting at an offset. This allows you to offer pagination.
By the way, as content is being created and edited, Scrivito indexes it on the fly, resulting in always-up-to-date search results.