taking full control of product navigation in liferay dxp
TRANSCRIPT
Taking Complete Control of Product Navigation in Liferay DXP
Julio Camarero, Software Architect, WEM Lead @juliocamarero
DEVCON | MODCONF 2016
@juliocamareroDEVCON | MODCONF 2016
What is the Product Navigation?
#LSNA16 | @juliocamareroDEVCON | MODCONF 2016
Consistent Navigation across all sites even with different themes
#LSNA16 | @juliocamareroDEVCON | MODCONF 2016
<@liferay.control_menu />
… inside the portal_normal.ftl of your theme
@juliocamarero
#LSNA16 | @juliocamareroDEVCON | MODCONF 2016
<@liferay.user_personal_bar />
… inside the portal_normal.ftl of your theme
@juliocamareroDEVCON | MODCONF 2016
Does that mean I can’t change the look and feel?
@juliocamareroDEVCON | MODCONF 2016
Does that mean I can’t change the look and feel?
… of course not
#LRDEVCON | @juliocamarero
Site Themes vs Product Themes
#LSNA16 | @juliocamareroDEVCON | MODCONF 2016
how can I build a product theme?
Creating a control menu theme contributor and a product menu theme contributor.
(Each contributor is just a set of css files)
https://dev.liferay.com/develop/tutorials/-/knowledge_base/7-0/theme-contributors
@juliocamareroDEVCON | MODCONF 2016
Control MenuThe right information, right when you need it
@juliocamarero
Control MenuControl Menu
@juliocamarero
@juliocamarero
@juliocamarero
@juliocamarero
NavigationContext
Information Tools
Advanced Management
@juliocamarero
NavigationContext
Information Tools
Advanced Management
@juliocamarero
@Component( immediate = true, property = { "product.navigation.control.menu.category.key=" + ProductNavigationControlMenuCategoryKeys.TOOLS, "product.navigation.control.menu.entry.order:Integer=500" }, service = ProductNavigationControlMenuEntry.class) public class FavouritesProductNavigationControlMenuEntry
USERSITE
Category
Order
Create a Control Menu Entry
@juliocamarero
@Overridepublic String getIcon(HttpServletRequest request) { return "star"; } @Overridepublic String getLabel(Locale locale) { return "favourites"; } @Overridepublic String getURL(HttpServletRequest request) { return “http://… “; }
Simple Icon
@juliocamarero
public boolean isUseDialog() { return false; }
@juliocamarero
@Overridepublic boolean includeIcon( HttpServletRequest request, HttpServletResponse response) throws IOException { RequestDispatcher requestDispatcher = _servletContext.getRequestDispatcher(“/render_my_icon.jsp”); requestDispatcher.include(request, response); return true; }
@Overridepublic boolean includeBody( HttpServletRequest request, HttpServletResponse response) throws IOException {
Custom UI (any template language)
@juliocamarero
@Overridepublic boolean includeBody( HttpServletRequest request, HttpServletResponse response) throws IOException { RequestDispatcher requestDispatcher = _servletContext.getRequestDispatcher(“/render_my_body.jsp”); requestDispatcher.include(request, response); return true; }
Advanced Management (any template language)
@juliocamarero
@Overridepublic boolean includeBody( HttpServletRequest request, HttpServletResponse response) throws IOException { RequestDispatcher requestDispatcher = _servletContext.getRequestDispatcher(“/render_my_body.jsp”); requestDispatcher.include(request, response); return true; }
Advanced Management (any template language)
@juliocamareroDEVCON | MODCONF 2016
Product MenuEverywhere you may need to go at one click distance
@juliocamarero
Product Menu
@juliocamarero
Categories and Subcategories
They are only shown to the right users and only if they have something inside
@juliocamarero
Categories and Subcategories
@Component( immediate = true, property = { "panel.category.key=" + PanelCategoryKeys.CONTROL_PANEL, "panel.category.order:Integer=200" }, service = PanelCategory.class) public class UsersPanelCategory extends BasePanelCategory { @Override public String getKey() { return PanelCategoryKeys.CONTROL_PANEL_USERS; } @Override public String getLabel(Locale locale) { return LanguageUtil.get(locale, "users"); } }
@juliocamarero
Categories with custom UI
@Overridepublic boolean include( HttpServletRequest request, HttpServletResponse response) throws IOException { // include the body of your panel } @Overridepublic boolean includeHeader( HttpServletRequest request, HttpServletResponse response) throws IOException { // include the header of your panel }
@juliocamarero
Existing PanelCategories
PanelCategoryKeys.ROOT
PanelCategoryKeys.CONTROL_PANEL PanelCategoryKeys.CONTROL_PANEL_USERS PanelCategoryKeys.CONTROL_PANEL_SITES PanelCategoryKeys.CONTROL_PANEL_APPS PanelCategoryKeys.CONTROL_PANEL_CONFIGURATION
PanelCategoryKeys.USER PanelCategoryKeys.USER_MY_ACCOUNT
PanelCategoryKeys.SITE_ADMINISTRATION PanelCategoryKeys.SITE_ADMINISTRATION_NAVIGATION PanelCategoryKeys.SITE_ADMINISTRATION_CONTENT PanelCategoryKeys.SITE_ADMINISTRATION_MEMBERS PanelCategoryKeys.SITE_ADMINISTRATION_CONFIGURATION PanelCategoryKeys.SITE_ADMINISTRATION_PUBLISHING
@juliocamarero
Create Panel Apps
@Component( immediate = true, property = { "panel.app.order:Integer=100", "panel.category.key=" + PanelCategoryKeys.CONTROL_PANEL_USERS }, service = PanelApp.class) public class UsersPanelApp extends BasePanelApp { @Override public String getPortletId() { return “myPortletName"; } @Override @Reference( target = “(javax.portlet.name=myPortletName)", unbind = "-" ) public void setPortlet(Portlet portlet) { super.setPortlet(portlet); } }
@juliocamarero
Add a Notifications Badget
@Overridepublic int getNotificationsCount(User user) { return user.getUnreadEmails(); }
@juliocamarero
Create a custom UI
public boolean include( HttpServletRequest request, HttpServletResponse response)
throws IOException { // render your UI …
return true; }
@juliocamareroDEVCON | MODCONF 2016
User Personal BarActions for all your registered users
@juliocamarero
Control MenuUser Personal Bar
@juliocamarero
@juliocamareroDEVCON | MODCONF 2016
Just a portlet, you can deploy your own with a Portlet Provider:
@Component( immediate = true, property = { "model.class.name=" + PortalUserPersonalBarApplicationType.UserPersonalBar.CLASS_NAME }, service = ViewPortletProvider.class) public class MyPersonalPortletProvider extends BasePortletProvider implements ViewPortletProvider { @Override public String getPortletName() { return "myPortletName"; } }
@juliocamareroDEVCON | MODCONF 2016
Simulation MenuSee what the others will see
@juliocamarero
Simulation Menu
@juliocamarero
@Component( immediate = true, property = { "panel.app.order:Integer=100", "panel.category.key=" + SimulationPanelCategory.SIMULATION }, service = PanelApp.class) public class LanguagePreviewPanelApp
public boolean include( HttpServletRequest request, HttpServletResponse response) {
… // render your UI
Order
Create a Simulation Panel
@juliocamarero
Interact with the Simulation Window
var iframe = A.one('#simulationDeviceIframe');
…
iframe.setAttribute('src', newUrlWithCustomParameters);
@juliocamareroDEVCON | MODCONF 2016
Easier than Ever! ;)
@juliocamareroDEVCON | MODCONF 2016
@juliocamareroDEVCON | MODCONF 2016
Command Line
blade create -l > controlmenuentry > panelapp > simulationpanelentry ...
blade create -t controlmenuentry favorite
gradle deploy
#LSNA16 | @juliocamareroDEVCON | MODCONF 2016
Some ResourcesProduct Navigation Tutorials: https://dev.liferay.com/develop/tutorials/-/knowledge_base/7-0/product-navigation
Theme Contributors Tutorial: https://dev.liferay.com/develop/tutorials/-/knowledge_base/7-0/theme-contributors
@juliocamarero
Thank you! :)Questions?