Disable Emojis in WordPress Without a Plugin

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_script is the inline loader. Since WordPress 6.9 it prints in the footer, but it is still hooked to wp_head, admin_print_scripts and embed_head, so those three are removed.
  • Since WordPress 6.4 the emoji CSS is enqueued by wp_enqueue_emoji_styles on wp_enqueue_scripts, admin_enqueue_scripts and enqueue_embed_scripts. Removing only print_emoji_styles, as older copies of this snippet did, no longer removes it. The print_emoji_styles lines stay for sites on older versions.
  • wp-admin registers its emoji hooks in wp-admin/includes/admin-filters.php, which loads after init. That is why the same function also runs on admin_init; without it the admin keeps its emoji script.
  • wp_staticize_emoji and wp_staticize_emoji_for_email turn emoji into <img> tags in feeds and emails; removing them keeps the plain characters.
  • The tiny_mce_plugins filter drops the wpemoji plugin from the classic editor.
  • Current WordPress no longer adds a DNS prefetch for s.w.org. The wp_resource_hints filter 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.org images; 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.

// newsletter

Three tested WordPress snippets a week

Blocks, security, performance, Tailwind, PHP and React. Copy, paste, ship. You’ll also get DPlugins product updates. No spam, and you can unsubscribe anytime.

// newsletter

Three tested WordPress snippets a week

Blocks, security, performance, Tailwind, PHP and React. Copy, paste, ship. You'll also get DPlugins product updates. No spam, and you can unsubscribe anytime.