This is a followup of the blog entry about
Liferay1 2 3.
As I wished to tailor the website layout of my Liferay instance, I started looking at themes. What I found was a bit of a surprise for me, as it seems themes for Liferay needs to be compiled/build using ant or maven.
There is a big body of documentation regarding the creation of Themes, but the procedure seems a bit brittle. It uses ant, needs to be able to reach the files of the classic theme, is dependent of the type of Application Server you are using, and a bit of other stuff.
Below are some of the error messages I got and had to solve before I got anything that worked.
Creating a Theme with Ant
- Download the Plugins SDK that compiles new themes (and plugins) using Ant.
- Create a properties file like build.<username>.properties
[glassfish@localhost glassfish]$ cat liferay-plugins-sdk-6.2/build.glassfish.properties
app.server.type=glassfish
app.server.parent.dir=/home/glassfish
app.server.glassfish.dir=${app.server.parent.dir}/glassfish4/glassfish
javac.compiler=modern
- In this directory, there should be a directory themes, where we can create our new theme6.
[glassfish@localhost themes]$ ./create.sh mine "Mine"
Parallel execution with configuration on demand is an incubating feature.
:createTheme
BUILD SUCCESSFUL
Total time: 2.377 secs
- Changed the build.xml in mine-theme, to use 'classic' as the parent theme.
<property name="theme.parent" value="classic" />
If you create your own theme with the Plugins SDK, place the icon in themes/Your_theme/docroot/_diffs/images/favicon.ico if you want to have your own favicon to bookmark.
- Then "ant war"
- Then "ant deploy" (or just copy the war into glassfish4/deploy)
The first problem I ran into was a problem with the xml file.
[2015-09-19T20:45:06.136+0000] [glassfish 4.1] [INFO] [] [] [tid: _ThreadID=140 _ThreadName=Thread-8] [timeMillis: 1442695506136] [levelValue: 800] [[
20:45:06,136 INFO [AutoDeployer][HotDeployEvent:145] Plugin mine-theme requires marketplace-portlet]]
[2015-09-19T20:45:06.142+0000] [glassfish 4.1] [INFO] [] [] [tid: _ThreadID=140 _ThreadName=Thread-8] [timeMillis: 1442695506142] [levelValue: 800] [[
20:45:06,136 INFO [AutoDeployer][HotDeployImpl:217] Deploying mine-theme from queue]]
[2015-09-19T20:45:06.149+0000] [glassfish 4.1] [INFO] [] [] [tid: _ThreadID=140 _ThreadName=Thread-8] [timeMillis: 1442695506149] [levelValue: 800] [[
20:45:06,142 INFO [AutoDeployer][PluginPackageUtil:1016] Reading plugin package for mine-theme]]
[2015-09-19T20:45:06.193+0000] [glassfish 4.1] [INFO] [] [javax.enterprise.web] [tid: _ThreadID=140 _ThreadName=AutoDeployer] [timeMillis: 1442695506193] [levelValue: 800] [[
WebModule[null] ServletContext.log():Initializing Spring root WebApplicationContext]]
[2015-09-19T20:45:06.204+0000] [glassfish 4.1] [INFO] [] [] [tid: _ThreadID=140 _ThreadName=Thread-8] [timeMillis: 1442695506204] [levelValue: 800] [[
20:45:06,204 INFO [AutoDeployer][ThemeHotDeployListener:98] Registering themes for mine-theme]]
[2015-09-19T20:45:06.236+0000] [glassfish 4.1] [INFO] [] [] [tid: _ThreadID=140 _ThreadName=Thread-8] [timeMillis: 1442695506236] [levelValue: 800] [[
20:45:06,228 ERROR [AutoDeployer][ThemeLocalServiceImpl:278] com.liferay.portal.kernel.xml.DocumentException: Error on line 8 of document : Element type "theme" must be followed by either attribute specifications, ">" or "/>". Nested exception: Element type "theme" must be followed by either attribute specifications, ">" or "/>".
com.liferay.portal.kernel.xml.DocumentException: Error on line 8 of document : Element type "theme" must be followed by either attribute specifications, ">" or "/>". Nested exception: Element type "theme" must be followed by either attribute specifications, ">" or "/>".
at com.liferay.portal.xml.SAXReaderImpl.read(SAXReaderImpl.java:429)
at com.liferay.portal.xml.SAXReaderImpl.read(SAXReaderImpl.java:447)
at com.liferay.portal.kernel.xml.SAXReaderUtil.read(SAXReaderUtil.java:187)
at com.liferay.portal.service.impl.ThemeLocalServiceImpl._readThemes(ThemeLocalServiceImpl.java:472)
at com.liferay.portal.service.impl.ThemeLocalServiceImpl.init(ThemeLocalServiceImpl.java:272)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at com.liferay.portal.spring.aop.ServiceBeanMethodInvocation.proceed(ServiceBeanMethodInvocation.java:115)
at com.liferay.portal.spring.transaction.DefaultTransactionExecutor.execute(DefaultTransactionExecutor.java:62)
at com.liferay.portal.spring.transaction.TransactionInterceptor.invoke(TransactionInterceptor.java:51)
at com.liferay.portal.spring.aop.ServiceBeanMethodInvocation.proceed(ServiceBeanMethodInvocation.java:111)
at com.liferay.portal.spring.aop.ChainableMethodAdvice.invoke(ChainableMethodAdvice.java:56)
at com.liferay.portal.spring.aop.ServiceBeanMethodInvocation.proceed(ServiceBeanMethodInvocation.java:111)
at com.liferay.portal.spring.aop.ChainableMethodAdvice.invoke(ChainableMethodAdvice.java:56)
at com.liferay.portal.spring.aop.ServiceBeanMethodInvocation.proceed(ServiceBeanMethodInvocation.java:111)
at com.liferay.portal.spring.aop.ChainableMethodAdvice.invoke(ChainableMethodAdvice.java:56)
at com.liferay.portal.spring.aop.ServiceBeanMethodInvocation.proceed(ServiceBeanMethodInvocation.java:111)
at com.liferay.portal.spring.aop.ChainableMethodAdvice.invoke(ChainableMethodAdvice.java:56)
at com.liferay.portal.spring.aop.ServiceBeanMethodInvocation.proceed(ServiceBeanMethodInvocation.java:111)
at com.liferay.portal.spring.aop.ChainableMethodAdvice.invoke(ChainableMethodAdvice.java:56)
at com.liferay.portal.spring.aop.ServiceBeanMethodInvocation.proceed(ServiceBeanMethodInvocation.java:111)
at com.liferay.portal.spring.aop.ChainableMethodAdvice.invoke(ChainableMethodAdvice.java:56)
at com.liferay.portal.spring.aop.ServiceBeanMethodInvocation.proceed(ServiceBeanMethodInvocation.java:111)
at com.liferay.portal.spring.aop.ChainableMethodAdvice.invoke(ChainableMethodAdvice.java:56)
at com.liferay.portal.spring.aop.ServiceBeanMethodInvocation.proceed(ServiceBeanMethodInvocation.java:111)
at com.liferay.portal.spring.aop.ChainableMethodAdvice.invoke(ChainableMethodAdvice.java:56)
at com.liferay.portal.spring.aop.ServiceBeanMethodInvocation.proceed(ServiceBeanMethodInvocation.java:111)
at com.liferay.portal.spring.aop.ChainableMethodAdvice.invoke(ChainableMethodAdvice.java:56)
at com.liferay.portal.spring.aop.ServiceBeanMethodInvocation.proceed(ServiceBeanMethodInvocation.java:111)
at com.liferay.portal.spring.aop.ServiceBeanAopProxy.invoke(ServiceBeanAopProxy.java:175)
at com.sun.proxy.$Proxy269.init(Unknown Source)
at com.liferay.portal.service.ThemeLocalServiceUtil.init(ThemeLocalServiceUtil.java:118)
at com.liferay.portal.deploy.hot.ThemeHotDeployListener.doInvokeDeploy(ThemeHotDeployListener.java:103)
at com.liferay.portal.deploy.hot.ThemeHotDeployListener.invokeDeploy(ThemeHotDeployListener.java:49)
at com.liferay.portal.deploy.hot.HotDeployImpl.doFireDeployEvent(HotDeployImpl.java:227)
at com.liferay.portal.deploy.hot.HotDeployImpl.fireDeployEvent(HotDeployImpl.java:96)
at com.liferay.portal.kernel.deploy.hot.HotDeployUtil.fireDeployEvent(HotDeployUtil.java:28)
at com.liferay.portal.kernel.servlet.PluginContextListener.fireDeployEvent(PluginContextListener.java:164)
at com.liferay.portal.kernel.servlet.PluginContextListener.doPortalInit(PluginContextListener.java:154)
at com.liferay.portal.kernel.util.BasePortalLifecycle.portalInit(BasePortalLifecycle.java:44)
at com.liferay.portal.kernel.util.PortalLifecycleUtil.register(PortalLifecycleUtil.java:74)
at com.liferay.portal.kernel.util.PortalLifecycleUtil.register(PortalLifecycleUtil.java:58)
at com.liferay.portal.kernel.util.BasePortalLifecycle.registerPortalLifecycle(BasePortalLifecycle.java:54)
at com.liferay.portal.kernel.servlet.PluginContextListener.contextInitialized(PluginContextListener.java:116)
at org.apache.catalina.core.StandardContext.contextListenerStart(StandardContext.java:5394)
at com.sun.enterprise.web.WebModule.contextListenerStart(WebModule.java:743)
at org.apache.catalina.core.StandardContext.start(StandardContext.java:5932)
at com.sun.enterprise.web.WebModule.start(WebModule.java:691)
at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:1041)
at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:1024)
at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:747)
at com.sun.enterprise.web.WebContainer.loadWebModule(WebContainer.java:2286)
at com.sun.enterprise.web.WebContainer.loadWebModule(WebContainer.java:1932)
at com.sun.enterprise.web.WebApplication.start(WebApplication.java:139)
at org.glassfish.internal.data.EngineRef.start(EngineRef.java:122)
at org.glassfish.internal.data.ModuleInfo.start(ModuleInfo.java:291)
at org.glassfish.internal.data.ApplicationInfo.start(ApplicationInfo.java:352)
at com.sun.enterprise.v3.server.ApplicationLifecycle.deploy(ApplicationLifecycle.java:500)
at com.sun.enterprise.v3.server.ApplicationLifecycle.deploy(ApplicationLifecycle.java:219)
at org.glassfish.deployment.admin.DeployCommand.execute(DeployCommand.java:491)
at com.sun.enterprise.v3.admin.CommandRunnerImpl$2$1.run(CommandRunnerImpl.java:539)
at com.sun.enterprise.v3.admin.CommandRunnerImpl$2$1.run(CommandRunnerImpl.java:535)
at java.security.AccessController.doPrivileged(Native Method)
at javax.security.auth.Subject.doAs(Subject.java:360)
at com.sun.enterprise.v3.admin.CommandRunnerImpl$2.execute(CommandRunnerImpl.java:534)
at com.sun.enterprise.v3.admin.CommandRunnerImpl$3.run(CommandRunnerImpl.java:565)
at com.sun.enterprise.v3.admin.CommandRunnerImpl$3.run(CommandRunnerImpl.java:557)
at java.security.AccessController.doPrivileged(Native Method)
at javax.security.auth.Subject.doAs(Subject.java:360)
at com.sun.enterprise.v3.admin.CommandRunnerImpl.doCommand(CommandRunnerImpl.java:556)
at com.sun.enterprise.v3.admin.CommandRunnerImpl.doCommand(CommandRunnerImpl.java:1464)
at com.sun.enterprise.v3.admin.CommandRunnerImpl.access$1300(CommandRunnerImpl.java:109)
at com.sun.enterprise.v3.admin.CommandRunnerImpl$ExecutionContext.execute(CommandRunnerImpl.java:1846)
at org.glassfish.deployment.autodeploy.AutoOperation.run(AutoOperation.java:164)
at org.glassfish.deployment.autodeploy.AutoDeployer.deploy(AutoDeployer.java:597)
at org.glassfish.deployment.autodeploy.AutoDeployer.deployAll(AutoDeployer.java:484)
at org.glassfish.deployment.autodeploy.AutoDeployer.run(AutoDeployer.java:412)
at org.glassfish.deployment.autodeploy.AutoDeployer.run(AutoDeployer.java:403)
at org.glassfish.deployment.autodeploy.AutoDeployService$1.run(AutoDeployService.java:233)
at java.util.TimerThread.mainLoop(Timer.java:555)
at java.util.TimerThread.run(Timer.java:505)
Caused by: org.dom4j.DocumentException: Error on line 8 of document : Element type "theme" must be followed by either attribute specifications, ">" or "/>". Nested exception: Element type "theme" must be followed by either attribute specifications, ">" or "/>".
at org.dom4j.io.SAXReader.read(SAXReader.java:482)
a]]
[2015-09-19T20:45:06.236+0000] [glassfish 4.1] [INFO] [] [] [tid: _ThreadID=140 _ThreadName=Thread-8] [timeMillis: 1442695506236] [levelValue: 800] [[
t org.dom4j.io.SAXReader.read(SAXReader.java:365)
at com.liferay.portal.xml.SAXReaderImpl.read(SAXReaderImpl.java:426)
... 82 more]]
Seems the problem was Quotes (") around the name of the theme "Mine" in the docroot/WEB-INF/liferay-plugin-package.properties file. Removed quotes, and things get picked up now.
Creating a Theme with Maven
mvn archetype:generate \
-DarchetypeArtifactId=liferay-theme-archetype \
-DarchetypeGroupId=com.liferay.maven.archetypes \
-DarchetypeVersion=6.1.0 \
-DartifactId=sample-theme \
-DgroupId=com.liferay.sample \
-Dversion=1.0-SNAPSHOT
I tried with Maven
4 5 instead of Ant to develop a theme, but I couldn't rightly get it to work. Needs some time to work on it.
Uploading a theme
So there's a war file created containing the files. You can deploy the file into the application server.
There are several ways to do this. You can upload it to glassfish4/glassfish/domains/domain1/autodeploy.
But I find that in some cases the theme is not recorded by Liferay. Liferay listens to specific directories for new war files that are theme related. In my case the additional directory could well be glassfish4/deploy, because glassfish4 is the "home" of Liferay in my case.
You can verify if the theme was successfully picked up in your glassfish server log. You should see something lke:
[2016-01-11T14:38:26.668+0000] [glassfish 4.1] [INFO] [] [] [tid: _ThreadID=112 _ThreadName=Thread-8] [timeMillis: 1452523106668] [levelValue: 800] [[
14:38:26,667 INFO [com.liferay.portal.kernel.deploy.auto.AutoDeployScanner][AutoDeployDir:204] Processing mine-theme-6.2.0.1.war]]
[2016-01-11T14:38:26.673+0000] [glassfish 4.1] [INFO] [] [] [tid: _ThreadID=112 _ThreadName=Thread-8] [timeMillis: 1452523106673] [levelValue: 800] [[
14:38:26,673 INFO [com.liferay.portal.kernel.deploy.auto.AutoDeployScanner][ThemeAutoDeployListener:51] Copying themes for /home/glassfish/glassfish4/deploy/mine-theme-6.2.0.1.war]]
[2016-01-11T14:38:26.723+0000] [glassfish 4.1] [INFO] [] [] [tid: _ThreadID=112 _ThreadName=Thread-8] [timeMillis: 1452523106723] [levelValue: 800] [[
14:38:26,722 INFO [com.liferay.portal.kernel.deploy.auto.AutoDeployScanner][BaseDeployer:863] Deploying mine-theme-6.2.0.1.war]]
[2016-01-11T14:38:27.119+0000] [glassfish 4.1] [INFO] [] [] [tid: _ThreadID=112 _ThreadName=Thread-8] [timeMillis: 1452523107119] [levelValue: 800] [[
Expanding: /home/glassfish/glassfish4/deploy/mine-theme-6.2.0.1.war into /tmp/20160111143826861]]
[2016-01-11T14:38:27.563+0000] [glassfish 4.1] [INFO] [] [] [tid: _ThreadID=112 _ThreadName=Thread-8] [timeMillis: 1452523107563] [levelValue: 800] [[
Copying 1 file to /tmp/20160111143826861/WEB-INF]]
[2016-01-11T14:38:27.568+0000] [glassfish 4.1] [INFO] [] [] [tid: _ThreadID=112 _ThreadName=Thread-8] [timeMillis: 1452523107568] [levelValue: 800] [[
Copying 1 file to /tmp/20160111143826861/WEB-INF]]
[2016-01-11T14:38:27.581+0000] [glassfish 4.1] [INFO] [] [] [tid: _ThreadID=112 _ThreadName=Thread-8] [timeMillis: 1452523107581] [levelValue: 800] [[
Copying 1 file to /tmp/20160111143826861/WEB-INF/classes]]
[2016-01-11T14:38:27.589+0000] [glassfish 4.1] [INFO] [] [] [tid: _ThreadID=112 _ThreadName=Thread-8] [timeMillis: 1452523107589] [levelValue: 800] [[
Copying 1 file to /tmp/20160111143826861/WEB-INF/classes]]
[2016-01-11T14:38:27.606+0000] [glassfish 4.1] [INFO] [] [] [tid: _ThreadID=112 _ThreadName=Thread-8] [timeMillis: 1452523107606] [levelValue: 800] [[
Copying 1 file to /tmp/20160111143826861/WEB-INF]]
[2016-01-11T14:38:27.760+0000] [glassfish 4.1] [INFO] [] [] [tid: _ThreadID=112 _ThreadName=Thread-8] [timeMillis: 1452523107760] [levelValue: 800] [[
14:38:27,760 INFO [com.liferay.portal.kernel.deploy.auto.AutoDeployScanner][BaseDeployer:2391] Modifying Servlet 2.4 /tmp/20160111143826861/WEB-INF/web.xml]]
[2016-01-11T14:38:27.860+0000] [glassfish 4.1] [INFO] [] [] [tid: _ThreadID=112 _ThreadName=Thread-8] [timeMillis: 1452523107860] [levelValue: 800] [[
Building war: /tmp/20160111143827761]]
[2016-01-11T14:38:28.307+0000] [glassfish 4.1] [INFO] [] [] [tid: _ThreadID=112 _ThreadName=Thread-8] [timeMillis: 1452523108307] [levelValue: 800] [[
Deleting directory /tmp/20160111143826861]]
[2016-01-11T14:38:28.331+0000] [glassfish 4.1] [INFO] [] [] [tid: _ThreadID=112 _ThreadName=Thread-8] [timeMillis: 1452523108331] [levelValue: 800] [[
14:38:28,330 INFO [com.liferay.portal.kernel.deploy.auto.AutoDeployScanner][ThemeAutoDeployListener:57] Themes for /home/glassfish/glassfish4/deploy/mine-theme-6.2.0.1.war copied successfully. Deployment will start in a few seconds
[2016-01-11T14:38:29.675+0000] [glassfish 4.1] [INFO] [NCLS-DEPLOYMENT-02027] [javax.enterprise.system.tools.deployment.autodeploy] [tid: _ThreadID=221 _ThreadName=AutoDeployer] [timeMillis: 1452523109675] [levelValue: 800] [[
Selecting file /home/glassfish/glassfish4/glassfish/domains/domain1/autodeploy/mine-theme.war for autodeployment]]
[2016-01-11T14:38:30.239+0000] [glassfish 4.1] [INFO] [] [javax.enterprise.system.tools.deployment.common] [tid: _ThreadID=221 _ThreadName=AutoDeployer] [timeMillis: 1452523110239] [levelValue: 800] [[
visiting unvisited references]]
[2016-01-11T14:38:31.349+0000] [glassfish 4.1] [INFO] [] [] [tid: _ThreadID=221 _ThreadName=Thread-8] [timeMillis: 1452523111349] [levelValue: 800] [[
14:38:31,348 INFO [AutoDeployer][HotDeployEvent:145] Plugin mine-theme requires marketplace-portlet]]
[2016-01-11T14:38:31.350+0000] [glassfish 4.1] [INFO] [] [] [tid: _ThreadID=221 _ThreadName=Thread-8] [timeMillis: 1452523111350] [levelValue: 800] [[
14:38:31,349 INFO [AutoDeployer][HotDeployImpl:217] Deploying mine-theme from queue]]
[2016-01-11T14:38:31.350+0000] [glassfish 4.1] [INFO] [] [] [tid: _ThreadID=221 _ThreadName=Thread-8] [timeMillis: 1452523111350] [levelValue: 800] [[
14:38:31,350 INFO [AutoDeployer][PluginPackageUtil:1016] Reading plugin package for mine-theme]]
[2016-01-11T14:38:31.404+0000] [glassfish 4.1] [INFO] [] [javax.enterprise.web] [tid: _ThreadID=221 _ThreadName=AutoDeployer] [timeMillis: 1452523111404] [levelValue: 800] [[
WebModule[null] ServletContext.log():Initializing Spring root WebApplicationContext]]
[2016-01-11T14:38:31.414+0000] [glassfish 4.1] [INFO] [] [] [tid: _ThreadID=221 _ThreadName=Thread-8] [timeMillis: 1452523111414] [levelValue: 800] [[
14:38:31,413 INFO [AutoDeployer][ThemeHotDeployListener:98] Registering themes for mine-theme]]
[2016-01-11T14:38:33.507+0000] [glassfish 4.1] [INFO] [] [] [tid: _ThreadID=221 _ThreadName=Thread-8] [timeMillis: 1452523113507] [levelValue: 800] [[
14:38:33,507 INFO [AutoDeployer][ThemeHotDeployListener:113] 1 theme for mine-theme is available for use]]
[2016-01-11T14:38:33.736+0000] [glassfish 4.1] [INFO] [AS-WEB-GLUE-00172] [javax.enterprise.web] [tid: _ThreadID=221 _ThreadName=AutoDeployer] [timeMillis: 1452523113736] [levelValue: 800] [[
Loading application [mine-theme] at [/mine-theme]]]
[2016-01-11T14:38:33.992+0000] [glassfish 4.1] [INFO] [] [javax.enterprise.system.core] [tid: _ThreadID=221 _ThreadName=AutoDeployer] [timeMillis: 1452523113992] [levelValue: 800] [[
mine-theme was successfully deployed in 4,148 milliseconds.]]
[2016-01-11T14:38:33.998+0000] [glassfish 4.1] [INFO] [NCLS-DEPLOYMENT-02035] [javax.enterprise.system.tools.deployment.autodeploy] [tid: _ThreadID=221 _ThreadName=AutoDeployer] [timeMillis: 1452523113998] [levelValue: 800] [[
[AutoDeploy] Successfully autodeployed : /home/glassfish/glassfish4/glassfish/domains/domain1/autodeploy/mine-theme.war.]]
Setting your theme
See Control Panel -> Configuration -> Portal settings -> Display Settings and below there's Look & Feel.
Also, there's this place: Control Panel -> Sites -> Your site -> Site Pages -> Look and Feel + Current Theme. You can select another theme from a list below in the same configuration page.
Your theme is actually a Plugin, and can be found among the Theme Plugins. Navigate to Control Panel -> Apps -> Plugins Configuration. Select the tab "Theme Plugins". Your theme should be visible in the list.
If not, you are likely to receive something like this in your logs
7 8:
[2015-12-31T23:38:41.633+0000] [glassfish 4.1] [INFO] [] [] [tid: _ThreadID=29 _ThreadName=Thread-8] [timeMillis: 1451605121633] [levelValue: 800] [[
23:38:41,633 WARN [http-listener-1(4)][ThemeLocalServiceImpl:156] No theme found for specified theme id mine_WAR_minetheme. Returning the default theme.]]
I don't know why this happened in my case, but I found a reference in the Liferay database to the old mine-theme. Even though I thought I got rid of it permanently, but removing it from the autodeploy directory. If I remove it from the glassfish autodeploy directory, it is also removed from the Application Server. Liferay is listening to what happenes on the autodeploying front, detects the deletion, and starts cleaning up after itself as well.
Apparently, there still was an entry left hanging. I had to update the database manually to reset a database tablerow back to "classic".
Adapting your theme
It is possible to adapt your theme, by replacing images and css and html files judiciously.
The interesting bit of theming is that you specify the parent theme. So, you've got "styled" and "unstyled" and the default theme called "classic" to choose from. But it would also be easy to create for example a "Christmas" theme, that is derived from the theme that you normally use. So it's kind of an Inheritance structure, similar to Object Oriented Programming.
I also like the fact that in your new theme you specify the "changes" compared to the parent theme in the _diffs folder. This way, when a parent theme changes (upon a new release of Liferay Portal), you automatically get the new updates, and if you do not change these defaults in your theme, they are just build into the target war upon the next release.
If you wish to start making bigger changes, there is the possibility of using the Liferay Application Display Templates
9 (ADT).
Liferay uses Apache Velocity
10 as its templating engine.
Adding JQuery to the Liferay portal can be done as described at [11].
References
- [1] Randomthoughts - Liferay
- http://randomthoughtsonjavaprogramming.blogspot.nl/2015/12/liferay.html
- [2] Liferay
- http://www.liferay.com/
- [3] Wikipedia - Liferay
- https://en.wikipedia.org/wiki/Liferay
- [4] Liferay Company Blogs - Creating Liferay Themes with Maven
- https://www.liferay.com/web/mika.koivisto/blog/-/blogs/creating-liferay-themes-with-maven#_33_message_13069757
- [5] Liferay Developer Network - Developing Liferay Theme Plugins with Maven
- https://dev.liferay.com/develop/tutorials/-/knowledge_base/6-2/developing-liferay-theme-plugins-with-maven
- [6] Liferay Developer Network - Creating a Theme Project in the Plugins SDK
- https://dev.liferay.com/develop/tutorials/-/knowledge_base/6-2/creating-a-theme-project-in-the-plugins-sdk
- [7] StackOverflow - Error occures when deploying theme to liferay portal. “No theme found for specified theme id .”
- http://stackoverflow.com/questions/11721220/error-occures-when-deploying-theme-to-liferay-portal-no-theme-found-for-specif
- [8] Techspace - No theme found for specified theme id abc_WAR_xyztheme
- http://parasjain.net/2012/07/11/no-theme-found-for-specified-theme-id-abc_war_xyztheme/
- [9] LiferaySavvy - List of Velocity Variables in Liferay
- http://www.liferaysavvy.com/2015/02/list-of-velocity-variables-in-liferay.html
- [10] Wikipedia - Apache Velocity
- https://en.wikipedia.org/wiki/Apache_Velocity
- [11] Liferay Company Blogs - Using jQuery (or any Javascript library) in Liferay 6.0
- http://www.liferay.com/web/nathan.cavanaugh/blog/-/blogs/using-jquery-or-any-javascript-library-in-liferay-6-0