Modules Templates - happy-geeks/wiser GitHub Wiki
[!WARNING] This document is still work in progress, more will be added in the future.
Introduction
Wiser is also made to be used as a tool to build websites, the templates module is an integral part of this. Wiser uses the GeeksCoreLibrary (GCL) as it's base and so do any websites we build with Wiser. The GCL then reads data from the template module of Wiser, to render most or all of the pages for that website.
In the templates module, we can add all kinds of templates and components to build a website with. The different template types we can have, are divided into tabs. In each tab we can add directories and templates to create a neat structure for the website. We have the following tabs / template types available:
- HTML: These are the main templates that are used by the website. An HTML template is needed for each kind/type of page that your website will have. For example, a template for the homepage, a template for a simple content page, one for the product overview page and one for a product detail page. This template will then contain the HTML that is necessary to run that kind of page. Inside this HTML, variables and components can be added to make the page dynamic. For example, you can add a Repeater component on the homepage to create a live-board. This repeater can then get all the slides that should be shown from the Wiser database. The customer can then use a live-board module in Wiser to add/remove/update these slides. On HTML templates you can also change all kinds of settings, such as caching settings, whether users need to be logged in to view pages of this type, or a regex that decides on which URLs this template should be used.
- JS: This is for javascript files. Here you can add any javascript that your website might need. Javascript files can then be loaded on all pages, or linked to specific HTML templates if it only needs to be loaded on specific pages.
- SCSS: Here you can add any SCSS files for your website. These will automatically be compiled to browser-readable CSS. You can also load these on all pages or only on specific pages by linking them to HTML templates.
- CSS: This works the same as SCSS templates, except that these won't be compiled. If you don't want to use SCSS, you can use this.
- SQL: This is for adding SQL queries. These queries can be made available to be opened from front-end, so that you can use XHR or fetch requests in javascript to get data from the database. The GCL will automatically execute the query and return the results of that query as JSON, so that it can be used in javascript. These query templates can also be included in components or other queries, which is useful if you need the same query in multiple places, to not have duplicate code.
- SERVICES: This is for managing the Wiser Task Scheduler (WTS). XML files can be added here to configure the WTS to do certain tasks. More information about that can be found in the wiki of the WTS.
- ROUTINES: All stored procedures/functions from the databases can be found and managed here. We recommend always managing them via this place, so that you have a version history of all changes. If you update a stored procedure/function directly in the database, you will not have any history of that nor can you revert your changes. Wiser does keep track of all these changes.
- VIEWS: The same as ROUTINES, but for database views.
- TRIGGERS: the same as ROUTINES, but for database triggers.
Components
The GCL contains several different ViewComponents, all of those can be added to website pages via the templates module in Wiser. When adding a component this way, Wiser will add certain HTML to the page. The GCL will parse this HTML and render the component, when a user opens a webpage that uses that particular template.
We have different components available that can be used to add/configure most default functionality that you expect a website to have. Components can have different modes, and you can select the mode you want to use when adding a component. Each mode is a different way to use a component.
All components have several settings for customizing the way things are done and rendered. All settings have default values, but those default values change depending on the mode you select. Most components are fully functional after just selecting a mode and entering a name for the component. When you want something different from the default functionality, you can change that via these settings in the Wiser interface. This includes the HTML output of the component. When fields/settings in Wiser are semi-transparent, it means that the current value is the default value for the selected component mode.
The following components are available:
[!NOTE] We have plans for adding more components in the future, such as a component for creating product overview pages. A product overview page almost always requires the
Filter
,Pagination
andRepeater
components, which then have to work together to create a product overview with filtering and paging. This requires good amount of configuration, which we want to make easier by adding a new component that has all this functionality built in.
Account
This component is for adding all kind of account functionality to a website. This includes logging in, logging out, registering new users, updating existing users and other things like password reset functions.
This component also supports subaccounts. Accounts can have multiple subaccounts and subaccounts can be linked to multiple accounts. One example what this can be used for is a web application for a big company that has many different branches and employees. Each branch could then have a main account and each employee would be a subaccount. Some employees work for a single branch and are then only linked to that branch. This way they will not have access to data of other branches. Other employees might do work for multiple branches, so their subaccounts can then be linked to all of those, so that they gain access to the data of all those branches.
Data Selector Parser
With this component, you can parse a data selector and generate HTML from the results of that data selector. For more information about data selectors, see this article.
Filter
This is for adding filters to a web page. Most often this is used on product overview pages, but it can also be used for blog/news overview pages. This component requires a lot of setup, because you need to let it know which properties can be filtered on and what kind of filters should be used.
There are two modes for this component:
- Direct: This mode finds all filter groups and filter options directly when a user opens a page with this component. It will use the
Filter items query
to find them. This mode is not recommended for big database, because this can become really slow when there are a lot of items to go through. - Aggregation: This mode uses aggregation tables to get all available filter groups/options. The default table for this is
wiser_filter_aggregation
, orwiser_filter_aggregation_[LanguageCode]
for a multi-language website. These tables need to be generated periodically via the Wiser Task Scheduler or another tool. To use a different table, you can change theFilter items query
of this component.
[!NOTE]
A filter group is a property that can be filtered on, such asColor
for example. A filter option is a value that this property can have, such asRed
.
The component itself does not have a lot of settings. This component requires the entity type filter
(which is added by default to all Wiser installations) when you use the default Filter items query
. For each filter group, an item of the type filter
should be added to the Wiser data (this is usually done via the module Master data ("Stamgegevens" in Dutch)). On these items, it's possible to specify what kind of filter it should be. If you have a different way of configuring the filter groups, you can add a custom query to the component to get this configuration.
Order process
Setting up an order process / checkout
This is for adding a complete checkout to a website, so that users can order and pay for products. This component handles everything that comes after adding products to the shopping basket. This means entering user information, showing an order summary (before and/or after payment), handling payments (and payment results) and sending order confirmation e-mails.
Similar to the Filter component, the Order Process component also depends on configuration via the master data (stamgegevens) module via entity types that are made specifically for this module. These entity types are the following:
- WiserOrderProcess: This is the main/root item that contains the basic settings for the order process, such as the URL, the checkout steps and the payment methods.
- WiserOrderProcessStep: This is a step in the checkout, and they can be added via the
Steps
grid on an item of typeWiserOrderProcess
. A checkout can have one or more steps, depending on the requirements of your application. Steps can be added in any order, and you can have multiple steps of the same type. A step can be one of the following types:- Step with groups and fields: This type is for creating forms where users need to enter information such as their name and address.
- Summary: For creating an order overview for the user. This can be used as a final overview before they are sent to the PSP.
- Success page: For adding a "Thank you for your order" page, when the user completes their order and/or payment.
- In progress: This is a page that the user will be shown if their payment could not be automatically/directly verified. This can happen with payment methods such as creditcards and PayPal. If a user sees this page, it means that their order cannot be sent right away, that someone or some system still needs to verify their payment.
- WiserOrderProcessGroup: A group of fields in a form, can be added via the
Groups
grid on an item of typeWiserOrderProcessStep
, with subtypeStep with groups and fields
. This is useful when you want to create multiple groups of fields, such as a group for the shipping address and a group for the invoice address. A group can also have different types:- Group with fields: A normal group with form fields.
- Payment methods: A list of payment methods.
- Summary: For adding any kind of simple summary at certain points in the checkout process.
- WiserFormField: A form field that users need to enter data in, can be added via the
Fields
grid on an item of typeWiserOrderProcessGroup
with subtypeGroup with fields
. Such a field can be given a label, placeholder, ID, type etc. Everything you'd expect from a field in a form, including validation settings. A field can be one of the following types:- Text field: A normal text field that can be used for any kind of text.
- Multi line text field: A bigger text field that supports multiple lines. Can be used for things like order comments.
- Radio button: A multiple choice field in the form of radio buttons. The possible options can be entered in the
Possible values
grid. - Combo box: A multiple choice field in the form of radio buttons. The possible options can be entered in the
Possible values
grid. - Checkbox: A simple checkbox for yes/no options.
- WiserPaymentProvider: For adding a payment service provider. The payment providers that we support can be found on NuGet (all packages that start with
GeeksCoreLibrary.Modules.Payments
). Every PSP that we support, has a separate NuGet package. Users will usually not see (much) from this, except for PSPs that have their own custom payment pages. Most websites only have one PSP, but it's possible to add more. - WiserPaymentMethod: For adding payment methods that you want to make available for users to pay orders with. They can be added via the
Payment methods
grid on anWiserOrderProcess
item. On each payment method, you need to select whichWiserPaymentProvider
needs to be used for that method.
If you don't need to customize the HTML of the order process, then you don't even have to add an Order Process component in the templates module, just entering a URL in the WiserOrderProcess
item is enough to add the order process to the website. The component is only required if you want to customize the HTML that is generated for the checkout, which can be done via that component in the templates module.
With all of these things, it's possible to add a complete checkout/order process to a webshop, without the need of any programming. If custom functionality is needed that cannot be setup with the above functionality, then we also have ways to extend the order process and add custom code to it.
Adding custom code to the order process / checkout
The order process of the GCL can be customized, it's possible to overwrite most functionality of the order process and to add extra functionality to it. To make this easier, we created the abstract class DecoratorOrderProcessesService
. This is a decorator for the default OrderProcessesService
. By default, this service does nothing extra except for making all functions virtual so that you can overwrite them. In your project you can create a new class that inherits from DecoratorOrderProcessesService
, then you only need to overwrite the method(s) that you want to customize. In those methods you can then call base.MethodName()
to execute the original code (or not, if you don't want that) and add your custom code above or below that, depending on what you want to do and when you want to do that. Then don't forgot to add the following line to your Program.cs
or Startup.cs
:
builder.Services.Decorate<IOrderProcessesService, MyCustomOrderProcessService>();
There are also a few methods that can be overwritten to add custom code at specific points in the order process. These don't do anything by default, they are purely meant to be able to add things like custom validation before sending a user to the payment page. At the moment we have the following method/events available:
PaymentRequestBeforeOutAsync
: This will be executed just before the user gets sent to the PSP, after the concept order has been created. If you return aPaymentRequestResult
withSuccessful
set tofalse
here, then the concept order(s) will be deleted and the user will be sent back to the checkout page with the error that you returned in theErrorMessage
property of thePaymentRequestResult
object. This can be used if you need to do custom validations before allowing users to pay for an order.PaymentStatusUpdateBeforeCommunicationAsync
: This will be executed after a status update (webhook) of the PSP has been handled, but before the order confirmation is being sent to the user. If the user paid for multiple orders at once, this function will be called once for each order. This can be used when you need to send order updates to external systems, to do some custom calculations in the order(s), etc.
Pagination
Websites often need pagination functionality for pages that show lists of items, such as products and blogs. This component can be used for generating a list with page numbers that users can use to navigate through the pages of the overview. This has functionality such as showing what the currently opened page is, how many pages/items there are in total, etc.
This component can also be used for adding infinite scrolling functionality. This can be done by customizing the settings and HTML so that it adds a hidden HTML element to the page that links to the next page. Then add some javascript to detect when that hidden element comes into "view" and automatically load the contents of that URL and add it to the bottom of the list.
Repeater
This is the most generic and most used component that we have. As the name indicates, it can be used for repeating things on a page. To use this component, you first need to decide where the data comes from (in most cases this is an SQL query). Then set that up in the DataSource
tab. This data can have multiple layers (i.e. for creating a menu with sub menus). In that case, the data source is required to have columns named idN
, where N
is the depth number (starting with 1
), so if you want to create something that has 3 layers, your data source needs to have the columns id1
, id2
and id3
. The rest of the columns can be named whatever you want. If you only need 1 layer, then you can ignore this and just use any columns names.
In the Layout
tab of the component settings, you can add the HTML that should come out of the component. All data from your data source can be used as variables/replacements here. By default, you'll only see a Layer 0
here, but there is a button for adding more layers. If your data source only has one layer, then you can just use the settings for Layer 0
and not add more layers. If you data source does have more than one layer, then this changes. If it has three layers like in the previous example, then you should also add three layers (so you will have four layers in total). In that case, Layer 0
is for adding a global header and footer around your results, which is independent of the data in your data source.
For each layer, we have different HTML fields available to render different parts (all of these are optional and can be left empty):
- Header template: This HTML will be added at the start of that particular layer, before rendering all the items of that layer. You can use any data from your data source in here, but it will always use the data from the first row, that contains an ID, of the data source for this.
- Item template: This HTML will be added for each row of your datasource with a unique ID. So if you have 3 layers, and you're working on the
Item template
for layer 1, then the GCL will place this HTML one time for each row that contains a new value in theid1
column. - No data template: This HTML is only rendered on the page if your data source contains no data, or if all rows in the datasource contain
null
in the correspondingid
column for that layer. - Between items template: HTML from this field will only be placed between two items of that layer. This means that this HTML will not be placed before the first item and also not after the last item of that layer.
- Footer template: This is the same as the
Header template
, except that this is added at the end of that layer, when there are no more items.
Product banners
The Repeater component also has support for adding banners in between results. This is often used on product overviews (hence the name "Product banners"), to show banners/commercials/tips in between products. In this component you can enable the option for product banners and add an HTML template for how such a banner should be rendered. The banners themselves and other settings (such as at which location(s) the banners should be shown) can be configured in a separate Wiser module called Product banners
.
Groups
Results from a repeater can be divided into groups, but only for repeaters with a single layer. This is useful for certain overviews, where you want to split items horizontally or vertically and/or add content and/or dividers at certain points. This can be enabled by increasing the number in the Create groups of N items
field to something higher than 1 and entering HTML in the Group header
and/or Group footer
fields.
Shopping basket
Like the name suggests, this component is used for adding shopping basket functionality to the website. This component handles all shopping basket functionality, this includes but is not limited to: Rendering a basket overview, adding products to a basket, adding coupons and even exporting baskets to PDF or e-mail. There is a different mode for each of these functionalities, which also means that you will most likely need several different instances of this component.
TODO: Explain the specifics and the customizations that can be done via query templates and other settings.
Web form
TODO: Explain this component
Web page
TODO: Explain this component
Working with the template module to create website pages
TODO: Explain basic/general functionality of adding templates, setting up caching, binding templates to URLs, using includes, how javascript/css/query templates work etc.
Versioning
TODO: Explain how template versioning works.
We also have a version controle module, that is used for committing templates and doing code reviews, similar to version control systems such as Git. Documentation for that module can be found here.