<p>Hi Frank, forum rich text editor: formatted posts show their HTML tags as plain text.</p>
<p><strong>Observations</strong></p>
<ol>
<li>Matteo uses only the toolbar buttons (bold, italic, underline, colour, lists, blockquote). The editor produces correct HTML, but the post shows the tags as text.</li>
<li>Editing an existing post without changing anything and saving: all tags become visible text. Some of his posts are escaped several times over (&amp;lt;p&amp;gt

, so every edit seems to escape again.</li>
<li>My test on beta works: I opened a rendered HTML page, copied the visible text and pasted it into a new post. Headings, bold and umlauts render correctly. Pasting HTML source shows tags as text, which is correct.</li>
</ol>
<p><strong>Repro (edit bug)</strong></p>
<ol>
<li>Create a new post with bold text and a list. It renders fine.</li>
<li>Open Edit, change nothing, save.</li>
<li>Expected: unchanged. Actual: tags shown as text. Every further edit adds another layer of escaping (to be confirmed).</li>
</ol>
<p><strong>Open question</strong></p>
<p>Why does it work for me and not for Matteo? Either beta vs live, or role-based (admin posts render, normal users get escaped), or old posts are handled differently. I'll post the same toolbar test on live to narrow it down.</p>
<p><strong>How it should work</strong></p>
<ul>
<li><strong>Save:</strong> store the editor's HTML as is, no escaping on save.</li>
<li><strong>Display:</strong> output the HTML through an allowlist sanitizer (HTMLPurifier / DOMPurify), allowing only what the toolbar produces: p, br, strong, em, u, s, span[style=color], ul, ol, li, blockquote (plus h2-h4 / table if wanted). Strip script, on* attributes, javascript: links. That covers XSS without breaking the formatting.</li>
<li><strong>Edit:</strong> load the stored HTML through the editor API (setContent/setHTML), not as text in a textarea. Saving without changes must give byte-identical content. Good regression test.</li>
<li><strong>Paste:</strong> rendered content becomes sanitized formatting; plain text stays plain text.</li>
<li><strong>Old posts:</strong> the ones that are already escaped need a one-off migration (unescape as many times as they were escaped), or the authors repost.</li>
</ul>
<p>Thanks!</p>
<p><em><u>your friendly neighbour admin</u></em></p>