The following features are deprecated or retired. Review details and recommendations to plan migrations.
Showing 1-10 of 27 deprecations
Page 1 of 3
Likely to be retired in six months.
This plugin has been moved into the dotCMS core as of 26.06.06-01. If you are on this or a more recent version, you may remove the plugin and continue using the functionality normally.
If you are on a prior version, dotCMS recommends upgrading. The plugin will continue to function, in the meantime.
As of the beginning of 2027, the anonymous content API access will be disallowed by default.
dotCMS will be altering its default settings to disallow anonymous content access via API. As a result, dotCMS will always require an authenticated user for API content access.
Users currently allowing anonymous API access to content should create a front-end key for server-side use, and establish a pattern for what elements of the returns are permitted to be shared with anonymous users.
Content always respects content permissions; only content specified as anonymously accessible is available for reading without authentication.
Should a customer require anonymous API access, it remains possible to retain the prior permissive behavior, though this is not recommended. The DOT_CONTENT_APIS_ALLOW_ANONYMOUS environment variable can be used restore the old default. Possible values are as follows:
NONE | New default value; no anonymous API access. |
|---|---|
READ | Old default value; allows read-only anonymous access to content API endpoints. Not recommended. |
WRITE | Allows anonymous read OR write content behaviors. Doubly unrecommended, but may be useful in certain testing or development environments. |
A full inventory of affected endpoints is forthcoming.
Data security is the goal of this change. Anonymous, unauthenticated API calls permit full access to every content property — including hidden and system properties — and this may ultimately compromise more data than a user may wish. Making API calls require a level of authentication by default forces content-access decisions to be intentional at the level a site or app's front end.
Scheduled for removal on March 31, 2027. Current behaviour depends on the release. Before 26.09.23-01 these methods keep answering from Elasticsearch at every migration phase, and stop only when that cluster is decommissioned. From 26.09.23-01 they refuse to run once an installation reaches the final migration phase, rather than answering from an index that no longer receives writes.
Plugins and integrations calling the Elasticsearch-typed search methods should move to their vendor-neutral equivalents.
Stop using | Use instead |
|---|---|
ContentletAPI.esSearch(...) | ContentletAPI.search(...) |
ContentletAPI.esSearchRaw(...) | ContentletAPI.searchRaw(...) |
APILocator.getEsSearchAPI() | APILocator.getSearchAPI() |
ContentletAPIPreHook.esSearch / esSearchRaw | ContentletAPIPreHook.search / searchRaw |
ContentletAPIPostHook.esSearch / esSearchRaw | ContentletAPIPostHook.search / searchRaw |
The replacements are default interface methods, so existing implementors inherit them without change, and the hook replacements have no-op default bodies — override them only if you actually intercept search.
Return types change from Elasticsearch classes to neutral ones: ESSearchResults becomes ContentSearchResults<Contentlet>, which is a typed List<T> — the old (Contentlet) casts go away — and org.elasticsearch.action.search.SearchResponse becomes ContentSearchResponse. ElasticsearchException becomes DotSearchException, which extends DotRuntimeException and so stays unchecked; only code that explicitly catches the Elasticsearch type needs an edit.
Watch the imports. IndexStats, ClusterStats and NodeStats each exist in more than one package. Use the versions in com.dotcms.content.index.domain — importing an older one compiles cleanly and fails later at runtime.
A note on scope. Everything in com.dotcms.content.index.*, the engine-specific implementations, and anything reached through CacheLocator or FactoryLocator exists so dotCMS can swap search engines. It is not an extension surface. Plugins should stay on APILocator and the published interfaces.
dotCMS is migrating its search layer from Elasticsearch to OpenSearch. The deprecated methods return Elasticsearch-specific types, which cannot be provided once Elasticsearch is no longer in use.
They also bypass dotCMS's search engine routing entirely and read Elasticsearch directly, whatever engine the rest of the installation is using. While an installation is dual-writing, that means a plugin can return results from one engine while the surrounding site returns results from another, with no error raised and nothing recorded in the logs.
From 26.09.23-01 this stops being silent at the end: at the final migration phase the methods throw DotStateException rather than answer from an Elasticsearch index that is no longer being written to. The divergence window is therefore the dual-write phases, not the whole migration.
Scheduled for removal on March 31, 2027. Current behaviour depends on the release. Before 26.09.23-01 these methods keep answering from Elasticsearch at every migration phase, and stop only when that cluster is decommissioned. From 26.09.23-01 they refuse to run once an installation reaches the final migration phase, rather than answering from an index that no longer receives writes.
Templates calling the Elasticsearch-typed viewtool methods should move to their neutral equivalents:
Stop using | Use instead |
|---|---|
$estool.esSearch($query) | $estool.search($query) |
$estool.esRaw($query) | $estool.raw($query) |
To find affected templates, including widget code and workflow scripts: grep -rn "esSearch\|esRaw" <your-templates>
Check your aggregation names when you make the swap. $estool.search() and $estool.raw() normalize the whole query before executing it, so an aggregation declared as "tagAgg" comes back keyed tagagg. $results.aggregations.get("tagAgg") returns null, and a #foreach over null renders nothing rather than raising an error. Lowercase the name in both the query and the lookup.
Separately — if you are on 26.05.19-01 or later, $estool.search() and $estool.raw() have already changed. Most templates are unaffected: #foreach, $results.size(), $item.title, $results.aggregations, $results.hits and $results.response all continue to work, and the structure of the aggregation tree is unchanged. Three things did change:
$item.map.fieldName no longer resolves on search() results. Items are now ContentMap objects, which have no map property. Read the field directly — $item.fieldName. The old expression silently returns nothing.
$raw.toString() no longer produces JSON. Use $json.generate($raw) instead. It produces dotCMS's neutral response shape, not Elasticsearch's: took is tookInMillis, hits.total is hits.totalHits, and _index / _id / _score / _source are index / id / score / sourceAsMap. Anything downstream that parsed the old output will need remapping to the new keys. Elasticsearch's own wire format is not available under any method.
$r.took is now $r.tookInMillis, a plain number of milliseconds.
While testing a converted template, replace any quiet references ($!{...}) with ${...} so a failed expression is visible rather than rendering as a blank space.
Full detail: Elasticsearch Viewtool.
dotCMS is migrating its search layer from Elasticsearch to OpenSearch. The deprecated methods return Elasticsearch-specific types, which cannot be provided once Elasticsearch is no longer in use.
They also bypass dotCMS's search engine routing entirely and read Elasticsearch directly, whatever engine the rest of the installation is using. While an installation is dual-writing, a page can therefore serve results from one engine while everything around it serves another — with no error, and nothing in the logs to indicate it.
From 26.09.23-01 this stops being silent at the end: at the final migration phase these methods fail the page render instead of answering from an Elasticsearch index that is no longer being written to. Support can enable FEATURE_FLAG_OPEN_SEARCH_LEGACY_ES_SEARCH_RETURNS_NULL to have them return nothing and log a rate-limited warning instead of failing the render.
One further difference: esSearch() returns raw content objects rather than ContentMap, which is why $item.map.fieldName works there. That also exposes a field-shadowing problem — a custom field whose name matches a built-in getter, such as contentTypeId, resolves to the getter rather than your field's value. Moving to search() resolves it.
Scheduled for removal on March 31, 2027, by which time the migration to Opensearch will be complete.
Plugins using the index metadata API should move to the versioned replacement. Note the spelling correction — Indicies becomes Indices.
Stop using | Use instead |
|---|---|
IndiciesAPI | VersionedIndicesAPI |
APILocator.getIndiciesAPI() | APILocator.getVersionedIndicesAPI() |
IndiciesInfo | VersionedIndices |
IndiciesFactory | IndicesFactory |
ContentletIndexAPI.timestampFormatter | ContentletIndexAPI.threadSafeTimestampFormatter |
Three of these are not drop-in replacements.
loadIndicies() becomes loadIndices(String version) — it takes a version argument, returns an Optional, and ignores legacy rows whose version is null. A plugin that assumed a single global index set has to decide which version it wants.
loadIndicies(Connection) has been split into loadAllIndices(), loadNonVersionedIndices() and loadDefaultVersionedIndices(), by intent. There is no connection-scoped variant in the new API.
point(IndiciesInfo) becomes saveIndices(VersionedIndices), which throws DotDataException when the object carries no version. The old method accepted anything, so this is the most likely upgrade break in this group.
The timestampFormatter replacement is worth taking now regardless of the migration: the old constant is a SimpleDateFormat, which is not thread-safe.
Index metadata is being made version-aware and vendor-neutral ahead of the migration from Elasticsearch to OpenSearch. The deprecated types sit in the Elasticsearch package and assume a single, unversioned index set.
Use a content type to create a form; use the workflow viewtool or workflow API to ingest each submission as a new contentlet of that content type.
See How to Build A Schema Driven Form in dotCMS for a tutorial.
Original legacy form functionalities, such as the FormTool, depended on Struts components, removed years ago — version 5.2.0, back in 2019.
The successor, the Form Builder, has likewise aged out; it renders out-of-date (sometimes nonstandard) tags that frequently fall short of WCAG or other standards, and custom fields like a captcha are not possible. Given more coherent alternative methods outlined above, we deemed this feature no longer worth updating.
The Page Viewing Modes of yesterday have been superseded by the Universal Visual Editor, which unifies the traditional page-editing tools with the ability to perform in-context editing headlessly — likewise superseding Edit Mode Anywhere.
The UVE has been designed to be both simpler and more powerful than all previous page-editing tools, across both traditional and headless paradigms.
Edit Mode Anywhere has been superseded by the Universal Visual Editor, which is easier to configure, easier to use, and more versatile. The UVE even boasts a still-expanding JavaScript SDK for modern framework integrations.
The UVE has been designed to be both simpler and more powerful than all previous page-editing tools, across both traditional and headless paradigms.
WebDAV will be disabled as the default setting as of the end of 2026.
File system management can also be handled via the dotCMS Command-Line Interface, or dotCLI.
WebDAV is an outgoing technology that faces declining platform-level support — e.g., it has been deprecated on the Windows platform, where it is no longer enabled by default.
Please use the official dotCMS Command-Line Interface (dotCLI).
The legacy CLI was a series of Bash scripts, no longer maintained, with fewer options and less overall utility than the modern, comprehensive dotCLI.