“Hello, I need to generate PDF files using content from a rich text editor. However, the template currently outputs plain text and includes the raw HTML tags (e.g., <p>
, <strong>
, etc.) in the content. What would be the recommended approach to correctly render this rich text in the generated PDF documents?”
We use Gotenberg for generating PDF documents from HTML templates.
Generally, you’d define a template in your Admin webapp, and then use a workflow to render it as a PDF (You will need to run a new service though).
I suppose what could work is creating a new, empty template with a placeholder for your rich-text content.
Hi @tjerman
I found a solution that might interest other users. For a field called “content” that you want to edit with the rich text editor, create a second field called “raw_content” that will contain the plain text stripped of HTML tags. Before updating the record, replace the HTML tags with their text equivalents (you can find the list with ChatGPT, for example) and save the result in raw_content. Use raw_content for templates and content for views.
In the template, apply a CSS style such as:
.styled {
white-space: pre-line;
line-height: 1.6;
}
to the container (<p>
or <div>
) where the raw_content field will be displayed, in order to avoid line concatenation.
Certainly, but that might result in a long list of nested functions.
Fair enough a workflow/script would be a better fit to automize this
Oops! I had forgotten — here is the workflow
{
"workflows": [
{
"handle": "htmlToText",
"enabled": true,
"meta": {
"name": "htmlToText",
"description": "convert html content to text\nIN: html, OUT: text",
"visual": null,
"subWorkflow": true
},
"keepSessions": 0,
"steps": [
{
"stepID": "6",
"kind": "expressions",
"ref": "",
"arguments": [
{
"target": "replacements",
"expr": "[\n [\"</p>\",\"\\n\"],\n [\"<br/>\", \"\"],\n [\"<br />\",\"\"],\n [\"<br>\",\"\"],\n [\"</div>\",\"\\n\\n\"],\n [\"</li>\",\"\"],\n [\"</tr>\",\"\\n\"],\n [\"</td>\",\"\\t\"],\n [\"<th>\",\"\\t\"],\n [\"</ul>\",\"\"],\n [\"</ol>\",\"\"],\n [\"</u>\",\"\"],\n [\"</s>\",\"\"],\n [\"</strong>\",\"\"],\n [\"</pre>\",\"\"],\n [\"</code>\",\"\"],\n [\"</h1>\",\"\\n\\n# \"],\n [\"</h2>\",\"\\n\\n## \"],\n [\"</h3>\",\"\\n\\n### \"],\n [\"</h4>\",\"\\n\\n#### \"],\n [\"</h5>\", \"\\n\\n##### \"],\n [\"</h6>\",\"\\n\\n###### \"],\n [\"</blockquote>\", \"\\n> \"],\n [\"</hr>\",\"\\n---\\n\"],\n [\"<p>\",\"\"],\n [\"<div>\",\"\"]\n [\"<li>\",\"\"],\n [\"<tr>\",\"\"],\n [\"<td>\",\"\"],\n [\"<th>\",\"\"],\n [\"<ul>\",\"\"],\n [\"<ol>\",\"\"],\n [\"<u>\",\"\"],\n [\"<s>\",\"\"],\n [\"<strong>\",\"\"],\n [\"<pre>\",\"\"],\n [\"<code>\",\"\"],\n [\"<h1>\",\"\"],\n [\"<h2>\", \"\"],\n [\"<h3>\",\"\"],\n [\"<h4>\",\"\"],\n [\"<h5>\",\"\"],\n [\"<h6>\",\"\"],\n [\"<blockquote>\",\"\"],\n [\"<hr>\",\"\"]\n \n]\n",
"type": "Array"
},
{
"target": "text",
"expr": "html",
"type": "String"
}
],
"results": [],
"meta": {
"name": "",
"description": "",
"visual": {
"defaultName": true,
"id": "6",
"parent": "1",
"value": "Define and mutate scope variables",
"xywh": [
1920,
1760,
200,
80
]
}
}
},
{
"stepID": "7",
"kind": "iterator",
"ref": "loopEach",
"arguments": [
{
"target": "items",
"expr": "replacements",
"type": "Array"
}
],
"results": [
{
"target": "rep",
"expr": "item",
"type": "Any"
}
],
"meta": {
"name": "",
"description": "",
"visual": {
"defaultName": true,
"id": "7",
"parent": "1",
"value": "Items",
"xywh": [
2168,
1760,
200,
80
]
}
}
},
{
"stepID": "9",
"kind": "expressions",
"ref": "",
"arguments": [
{
"target": "text",
"expr": "replace(text,rep[0],rep[1],-1)",
"type": "String"
}
],
"results": [],
"meta": {
"name": "",
"description": "",
"visual": {
"defaultName": true,
"id": "9",
"parent": "1",
"value": "Define and mutate scope variables",
"xywh": [
2168,
1904,
200,
80
]
}
}
},
{
"stepID": "13",
"kind": "termination",
"ref": "",
"arguments": null,
"results": [],
"meta": {
"name": "",
"description": "",
"visual": {
"defaultName": true,
"id": "13",
"parent": "1",
"value": "Terminate workflow execution",
"xywh": [
2456,
1760,
200,
80
]
}
}
}
],
"paths": [
{
"parentID": "6",
"childID": "7",
"meta": {
"name": "",
"description": "",
"visual": {
"id": "8",
"parent": "1",
"points": [],
"style": "exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;",
"value": null
}
}
},
{
"parentID": "7",
"childID": "9",
"meta": {
"name": "",
"description": "",
"visual": {
"id": "10",
"parent": "1",
"points": [],
"style": "exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;",
"value": "Body"
}
}
},
{
"parentID": "7",
"childID": "13",
"meta": {
"name": "",
"description": "",
"visual": {
"id": "14",
"parent": "1",
"points": [],
"style": "exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;",
"value": "End"
}
}
}
]
}
]
}
Would you mind if we put this in the documentation?
Sure, please go ahead — I’d be happy to see it included in the documentation.