-
Notifications
You must be signed in to change notification settings - Fork 83
Emoji: First pass at support in Interactions #1129
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: trunk
Are you sure you want to change the base?
Conversation
|
I think before allowing images in comments, we have to think about/implement a proper blocking and moderation tooling (even more if it is about side-loading images): https://www.theverge.com/2023/7/24/23806093/mastodon-csam-study-decentralized-network |
|
I just pushed an update that moves the replacement into a filter that runs after comment_content and the author have been sanitized. That way, only custom emoji images will be added to the content. |
Would sideloading the image onto the site with
Of course, we'd need to be okay adding potentially a lot of new media to a site once that's enabled. I'm not sure that's okay. |
With custom emoji being shared tags, is that not kind of expected? |
76f5d33 to
47a6493
Compare
This comment was marked as outdated.
This comment was marked as outdated.
|
@Jiwoon-Kim I appreciate your input and feedback, but comments and issues of this length are not helpful. They generally lack a specific ask or suggestion and are incredibly hard to read. Going forward, please keep comments/issues concise and actionable, like I asked for previously. |
This comment was marked as off-topic.
This comment was marked as off-topic.
|
I do understand, maybe part of your workflow could be to instruct your LLM to use natural language and distill its response to a sentence or two? |
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
51eeb14 to
ffbce79
Compare
|
Todo:
|
|
It’s possible to display custom emojis from remote instances by extending the Smiley feature. |
Replace multiple database queries with single batched query and fast lookup arrays. This eliminates N+1 query problem where each emoji required separate database calls. Changes: - Single get_posts() query instead of one per emoji - Fast O(1) lookup arrays instead of O(n) loops - Consolidated meta query building into single loop - Removed redundant array collections
Instead of storing HTML markup in the comment_author field, now stores the shortcode (e.g., ":emoji:") and replaces it on display. This makes the implementation more future-proof: - If the plugin is disabled, shortcodes display gracefully - Emoji images can be updated dynamically - Database stays clean without HTML markup Implementation: - Store ActivityPub emoji tag data in comment meta - Use get_comment_author filter to replace shortcodes with img tags - Use comment_author filter to selectively unescape only emoji images - Maintain WordPress security by only unescaping known emoji markup
c956b33 to
55e986c
Compare
- Add import_emoji() method to Attachments class for downloading and caching emoji images
- Store emoji files organized by source domain: /activitypub/emoji/{domain}/
- Simplify Emoji class from 225 lines to 89 lines by delegating storage to Attachments
- Remove WordPress attachment posts for emoji, use lightweight file storage instead
- Add img tag to allowed HTML in comments for emoji support
- Fix comment_author to store shortcodes (replaced at display time, not save time)
- Add prepare_comment_data() for content emoji replacement at insert-time - Add prepare_actor_meta() for storing emoji data on remote actors - Add replace_from_json() for display-time emoji replacement - Store emoji on remote actors instead of duplicating in comment meta - Look up author emoji from linked remote actor at display time - Remove redundant pre_comment_content filters from Interactions
- Add get_emoji_tags() to filter only Emoji-type tags - Store filtered emoji tags instead of entire tag array - Use to_json() and to_array() while filters are removed
- Add accessibility attributes to emoji img tags (width, height, title, draggable) - Add CSS for reduced-motion preference to pause animated emoji - Update allowed HTML attributes for emoji in comments - Add cache invalidation via filemtime for emoji with updated timestamps - Add emoji support for actor names and descriptions in follower emails - Add tests for emoji cache invalidation behavior
- Use correct method Remote_Actors::get_by_uri() instead of get_by_actor() - Update test assertions to check for locally cached emoji URLs
Extracts emoji data from stored actor JSON and saves it as _activitypub_emoji post meta, enabling display-time emoji replacement for comments from actors that were stored before emoji support was added.
Mastodon sends emoji names in lowercase in tags but may use different casing in the content (e.g., :KannaWave: vs :kannawave:). Changed str_replace to str_ireplace for case-insensitive matching. Added comprehensive unit tests for the Emoji class covering multiple emoji, repeated emoji, adjacent emoji, and case-insensitive replacement.
Use wp_add_inline_style to add emoji float fix only on edit-comments.php, attached to wp-emoji-styles handle. Removes unused CSS from admin stylesheet.
|
@pfefferle Might need some testing, but should be close now. See https://mas.to/@obietester/115741669531612641 |
There was a problem hiding this comment.
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 implements custom emoji support for ActivityPub interactions, enabling custom emoji from federated sources (like Mastodon) to be displayed as images in WordPress comments. The implementation caches emoji images locally, stores emoji metadata with remote actors, and provides display-time rendering for author names while processing emoji in comment content at insert-time.
Key Changes
- Adds new
Emojiclass to handle custom emoji replacement with image tags - Implements emoji caching system that downloads and stores emoji files organized by domain
- Adds migration to extract and store emoji metadata from existing remote actors
Reviewed changes
Copilot reviewed 13 out of 13 changed files in this pull request and generated 18 comments.
Show a summary per file
| File | Description |
|---|---|
| includes/class-emoji.php | New class providing emoji processing, replacement, and metadata extraction functionality |
| includes/class-attachments.php | Adds emoji import/caching with timestamp-based refresh logic |
| includes/collection/class-interactions.php | Integrates emoji processing into comment creation/updates and allows img tags in comments |
| includes/class-comment.php | Adds filters to render emoji in author names at display-time |
| includes/collection/class-remote-actors.php | Stores emoji metadata when upserting remote actors |
| includes/class-migration.php | Adds batch migration to populate emoji metadata for existing actors |
| includes/class-mailer.php | Applies emoji replacement in email notifications |
| includes/wp-admin/class-admin.php | Adds CSS to prevent emoji float in comment author column |
| tests/phpunit/tests/includes/class-test-emoji.php | Comprehensive test suite for emoji functionality |
| tests/phpunit/tests/includes/class-test-interactions.php | Adds integration test for emoji in comments |
| tests/phpunit/tests/includes/class-test-migration.php | Tests emoji migration batching and data extraction |
| tests/phpunit/tests/includes/class-test-attachments.php | Tests emoji import, caching, and refresh logic |
Comments suppressed due to low confidence (1)
includes/class-attachments.php:184
- The emoji import accepts any valid URL without checking if it's an image file. While download_url will fetch any URL, consider validating that the URL path ends with a recognized image extension (.png, .jpg, .jpeg, .gif, .webp) or checking the Content-Type header after download to prevent non-image files from being cached in the emoji directory.
public static function import_emoji( $emoji_url, $updated = null ) {
if ( empty( $emoji_url ) || ! \filter_var( $emoji_url, FILTER_VALIDATE_URL ) ) {
return false;
}
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Validate emoji downloads are actual images using wp_get_image_mime() - Handle wp_mkdir_p() failure by cleaning up temp file - Use glob for timestamp comparison to handle webp-optimized files - Add unslash/re-slash in prepare_comment_data() to avoid escaping img attributes - Add test for download failure handling
- Add Emoji::get_kses_allowed_html() with strict validation: - Requires class="emoji" attribute - Validates src URL points to local emoji uploads directory - Requires standard emoji dimensions (20x20) - Update Interactions::allowed_comment_html() to use strict KSES - Update Comment::unescape_emoji() to use strict KSES - Only replace emoji shortcodes when local import succeeds - Add activitypub_pre_import_emoji filter for test mocking - Non-emoji img tags are now stripped from incoming content
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Copilot reviewed 13 out of 13 changed files in this pull request and generated 7 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| foreach ( $emoji_data as $emoji ) { | ||
| $local_url = Attachments::import_emoji( $emoji['url'], $emoji['updated'] ?? null ); | ||
|
|
||
| // Only replace if the emoji was successfully uploaded locally. | ||
| if ( $local_url ) { | ||
| $text = self::replace_emoji_in_text( $text, $emoji['name'], $local_url ); | ||
| } | ||
| } |
Copilot
AI
Dec 19, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Performance concern: Emoji images are imported one by one in a loop, with each import potentially making an HTTP request to download the emoji. For comments with many emojis, this could result in multiple sequential HTTP requests. Consider implementing batch download or parallel processing of emoji imports to reduce latency when processing comments with multiple emojis.
Verifies that sanitize_file_name() prevents glob patterns like
[abc].png, test*.png, tes?.png, and {foo,bar}.png from matching
unintended cached files.
- Add missing @param tags for data provider test - Add emoji import mock to interactions test for KSES validation


Fixes #970.
See https://mas.to/@obietester/115741669531612641
See https://obietester.blog/2025/12/02/battery-powered-tools-vs-air-compressor-tools-a-comprehensive-comparison/#comment-1946
Proposed changes:
Other information:
Testing instructions:
:yikes:,:AngeryCat:, etc.