Widgets
"Widget" is the main term we use for all placeholders, blocks and callbacks available in templates. They may be available globally ("global widgets") or in one (or more) specific application templates or within other widgets. Global widgets are always available everywhere (excluding non-parsed files like CSS or JS files) including other widgets.
This article describes global widgets. Non-global widgets are described in Template System.
How to create/register a global widget
Any component can register any number of global widgets. Their names need to be unique across all components. Global widgets are registered in postInit()
hook and are handled by the Widget class of the Widget component.
Here's a simple widget registration example:
This registers a global widget that replaces the placeholder [[MY_SIMPLE_WIDGET]]
by the string Hello world
.
Global widget types
The same types as for non-global widgets are available. The widget type can be specified as an argument to the constructor of the widget class. Note that not all widget classes support all types. See Global widget Classes for more info about this.
Type |
Description |
Template-Format |
Identifier |
---|---|---|---|
|
A widget of type placeholder is simply replaced by some content. |
Placeholder widget names are written in uppercase. In the template it has the following format:
|
|
|
A widget of type block has content, which can be altered while parsing the widget. The block is then replaced with the parsed content. |
Block widget names are written in lowercase. In the template it has the following format:
Everything between the start and the end tag is passed to the widget for parsing. |
|
|
A widget of type callback is like a placeholder with arguments. |
Callback widget names are written in lowercase. In the template it has the following format:
'foo' and 'bar' are passed to the widget render method as arguments. The widget name is passed in uppercase to the rendering method as it is internally parsed as a block widget. |
|
Global widget classes
Class | Description | Supported Types |
---|---|---|
FinalStringWidget |
Use for static content | Placeholder |
EsiWidget |
Use for dynamic content | Placeholder / Block / Callback |
RandomEsiWidget |
Use for randomized content | Placeholder / Block / Callback |
FinalStringWidget
FinalStringWidgets can only be used for things that have no dependency to anything other than things that flush the whole page and ESI cache. Examples for this would be:
[[CHARSET]]
: This should never change on a live system.[[PATH_OFFSET]]
: This should never change on a live system.[[TIME]]
,[[DATE_...]]
: These are aliases to non-cached ESI functions like$strftime('%Y')
.[[CONTACT_...]]
: These are part of base config.
EsiWidget
In order to circumvent the cache limitations of a FinalStringWidget
there are ESI widgets. ESI widgets are cached separately. Each ESI widget has its own cache lease time and its cache can be flushed individually (see Cache control).
This is achieved by replacing ESI widgets (resp. their template-notation) by ESI element tags. The ESI element tags are then (before the response is sent back to the client) being replaced (by a reverse proxy or Cloudrexx itself) by the response of an Exposed method.
You can register your own EsiWidget
along with any other widget class in postInit()
of your ComponentController
. You'll then have to implement and register a new controller (see Add another controller) that inherits from \Cx\Core_Modules\Widget\Controller\EsiWidgetController
. Your own EsiWidgetController
must implement the method parseWidget()
which will then be used to fetch the content of your ESI widget.
For more info about the ESI specification see https://www.w3.org/TR/esi-lang.
For more info about ESI widgets in Cloudrexx see ESI widgets.
RandomEsiWidget
If one or more entries of a list should be shown, randomly changing for each request, then RandomEsiWidget
is the way to go. It basically works the same as a normal ESI widget, with the following differences:
- Use
setUniqueRepetitionCount()
to set the number of entries to show (default is 1) - Implement
\Cx\Core_Modules\Widget\Controller\RandomEsiWidgetController
instead of\Cx\Core_Modules\Widget\Controller\EsiWidgetController
- Use
RandomEsiWidgetController::getRandomEsiWidgetContentInfos($widgetName, $params, $template)
to return the list of available entries
ESI widgets
ESI widgets are replaced by ESI tags. The reverse proxy then replaces them separately even when the request is answered from cache. Cloudrexx comes with an internal ESI parser that can replace the need for an external reverse proxy.
Parse Targets
Widgets are parsed in the scope of so-called Parse Targets. A Parse Target represents a website element that contains HTML-code as well as Widgets. Currently the following parse targets exist:
Parse Target | Description |
---|---|
\Cx\Core\View\Model\Entity\Theme |
A functional HTML file of a webdesign template. Technically this means index.html of a theme as all other files are included using widgets. |
\Cx\Core\ContentManager\Model\Entity\Page |
Any page managed by the Content Manager. |
\Cx\Modules\Block\Model\Entity\Block |
Any content pane. |
Implement your own Parse Target
To add your own parse target (i.e. an entity of your own component), your entity has to implement \Cx\Core_Module\Widget\Model\Entity\WidgetParseTarget
.
Then you could parse any widgets within your own parse target as follows:
Cache control
If SSI/ESI-Caching is enabled or an external caching reverse proxy is used to parse ESI, then the content of ESI widgets and Random ESI widgets is being cached.
See Caching strategy as a guide on how to handle the cache of your widget.
Lease time
A cache lease time per ESI widget instructs the reverse proxy to only cache the widget for a certain amount of time.
The default lease time for ESI widget equals the page cache lease time. The default cache lease time can be overwritten for each widget in EsiWidgetController::parseWidget()
by setting an expiration date on the response:
Manually clear cache
The cache of one or more ESI widgets can be cleared manually by calling:
Automatic cache management
If a widget depends on an element that is being changed through Cloudrexx, Cloudrexx drops the respective cache automatically.
Widgets always depend on their parse target. Additionally, you may specify other things your widget depends on. This is done using widget cache variables. All necessary variables should be selected to ensure all necessary data is available for parsing and the associated cache pages are dropped whenever necessary. The less variables are selected, the more efficient the widget can be cached. Therefore only choose the necessary variables.
The data corresponding to the selected cache variables is passed as $params[<key>]
to the EsiWidgetController::parseWidget($name, $template, $response, $params)
method. Only data of selected variables is passed.
ESI cache variable | EsiWidget constant | Description | Datatype | Description | Short name 1 |
---|---|---|---|---|---|
page |
ESI_VAR_ID_PAGE |
Widget depends on current page | \Cx\Core\ContentManager\Model\Entity\Page |
The resolved page the widget is located on | p |
locale |
ESI_VAR_ID_LOCALE |
Widget depends on current locale | \Cx\Core\Locale\Model\Entity\Locale |
The locale of the resolved page | l |
path |
ESI_VAR_ID_PATH |
Widget depends on current path | string |
The path of the requested resource | pa |
query |
ESI_VAR_ID_QUERY |
Widget depends on current URL query arguments | array |
The query string arguments of the requested resource | q |
theme |
ESI_VAR_ID_THEME |
Widget depends on current theme | \Cx\Core\View\Model\Entity\Theme |
The resolved theme | t |
channel |
ESI_VAR_ID_CHANNEL |
Widget depends on current channel | string |
The resolved channel | ch |
user |
ESI_VAR_ID_USER |
Widget depends on session | string 2 |
The session-ID of the request | u |
currency |
ESI_VAR_ID_CURRENCY |
Widget depends on current currency | string 2 |
The currently set currency code (i.e. EUR ) |
c |
country |
ESI_VAR_ID_COUNTRY |
Widget depends on current country | string 2 |
The country code the current request (/its IP) originates from | g |
ESI widget variables can be set on the EsiWidget instance by using setEsiVariables()
or setEsiVariable()
. \Cx\Core_Modules\Widget\Model\Entity\EsiWidget
provides the appropriate constants which can be combined using the bitwise OR
operation.
Example
When does an ESI variable need to be set
There are certain cases where it's not obvious which variables need to be set. All of the variables' associated information can be fetched from the Referer URL and the cookies without the need for any ESI variables. The variables are necessary anyway as the main reason for them is to know when to drop the cache for the widget. Therefore the main criterion when deciding whether to set an ESI variable or not is whether the Widget's cache should be dropped if the associated information changes.
Keep the following in mind:
- For setting the ESI cache variables the parse target does not matter. In other words it does not matter where your widget is parsed in. Either it depends on some data or not. Set all cache variables that represent data your widget needs to parse itself.
- If a widget depends on the current page it most likely also depends on locale as the cache gets invalid when the locale changes.
Example [[CANONICAL_LINK]]
First of all this is not a FinalStringWidget because it depends on the page which is not static (/final). It has the following ESI cache variables set:
page
: If the page changes the page's slug changes and the cache becomes invalid.locale
: If the locale changes the virtual language directory changes and the cache becomes invalid.path
: As components may resolve additional path parts the path could lead to a different canonical URL.query
: Components may display different content (i.e. paging) based on URL arguments which would lead to a different canonical URL.user
: Components may display different content based on the user. If a user has no access to the page the canonical URL may be empty.
It does however not depend on the following:
theme
: The canonical URL does not change depending on the theme.channel
: The canonical URL does not change depending on the channel.currency
: The canonical URL does not change depending on the channel as in our current implementation the currency is never part of the URL.country
: The canonical URL does not change depending on the channel as the country is not part of the URL outside of the locale.
Caching strategy
- Use automatic caching by setting the correct ESI caching variables.
- If your widget depends on time (birthdays, scheduled publishing, ...) additionally set an appropriate lease time.
- If your widget depends on one or more entity (that is not available as a ESI cache variable) manually drop the widget's cache in a model event listener.
ESI and SSI
This article only mentioned ESI so far. The same result can also be achieved using the SSI specification. If your reverse proxy supports SSI instead of ESI Cloudrexx can also output SSI- instead of ESI-tags. The usage of everything else stays the same: Use the EsiWidget, RandomEsiWidget and EsiWidgetController classes as described above. Cloudrexx will use the correct notation as set in the caching settings automatically.