Skip to main content

Why the testimonial quote allows safe inline HTML, not a rich editor

· 2 min read
Jon-Michael Lastimosa
Senior Web Developer

The question: Would it be better to make the testimonial Quote field a wp_editor (a full visual editor) so authors can format their quotes?

Context

The Quote is currently a plain textarea, and every testimonial design renders it with esc_html(). The prompt was reasonable: give authors formatting. But a testimonial is a short quote, and the whole design system leans on controlled typography — each design sets its own quote size and line-height.

There's also a rendering trap. Switching the field to wp_editor makes the saved value HTML (<p>…</p>, <strong>, etc.). The moment that happens, esc_html() prints the tags as literal text — so a "just change the field type" edit silently forces a change to the escaping in every design template plus the shared card renderer.

Options considered

  • Full wp_editor. Most formatting freedom. But it's a TinyMCE instance per repeatable row, and it invites headings, lists, font sizes and colours pasted from Word — which blow out the marquee card, the split slide, the coverflow tile. And it forces the escaping change above across all templates.
  • Keep the textarea, leave it plain. Zero risk, but no emphasis, links, or line breaks at all.
  • Keep the textarea, render a safe inline subset. Run the value through wp_kses allowing only <strong>, <em>, <a>, <br> (newlines → <br>), stripping everything block-level. Authors get the only formatting a quote realistically needs; typography stays protected; no editor weight.

Decision

Textarea + a wp_kses inline subset. A shared sc_testimonial_quote_html() helper renders the quote with a tight allowlist (bold / italic / link / line-break) and is used in place of esc_html() across all designs. No wp_editor.

Why

Rich text is the wrong fit for a short endorsement: block-level content is almost never wanted, and when it is pasted it fights the design's controlled type — which is a feature, not a limitation. The safe-subset route gives the realistic 90% (emphasise a phrase, add a link) without a TinyMCE per row and without the tag-leakage that a naïve field swap would cause. The one honest cost, noted in the changelog: a pre-existing quote that contained a literal < now gets that fragment sanitised rather than shown verbatim — rare for testimonials, and worth it for XSS-safe, typography-safe output everywhere.