WooCommerce 11.1 personalization callbacks can receive the destination content type. Optional defaults preserve HTML for compatibility, while auto escaping applies to newly registered text-typed tags. A callback that returns HTML, text, a URL fragment, or customer-controlled order data can be double-escaped, rendered as markup, or become unsafe when the destination changes.
Use this for WooCommerce extensions and custom email tags that insert customer names, addresses, order notes, product labels, URLs, coupon text, or formatted HTML into email templates.
Quick answer
Inventory every custom and third-party personalization tag with source field, trust level, declared content type, destination context, default, and callback version. Test ordinary text plus ampersands, quotes, angle brackets, Unicode, line breaks, URLs, missing values, and markup-like input in HTML and plain text. Escape at the final destination boundary. Keep legacy behavior explicit and migrate one tag at a time with snapshot tests of delivered MIME output.
What to check first
- List every registered tag, callback owner, input source, declared type, default, and template destination.
- Classify values as trusted formatting, plain text, URL, attribute value, or customer-controlled order content.
- Test HTML, plain text, subject, preview text, link, and missing-value contexts with hostile and international fixtures.
- Compare legacy default behavior with explicit text-typed and HTML-typed registrations before changing production.
- Review final MIME parts and inbox rendering for both unsafe output and visible double escaping.
Diagnostic table
Use this table to connect the observed behavior to evidence and a verification step.
| Action | Evidence to collect | How to verify |
| Inventory tags and classify source trust plus destination context. | List every registered tag, callback owner, input source, declared type, default, and template destination. | Customer-controlled text never becomes executable or unintended markup. |
| Declare content types explicitly for new and migrated tags. | Classify values as trusted formatting, plain text, URL, attribute value, or customer-controlled order content. | Approved HTML remains formatted without double escaping. |
| Escape once at the final rendering boundary with context-appropriate functions. | Test HTML, plain text, subject, preview text, link, and missing-value contexts with hostile and international fixtures. | URL and attribute values are encoded for their exact destination. |
| Add hostile, Unicode, empty, and legacy snapshot fixtures for HTML and text. | Compare legacy default behavior with explicit text-typed and HTML-typed registrations before changing production. | Legacy tags retain reviewed behavior until their explicit migration passes. |
Why this usually happens
- Escaping rules depend on whether a value lands in text, HTML, an attribute, or a URL.
- Legacy callbacks may assume the destination is always HTML.
- A new automatic escape can expose existing manual escaping as visible entities.
- Order and customer fields can contain punctuation, Unicode, and markup-like characters that happy-path fixtures miss.
Useful command or data shape
Adapt paths, IDs, and privacy handling to the site before running commands or storing data on production.
tag,source,declared_type,destination,input,expected
customer_name,order,text,html,<b>Ana & Co</b>,escaped
order_link,system,url,html_attr,quote+query,encoded
promo_html,approved,html,html,<strong>Save</strong>,allowed
missing_city,order,text,plain,null,default
Test scenarios to run
Run the same controlled fixture across these branches. Write down the expected result before testing so a surprising response is easy to identify.
| Scenario | Fixture | Expected result |
| Plain text tag | <b>Ana & Co</b> | Escaped in HTML, literal in text |
| HTML tag | Approved strong markup | Allowed markup only |
| Missing value | Null or empty | Safe documented default |
| URL destination | Quotes and query data | Encoded valid destination |
Safe fix order
Use a sequence that makes each result easy to prove. Stop when new evidence changes the scope or owner of the problem.
- Inventory tags and classify source trust plus destination context.
- Declare content types explicitly for new and migrated tags.
- Escape once at the final rendering boundary with context-appropriate functions.
- Add hostile, Unicode, empty, and legacy snapshot fixtures for HTML and text.
- Migrate one tag family at a time and compare delivered email output.
Decision rule
Ship a personalization tag only when its declared type, source trust, destination context, escaping, fallback, and delivered output agree for both normal and hostile fixtures.
Production verification checklist
- Customer-controlled text never becomes executable or unintended markup.
- Approved HTML remains formatted without double escaping.
- URL and attribute values are encoded for their exact destination.
- Legacy tags retain reviewed behavior until their explicit migration passes.
Field notes
- Use synthetic IDs and examples that can be traced from the first request to the final record.
- Keep a before and after result for every changed setting or deployed version.
- Review the evidence again after caches, queues, and scheduled work have had time to settle.
Questions teams ask during testing
Can this be tested on production?
Use production for read-only confirmation and one narrow synthetic fixture that cannot charge a card, email a real customer, expose personal data, or alter inventory. Run upgrades, schema changes, cache changes, and destructive repairs on staging first.
What evidence should the report keep?
Keep exact versions, UTC timestamps, stable synthetic IDs, expected and actual results, the decision owner, rollback point, and final verification. Redact credentials, tokens, customer data, addresses, and private infrastructure details.
When is the task complete?
Complete it when the primary user path passes, downstream records reconcile, failure branches are understood, monitoring is active, and an established owner page links to the new guide in context.
Mistakes to avoid
- Changing production before recording exact versions, UTC timestamps, stable fixture IDs, settings, and a reproducible baseline.
- Treating one successful screen as proof that APIs, caches, jobs, roles, reports, and downstream records agree.
- Testing only an administrator session instead of the devices, roles, networks, data states, and failure branches customers use.
- Closing the task without a named owner, rollback point, observation window, and contextual incoming link from an established guide.
What to tell the client or owner
Give the site owner the affected versions, exact synthetic fixture, UTC timeline, before and after evidence, cause class, decision, rollback point, unresolved risks, and next review date. State which measurements prove success and which observation window remains open.
When HandL WP should help
Bring in help when this affects leads, checkout, search visibility, security, paid media reporting, or a client production site. HandL WP can trace the issue through WordPress, hosting, cache, tracking, and Search Console, then verify the workflow after the technical fix.
If this is active on a production site, audit WooCommerce email personalization.
Related HandL WP guides
Use these related guides when the same issue touches tracking, security, checkout, or crawler visibility.
Helpful references