Hippo CMS treats internal links differently from external ones. Even when they are a part of an HTML field in a content document, they are stored as a reference to the referred content document and not as a regular hyperlink. When you're using the hst:html tag for rendering HTML fields in the template, it will take care of that automatically. But if you want to use the raw HTML string in some other way, the internal links inside it won't be valid.
Posts about Hippo CMS
Hippo CMS has built-in support for configuring components through auto-generated dialogs in the Channel Editor. These can easily be defined by using annotations in the component's ParametersInfo interface. Although there's an option to open a document picker, the documentation only hints at different configurations for it. After reading, it wasn't clear how to use it for picking a content folder instead of a document.
Once a Hippo CMS project is deployed to production for the first time, editors will start changing the content there. There's no easy way to merge those changes with the ones coming from developers. The official recommendation is to use Groovy updater scripts to do that when necessary. It's possible to automatically execute these scripts on startup, but this feature is almost completely undocumented.
In a Hippo CMS site, all URLs are under its control. Using the sitemap configuration, you can to some extent influence how URLs will map to content but there's no obvious or well-documented way to make Hippo CMS ignore the URL and let it be processed by a different servlet.
If untrusted values are not correctly escaped when included in web page markup, they can easily make the site susceptible to attacks. To reduce the risk of developer mistakes, many template engines can take care of escaping by default. FreeMarker template engine is no exception. Unfortunately, Hippo CMS default configuration doesn't enable automatic escaping in FreeMarker templates.
Freemarker, the Hippo CMS template language, includes special directives for working with sequences. Additional built-ins can be used to get more information about the loop variable. However, I've noticed that they don't always work.
In Hippo CMS, a page is generated from a hierarchy of Freemarker templates. Child contents can inject content into other parts of the root page using head contributions. In this post, I'm listing some restrictions which apply when using them.
One could argue that a JSON REST service should never return an empty body, but you might not always have a say in how a service you need to call will behave. Unfortunately, CRISP API in Hippo CMS throws a NullPointerException if the response body is empty.
The recommended way for integrating external services in Hippo CMS is the CRISP API. The official documentation provides detailed enough instructions for installing, configuring and using it. However, when I needed to customize the default Jackson ObjectMapper, it wasn't all that obvious how I could do it.
In Log4j, Mapped Diagnostic Context (MDC) can be used to provide additional context information for every log message. In server applications it will usually be initialized for every request in a filter. In Hippo CMS, a custom valve must be injected into the request pipeline for that purpose.
If you want to post-process the application logs, using the JSON format will usually make it easier. In Log4j, there's the JSON Layout available for that purpose. Making it work in Hippo CMS took me longer than expected.
Most built-in components in Hippo CMS have a link to one or more documents as they are designed to render the CMS content documents. Sooner or later you'll want to achieve that with your own custom component as well.
As a part of getting acquainted with Hippo CMS I took on the task of creating a custom Hippo component for including a Stencil web component in a portal page using the CMS editor. I based my work on a similar component I found on GitHub for a Polymer web component.