Learn how Scrivito CMS can help you deliver amazing digital experiences
See Scrivito CMS in action

Maintaining Website Settings Using Configuration Objects and Custom Dialogs

Maintaining Website Settings Using Configuration Objects and Custom Dialogs

Typically, websites as a whole require some configuration. The Scrivito Example App, for instance, lets editors specify the logo to display, set IDs for authenticating against third-party services like Google Analytics, and a couple more. To do this, an editor navigates to the homepage, clicks “Edit page properties” from the main menu, and selects the “Site settings” tab where the desired changes can be applied.

Now, attaching site settings to the homepage is neither complicated nor special. But, for editors, it’s also not always the most practical approach because

  • You have to navigate to the homepage to access the settings.
  • It is not always clear which of those settings are related to the website as a whole, and which refer to the homepage only.
  • Sooner or later, with lots of settings, the properties dialog will be cluttered.

So let’s take a look at a more flexible solution to the settings matter. As Scrivito lets us extend the main menu and open custom dialogs, we are going to take advantage of these features and develop a dialog for configuring the properties of a coupon. This coupon is to be displayed on any number of pages, so we need a global configuration for it. Its properties could of course refer to any other kind of website settings as well or…

Defining a configuration object class and editing configuration

To persist settings and make them accessible independently of a page, we can simply use a configuration object, an ordinary CMS object equipped with attributes suitable for the data to be stored.

As announced above, our use case here is a website that displays a coupon on several pages using a widget. The coupon needs to be changed on a daily basis, which would be error prone and too time consuming if this had to be done manually for each widget. Instead, we are going to create a single coupon configuration to which all those widgets will refer.

So let’s first define an object class, CouponConfig, with attributes for maintaining the couponCode as well as the message to the visitor:

src/Objs/CouponConfig/CouponConfigObjClass.js
import * as Scrivito from "scrivito"; const CouponConfig = Scrivito.provideObjClass("CouponConfig", { attributes: { couponCode: "string", message: "html", }, }); export default CouponConfig;

Next, we are going to provide a configuration for editing objects of this class, even though CouponConfig objects aren’t pages and thus don’t have a means for editing attribute values. However, for testing purposes, we want couponCode and message to have initial values. And, even more important, editors should be prevented from creating additional CouponConfig objects.

src/Objs/CouponConfig/CouponConfigEditingConfig.js
import * as Scrivito from "scrivito"; Scrivito.provideEditingConfig('CouponConfig', { hideInSelectionDialogs: true, initialContent: { couponCode: 'BOOKS15OFF', message: 'Get 15 % off on all books today!', }, });

For the reason stated (the objects aren’t pages) we don’t require a component for rendering CouponConfig objects. Instead, we are going to provide a component we can pass to Scrivito’s openDialog function for making the attributes editable.

Providing the configuration object and dialog

Now that we have a CouponConfig object class as well as an editing configuration for it, let’s create an instance of it. First,

  • npm start your app,
  • activate the editing mode,
  • open the browser console,
  • set the context to “scrivito_application”.

Then execute:

Scrivito.getClass('CouponConfig').create({_permalink: 'couponconfig'})

This creates the coupon configuration object and assigns to it the couponconfig permalink.

Next, we require the dialog component for editing this object’s attribute values. Note that we are using the permalink that was given to the object to retrieve it in the dialog:

src/Components/ScrivitoExtensions/CouponConfigDialog.js
import * as React from "react"; import * as Scrivito from "scrivito"; function CouponConfigDialog() { const couponConfig = Scrivito.Obj.getByPermalink("couponconfig"); const attributes = { couponCode: "Coupon code", message: "Message" }; return ( <div className="container-fluid pt-4"> {Object.keys(attributes).map(key => ( <div key={key} className="card mb-2"> <div className="card-title strong ml-2 mr-2 mt-1"> <span>{attributes[key]}</span> </div> <hr className="mt-0 mb-1" /> <div className="pb-2"> <Scrivito.ContentTag className="card-text ml-2 mr-2 mt-1" content={couponConfig} attribute={key} /> </div> </div> ))} </div> ); } Scrivito.registerComponent("CouponConfigDialog", CouponConfigDialog);

After successfully fetching the /couponconfig object, its couponCode and message attribute values are made editable using Scrivito.ContentTag. That’s all; the rest is styling for which we limited ourselves to Bootstrap. Feel free to swipe the CSS used on the custom tabs in the properties dialog of the homepage.

Providing a menu item for the custom dialog

As the final step to be made, we’ll add an item to the main menu for opening a dialog and rendering the above component. Don’t forget to import the “scrivitoExtendMenu.js” file via “index.js” in the same directory.

src/config/scrivitoExtendMenu.js
import * as Scrivito from 'scrivito'; import couponConfigDialogMenuIcon from '../assets/images/arrow_next.svg'; Scrivito.extendMenu(menu => { menu.insert({ id: "couponConfiguration", title: "Edit coupon configuration", icon: couponConfigDialogMenuIcon, onClick: () => Scrivito.openDialog('CouponConfigDialog'), position: { after: 'system.openPageDetails' }, group: 'system.details', }); });

The Scrivito.extendMenu API is quite versatile as it not only lets you add menu items but also remove, reposition, group them, and, last but not least, define their onClick event handler. The latter can be seen above where Scrivito.openDialog is called.

Try it out!

Start your app, switch to editing mode, then open the main menu to the top right, and select “Edit coupon configuration”.

That was it – now you can create your own custom dialogs and open them via the main menu!

Finally, the coupon widget

To utilize our configuration object, here’s, in brief, the CouponWidget that accesses our global coupon settings.

src/Widgets/CouponWidget/CouponWidgetClass.js
import * as Scrivito from "scrivito"; const CouponWidget = Scrivito.provideWidgetClass("CouponWidget", {}); export default CouponWidget;
src/Widgets/CouponWidget/CouponWidgetComponent.js
import * as React from "react"; import * as Scrivito from "scrivito"; Scrivito.provideComponent("CouponWidget", ({ widget }) => { const couponConfig = Scrivito.Obj.getByPermalink("couponconfig"); return ( <Scrivito.InPlaceEditingOff> <div className="card text-center bg-warning"> <div className="card-body pb-0"> <Scrivito.ContentTag content={couponConfig} attribute="couponCode" className="h4 mb-0 strong" /> <Scrivito.ContentTag content={couponConfig} attribute="message" className="mt-0 strong" /> </div> </div> </Scrivito.InPlaceEditingOff> ); });

Note that there’s no editing configuration for the widget class. This is because it doesn’t define any attributes for its instances, e.g. for styling purposes. In our case, all widget instances were meant to look the same, so if we had wanted to style them, we would have had to provide attributes for this in the widget’s configuration, and take account of them in the component.

Furthermore, to make it clear to editors that the contents of coupon widgets cannot be altered individually (contrary to what one might expect), Scrivito’s in-place editing capability built into Scrivito.ContentTag has been disabled by means of Scrivito.InPlaceEditingOff. If changing all those widgets at once by touching a single one is desirable in your use case, simply remove this component.