Describe the bug
When a WordPress taxonomy term (e.g. a category) has an emoji in its name, the
Popup Maker AJAX object-search dropdown (used by conditions such as
"Categories: Name" / "Taxonomies: Name") breaks. The dropdown shows duplicate
categories (repeats) and misses some categories completely.
Video recording of the issue:
https://jam.dev/c/81bcc328-e5c0-4b6e-8ba1-a6da73a58e35
Site information
Popup Maker version: 1.22.0
WordPress version: 6.9.4
PHP version: 8.1.33
Expected behavior
The dropdown renders and searches category names that contain emoji characters
(e.g. 🎉 Sale, 📦 Products) exactly as WordPress stores them, allowing
the user to select those terms normally.
Current behavior
WordPress registers wp_staticize_emoji as an output-buffer filter for admin
AJAX responses. When the pum_object_search AJAX handler outputs its JSON
payload, WordPress intercepts the output and converts emoji Unicode characters
inside the JSON string values into <img> HTML tags, e.g.:
becomes something like:
"text":"<img src=\"...emoji/72x72/1f389.png\" ...> Sale (ID: 42)"
This corrupts the JSON structure, causing the Select2 dropdown to receive an
unparseable response or to display raw HTML markup instead of the category name.
Root cause
File: classes/Admin/Ajax.php, line 279
// Handler exits via echo + die(), not wp_send_json()
echo PUM_Utils_Array::safe_json_encode( $results );
die();
The handler builds an items array where each entry's text field contains the
raw term name:
// classes/Admin/Ajax.php:204-208 (taxonomy branch)
foreach ( $query['items'] as $id => $name ) {
$results['items'][] = [
'id' => $id,
'text' => "$name (ID: $id)", // $name may contain emoji
];
}
PUM_Utils_Array::safe_json_encode() (classes/Utils/Array.php:544-546) calls
wp_json_encode() which itself is fine — but before the output reaches the
browser, WordPress's wp_staticize_emoji filter (hooked to the output buffer
for admin AJAX) rewrites emoji codepoints inside the raw JSON bytes to <img>
tags, invalidating the JSON.
The same pattern exists in the REST API fallback:
classes/RestAPI/ObjectSearch.php:264-269.
Steps to reproduce
- Create a WordPress category whose name includes an emoji character
(e.g. 🎉 Promotions).
- Open a popup in the Popup Maker editor and navigate to the Conditions tab.
- Add a condition of type "Categories: Name" (or any taxonomy-name
condition).
- Open the dropdown and search for the emoji category name.
- Observe that the dropdown either fails to load, shows blank results, or
displays raw HTML <img> markup.
Workaround
Use the "Categories: IDs" condition variant instead of "Categories: Name".
Because IDs are integers, no emoji characters appear in the JSON response and
the issue does not occur. (This is the same pattern used to work around the
prior "Pages: Selected" encoding bug.)
Potential fix
Remove (or temporarily unhook) WordPress's emoji-staticizing filter before
outputting the JSON response, so that valid UTF-8 emoji characters are preserved
in the JSON payload:
// classes/Admin/Ajax.php — before echo on line 279
remove_filter( 'admin_footer', 'wp_print_emoji_detection_script' );
// Disable emoji conversion on the output buffer for this response.
// wp_staticize_emoji is hooked at priority 10 on output filters.
if ( function_exists( 'wp_staticize_emoji' ) ) {
// The filter may be applied at ob level; safest is to encode
// emoji codepoints ourselves so they survive as JSON unicode escapes.
add_filter( 'wp_json_encode_options', function( $options ) {
return $options | JSON_UNESCAPED_UNICODE;
} );
}
echo PUM_Utils_Array::safe_json_encode( $results );
die();
A cleaner long-term fix is to switch from echo … die() to wp_send_json()
(which sets the correct Content-Type: application/json header) and to ensure
the emoji output-buffer filter is not running at that point, or to encode emoji
as \uXXXX sequences which survive the staticize pass intact.
The same fix should be applied to classes/RestAPI/ObjectSearch.php.
Errors
See screencast above.
Example AJAX response:
https://pumprodemo.instawp.xyz/wp-admin/admin-ajax.php?action=pum_object_search&nonce=a6f8039064&s=&paged=2&object_type=taxonomy&object_key=category&exclude=
{"items":[{"id":"81","text":"\u2665\ufe0f Social Responsibility (ID: 81)"},{"id":"82","text":"\u2696\ufe0f Economy (ID: 82)"},{"id":"80","text":"\u2699\ufe0f Development & Sustainability etc. etc.@!.etc (ID: 80)"},{"id":"74","text":"\u2708\ufe0f Travel (ID: 74)"},{"id":"75","text":"Japan (ID: 75)"},{"id":"77","text":"Tech (ID: 77)"},{"id":"69","text":"Test (ID: 69)"},{"id":"1","text":"Uncategorized (ID: 1)"},{"id":"79","text":"\ud83c\udf0f World News (ID: 79)"},{"id":"83","text":"\ud83c\udf31 Health & Wellness (ID: 83)"}],"total_count":"14"}
Total count is 14, but only 10 are returned. The list is missing the AI, Gaming, Photography, and Emoji categories.
Additional context
- Affects all taxonomy/category name-based conditions that use the
pum_object_search AJAX action.
- Does not affect ID-based conditions (numeric-only values, no emoji).
- WordPress enables emoji handling by default; disabling it site-wide via
remove_action( 'wp_head', 'print_emoji_detection_script', 7 ) is a
valid (but heavy-handed) site-level workaround.
- This issue was co-written by Claude Code, so there could be errors 😬
Describe the bug
When a WordPress taxonomy term (e.g. a category) has an emoji in its name, the
Popup Maker AJAX object-search dropdown (used by conditions such as
"Categories: Name" / "Taxonomies: Name") breaks. The dropdown shows duplicate
categories (repeats) and misses some categories completely.
Video recording of the issue:
https://jam.dev/c/81bcc328-e5c0-4b6e-8ba1-a6da73a58e35
Site information
Popup Maker version: 1.22.0
WordPress version: 6.9.4
PHP version: 8.1.33
Expected behavior
The dropdown renders and searches category names that contain emoji characters
(e.g.
🎉 Sale,📦 Products) exactly as WordPress stores them, allowingthe user to select those terms normally.
Current behavior
WordPress registers
wp_staticize_emojias an output-buffer filter for adminAJAX responses. When the
pum_object_searchAJAX handler outputs its JSONpayload, WordPress intercepts the output and converts emoji Unicode characters
inside the JSON string values into
<img>HTML tags, e.g.:becomes something like:
This corrupts the JSON structure, causing the Select2 dropdown to receive an
unparseable response or to display raw HTML markup instead of the category name.
Root cause
File:
classes/Admin/Ajax.php, line 279The handler builds an
itemsarray where each entry'stextfield contains theraw term name:
PUM_Utils_Array::safe_json_encode()(classes/Utils/Array.php:544-546) callswp_json_encode()which itself is fine — but before the output reaches thebrowser, WordPress's
wp_staticize_emojifilter (hooked to the output bufferfor admin AJAX) rewrites emoji codepoints inside the raw JSON bytes to
<img>tags, invalidating the JSON.
The same pattern exists in the REST API fallback:
classes/RestAPI/ObjectSearch.php:264-269.Steps to reproduce
(e.g.
🎉 Promotions).condition).
displays raw HTML
<img>markup.Workaround
Use the "Categories: IDs" condition variant instead of "Categories: Name".
Because IDs are integers, no emoji characters appear in the JSON response and
the issue does not occur. (This is the same pattern used to work around the
prior "Pages: Selected" encoding bug.)
Potential fix
Remove (or temporarily unhook) WordPress's emoji-staticizing filter before
outputting the JSON response, so that valid UTF-8 emoji characters are preserved
in the JSON payload:
A cleaner long-term fix is to switch from
echo … die()towp_send_json()(which sets the correct
Content-Type: application/jsonheader) and to ensurethe emoji output-buffer filter is not running at that point, or to encode emoji
as
\uXXXXsequences which survive the staticize pass intact.The same fix should be applied to
classes/RestAPI/ObjectSearch.php.Errors
See screencast above.
Example AJAX response:
https://pumprodemo.instawp.xyz/wp-admin/admin-ajax.php?action=pum_object_search&nonce=a6f8039064&s=&paged=2&object_type=taxonomy&object_key=category&exclude=
{"items":[{"id":"81","text":"\u2665\ufe0f Social Responsibility (ID: 81)"},{"id":"82","text":"\u2696\ufe0f Economy (ID: 82)"},{"id":"80","text":"\u2699\ufe0f Development & Sustainability etc. etc.@!.etc (ID: 80)"},{"id":"74","text":"\u2708\ufe0f Travel (ID: 74)"},{"id":"75","text":"Japan (ID: 75)"},{"id":"77","text":"Tech (ID: 77)"},{"id":"69","text":"Test (ID: 69)"},{"id":"1","text":"Uncategorized (ID: 1)"},{"id":"79","text":"\ud83c\udf0f World News (ID: 79)"},{"id":"83","text":"\ud83c\udf31 Health & Wellness (ID: 83)"}],"total_count":"14"}Total count is 14, but only 10 are returned. The list is missing the AI, Gaming, Photography, and Emoji categories.
Additional context
pum_object_searchAJAX action.remove_action( 'wp_head', 'print_emoji_detection_script', 7 )is avalid (but heavy-handed) site-level workaround.