To disable emojis in WordPress you have to unhook more than one script. WordPress adds an emoji detection script and an emoji stylesheet to every front-end page and every wp-admin screen, swaps emoji for s.w.org images in feeds and emails, and loads an emoji plugin in the classic editor. Every current browser and operating system draws emoji on its own, so all of that is extra code on every page.
This snippet removes all of it. Emoji you type still show up; they are simply drawn by the visitor’s system instead of being replaced by images.
The snippet
<?php
/**
* Disable WordPress emoji scripts and styles on the front end, in wp-admin,
* in embeds, feeds, emails and the classic editor.
*/
add_action( 'init', 'dpc_disable_emojis' );
// wp-admin adds its emoji hooks after init, so remove them again on admin_init.
add_action( 'admin_init', 'dpc_disable_emojis' );
function dpc_disable_emojis(): void {
// Detection script (front end, wp-admin, embeds).
remove_action( 'wp_head', 'print_emoji_detection_script', 7 );
remove_action( 'admin_print_scripts', 'print_emoji_detection_script' );
remove_action( 'embed_head', 'print_emoji_detection_script' );
// Styles: WordPress 6.4+ enqueues them, older versions print them.
remove_action( 'wp_enqueue_scripts', 'wp_enqueue_emoji_styles' );
remove_action( 'admin_enqueue_scripts', 'wp_enqueue_emoji_styles' );
remove_action( 'enqueue_embed_scripts', 'wp_enqueue_emoji_styles' );
remove_action( 'wp_print_styles', 'print_emoji_styles' );
remove_action( 'admin_print_styles', 'print_emoji_styles' );
// Emoji converted to <img> tags in feeds and emails.
remove_filter( 'the_content_feed', 'wp_staticize_emoji' );
remove_filter( 'comment_text_rss', 'wp_staticize_emoji' );
remove_filter( 'wp_mail', 'wp_staticize_emoji_for_email' );
}
// Classic editor (TinyMCE) emoji plugin.
add_filter( 'tiny_mce_plugins', 'dpc_disable_emojis_tinymce' );
function dpc_disable_emojis_tinymce( $plugins ): array {
return is_array( $plugins ) ? array_values( array_diff( $plugins, array( 'wpemoji' ) ) ) : array();
}
// Older WordPress versions also prefetch the emoji CDN (s.w.org).
add_filter( 'wp_resource_hints', 'dpc_disable_emojis_dns_prefetch', 10, 2 );
function dpc_disable_emojis_dns_prefetch( $urls, $relation_type ) {
if ( 'dns-prefetch' !== $relation_type || ! is_array( $urls ) ) {
return $urls;
}
foreach ( $urls as $key => $url ) {
$href = is_array( $url ) ? ( $url['href'] ?? '' ) : (string) $url;
if ( false !== strpos( $href, 's.w.org/images/core/emoji' ) ) {
unset( $urls[ $key ] );
}
}
return $urls;
}
Add it with Scripts Organizer
Scripts Organizer ships this snippet in its One-Click Import library as Disable the Emoji. To add it by hand, go to Code Blocks → Add New, give the block a name, set Trigger location to Everywhere, tick PHP under Script location, paste the code into the PHP editor and publish. Leave Action/Hook empty.
Use Everywhere, not Admin only: the front end, feeds and emails need the same changes as wp-admin. The removals run on init and admin_init, after WordPress has registered its own emoji hooks.
The same code also works unchanged in a small plugin or an mu-plugin.
How it works
print_emoji_detection_scriptis the inline loader. Since WordPress 6.9 it prints in the footer, but it is still hooked towp_head,admin_print_scriptsandembed_head, so those three are removed.- Since WordPress 6.4 the emoji CSS is enqueued by
wp_enqueue_emoji_stylesonwp_enqueue_scripts,admin_enqueue_scriptsandenqueue_embed_scripts. Removing onlyprint_emoji_styles, as older copies of this snippet did, no longer removes it. Theprint_emoji_styleslines stay for sites on older versions. - wp-admin registers its emoji hooks in
wp-admin/includes/admin-filters.php, which loads afterinit. That is why the same function also runs onadmin_init; without it the admin keeps its emoji script. wp_staticize_emojiandwp_staticize_emoji_for_emailturn emoji into<img>tags in feeds and emails; removing them keeps the plain characters.- The
tiny_mce_pluginsfilter drops thewpemojiplugin from the classic editor. - Current WordPress no longer adds a DNS prefetch for
s.w.org. Thewp_resource_hintsfilter only removes it on older versions or if a plugin adds it back. It handles both plain URLs and the array format.
Compared with the older version, all functions are prefixed with dpc_, the WordPress 6.4+ styles and embeds are covered, the admin removal actually works, and the closing ?> is gone.
Gotchas
- The block editor has its own emoji picker in the operating system, not in WordPress, so nothing changes there.
- Clear page caches after enabling the snippet, or cached pages keep the old script.
- Old emails and cached feed items keep their
s.w.orgimages; only new output changes.
Block styles are a separate cleanup: see Remove the Gutenberg Block Library CSS from WordPress.
In the Scripts Organizer library Import it with one click from Scripts Organizer.