How to convert double dash to em dash in WordPress Gutenberg

How I made double dashes automatically convert to em dashes in WordPress Gutenberg Editor

Over the weekend, I was tackling a client request requesting for us to help modify their WordPress backend so that when writing posts, the Gutenberg Editor will automatically convert consecutive double dashes -- to an em dash character.

It was a particularly difficult task for me, despite having coding in WordPress for many years, simply because the Gutenberg editor was relatively new, and there is very little documentation regarding it.

If you are just looking for my code, skip right to the end.

WordPress already automatically converts double dashes

The first thing I told this client was that WordPress already automatically does that. If you were to type in double dashes -- into the Gutenberg Editor, when you preview or publish your post, it will show up as an en dash (i.e. practically a short em dash); and if you were to type in triple dashes --- or double dashes with a space preceding and succeeding it -- , it will be replaced with an em dash.

The replacement of these characters does not occur in the Gutenberg Editor, so the original post content is the one that is saved on the database; but view it on the front-end, and you will see the beautified characters. This functionality is provided by the wptexturize(), and is on by default on a WordPress site. It also does more than just convert em dashes — it also beautifies ellipses ... and quotation marks among other things, and you can see a full list of the characters it converts by clicking on the aforementioned link.

You can disable wptexturize by adding the following code to the functions.php of your theme. I’m not sure if it can work by adding it to wp-config.php though — I’ll probably try that and update this article at a later date.

add_filter('run_wptexturize', '__return_false', 100, 2);

Making Gutenberg listen for dashes

The first thing I did was tell my client that WordPress already converts these characters on the front-end, because I don’t like to sell my clients things that they don’t need, but they told me they still wanted it. So I started reading the sparse documentation that WordPress had. What I wanted to do was to hook an event listener onto the Editor that fired either:

  1. Whenever the post content was changed, or;
  2. Whenever a key was pressed.

This proved to be particularly challenging, because the only event I found I was able to hook to was, which I didn’t like because it fired every time the post content changed. This was inefficient because this means that every character typed on Gutenberg was going to fire the function.

But this was not the only problem — because fires every time post content was changed, regardless of whether it was user input or by code, my code to listen to and convert the dashes also fired the event, causing an infinite recursion. If you would like to see the code, you can look at this Stack Overflow topic.

Article continues after the advertisement:

Using Gutenberg’s Autocompleter

It became clear to me after awhile, due to the combination of Gutenberg’s obtuseness, and the lack of documentation, that this wasn’t going to work (even ChatGPT couldn’t provide answers to the questions I asked, because a lot of things in WordPress were simply undocumentated).

Hence, I just started scouring through WordPress’s Gutenberg documentation randomly, looking for something relevant that I could use, and I found that it had an autocomplete functionality that developers could extend. So after some tinkering, this is what I came up with:

Gutenberg Autocompleter example
When you type in a dash or double dash, the Autocompleter will give you a variety of dash characters to choose from.

This is the code that I used, and it’s much simpler than the one I used for

(function(wp) {
	// Define the completer
	var AutocompleteSingleDash = {
		'name': 'singleDashes',
		'triggerPrefix': '-',
		'options': [
			{ 'character': '-', 'name': 'Figure Dash'},
			{ 'character': '−', 'name': 'Minus'},
			{ 'character': '–', 'name': 'En Dash'},
			{ 'character': '—', 'name': 'Em Dash'}
		'getOptionLabel': function(opt) { return opt.character + " " +; },
		'getOptionKeywords': function(opt) { return },
		'getOptionCompletion': function(opt) { return opt.character },
	}, AutocompleteDoubleDash = {
		'name': 'doubleDashes',
		'triggerPrefix': '--',
		'options': [
			{ 'character': '—', 'name': 'Em Dash'},
			{ 'character': '―', 'name': 'Horizontal Bar'},
			{ 'character': '〜', 'name': 'Wave Dash'},
			{ 'character': '〰', 'name': 'Wavy Dash'}
		'getOptionLabel': function(opt) { return opt.character + " " +; },
		'getOptionKeywords': function(opt) { return },
		'getOptionCompletion': function(opt) { return opt.character },

	// Trigger our callback on the `editor.Autocomplete.completers` hook
	wp.hooks.addFilter( 'editor.Autocomplete.completers', 'sn-bloody-elbow/completers',
		function ( completers, blockName ) {
			completers.push(AutocompleteDoubleDash, AutocompleteSingleDash);
			return completers;
		}, 11

If you’re reading this, I assume that you are a semi-proficient WordPress developer at least (otherwise, you wouldn’t have even found this), so I will leave you to figure the code out for yourself. Note that it’s Javascript, so you will have to enqueue it on the backend.

I hope this post helped you find the answers you were looking for!

Article continues after the advertisement:

Leave a Reply

Your email address will not be published. Required fields are marked *

Note: You can use Markdown to format your comments.

This site uses Akismet to reduce spam. Learn how your comment data is processed.