107
I Use This!
Very High Activity

News

Analyzed about 19 hours ago. based on code collected 1 day ago.
Posted over 2 years ago by Olaf Kock
In case you're working on multiple Liferay servers, like I frequently do, you might have seen this problem, and fell for it: In the backend, namely Control Panel and Site Administration, they all look the same. Rarely do I see anybody working on a ... [More] new "Admin Theme" for those places. I've had enough of trying to decipher the URL and host name, and decided to do something about it, that doesn't require a whole new theme: The configurable admin-theme-background plugin. You can configure it with your own color and text of choice, and make sure that you never need to double check if you're currently on a Production-, Test- or Development server. Or, if you're demoing multiple systems at the same time, which one you're on.   Find the source code and an installable bundle (currently built and tested on DXP 7.3) on github. [Less]
Posted over 2 years ago by Anne Durey
You thought "I'd love to present something on /dev/24" but totally missed the deadline of the call for presentations? Say no more! The deadline for answering the call for presentations is extended until 15th Oct, 23:59:59 UTC. This is your final ... [More] chance to come and help to build /dev/24 and also brag about what you have developed for Liferay Portal/DXP 7.4. Right now all you need to provide is the basic information like the topic you'll be talking about, how long do you plan to talk about it (20-40 minutes) and your time availability. /dev/24 will take place on the 3rd and 4th November, so you'll have some time between saying you'll present and the actual presentation.  And remember: Don't worry about Power Point slides. /dev/24 is less PPT, more IDE.  The call goes out to everybody who gets their hands dirty with curly braces - be it in Java, JS, CSS. Those who have created 7.4 features, those who have used them already and those who can't wait to use them. No matter if you're with a Liferay Customer, Partner, part of the Open Source community, Employee, or otherwise interested: Presentations, Showcases, Showing off, Tutorials and neat Tips and Tricks. Add in some fun, conversations, Q&A. If you have already submitted a presentation, thank you! The preliminary agenda will be available soon, so you can take a look at what's coming. And for those who are curious about this year's format, besides going 12 hours straight each day, we're going 8-bits! More on that soon. If you want to volunteer for other help (hosting presentations, testing things, moderating chats, making sure everything is working as it should, etc), please contact dev24 at liferay.com (turn that into an email address first). That email address is also available for further questions regarding the submission process. [Less]
Posted over 2 years ago by Allen Ziegenfus
Did you know that you could subscribe to a RSS feed for Liferay blogs? You can use this URL to subscribe to community blogs on the liferay.dev site: https://liferay.dev/c/blogs/rss?plid=119785330&groupId=14 In addition to the community blogs ... [More] , we also have blogs on our main web site on a variety of topics: https://www.liferay.com/blog Starting next week (by October 14th or 15th), we will also offer an RSS feed for our main web site blogs at https://www.liferay.com/c/blogs/rss. Up till now, the blogs RSS feed for our main web site was pointing to the community blogs, so if you happened to have set up your community blog RSS feed through our main web site URL(https://www.liferay.com/c/blogs/rss) - please update your RSS url to the liferay.dev one above. ​​​​​Coming later this year we are also redesigning the blogs on https://www.liferay.com/blog to have a new look and feel and also to take advantage of new features like collection providers and display page templates for publishing our blog content.     [Less]
Posted over 2 years ago by Anne Durey
It's that time of the year.  You've worked on/with Liferay Portal 7.4.  You are about to use Liferay Portal 7.4 to solve a problem.  You have any other awesome contribution you've made or plan on doing.  This is your chance to show it to the world ... [More] during /dev/24, on the 3rd and 4th November.  The Call for Presentations is open, and here's why you should submit your 20 to 40-minute talk now: The sooner you submit, the better your chances to get exactly the date and time slot of your preference. The sooner you submit, the sooner you (and the whole community) have a sneak peek at the agenda. The sooner you submit, the more time you get to work on your presentation, thus avoiding last-minute frights. Deadline for submissions: 8 October 2021, 23:59:59 UTC (here's some help to navigate time zones). Don't worry about Power Point slides. /dev/24 is less PPT, more IDE.  The call goes out to everybody who gets their hands dirty with curly braces - be it in Java, JS, CSS. Those who have created 7.4 features, those who have used them already and those who can't wait to use them. No matter if you're with a Liferay Customer, Partner, part of the Open Source community, Employee, or otherwise interested: Presentations, Showcases, Showing off, Tutorials and neat Tips and Tricks. Add in some fun, conversations, Q&A. And if you want to volunteer for other help, rather than submitting a presentation (hosting presentations, testing things, moderating chats, making sure everything is working as it should, etc), please contact dev24 at liferay.com (turn that into an email address first). That email address is also available for further questions regarding the submission process. /dev/24 will take place on the 3rd and 4th November, on two 12-hour streams of content, from 11:00 through 23:00 UTC, each day.   [Less]
Posted over 2 years ago by David H Nebinger
Introduction So when you start building your own fragments and using them on your content pages, you will often times run into an issue with propagation... So I like to create fragments for headers and footers and then use those fragments on every ... [More] page that I build. But when I update those fragments, I have to go into the usages panel to do the propagation so they all get updated. If you have a single page of usages or a couple of pages, this is not too bad. You hit the checkbox in the bar and then you can pick the Propagate button to update them all. When there are multiple pages, you just repeat this until you've finished all of the updates. However, if you have many pages of results to get through, this UI can be quite painful. Checkbox, Propagate, wait for page to update, Checkbox, Propagate, Wait, Checkbox, Propagate, Wait, ... I have a site with 750+ pages which (using the 20 per page) translates to 38 pages or 38 times I have to go through this title. Even if I change the window size, I'm still going to have to go through this over and over again... Given this UI annoyance, I decided to set out and fix it, and I'm going to share it with you because there's lots of learning opportunities here... Challenge #1 - Add an MVCActionCommand to the Liferay Fragment Portlet When you start digging into the modules/apps/fragment/fragment-web module that has the Fragment portlet, you'll find that it is a typical Liferay MVC-based portlet. It does have a PropagateFragmentEntryChangesMVCActionCommand which shows us how the checked fragment entries would each be propagated, so this is a good source for how we would be doing our implementation. You may not be aware, but it is super easy to add a custom command to an existing [Liferay] portlet. All you need is a module with your MVCActionCommand implementation and have the right properties to make it work. I'm not going to step you through how I built my implementation, but the code should be pretty much self-explanatory: /** * class PropagateAllFragmentEntriesMVCActionCommand: This new mvc action command will * enable propagating all changes for the fragment to every usage. * * @author dnebinger */ @Component( immediate = true, property = { "javax.portlet.name=" + FragmentPortletKeys.FRAGMENT, "mvc.command.name=/fragment/propagate_all_fragment_entries" }, service = MVCActionCommand.class ) public class PropagateAllFragmentEntriesMVCActionCommand extends BaseMVCActionCommand { @Override protected void doProcessAction(ActionRequest actionRequest, ActionResponse actionResponse) throws Exception { // we should probably check to see if the user has // permission to propagate before doing anything else // get the fragment entry to propagate final long fragmentEntryId = ParamUtil.getLong(actionRequest, "fragmentEntryId"); if (fragmentEntryId == 0) { if (_log.isInfoEnabled()) { _log.info("Propagate all with invalid fragment entry id"); } throw new PortalException("Fragment entry id is required"); } // Get the fragment entry, it will provide the key fields necessary for propagation final FragmentEntry fragmentEntry = _fragmentEntryLocalService.getFragmentEntry(fragmentEntryId); // to handle the propagation, we'll use an actionable dynamic query... ActionableDynamicQuery propagationQuery = _fragmentEntryLinkLocalService.getActionableDynamicQuery(); // match on group and fragment entry id propagationQuery.setAddCriteriaMethod( new ActionableDynamicQuery.AddCriteriaMethod() { @Override public void addCriteria(DynamicQuery dynamicQuery) { dynamicQuery.add(RestrictionsFactoryUtil.eq( "groupId", fragmentEntry.getGroupId())); dynamicQuery.add(RestrictionsFactoryUtil.eq( "fragmentEntryId", fragmentEntryId)); } }); // for each fragment entry link for this fragment entry propagationQuery.setPerformActionMethod( new ActionableDynamicQuery.PerformActionMethod() { @Override public void performAction(FragmentEntryLink fragmentEntryLink) throws PortalException { if (_log.isDebugEnabled()) { _log.debug("Updating the fragment entry link {} to the latest version", fragmentEntryLink.getFragmentEntryLinkId()); } // use the link service to it to update to the latest version _fragmentEntryLinkLocalService.updateLatestChanges( fragmentEntryLink.getFragmentEntryLinkId()); } }); try { // do the propagation propagationQuery.performActions(); } catch (PortalException e) { _log.error("Error updating the fragment entry links: {}", e.getMessage(), e); throw e; } } @Reference(unbind = "-") private FragmentEntryLocalService _fragmentEntryLocalService; @Reference(unbind = "-") private FragmentEntryLinkLocalService _fragmentEntryLinkLocalService; private static final Logger _log = LoggerFactory.getLogger( PropagateAllFragmentEntriesMVCActionCommand.class); } So this is basically your typical MVCActionCommand implementation, but from the javax.portlet.name property above I'm able to bind this new MVCActionCommand to the existing Liferay portlet. This would be a class in a completely separate module jar, but I'm attaching it to another portlet. There are some important things to remember with an implementation like this... I'm only able to attach my new action to the Liferay portlet, but this doesn't mean I have carte blanche access to all of the classes and stuff that are part of the Liferay Fragment portlet. I can only use whatever the Liferay Fragment portlet has exported. Fortunately for me, I didn't really need any of its internal stuff, so I was okay for this implementation. Now if I build and deploy this module, it will start up cleanly, but I can't really use it yet because nothing in the Liferay portlet knows how to invoke the new MVCActionCommand. To make that happen, I'll need to override the JSP. Challenge #2 - Override the Liferay Fragment Portlet JSP So the action is ready, but now the portlet needs to be able to invoke it. After looking at the Liferay JSP for the Fragment portlet, I've decided that I just need to override the view_fragment_entry_usages.jsp page. To make things easy on me, I started by creating a fragment module using the blade tool, then I updated the bnd.bnd file with a version range: Bundle-Name: Santander Fragment Propagation Bundle-SymbolicName: fragment.propagation.web Bundle-Version: 1.0.0 Fragment-Host: com.liferay.fragment.web;bundle-version="[2.0.50,3.0.0)" By using a version range, I can continue to apply new fixpacks into my DXP environment without having to recompile my fragment bundle. The risk here, though, is that if Liferay does an update to this JSP to fix, say, a security issue, my JSP file might not have that fix but it will still be overriding Liferay's patched version. So if you do go this route, try to remember to check Liferay's version for important updates that you should pull into your override file. Speaking of which, the only other file I have in my fragment bundle is my overriding view_fragment_entry_usages.jsp page. I'm not going to show the whole thing here, but I can share the portion that I added to the original. I started by copying the Liferay file, then I inserted the following lines at line number 118: So first I define a portlet action url that has the name of my action command (see same from the MVCActionCommand class above), and then I just added a simple form w/ a button with the Propagate All label. Now, when I build and deploy this fragment bundle, now on the Fragment portlet usage page, I now see: When you hit the button, the form will submit back to the Fragment portlet which will look up the MVCActionCommand that matches the /fragment/propagate_all_fragment_entries action, the portlet will find my custom action command handler which will use an ActionableDynamicQuery to update all 753 of the usages of my Site Footer fragment. Conclusion Well, my work here is done! This isn't a perfect solution of course. I didn't use localization for my Propagate All button, I didn't really do a good integration of the button into the existing UI, and I didn't handle the group propagation either. There's definitely some more work to do here, but I think what I have shared might give you some ideas about how you can consider adding your own custom functionality to an existing Liferay portlet! [Less]
Posted over 2 years ago by Roselaine Marques
Created in the middle of the Covid Pandemic in 2020, /dev/24 has come to stay { yeaaahh!! :clapping: }  Following the big success of the 24-hour-non-stop event last year...  We will do it again until:   For those of you who missed /dev/24 last ... [More] year, or are not sure and asking yourself: “What is this event?”. Let me give you a quick overview: This is not a company event, this is about us, the community, the chain of knowledge. The main aim of this event is to give us the space to share our discoveries, knowledge, news... about our experience with our “Liferay World”. Let the world hear our voice, in a multinational on-line event, totally free of cost (well… you will need an internet connection). A fun way to participate and watch: presentations, showcases, tutorials, new features, tips and tricks... everything on Liferay 7.4 (the latest version). Summarizing… Here you are invited to be a volunteer, a speaker and an attendee.        Good News! The Call for Presentation is open: Save the date! This year the event will be hosted in 2 sessions of 12 hours each, November 3rd and 4th. Applications are now open on  “Presentation Submission for Liferay /dev/24 2021” (deadline for applications October 8th). Be on the lookout! In the next few days the URL to subscribe to the event will be published. Would you like to participate in the agenda committee, or help organize? As always, we welcome volunteers. Please contact us at [email protected]. Let’s go! Let's immerse ourselves in technology for 24 hours! Let’s boost our knowledge by learning together!                                                                                                                      Image by Gerd Altmann from Pixabay.                                                                                    See you soon ;)  [Less]
Posted over 2 years ago by Vitaliy Koshelenko
Overview   Search is one of the fundamental Liferay features, which provides users with the possibility to quickly find the content they look for. It’s powerful, pretty much configurable, and flexible.  However, during implementation of the latest ... [More] project for our client we run into a bunch of issues. Some of them were Liferay bugs or missing functionality, other ones - configuration issues. I’d like to share our experience in troubleshooting them in this post.   The Scenario   Let’s assume, we have a portal with books/tutorials (with restricted access). We have a main “Books” site, and a list of child sites for an individual book. Each book site has private pages with content on it (to represent the book's chapter/pages). Users should be able to search for content from a parent “Books” site (global search), or within an individual book site. Basically, the logic is similar to https://learn.liferay.com/ site.   1. Private Pages Indexing   Problem The first issue we came up with was the private pages indexing issue, already described here. The interesting thing is that it was working before, but after upgrading DXP 7.3 to FP2 it became broken. The client was frustrated, as the release date was close, and the search feature was not functional at all. After analyzing the sources we found out that the approach for indexing the page content had changed completely. Initially the content was taken from the database (basically, from fragments placed on the page being indexed), but later on the LayoutCrawler was introduced, which tries to fetch page content by URL (using Guest account), and obviously can’t do that for the restricted private pages. Solution The solution/workaround for the private pages indexing was similar to the one in the blog mentioned above. The main difference - I have implemented a custom auto-login, which signs in the “crawler” user automatically without password (IMHO, providing raw password even in the portal settings is not secure). Components: LayoutModelDocumentContributorOverride - customized version of Liferay’s com.liferay.layout.internal.search.spi.model.index.contributor.LayoutModelDocumentContributor . The logic is the same, but it calls a custom crawler instead of Liferay’s one; LayoutCrawler - custom layout crawler. It makes authenticated requests to fetch pages content (using current user’s session if it’s available, or auto-logins a predefined “crawler” user otherwise, and re-uses the session in subsequent calls); LayoutCrawlerAutoLogin - custom auto-login to sign in a “crawler” user without providing password (generated “autoLoginKey” is used instead); SessionIdThreadLocal - custom thread-local class to store sessionId to be reused in subsequent calls (in order not to create a session on each crawler call). Sources: https://github.com/liferay-apps/liferay-search-override p.s. Also, after this implementation we had to blacklist the original LayoutModelDocumentContributor: Otherwise, it may run after a custom one and break the indexed data.   2. Displaying Search Results   Problem There were two issues here: what is displayed in results and how it’s displayed: The preview for search results contained some improper data. We had to customize the layout and how the information is displayed.   Solution 1: pre-processing content   If we look again into the sources of newly introduced page crawler - we’ll found out, that the logic for fetching content is very simple, but not too smart. Actually, it just indexes everything that is after id=”wrapper”. From the default theme structure it means, that data from header (or even footer) will be included. This generates “strange” previews for search results, which displays data from header navigation, breadcrumbs, menus etc. instead of the actual page content.  Considering, we had created a customized version of LayoutModelDocumentContributor - I have included a content pre-processor step before putting it into Elastic index. In my case I get everything inside “content” (yes, “content” and not “wrapper” to exclude data from header), and cut-off all portlets data to index only fragments inside the content. Of course, this logic may be different according to the requirements and a custom theme structure: This fix made the preview for pages more accurate, and not displaying the same “random" information for each page.   Solution 2: custom widget template The default template for displaying search results contained some information, which should not be shown according to the requirements (icon, author, modified date, etc.): Thanks to the Widget Templates feature it’s easy to modify the widget’s content template, including “Search Results Widget”. We had just to create a new “Search Results Template” based on “List Layout” one in a Global site, and remove the redundant elements:   After applying the display template for search results we’ve got the desired view:   3. Filtering Search Results   Problem Search results should be filtered against associated tags and categories. Only pages should be displayed in search results. Solution Using the Facet widgets we can filter the search results. Just added “Type Facet”, “Category Facet”, “Tag Category” to the search results page:   Also, pre-configured the “Type Facet” to display pages only:   Considering this selection makes no sense for the end user (as there is only on option to select - “Page”), we made it hidden (except edit mode):   4. Scoping Search Results   Problem When performing the “global” search (search from the main “Books” site) - search results should be displayed from any book (child site), but not from other Liferay sites. Actually, Liferay provides the capability to select the “scope”: But there are only options to restrict scope to “This Site” or “Everything”, we can’t choose an option like “This site and all child sites”. Solution Fortunately, we can use custom filters to restrict the search results by specifying the site’s groupId, as described here. We need to add a “Custom Filter” widget to the search results page for “parent” filter with the configuration below: And also add a “Custom Filter” widget for each individual child site, specifying the appropriate groupId in the configuration:  But even after proper configuration it will not work, and you may be wondering - why? This is due to another Liferay bug. However, the solution is simple: just give your search result page a different name - e.g. “Search Results” instead of “Search” to generate a different friendly URL from “/search”. Also, make sure you specify this page’s URL as “Destination Page” in the Search Bar configuration. This way, you should be able to find the result from child sites, and also filter them by site (if you add the “Site Facet” to the search results page): Conclusion   Even though Liferay search is a powerful tool, providing users with a flexible way for looking for the content they need, it’s node ideal, and has some issues currently. But all of them can be overcame, if you put enough effort, ask community support, analyze Liferay sources and try to make Liferay better 😏 Hope, this will be helpful for somebody. Add your thoughts and questions into the comments, or contact me directly.   Enjoy 😏 Vitaliy [Less]
Posted over 2 years ago by Olaf Kock
In the ancient past, Liferay had a feature to discover individual portlet's rendering times. It looks like this got lost with the move to OSGi -  but it's also reasonably simple to replace. Especially when it's for portlets only (fragments are still ... [More] on the to-do list) Some portlets take longer than others. While that's ok - they typically provide more value and dynamic content - you might want to limit their use to the less frequented page and not have them on your most public landing page. Here's a quick proof-of-concept that you can use to display each individual widget's rendering time. It's also a sample for introducing a PortletFilter to each and every existing portlet in the system. Let me know if you find it useful, discover bugs, or have extensions that you'd like to see in there. [Less]
Posted over 2 years ago by Maurice Sepe
Overview While working on an intranet with on of our clients in the APAC region, we discovered that private pages are not indexed correctly, thus having issues when searching content. Product team is already aware of this and have already logged a ... [More] ticket here. While adding features to Liferay is all good and well, we don't have the time to wait for the product team, and thus this workaround was created. However, I'd still recommend using the solution provided by product team over this workaround once that becomes available. Why aren't private pages searchable? Private pages are not indexed properly since the layout crawler responsible for them uses Guest user access.  Workaround Details So the workaround is a custom module that you deploy to your Liferay workspace. Below are the steps we did during development. Create a custom page crawler that's specifically targets private pages. The custom page crawler will leverage OOTB auto-login of the Remember Me feature to authenticate and access private pages. Attach a dummy user to the said page crawler. The dummy user should be a site member of the site where the private pages are stored. Call the custom page crawler after indexing via a custom implementation of the IndexerPostProcessor interface. You can read more about this here. Source Code The source code contains 3 major files CrawlerConfiguration.java - Contains the hashed username / password of the dummy user that we will use to crawl the private pages. LayoutCrawler.java - The custom layout crawler that crawls private pages. LayoutIndexerPostProcessor.java - The post processor hook that calls our custom crawler. You can find the source code here and the steps on how to set it up here. Acknowledgements I would like to thank Ha Tang for coming up with this brilliant idea and implementing it for our client.  As always, constructive feedback is appreciated.     [Less]
Posted over 2 years ago by Ashley Yuan
The new Liferay IntelliJ 1.9.4 plugin supports IntelliJ 2021.2 and 2021.2.1. Head over to this page for downloading.   Release Highlights improvements on new liferay module wizard upgrade sinceBuild to 212 and fix compatibility issues ... [More] support creating a maven workspace using target platform bug fix for rerun server button inside of a maven workspace improvements on liferay docker server add validation on adding a liferay docker server delete docker image and container when removing docker server more support on starting a liferay docker server in debug mode Bug fixes   Screenshots   Feedback If you run into any issues or have any suggestions please come find us on our community forums or report them on JIRA (INTELLIJ project), we are always around to try to help you out. Good luck!               [Less]