Detailed Architecture for Implementing Fediverse Custom Emoji Using WordPress ActivityPub Plugin #2371
Replies: 1 comment 1 reply
-
| How about using the path  Remote Emoji Handling and Interoperability ( The suggested  
 
 The suggested  Below is a detailed explanation of the differences between using the two paths and the recommended approach from a Fediverse perspective. 1. Using a Path for Local Display (Smilies) ( | 
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
Detailed Architecture for Implementing Fediverse Custom Emoji Using WordPress ActivityPub Plugin
I. Establishing Fediverse Protocol Requirements and WordPress Context
To reliably display WordPress content on ActivityPub-based Fediverse instances, especially major platforms like Mastodon, it is essential to understand and address the fundamental differences between WordPress's traditional emoji handling and the strictly structured JSON-LD data format of the ActivityPub protocol. Implementing custom emojis is not merely a text replacement task but a process of metadata injection following the ActivityStreams 2.0 (AS2) standard.
1.1. Understanding ActivityStreams 2.0 and FEP-9098: Emoji Objects
Custom emojis are handled as an extension of the ActivityStreams 2.0 data format, which underlies the ActivityPub protocol. ActivityPub serializes content in JSON-LD format, in which entities (mention, hashtag, emoji) included within a post object (Note type) must be defined in structured arrays.
According to core protocol specifications, custom emojis in the Fediverse function as metadata that supplements shortcodes embedded in the content property of Note objects (the original text authored by the user). This structured data is placed within the tag property, allowing the receiving server to parse shortcodes in the raw text and replace them with the image objects defined in the tag for rendering.
The Emoji object structure, defined according to the standard extension specification for custom emojis (FEP-9098), is as follows:
1.2. Interoperability Constraints and Mastodon Compatibility
The most critical aspect of implementing ActivityPub is interoperability. If WordPress’s local content rendering method is transmitted directly in the ActivityPub payload, the receiving server may not display the content as intended.
Typically, WordPress uses the smilies filter hook and the convert_smilies function to convert :shortcode: format shortcodes into HTML <img...> tags. However, receiving servers like Mastodon sanitize HTML content received from external sources for security and stability. During this sanitization process, HTML elements not supported by the ActivityPub standard, including image tags, are likely to be removed. For instance, Mastodon only supports limited elements and attributes such as <p>, <span>, and <a>, and even list tags are converted into <p> and <br>.
To address these interoperability issues, the implementation architecture must follow a strategy of separating content (content property) and tags (tag property). In the ActivityPub payload, the content property must maintain the shortcodes in raw text form without HTML conversion. Even if the local rendering pipeline converts shortcodes to HTML for local display, when generating outgoing Activity JSON, the plugin must bypass WordPress’s usual HTML output filters and parse shortcodes from the original text extracted from the database. This ensures that local display and Fediverse serialization processes are entirely separated.
Additionally, image files themselves have constraints for receiving server compatibility. Fediverse implementations generally support custom emojis in PNG or GIF format, and Mastodon strongly recommends a file size below 50kb. When storing or referencing emoji URLs, only HTTPS/HTTP schemes should be allowed for security reasons. ActivityPub servers must not trust externally received content or URI schemes, and strict whitelisting is necessary to prevent malicious file:// schemes or localhost access attempts. Therefore, if possible, caching external emoji URLs in the internal media library to ensure URL reliability and permanence is the most desirable approach.
II. WordPress Data Architecture Design: Performance and Persistence
The ActivityPub serialization process occurs each time a post is transmitted, requiring a high-performance data model that can efficiently access and provide all necessary emoji metadata.
2.1. Defining Custom Emoji Data Model
Custom emoji data should be stored using the shortcode as a unique key. This data model must contain all elements needed for ActivityPub transmission, especially the image URL and MIME type required by FEP-9098.
The following is a proposed structure for storing emoji metadata. This data can be stored as a serialized array in WordPress’s wp_options table or in a dedicated custom database table for large-scale management.
Custom Emoji Metadata Storage Structure
2.2. High-Performance Caching Using Transient API
When creating ActivityPub objects, identifying all shortcodes in the post content and retrieving their metadata from the database can be frequent operations. Repeatedly looking up emoji maps for many characters can cause database load and serialization performance degradation. To mitigate this bottleneck, WordPress Transients API should be used to cache the emoji map.
Transients store cached data with an expiration time in the database (wp_options table) or object cache. During implementation, first use get_transient('activitypub_emoji_map') to retrieve the cached emoji map. Only if the cache does not exist should the full map be fetched from permanent storage and stored using set_transient() with a reasonable expiration time of 1 hour (3600 seconds) or 1 day (DAY_IN_SECONDS).
This dynamic data management structure allows immediate reflection of data changes. When an administrator adds, deletes, or modifies emojis, the plugin should immediately call delete_transient() to invalidate the cache. This ensures that the next ActivityPub serialization request reloads the new emoji map from the database and caches it (cache priming). The efficiency of Transients is maximized in environments with persistent object caching solutions like Redis or Memcached, allowing emoji map retrieval in milliseconds.
2.3. Local Caching Strategy for Remote Image Assets
If the icon.url included in the ActivityPub object points to an external server (hotlink), downtime or service discontinuation of that server can permanently break emoji rendering across the Fediverse. Therefore, for long-term stability, it is recommended to cache emoji images in WordPress’s local media library.
Storing a remote URL in WordPress cannot be handled by the standard file upload function media_handle_upload(), as this function is designed for files uploaded via forms (i.e., files in the $_FILES array). Therefore, a custom import logic must be implemented.
This logic proceeds as follows: first, use wp_remote_get() to download the content of the remote emoji file. Second, save the downloaded file to WordPress’s upload directory using wp_upload_bits(). Third, register the file path as a media library item with wp_insert_attachment() and obtain a permanent wp_attachment_id. This ID is used to generate the local URL for the cached emoji, stored in the ap_remote_url field, ensuring reliability and permanence in the ActivityPub payload.
This image caching module should also include validation for file size. If a file exceeding the Fediverse compatibility standard (50kb) is uploaded or imported, it must be resized using an image optimization plugin (e.g., WP-Optimize) or a custom compression logic.
III. WordPress Content Pipeline Integration and Shortcode Parsing
Content sent via ActivityPub must retain original shortcodes, but WordPress local environment must display them as HTML images. Conditional filtering is essential to satisfy these conflicting requirements.
3.1. Using Smilies Hook for Local WordPress Display
To display custom emojis as images in typical WordPress frontend output, the WordPress core smilies filter system can be used. Developers must add custom emojis to the $wpsmiliestrans array, mapping shortcodes to local image URLs.
This filter is typically added with add_filter('smilies', 'custom_emoji_smilies_register', 1); with priority 1 to ensure that the custom emoji map is set before the core smilies_init function executes. Once the map is defined, when the WP core function convert_smilies runs in the_content filter, the :shortcode: is converted into an <img...> tag pointing to the local server’s image URL for display.
3.2. Strategy for Acquiring Raw Content for ActivityPub
Converting shortcodes to HTML for local display is a major cause of interoperability issues. Using content already converted to HTML in ActivityPub serialization will cause receiving servers to sanitize it and fail to render emojis.
Therefore, the ActivityPub plugin must precisely target the filters it uses to fetch content (e.g., activitypub_the_content or activitypub_get_post_content). Within this ActivityPub context, WordPress core’s convert_smilies function must be prevented from executing. This can be achieved using context detection functions provided by the plugin (e.g., checking specific query variables) or by calling remove_filter('the_content', 'convert_smilies') just before the ActivityPub filter executes, temporarily disabling the WP core filter. This ensures that in ActivityPub request contexts, HTML conversion is skipped and raw shortcode text is obtained from the database.
3.3. Shortcode Parsing and Unique List Extraction
Immediately before ActivityPub JSON serialization, a regular expression (Regex) must be executed on the acquired raw content string to identify all custom emoji shortcodes (:word:) included in the content.
The robustness of the regular expression is essential. Fediverse shortcodes may contain various characters, including underscores, hyphens, numbers, and English uppercase/lowercase letters. Instead of a simple regex, a regular expression that clearly defines allowed characters within a pattern starting and ending with colons, such as /:([a-zA-Z0-9_-]+):/, should be used to minimize false positives.
The parsed shortcode list is then compared with the high-performance emoji map cached in Transients as described in Section II, retrieving all unique emoji metadata (URL, MIME Type) used in the post. The retrieved list must be optimized to remove duplicate shortcodes and convert them into unique ActivityPub Emoji objects. The ActivityPub tag array should include a structural definition for each emoji only once, even if the emoji is used multiple times within the post.
IV. ActivityPub JSON Serialization: Emoji Object Injection
The ActivityPub plugin (Matthias Pfefferle’s plugin) provides various filter hooks that can intervene in the process of generating outgoing Activity JSON-LD payloads. The core of the custom emoji functionality is to utilize these filters to inject Emoji objects that conform to the FEP-9098 standard into the final JSON.
4.1. Identifying ActivityPub Outgoing JSON Filters
In ActivityPub, posts are converted into Note objects within a Create Activity for transmission. Emoji data must be injected immediately before this object is sent to the Fediverse. The ActivityPub plugin provides filters (e.g., activitypub_activity_array or similar) that can modify the entire Activity array or the Object array, and these filters are the primary targets for emoji object injection.
For example, a filter can be added as follows to access the Activity array $activity_array and the corresponding WordPress post object $post:
4.2. Dynamic Generation and Injection Logic for JSON-LD tag Array
Within the filter function, emoji objects are constructed and injected in the following steps:
JSON Example:
{ "id": "https://example.com/emoji/123", "type": "Emoji", "name": ":kappa:", "icon": { "type": "Image", "mediaType": "image/png", "url": "https://example.com/files/kappa.png" } }PHP Example:
The design of this data model and serialization logic provides long-term scalability. Currently, the focus is on inline emojis within content, but the Fediverse has implemented emoji reactions (FEP-c0e0), which can attach specific emojis as variations of Like activities. The emoji data model we build can serve as a reusable foundation when the ActivityPub plugin supports these reaction features in the future.
4.3. JSON-LD Context Extension
ActivityPub uses JSON-LD, and to use extended object types (e.g., Emoji), the corresponding namespace definition must be included in the @context of the payload. The ActivityPub plugin generally provides filter hooks for context extension, so this filter should be used to inject the following namespace definition:
JSON Example:
{ "Emoji": "http://joinmastodon.org/ns#Emoji" }This definition ensures that receiving servers interpret type: "Emoji" objects in the payload correctly and handle them according to the Fediverse custom emoji standard.
V. Operations and Advanced Architecture Best Practices
The successful operation of a custom emoji system requires a comprehensive architecture that encompasses not only development but also administrative interfaces, performance optimization, and security considerations.
5.1. Administration Interface and User Experience (UX)
To enhance convenience for administrators and users, an intuitive interface should be provided. Administrators must be able to upload, modify, and replicate remote custom emojis through the UI. Particularly during the emoji upload stage, immediate validation and warning messages for file size (50kb limit) and PNG/GIF format, preventing Fediverse compatibility issues, are critical.
To improve the authoring experience, a custom emoji picker should be integrated into the WordPress editor (Gutenberg or Classic). Client apps like Fedilab improve user experience by providing a shortcode suggestion list when the user starts typing a colon (:). A similar mechanism should be applied in the WordPress editor so that users can easily find and insert custom emojis.
5.2. Performance Optimization and Reliability Assurance
As emphasized in Section II, to prevent performance degradation during ActivityPub serialization, activating persistent object caching solutions like Redis or Memcached is highly recommended. The Transients API plays a key role in optimizing emoji map retrieval speed in these environments.
Furthermore, for reliable Fediverse-wide emoji rendering, emoji image delivery performance is important. The icon.url property in ActivityPub payloads should ideally use a CDN (Content Delivery Network) URL instead of the local WordPress server URL. This improves the retrieval speed of emoji images for remote instances (Fediverse followers) and reduces load on the source WordPress server, enhancing overall user experience.
5.3. Security and Maintenance
From a security perspective, when implementing remote emoji caching, validation of external URL requests is crucial. The ActivityPub protocol warns that servers performing requests may be exposed to malicious URI schemes (e.g., file:// or data:) attempting access to the local file system. Therefore, the image fetch functionality must strictly whitelist only http and https schemes.
Maintenance and data sovereignty must also be considered. Custom emojis may involve copyright issues, and some platforms like Akkoma implement policies to block emoji replication from certain hosts. The administration interface should clearly warn users about copyright and licensing issues when replicating or uploading emojis.
Finally, the implemented custom emoji functionality should minimize dependence on the ActivityPub plugin and be developed as an independent feature extension plugin. The ActivityPub protocol and plugin are continuously evolving, and modularization reduces the risk of conflicts during core plugin updates and improves maintainability. Additionally, WordPress ActivityPub plugins often reuse the existing comment filter system (Disallowed Comment Keys) to process incoming activities. When implementing outgoing emojis, care must be taken to ensure that incoming comments containing emoji shortcodes are not accidentally blocked by WP core’s comment blacklist, maintaining interoperability.
Conclusion and Recommendations
Implementing Fediverse custom emojis through the WordPress ActivityPub plugin is not a simple content replacement task but requires a complex architecture that meets data model design, performance caching, and protocol serialization requirements.
Key recommendations for successful implementation are:
#1129
Beta Was this translation helpful? Give feedback.
All reactions