Skip to content

Fix: HTML leaking into meta description tags - #3727

Merged
daniellefrappier18 merged 4 commits into
mainfrom
daniellef/12700-fix-html-in-meta
Aug 6, 2026
Merged

Fix: HTML leaking into meta description tags#3727
daniellefrappier18 merged 4 commits into
mainfrom
daniellef/12700-fix-html-in-meta

Conversation

@daniellefrappier18

@daniellefrappier18 daniellefrappier18 commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

What are the relevant tickets?

Fixes https://github.com/mitodl/hq/issues/12700

Description (What does it do?)

Resource descriptions can contain HTML (e.g. <p>, <a>, &amp;), which was leaking directly into <meta name="description">, og:description, and twitter:description. The previous approach only stripped closing tags via regex, leaving opening tags and HTML entities intact.

  • Adds htmlToPlainText (frontends/main/src/common/utils.ts), which inserts a space at block-level boundaries (<p>, <div>, <li>,<h1>-<h6>, <br>) before stripping all tags via DOMPurify, so adjacent paragraphs/list items aren't mashed together, and decodes entities via .textContent.
  • Wires it into standardizeMetadata so all description-based meta tags get plain text.
  • Removes the old regex-only stripping in getMetadataAsync, now handled centrally by standardizeMetadata.

Screenshots (if appropriate):

  • Desktop screenshots
    BEFORE
Screenshot 2026-08-05 at 9 48 02 AM Screenshot 2026-08-05 at 9 47 37 AM

AFTER

Screenshot 2026-08-05 at 9 49 43 AM Screenshot 2026-08-05 at 9 49 01 AM
  • Mobile width screenshots

How can this be tested?

Using the same two examples from #3721

  • For example: /podcast/15925/trash-talking — "&" should render properly instead of &
  • For example: /podcast/17779/lock-the-quill — paragraphs should render as formatted text instead of showing literal

    tags

  • Manually verify a resource with an HTML description renders clean text in page source <meta name="description">, og:description, and twitter:description

Additional Context

@github-actions

github-actions Bot commented Aug 5, 2026

Copy link
Copy Markdown

OpenAPI Changes

No changes detected

View full changelog

Unexpected changes? Ensure your branch is up-to-date with main (consider rebasing).

@daniellefrappier18
daniellefrappier18 marked this pull request as ready for review August 5, 2026 14:33
Copilot AI lite review requested due to automatic review settings August 5, 2026 14:33

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR prevents HTML markup and entities from leaking into SEO/social meta description fields by converting description content to plain text during metadata standardization.

Changes:

  • Added htmlToPlainText helper to strip tags, preserve block boundaries with spacing, and decode HTML entities.
  • Updated standardizeMetadata to apply htmlToPlainText so description, og:description, and twitter:description are consistently plain text.
  • Removed the previous regex-only stripping from getMetadataAsync and added/expanded unit tests for the new behavior.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.

File Description
frontends/main/src/common/utils.ts Adds htmlToPlainText (uses DOMPurify + block-boundary spacing) and exports it.
frontends/main/src/common/utils.test.ts Adds unit tests covering tag stripping, entity decoding, and spacing behavior.
frontends/main/src/common/metadata.ts Routes all metadata descriptions through htmlToPlainText via standardizeMetadata; removes old regex stripping.
frontends/main/src/common/metadata.test.ts Adds a test ensuring all description fields are converted to plain text.

Comment thread frontends/main/src/common/utils.ts Outdated
Comment thread frontends/main/src/common/utils.test.ts Outdated
daniellefrappier18 and others added 2 commits August 5, 2026 10:39
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
@zamanafzal zamanafzal self-assigned this Aug 6, 2026
import DOMPurify from "isomorphic-dompurify"
import { collapseWhitespace } from "@/common/utils"

const BLOCK_BOUNDARY_TAGS = /<\/(?:p|div|li|h[1-6])>|<br\s*\/?>/gi

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BLOCK_BOUNDARY_TAGS covers p / div / li / h1-6 / br but not table cells (</td>, </th>), </blockquote>, or </pre>
How about adding them to the regex?

const BLOCK_BOUNDARY_TAGS =
  /<\/(?:p|div|li|h[1-6]|td|th|tr|blockquote|pre)>|<br\s*\/?>/gi

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, added those. Also threw tr in there too just in case, and added a couple tests to cover table cells and blockquote/pre.

@zamanafzal zamanafzal left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Image

@daniellefrappier18
daniellefrappier18 merged commit 8d0e5fe into main Aug 6, 2026
13 checks passed
@daniellefrappier18
daniellefrappier18 deleted the daniellef/12700-fix-html-in-meta branch August 6, 2026 14:21
@odlbot odlbot mentioned this pull request Aug 10, 2026
11 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants