Skip to content

Keep submitted shortcodes and merge tags encoded on WordPress 7.2 (6.18.0) - #1974

Merged
jakejackson1 merged 5 commits into
hot-patch-6.18.0from
fix/kses-keep-encoded-tags-wp72-6.18.0
Oct 27, 2026
Merged

jakejackson1 merged 5 commits into
hot-patch-6.18.0from
fix/kses-keep-encoded-tags-wp72-6.18.0

Conversation

@zamoragregory

@zamoragregory zamoragregory commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Gravity PDF encodes [ ] { } in submitted values as [ ] { }, so shortcodes and merge tags in them aren't processed in a PDF. The HTML then goes through Kses::parse(). WordPress 7.2 rebuilds wp_kses() on the HTML API, which decodes those character references, so Kses::parse() turned them back into real tags. On WordPress 7.2-beta1, a submitted {admin_email} printed the site admin's email address in the PDF, and a submitted [gravitypdf] shortcode printed a link. The 6.18 signing rules still kept those links unsigned.

encode_tags() now puts a zero-width no-break space (U+FEFF) after each [, { and : instead. Kses keeps it on both parsers, it stops shortcodes and merge tags matching, and mPDF strips it before drawing, so the PDF shows the text as typed. HTML attributes keep their URL-encoding, and their colons are neutralised too, so a merge tag opened in the text can't end inside one. $form_data values get the same.

Try it

  1. On WordPress 7.2-beta1, submit a form with a Paragraph field containing {admin_email} [gravitypdf id="<PDF ID>"].
  2. View the entry's PDF. The field shows the text as it was typed. Before this change it showed the admin's email address and a PDF link.

Test plan

  • yarn test:php -- --filter 'test_encode_tags|test_html_structure_keeps_user_tags_encoded'
  • On WordPress 7.2-beta1, the Try it steps above
More info
  • Found in the 6.18.0-RC3 review (C1). It affects every field. Field values have been encoded this way since 4.0, so released versions are affected too once WordPress 7.2 ships.
  • The third commit brings this in line with Keep submitted shortcodes and merge tags encoded on WordPress 7.2 #1972 on development. It replaces the second commit's word joiner (U+2060), which replaced the first commit's wp_kses_force_legacy_parser switch.
  • Why after : too: Gravity Forms' field merge tags ({Label:1}, {Label:1:value}, {:1}) and Gravity PDF's {Label:pdf:ID} allow any text after {, so a joiner there alone doesn't stop them.
  • Why U+FEFF: mPDF removes it before drawing, whatever the font, so it can't show as a box or a gap, and text copied out of the PDF doesn't include it. A zero-width space (U+200B) showed as a space in some fonts.
  • How it's applied:
    • Joiners go on the whole value, then the HTML tag processor takes them back out of attribute values. Text that only looks like a tag, such as I <3 {admin_email} >_<, is covered too.
    • In attributes, [ ] { } are URL-encoded as before. A colon gets %3A in a URL after the scheme, stays as a style declaration's property colon, and gets the joiner anywhere else. Without this, a rich-text value like {x <b title=":3:">} printed field 3's value. The second commit did that on current WordPress too, which RC3 didn't.
    • It's added once only, so a value encoded twice still matches the trusted administrative defaults, which are mapped back from both attribute forms.
    • Values without [ ] { } don't change.
  • Trade-offs:
    • $form_data values are plain text, so a URL there that contains brackets also gets a joiner after https:. It prints the same, but a custom template that uses it as a link would need to strip U+FEFF.
    • In a value that also contains [ ] { }, a link with a port, like https://example.org:8080/, gets %3A for the port's colon, which breaks the link.
  • Tests:
    • test_encode_tags covers 11 cases. Each is checked encoded twice, and against Gravity PDF's and Gravity Forms' merge tag patterns after kses.
    • test_default_tags_are_restored_in_attributes is new.
    • test_html_structure_keeps_user_tags_encoded runs on both kses parsers, and now covers I <3 {admin_email} >_<.
    • Four other tests' expected values change to U+FEFF.
  • Tested natively on WordPress 7.2-beta1 (Laragon, PHP 8.3). Full suite from a clean start, against RC3 on the same setup:
    • No new failures.
    • 2 tests that failed on RC3 under 7.2 now pass.
    • The 14 new tests pass.
    • The other failures come from WordPress 7.2's other kses output changes (attribute order, the / on mPDF's self-closing tags, &quot; in text), and fail on RC3 too.
  • End to end on a WordPress 7.2-beta1 site, on both parsers:
    • A forged Text entry ({admin_email}, field tags, {Doc:pdf:ID}, [gravitypdf]) and a forged rich-text entry with the attribute cases print as typed. No admin email, PDF link or other field's value appears.
    • RC3 on the same site printed the admin's email address and a PDF link on the HTML API parser.
    • U+FEFF is invisible in DejaVu Sans, FreeSerif, Times New Roman, Helvetica, Roboto, Calibri and Montserrat, with the same line breaks, and copied text has no joiners.
  • PHPCS and the PHP compatibility check are clean on the changed file.
  • CHANGELOG: the $form_data Developer line now names U+FEFF.

🤖 Generated with AI

Gravity PDF stops shortcodes and merge tags in submitted values being processed in a PDF by encoding [ ] { } as
&#91; &#93; &#123; &#125;. WordPress 7.2 rewrites wp_kses() on the HTML API, which decodes those character references,
so Kses::parse() turned them back into tags: a submitted {admin_email} printed the admin's address in the PDF. It
now forces kses' legacy parser while it runs, through the wp_kses_force_legacy_parser filter WordPress 7.2 adds.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
GreggyZamora and others added 4 commits October 27, 2026 11:22
…kses parser

Forcing kses' legacy parser only lasts as long as WordPress keeps the wp_kses_force_legacy_parser filter. encode_tags()
now puts an invisible word joiner (U+2060) after each [ { and : in the text instead of encoding [ ] { } as &#91; &#93;
&#123; &#125;, which WordPress 7.2's HTML API kses decodes. Kses keeps the joiner on either parser, and it stops
shortcodes and merge tags matching. $form_data values get the same, and HTML attributes keep their URL-encoding.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…olon handling

Same encode_tags() change as #1972. A zero-width no-break space (U+FEFF) replaces the word joiner, as mPDF strips it
before drawing. Joiners now go on the whole value and come back out of attribute values, so text that only looks like
a tag is covered, and an attribute's colons are neutralised so a merge tag opened in the text can't end inside one.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… line

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…form_data changelog line

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@jakejackson1
jakejackson1 merged commit ad9079c into hot-patch-6.18.0 Oct 27, 2026
13 checks passed
@jakejackson1
jakejackson1 deleted the fix/kses-keep-encoded-tags-wp72-6.18.0 branch October 27, 2026 22:06
@gravitypdf-bot gravitypdf-bot mentioned this pull request Oct 27, 2026
2 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants