Adding Custom Attributes capabilities on custom assets in Liferay 6 through plugins

The portal provides a framework to add custom attributes or called custom fields to any Service-Builder generated entities at runtime where indexed values, text boxes, and selection lists for input and dynamic UI are available. For example, you could add custom fields on any entities like Wiki page, Message Boards category, Message Boards message, Calendar event, page, organization, user, Web Content, Document Library document, Document Library folder, Bookmarks entry, Bookmarks folder, Image Gallery image, Image Gallery folder, Blogs entry, etc. Of course, you would be able to add custom fields on custom entities in plugins. (Abstracted from the book: Liferay Portal 6 Enterprise Intranets).

We have discussed how to apply custom attributes in portal core assets, as mentioned in the book Liferay Portal 6 Enterprise Intranets. But how to apply custom attributes on custom assets? And how to build a plugin with custom attributes capabilities on custom assets? This post will address how to apply custom attributes on custom assets, for example, Knowledge Base articles, and how to make custom attributes available in Liferay 6 through plugins.

Note that Knowledge Base articles are used as an example, one of custom assets. Actually you can use same approach for any custom assets as you expected through Plugins.

Managing Custom Fields on Custom Assets

For example, you’re going to add attribute Type on the custom entity Knowledge Base Article. The portal provides a Custom Fields framework, thus you could be able add attributes on custom entities, without writing any code. As shown in following screenshot, custom attributes are available to be added on the custom asset Knowledge Base Articles.

 It is nice feature that you would be able to add custom fields on any resources. Considering above requirement, you’re going to add attribute Type on the custom entity Knowledge Base Article, without writing any Java code. As shown in following screenshot, you could do it in Control Panel with the portlet Expando.

In order to add custom attribute Type, you would be able to use Custom Fields against Knowledge Base Article. You could simply click on Knowledge Base Article in the category Portal of Control Panel first; then click on icon Custom Fields next to the icon Add.

Once a few custom fields were added on a resource, you would be able to add values for custom fields when you edit that resource. For example, you have added custom field Type on the resource Knowledge Base Article. When you edit an instance of that resource, says “Lotti Stein”, you would be able to add values for custom field Type.

Of course, you would be able to display Knowledge Base Article with custom attributes and their values as shown in following screenshot

How to make it?

Abstracted from the book: Liferay User Interface Developement.

How to make it? In this section, we’re going to introduce how to add custom attributes on custom entities in plugins. The entities Knowledge Base Articles will be used as an example. In brief, it should be simple to make it with following steps.

Adding Custom Attributes as references

First, you have to add custom attributes as references in $PLUGIN_SDK_HOME/knowledge-base-portlet/docroot/WEB-INF/service.xml as follows.

<reference package-path="com.liferay.portlet.expando" entity="ExpandoValue" />

As shown in above code, the reference element allows you to inject services from another service.xml, that is, from portal core, within the same class loader. For example, if you inject the ExpandoValue entity, then you'll be able to reference the Custom Attributes services from your service implementation via the methods getExpandoValueLocalService and getExpandoValueService. You'll also be able to reference the Custom Attributes services via the variables ExpandoValueLocalService and ExpandoValueService.

Then, you need to run ANT target build-service to rebuild service based on newly added custom attributes reference.

Adding Custom Attributes Display

Liferay 6 provides pluggable custom attributes implementations, where developers can register their own custom attributes display implementation for any entity they build. It will appear automatically in the Custom Fields admin portlet so users can associate custom attributes entities with available permissions. To make it happening, we need to add Custom Attributes Display in $PLUGIN_SDK_HOME/knowledge-base-portlet/docroot/WEB-INF/liferay-portlet.xml of plugin as follows.

<custom-attributes-display>com.liferay.knowledgebase.admin.ArticleCustomAttributesDisplay</custom-attributes-display>

As you can see, the tag custom-attributes-display value must be a class that implements com.liferay.portlet.expando.model.CustomAttributesDisplay and is called by Custom Fields administration UI.

Then you need to create the class com.liferay.knowledgebase.admin.ArticleCustomAttributesDisplay, which implements com.liferay.portlet.expando.model.CustomAttributesDisplay as follows.

public class ArticleCustomAttributesDisplay extends BaseCustomAttributesDisplay {
public static final String CLASS_NAME = Article.class.getName();
public String getClassName() { return CLASS_NAME; }
public String getIconPath(ThemeDisplay themeDisplay) {
 return themeDisplay.getPathThemeImages() + "/common/pages.png"; }
}

As you can see, ArticleCustomAttributesDisplay extends BaseCustomAttributesDisplay and overrode the methods getClassName and getIconPath. That’s simple. Isn’t it?

Adding Custom Attributes UI tags

Last but not least, you need to add custom attributes UI tags in order to take custom attributes as input or to display custom attributes with values for current custom entity, for example, Knowledge Base Article.

To do so, you should add custom attributes UI tags to create or update custom attributes values after creating or updating content at $PLUGIN_SDK_HOME/knowledge-base-portlet/docroot/admin/edit_article.jsp as follows.

<liferay-ui:custom-attributes-available className="<%= Article.class.getName() %>">
 <liferay-ui:custom-attribute-list
  className="<%= Article.class.getName() %>"
  classPK="<%= (article != null) ? article.getArticleId() : 0 %>"
  editable="<%= true %>"
  label="<%= true %>"
 />
</liferay-ui:custom-attributes-available>

Logically you could re-arrange UI forms (title, content, description and custom attributes) as you expected. For example, you can add above code before or after the line <aui:input name="title" />.

