Multi-country content catalogs
Situation
- There are N regional websites, one per country.
- The global marketing teams are responsible for global content.
- The local marketing teams should be able to manage local content only.
- Global teams should be able to manage some local content also if they have enough permissions.
- The system should be idiot-proof, which means that any changes made by the regional administrators should affect only their website, not other local websites.
- “Multi-language”: It is good if all the websites have the same design and components. Any exceptions should be implemented as hybris CMS restrictions. It is impossible or very difficult to configure the proper permissions. In this solution, the CA website administrator can change US website content – this is why this solution is partial. When the number of regions/countries is more than 3-4 this solution is also inconvenient.
- Different pages for different countries. Per-page permissions. It will work, but with data duplications. Out-of-the-box apparel stores are implemented this way.
Complexity
Although the data model is prepared for having multiple content catalogs assigned to a single website (CMSSite), the cockpit itself is not ready. For the single content catalog, out-of-the-box hybris doesn’t have any capabilities to hide a particular content slot for the user who doesn’t have enough permissions to manage it.Challenge
Hide particular content slots in hybris WCMS, depending on the current administrator’s rights.Solution
Technical solution
Architecture
WCMS part
There is an “interceptor” – the hybris layer between the model class and the service class. This interceptor replaces slot names on the fly.Storefront part
Page Controller or Filter should set a variable “region” and push into JSP. JSP’s pageSlot tag has an attribute “position”. In our solution we will build the value of “position” attribute dynamically using value of “region” variable.PageTemplateModel.onLoad Interceptor
public class LoadVelocityTempateInterceptor implements LoadInterceptor<PageTemplateModel> {
@Resource
UserService userService;
@Resource
SessionService sessionService;
@Resource
CMSSiteService cmsSiteService;
@Override
public void onLoad(PageTemplateModel o, InterceptorContext var2) throws InterceptorException
{
// check if the request is from backoffice (WCMS)
if (cmsSiteService.getCurrentSite() != null) { return; }
String vt = o.getVelocityTemplate();
UserModel currentUser = userService.getCurrentUser();
Set < UserGroupModel > groups = userService.getAllUserGroupsForUser(currentUser);
Iterator < UserGroupModel > iter = groups.iterator();
while (iter.hasNext()) {
UserGroupModel ugm = iter.next();
String groupStr = ugm.getUid();
if (groupStr.indexOf("reg_")!=-1) {
vt = vt.replace("_regional_", "_reg_"+groupStr);
o.setVelocityTemplate(vt);
return;
}
}
}
}
@Resource
UserService userService;
@Resource
SessionService sessionService;
@Resource
CMSSiteService cmsSiteService;
@Override
public void onLoad(PageTemplateModel o, InterceptorContext var2) throws InterceptorException
{
// check if the request is from backoffice (WCMS)
if (cmsSiteService.getCurrentSite() != null) { return; }
String vt = o.getVelocityTemplate();
UserModel currentUser = userService.getCurrentUser();
Set < UserGroupModel > groups = userService.getAllUserGroupsForUser(currentUser);
Iterator < UserGroupModel > iter = groups.iterator();
while (iter.hasNext()) {
UserGroupModel ugm = iter.next();
String groupStr = ugm.getUid();
if (groupStr.indexOf("reg_")!=-1) {
vt = vt.replace("_regional_", "_reg_"+groupStr);
o.setVelocityTemplate(vt);
return;
}
}
}
}
Page Controller
...
model.addAttribute("regional", AreWeOnCanadianWebsite() ? "reg_ca" : "reg_us");
...
model.addAttribute("regional", AreWeOnCanadianWebsite() ? "reg_ca" : "reg_us");
...
Tobias Ouwejan
15 September 2016 at 04:41
Hi Rauf, interesting article and approach! Thanks for sharing. Not sure if you’re aware, but we (Expert Services) have implemented a multi-country solution to tackle this problem as well and provide that as a solution add-on to hybris. Have a look at https://wiki.hybris.com/display/hybrisALF/Multi+Country+and+Channel+WCMS+Enhancements or find more details at https://wiki.hybris.com/display/hybrisALF/Content+Catalog+Design.
Rauf Aliev
15 September 2016 at 16:38
Thank you for your comment;) will your extension allow to see only relevant components on the CMS page view? For example, there is 15 countries and each country has its own set of banners and it’s own CMS manager role (it is not an assumption, it is real project where I am working as SA). Will this manager see other (“alien”) components in the slot or he/she will see the filtered set (by the country the administrator belongs to)? In my solution there is a filtered set.
Tobias Ouwejan
28 September 2016 at 09:57
Hi Rauf, sorry for the delayed reply here. It is indeed only showing you the pages and components which are relevant to the user. Moreover, since it’s catalog based (global catalog, regional catalog, local catalog) you have a mixture of both global content (using a global workflow) as well as local catalogs using their own workflow. This basically means that in case of 15 countries, the workflows (sync) do not interfere each other.
Rauf Aliev
28 September 2016 at 10:14
As I remember, hybris doesn’t allow easily hiding components in the editor if you have no rights to edit it. Hybris can make them “gray” in the editor, that means that for 15 countries and 5 unique components in each country I will have 70 grayed components and 5 available for editing. In my solution I hide these 70 components. Can the mentioned extension hide them?
Tobias Ouwejan
28 September 2016 at 10:24
You need to think different. Each country has another catalog(version) for the given cms site. The content for a specific country is only in that specific catalog, so that you only see and sync country specific content. The country specific country is linked to a global catalog, where pagetemplates and global components are stored and managed. Additional tooling is provided so that you can “localize” a page from a global page, which results in a local page where you can further localize it by adding/removing components.
Rauf Aliev
28 September 2016 at 21:33
ok… You said that local content catalog pages are linked to global components… It means that if you add new country, you need to create a bunch of pages. And when you will need to add a section to the page (all pages of all countries), you will need to do it for all pages in all catalogs… Got it. I was finding something wrong in this approach but I forgot… Trying to remember..
Rauf Aliev
28 September 2016 at 21:39
I’ve just remembered. Global administrators won’t be able to add banners or other components to show them on the all country-specific websites. However, I can use a component container for it. So yes, this solution is also good!
Vikramjit
28 September 2016 at 05:11
Hi Rauf,
Thanks for sharing the important concepts in and around Multi country content catalog design and implementation
Is this extension available on request for reference?
Rauf Aliev
28 September 2016 at 09:46
Thank you! I will look in my archives… I am not sure I saved it.. Contact me directly please.
npkismyhomeRoy
30 August 2017 at 06:12
Hi Rauf, Could you share the extension you created for the multi country content catalog implementation or at least a comprehensive document. Thanks in anticipation
Rauf Aliev
30 August 2017 at 08:12
I am sorry, but it’s impossible. It was too long time ago, that was a shared code with other modules, it was’t separated from other experiments, data setup might be created manually, not via impex, some components of the module might be shared with the project I was working for at that time. so sorry (
Cistus Plus werking
29 October 2018 at 05:29
I enjoy reading through your site. With thanks!