DataLiberation: add a streaming ShortcodeProcessor tokenizer - #300
Open
adamziel wants to merge 6 commits into
Open
DataLiberation: add a streaming ShortcodeProcessor tokenizer#300adamziel wants to merge 6 commits into
adamziel wants to merge 6 commits into
Conversation
Builder content can interleave native WordPress shortcodes with HTML, CSS, JSON attributes, block markup, and third-party shortcodes. Passing the entire value through an HTML serializer can escape bytes belonging to those other grammars. Add a pull-based tokenizer that reports shortcode and text tokens, records source byte spans, and applies queued attribute or text updates without reserializing unrelated input. Opening and closing tokens remain independent, so same-name nesting does not depend on Core's enclosing shortcode regular expression. Cover Divi, WPBakery, Avada, Themify, Oxygen, Gutenberg, Elementor, Beaver Builder, and SiteOrigin shapes. Include mixed-region, malformed, ambiguous bracket syntax, nested shortcode, CSS URL, and encoded UTF-8 cases.
adamziel
force-pushed
the
adamziel/trace-css-corruption
branch
from
July 30, 2026 20:34
0d31a0d to
e12ef85
Compare
Route shortcode-bearing HTML text nodes through ShortcodeProcessor before inspecting direct URL and CSS attribute values. Preserve exact source bytes when applying nested updates so ampersands and builder CSS are not HTML-encoded.\n\nMove the mixed markup coverage out of the tokenizer unit suite and into a focused BlockMarkupUrlProcessor integration suite.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Introduces
ShortcodeProcessor, a pull-based tokenizer and minimal editor for native WordPress shortcode markup.Data Liberation needs to rewrite URLs without rendering content or changing unrelated bytes. Builder content can contain several nested languages:
Treating the complete value as HTML can turn the CSS into
content: "<";. Treating it as undifferentiated text cannot reliably separate a URL from adjacent CSS syntax. Runningdo_shortcode()is also unsuitable during an import: the original callbacks may be unavailable, and rendering discards the stored representation being migrated.ShortcodeProcessorsupplies the outer shortcode layer. It identifies shortcode and text regions, exposes shortcode attributes without normalizing them, and applies replacements to their original byte spans.Architecture
The processor follows the restricted, forward-only model of
WP_HTML_Tag_Processor:next_token()advances through#shortcodeand#texttokens.next_shortcode()skips text and optionally filters by exact tag, tag prefix, closer policy, match offset, or escaped status.get_updated_text()applies those replacements while copying every unrelated byte unchanged.It does not build a tree, invoke callbacks, or normalize the document. Opening and closing shortcodes are independent tokens, so same-name nesting remains visible:
The public API provides token location and text accessors; shortcode tag, closer, self-closing, and escaped state; attribute iteration, lookup, and replacement; and raw text-token replacement. It can update an existing attribute value or a complete text token, but does not add or remove attributes.
Where it applies
The class tokenizes a shortcode-bearing region. It does not guess whether an entire database field is HTML, CSS, JSON, serialized PHP, blocks, or shortcodes.
Divi's
custom_css_*attributes illustrate the composition model:This preserves
content: "<", the closing)inurl(...), and declarations following the URL. Standalone Customizer or theme-option CSS should go directly toCSSURLProcessor; no shortcode pass is needed.Parsing boundary
The processor finds shortcode candidates without WordPress or a registered shortcode table. Unlike Core's
get_shortcode_regex(), it reports individual opener, closer, self-closing, and[[escaped]]tokens rather than matching a registered enclosing shortcode.Quoted values may contain CSS, HTML, JSON, URLs, square brackets, and shortcode-like text. Named lookup is ASCII case-insensitive, positional attributes remain iterable, and the last duplicate named attribute wins. U+00A0 NO-BREAK SPACE and U+200B ZERO WIDTH SPACE are recognized as separators without changing the source.
[hidden]remains inherently ambiguous: it may be a shortcode, CSS selector, BBCode, or prose. Callers must isolate a shortcode-bearing region and should filter by registered names or known prefixes such aset_pb_,vc_,fusion_, orct_.Attribute updates preserve the existing delimiter when safe and switch delimiters when possible. If a new value requires quoting but contains both quote characters, the update returns
falserather than emitting malformed markup.Alternatives
do_shortcode()renders the content, runs plugin code, and destroys the builder representation.This class is not a sanitizer. Candidate matching does not prove that a tag is registered, and URL validation remains the URL-rewrite layer's responsibility.
Testing
The 35 focused tests and 94 assertions cover:
content: "<",url(...) no-repeat, and percent-encoded UTF-8 paths.The complete Data Liberation suite passes with 2,400 tests and 12,026 assertions. CI passes on PHP 7.2 through 8.5 across Linux, macOS, and Windows.
Follow-up
This PR supplies the tokenizer only. After it is merged and released, Reprint can classify fields from storage identity, plugin/post-meta signals, block markup, and known shortcode prefixes; decode structured containers; and dispatch each selected region to its owning processor.
Related: original
WP_HTML_Tag_Processorproposal,CSSURLProcessor, and URLInTextProcessor punctuation handling.