For the same reason, you should add custom attributes UI tags to display custom attributes with their values after displaying content at $PLUGIN_SDK_HOME/knowledge-base-portlet/docroot/admin/view_article.jsp as follows.

<liferay-ui:custom-attributes-available className="<%= Article.class.getName() %>">
 <liferay-ui:custom-attribute-list
  className="<%= Article.class.getName() %>"
  classPK="<%= (article != null) ? article.getArticleId() : 0 %>"
  editable="<%= false %>"
  label="<%= true %>"
 />
</liferay-ui:custom-attributes-available>

As you can see, the UI tag which is used to display custom attributes and their values is same as that of creating or updating custom attributes values.

Where would you find sample code - Knowledge base plugin with custom attributes capabilities?
You can simply download WAR of Knowledge Base plugin with custom attribute capabilities from

knowledge-base-portlet-6.0.6.1.war

And then deploy it. That’s it.

Note that above WAR was built by Liferay 6.0.6 (revision 62344) and JDK 6.0.12.

Summary

As you can see, you would be able to add custom attributes capabilities on any custom assets generated by Service-Builder in plugins. The asset Knowledge Base articles is one of them (custom assets).Try it now, you would be able to have custom attributes capabilities on your own custom assets. 

23
Blogs
Hi Jonas!!
Nice to read about custom attributes. However I always had this question. Is it better to have custom attributes or create an extra table if you want to add some fields to any liferay entities?
Hi Zankar, Thanks.

Both approaches (having custom attributes or creating an extra table) have their own advantages and disadvantages. You may choose one of them based on requirements.
Can any plz explain how to set custom attribute list values.
Hi Teo, thanks. you may refer to details about usage of Custom Attributes from the book: http://www.amazon.com/Liferay-Portal-6-Enterprise-Intranets/dp/1849510385.

or wiki pages.

Hope that it helps,
Hi all

Just FYI: You can't join Expando Hibernate entity with your entities. This means - you'll have problem when you try to create list of your entities with expando in one table. Moreover it is almost impossible to sort them (with paging) using expando column.
See http://issues.liferay.com/browse/LPS-8292
Nice article. But i believe custom attribute shouldnt be created for the portlets that we develop, since it is a mess to use the same in jsp with huge tags. For custom portlet since it is developed by us, its lot easier to modify service.xml and add the column there and rebuild service. Custom attributes is good i guess only for core liferay models.
Hi Sandeep, thanks.

As a developer, I would agree with you to use custom asset model in plugins

As a portal admin or content creator, I would never touch any Java code, but add additional fields in run-time. Thus custom attributes would be ideal approach.

Do you agree?

Best regards,

Jonas Yuan
Hmm true. But tht depends on size of the portlet too how big it is and number of custom attributes that we want. Suppose the portlet is very big with huge functionality and if there is a requirement to have less than 5 columns i would go for custom attribute. I would use custom attribute if its something in extension environment. As you see adding custom attribute still doesnt eliminate code writing. The main headache is updating the value, you have to update each column separately with class name and class pk. Whereas if its in model its quite easy. But it still depends on wht is the requirement.
Thank you, Sandeep!

It depends on what the requirement is ... :-)

Both approaches (having custom attributes or adding extra columns) have their own advantages and disadvantages.
I need to add a custom field to Calendar Events. Calendar events can be used to create lists of future Conferences, Workshops, etc. The current implementation however does not support rich text to be entered in the event dialog. However, it is also not possible to add a rich text box using the Custom Fields. Will this be supported in future?
RoK, this is not fault of Custom Fields. Custom Field will store any value you want (text=html). What you need to do is extend Calendar portlet with WYSIWYG editor (that will enables you to add HTML to event description) and then extend Calendar portlet view to not escape HTML tags.
Thanks, but this is evident: when you are able to programme you can change everything (although i this is only restricted possible when using EE edition). i am looking from the perspective of the current userinterface options in the control panel. It would be better that a type 'html text' could be selected there.
Hi Rok, custom fields only support simple types for now.

Complex types will get supported later,
like

Adding custom types (Image Gallery images and Document Library documents) in custom attributes (Expando)

see http://issues.liferay.com/browse/LPS-2087.
Hi Rok, Thanks. custom fields are available to Calendar Events by default. You can use custom fields on any calendar events in Control Panel.
Great article Jonas. I am trying to enhance the account creation form using hooks. So in this respect, I have created a couple of custom fields for User. Now, how do I register them so that it works with the hook (create_account.jsp) ?
Hello Jonas Yuan,
Thanks for guiding us in this context.
Good work.
Hi Jonas, i wanted to download your war example knowledge-base-portlet-6.0.6.1.war but when i clicked on it, i've a page not found. Can u give me another link ? thanks for advance
Hello All,
I am using Liferay 6.1 CE version. I added my custom attribute in User entity from control panel. I want to add this my custom field in create_account.jsp hook page. I added like this way.

<div class="exp-ctrl-holder">
<liferay-ui:custom-attribute className="<%=User.class.getName()%>"
classPK="<%=0%>" editable="<%=true%>" label="<%=true%>"
name="user-default-group-name" />

After that i am trying to getting this value in UserLocalService hook class which extends UserLocalServiceWrapper class - (hook). I find each value from this but can not able to get my custom field value.

I am trying to get custom field value like this.

String defaultGroup = (String) User.getExpandoBridge().getAttribute("defaultGroupName");
log.info("Default Group Name :" + defaultGroup);

But I am getting null value or default value which I set at the time of adding custom attribute. I can not find my entered value from jsp page.

Please help me.

Regards :
Pradip Bhatt
pradip.bhatt@aspiresoftware.in