Creating My First WordPress Plugin With JavaScript
Language
- unknown
by James Smith (Golang Project Structure Admin)
This post will document my very first foray into developing a WordPress plugin, which is used on this website. The majority of the code is contained within a single JavaScript file.
Table of Contents
Why Do I Use WordPress?
The blog runs on WordPress. I’ve created other websites and blogs in the past for which I wrote all the code myself, often in Go, and I’d highly recommend that you do that. It’s a great learning experience and you can create a very performant web server that will be able to compete with the very best.
But I wanted to focus, as much as possible, on creating content and sharing what I’ve learnt about Go programming, without worrying about having to maintain a new codebase, so I relied on a tried-and-true technology.
WordPress isn’t particularly innovative or cutting-edge, but it works — and it really does work well.
The code that powers WordPress is written in PHP. This programming language has been around for almost thirty years now, and its syntax and style is heavily influenced by C (albeit with less type-strictness), so I’ll openly admit that it’s not as fashionable or even as fast as more modern web languages. However, it’s a language that still powers a large proportion of the web. There are still many high-paying jobs for PHP developers, too, for precisely this reason.
What Does My WordPress Plugin Do?
I wanted to start small, so my WordPress plugin performs a very simple task. It finds all of the dashes on every page of your site and if they’re surrounded by spaces, it will swap the spaces for smaller hairspaces. This produces, in my opinion, a more elegant typographic effect.
Look at the following line of text, for example, which contains dashes (and spaces either side of each dash):
You will loveno, really lovemy plugin.
When my WordPress plugin is activated, the line of text will look like this:
You will loveno, really lovemy plugin.
It’s a subtle difference, but a real one. The smaller gaps on either side of the dashes help the text to flow better on the page.
What Is the Difference Between Em Dashes and En Dashes?
This section will discuss how dashes are used as punctuation marks in line with the basic rules of English grammar, so if you’re not interested in learning more about that, feel free to scroll down and skip over it to the next section.
Dashes are just long lines that appear in the middle of text. The lines run horizontally, not vertically. (A vertical line is used as the pipe character.)
There are two main types of dashes. A long dash (—) is known as an em dash and a short dash (–) is known as an en dash. They don’t just look different: they are also put to different uses.
You can write them in HTML by using the following entities: — for an em dash and – for an en dash. When you load the HTML page in a browser, the correct dashes should appear.
The entity names are the same as the names of the dashes themselves: you just need to remember that the initial e is missing and there’s no space.
Using the Em Dash
An em dash can be used to split up a sentence, and to provide extra information, a bit like the commas in this sentence. You saw that in the example we looked at in the previous section.
This kind of dash can also be used to mark a break between two parts of a sentence — something like this. It can separate a disjointed pair of thoughts or reflect a change in tone.
Some people see the use — or overuse — of dashes as a sign of informal writing, but they’re commonly used in academic and technical texts too.
Using the En Dash
An en dash is sometimes confused with a hyphen, but it is slightly longer than a hyphen in most fonts and it has a different purpose.
A hyphen is used simply to link two related words together, however, an en dash is rarely used in this role. When two numbers are linked, an en dash can be used to separate them.
For example, look at the birth and death dates for Ada Lovelace, often considered to be one of the first computer programmers, in the caption below this image:
The year when she was born, 1815, is separated from the year when she died, 1852, by an en dash.
This dash is also used to separate the scores in sports results. For example, the 2002 FIFA World Cup — one of the biggest international events in soccer — was won 2–0 by Brazil against Germany. We use an en dash between the two and the zero.
How Does the WordPress Plugin Work?
I used to be quite proficient in PHP many years ago, back when I first worked in web development, but since we now have superior programming languages like Go available, I haven’t used it at all and my skills have become rusty.
However, I do know JavaScript very well, so I wanted to build on my strengths, using as much JS code and as little PHP as possible.
Building my plugin in this way meant that I didn’t have to spend a lot of time getting to grips with the intricacies of the WordPress codebase. That will be something that I’ll spend more time on in future, if I ever decide to develop another WordPress plugin.
Looking at the PHP Code
In fact, I can show you all of the PHP code that my WordPress plugin contains, because there’s literally only a few lines in the entire plugin:
function hairspaces_around_dashes_enqueue_scripts() {
wp_register_script(
"hairspaces-around-dashes",
plugin_dir_url( __FILE__ ) . "/scripts/hairspaces-around-dashes.js",
null,
"1.0.3",
true,
);
wp_enqueue_script( "hairspaces-around-dashes" );
}
add_action( "wp_enqueue_scripts", "hairspaces_around_dashes_enqueue_scripts" );
That is it: just one function declaration and one function call!
The wp_register_script
function simply provides the necessary information about my JavaScript file. (Many of the most commonly used WordPress PHP functions begin with wp_
prefix, which acts, in effect, as a namespace.)
The wp_enqueue_script
function actually adds the correct tags to the HTML page, within one of the areas specified by your WordPress theme. It works with the information that we’ve already set, since we pass it the "hairspaces-around-dashes"
string as a handle.
Finally, the add_action
function ensures that the callback runs at the correct time when WordPress’ internal PHP code is processing the HTML page that will be sent to the client.
Looking at the JavaScript Code
There is considerably more JavaScript code in my WordPress plugin, but it isn’t particularly complicated.
I have consciously written the code in a more old-fashioned way than I normally would, in order to increase backwards-compatibility with older browsers.
For example, I use the var
keyword, instead of the more modern const
and let
. I have also declared all of the variables in one statement at the beginning of each function, in order to remind myself that variables defined with var
are function-scoped and hoisted by the interpreter.
I have also chosen to use old-style function declarations exclusively, rather than more modern arrow functions.
The main work of the JavaScript code is done by the following function, which is called initially with document.body
when the page loads:
function recursiveWalkFromNode(node) {
var childNodes,
childNodesLength,
node2,
i;
if (node) {
childNodes = node.childNodes;
childNodesLength = childNodes.length;
for (i = 0; i < childNodesLength; ++i) {
node2 = childNodes[i];
if (node2) {
switch (node2.nodeType) {
case 3:
handleTextNode(node2, node);
break;
case 1:
recursiveWalkFromNode(node2);
break;
}
}
}
}
}
You can see how it iterates through all of child nodes, and looks at the type of each child: if it is an element (i.e. its nodeType
equals one), the function will be called recursively, so that all of the child node’s children will be processed, too. This can be generalized, meaning that a descendant node of any level in the hierarchy will be processed.
Of course, this means that all of the elements within the body of our HTML will pass through this function. None of them will be missed out.
However, the function is only really interested in text nodes. If any of the children are text nodes (i.e. they have a nodeType
of three), then the text node will be passed to another function. That is where the dash-handling code sits, as you can see below:
function handleTextNode(node, parentNode) {
var content,
node2;
content = node.textContent || node.innerText || "";
if (content && hairSpaceRegExp.test(content)) {
content = content.replace(hairSpaceRegExp, function(match, p1, p2, p3) {
if (!p1 && !p3) {
return p2;
}
if (!p1) {
return p2 + hairSpace;
}
if (!p3) {
return hairSpace + p2;
}
return hairSpace + p2 + hairSpace;
});
node2 = document.createTextNode(content);
parentNode.replaceChild(node2, node);
}
}
We start by getting the text from the node (there are some significant differences between the value of textContent
and innerText
, but those differences shouldn’t matter in this case, especially since we’re only accessing innerText
if textContent
isn’t available, which would only be the case on older browsers). We then check that content
is truthy, since we don’t need to modify it if it’s just an empty string.
Before I discuss the string-replacement section of the function, note that I have declared hairSpace
as a global variable: it’s just a string containing the Unicode value for a hairspace character ("\u200a"
, using hexadecimal notation). Likewise, emDash
and enDash
are global variables that contain the Unicode values for the respective kinds of dash ("\u2013"
for the en dash and "\u2014"
for the em dash). Finally, hairSpaceRegExp
is a regular expression that recognizes a dash with optional whitespace before and/or after it (new RegExp("(\\s*)(" + enDash + "|" + emDash + ")(\\s*)", "g")
).
We use hairSpaceRegExp
to test that a dash can be found in the node’s content
string. If it can’t, there’s nothing for us to do, but if it can, we enter into the conditional block. This is where the main processing happens. We use the replace
method on the content
string in order to swap the existing whitespace for hairspaces.
The arguments p1
, p2
and p3
in the callback to the replace
method contain the content of the three groups that we defined in our regular expression. In other words, p2
will contain the dash. Then p1
and p3
will either contain one or more whitespace characters or the empty string; p1
will contain any whitespace before the dash and p3
will contain any whitespace after it.
So if both p1
and p3
are empty strings, the dash isn’t surrounded by any space and should just be returned as it is. If, on the other hand, either p1
or p3
contain space characters, they should be replaced with a single hairspace character. Finally, if both p1
and p3
contain space characters the original dash should be surrounded by two hairspace characters, one on either side of it.
Documenting a WordPress Plugin
All of the information about the plugin is contained in a text file (readme.txt). This file is processed automatically by WordPress in order to extract the important information, but it is also intended to be human-readable.
In fact, the readme file can be written using a subset of Markdown syntax (even though it doesn’t have the expected .md file extension). Links, lists, paragraphs and blockquotes will all be generated from the usual Markdown syntax. Text that is between a single pair of asterisks will be italicized (so *this*
will become this), and text that is a between a pair of double asterisks will be emboldened (so **this**
will become this).
The description within the readme file is perhaps the most important section, since it explains the plugin’s purpose and how it works. Anyone browsing through WordPress plugins online can read this description to decide whether it will meet their needs or not.
One of the things that disconcerted me, however, was the handling of tags. For example, I have included the following thirteen tags within my readme file:
dash, hairspace, space, whitespace, punctuation, design, style, typography, typesetting, fonts, dashes, spaces, spacing
But only four of them appear on the webpage for my WordPress plugin (the tags in bold). When I got in touch with someone from WordPress about this, seeking further clarification, I was informed that “tags that do not provide a better user-experience are not shown”.
Moreover, the response I received continued to say that “if there are few plugins using a given tag”, in general, “that tag will not be shown”. This may seem somewhat strange, since there could be cases where a rare tag would help to identify a niche plugin, however, tags are not intended to be used for search-engine optimization: they are simply used for categorization on the WordPress website.
I was also told that plugins are limited to a maximum of twelve tags, which is useful to know, since there’s no benefit to adding more tags than this. However, I’m unsure whether that total limit includes the tags that are excluded or not.
If you are intending to publish a WordPress plugin of your own, I would recommend looking at the tags used by similar plugins and focusing on including those.
Try the Hairspaces Around Dashes WordPress Plugin for Yourself
I only launched the plugin last week, so it hasn’t been downloaded much yet. It’s a niche plugin, for those who really care about typography, so I don’t expect it to become wildly popular, but it’s easy to install and can make your text look a little more sophisticated.
Enter “Hairspaces Around Dashes WordPress Plugin” into the search box on Google (or Bing, Yahoo, DuckDuckGo etc.) and you’ll find it straightaway.
You can also go to the main plugins directory on the WordPress website and search for the word “hairspace”, since it is currently the only result for that query.