WordPress Developers: This One Thing Made Me Thousands This Year

Like my grandma always said.
Like my grandma always said.
You want to stand out, get noticed, and make more money? Be nice.

I’m a freelance WordPress plugin developer who is maniacal about polite, prompt support ticket response. So far it has made me about $3000 over the last 10 months, plus one brand called about acquiring me and my plugin.

Free product + free support + prompt polite developer = $$ + opportunity

So many support requests come across my desk begging for a  “YOU SHOULD HAVE READ THE BLEEPING MANUAL” response.

Face it:

  1. People don’t read FAQs.
  2. People don’t scour forums for answers.
  3. People certainly don’t pay for support for a free plugin.

Instead, they open the support forums, create a new topic (or worse, tack their request onto the end of a resolved ticket), and blast off the same inane support request that you’ve answered (what feels like) 250 times.

That request may frustrate you, because you are the one who has answered it (what feels like) 250 times. This user? They’ve never come across it, and you have one chance to help them have a good first impression of you.

So far, I’ve gotten 3 monthly recurring clients for backups, maintenance, and now even hosting, from being nice to a stranger on the forums for my free plugins.

I’m working on a pretty great conversion rate, too. 19 tickets for one plugin and 30 tickets for the other, with 3 monthly clients now representing roughly $200 in recurring revenue, so far. That doesn’t count the handful of one-off code fixes and other things that I’ve contracted to do for folks after first meeting them in the forums. Those have grossed about $2000 total so far.

My oldest plugin is not even a year old yet. Could you handle an extra $3000 in your pocket* from being nice this year?

Could you handle an extra $3,000 in your pocket from using a grade-school trick? Share on X

Start by acknowledging that you’ve forgotten what it’s like to be an outsider to the WordPress community, and a novice user. Then answer every question like it’s your best friend asking it.

Just because you know to check the FAQ, do a simple Google search, or run down a list of possible solutions to the problem doesn’t mean that your users will, or even should.

My first inclination when I run into requests that are absurd or that could have been easily answered with a lmgtfy.com link is to assume the user is intentionally trying to be a jerk. They clearly know they are freeloading, and expecting not only a premium quality product, but also 24-7-365 service on that product, for free.

But that’s the thing: In most cases, the user has no idea they are being unreasonable, and if you gently answer the question you go a long way toward helping them to see their own absurdity.

Most of the time, novice users don't know their free support requests are unreasonable. You have to teach them. Share on X

Now, I don’t mean you need to get walked all over by entitled users who think everything should be free. A stock phrase I use often in support requests is “that falls outside the scope of the free support I’m able to offer here.” (coincidentally, that’s the exact phrase which has led to multiple ongoing financial relationships)

But I suppose this is all still anecdotal at this point, but it sure seems like the way any developer can stand out (and make some great spare coin) is to decide to be nice. I can assure you of one thing: here inside the anecdote, it’s quite pleasant.

*the governments of both these United States and my specific state of North Carolina have conspired to take (at gunpoint) 36% of those earnings. Because the alternative way to generate revenue—when being nice doesn't work—is forcibly taking it with the support of (unjust) laws. So my $3000 looks conspicuously like $1920 by the time it reaches my pocket. Your results may vary.

How To Internationalize TinyMCE Plugins in WordPress Plugins

To internationalize a TinyMCE button/plugin within a WordPress plugin, you have to interface with the TinyMCE API as well as the normal methods for i18n in WordPress. I didn’t find much help in figuring it out, so I decided to document my findings.

For the purposes of this tutorial, we are working with my Better Click To Tweet WordPress Plugin, which adds a button to the visual editor for users to add a Tweetable Quote to their posts.

Swap out hard-coded strings in the .js file

In the original js file, I have 5 strings that are in need of being translated. Let’s look at the first one: the ToolTip (line 8 of the file). Instead of hard-coding ‘Better Click To Tweet Shortcode Generator’ as in the original js file, I need to substitute

editor.getLang( 'bctt.toolTip', 'Better Click To Tweet Shortcode Generator' ),

Which tells the machine “Find ‘bctt.toolTip’ within the list of translatable strings loaded in TinyMCE, and echo that here.”

The optional (included) second parameter in the getLang() function gives a default text to fall back to, in this case “if you can’t find anything, echo ‘Better Click To Tweet Shortcode Generator'”

Repeat that process for all translatable strings in the .js file, giving them unique names.

Put the translatable strings into the php

Now we’ve told it to translate them within the js file, but there are two problems we need to solve:

  1. Put the translatable strings in the php somewhere, so that our .po and .mo files can get to them to translate them.
  2. Add the translatable strings to TinyMCE.

To solve problem one, create a file to store the strings in. In our case, I made a file named bctt-mce-locale.php.

Here’s the content of that file:

$strings =
	'tinyMCE.addI18n( 
		"' . $mce_locale .'.bctt", 
			{
			toolTip : "' . esc_js( _x( 'Better Click To Tweet Shortcode Generator', 'Text that shows on mouseover for visual editor button', 'better-click-to-tweet' ) ) . '",
			windowTitle : "' . esc_js( _x( 'Better Click To Tweet Shortcode Generator', 'Text for title of the popup box when creating tweetable quote in the visual editor', 'better-click-to-tweet' ) ) . '",
			tweetableQuote : "' . esc_js( _x( 'Tweetable Quote', 'Text for label on input box on popup box in visual editor', 'better-click-to-tweet' ) ) . '",
			viaExplainer : "' . esc_js( _x( 'Add \"via @YourTwitterName\" to this tweet', 'Text explaining the checkbox on the visual editor', 'better-click-to-tweet' ) ) . '",
			viaPrompt : "' . esc_js( _x( 'Include "via"?', 'Checkbox label in visual editor', 'better-click-to-tweet' ) ) . '",
			} 
  		);
  	';

This file is using the tinyMCE function addI18n() and making an associative array containing the translatable strings. The _x() allows me to add an explanation as the second parameter, to give translators some context for where this text appears in the plugin.

Each new .mo/.po file included in the main plugin’s language folder adds a new mce locale thanks to the $mce_locale variable in the third line.

Load the strings into TinyMCE

Now we are almost there. Our strings can be translated by .po and .mo files, but they are still not being added as external languages to TinyMCE. Luckily, there’s a filter for that.

In the same file that registers the TinyMCE plugin, we need to hook into the filter at mce_external_languages with a function that returns the location of our new file. That looks like this:

public function tinymce_loader() {
add_filter( 'mce_external_languages', array( __class__, 'bctt_tinymce_languages' ) );
}

public static function bctt_tinymce_languages( $bctt_locales) {
    	$bctt_locales[ 'bctt' ] = plugin_dir_path( __FILE__ ) . '/languages/bctt-mce-locale.php';
  		return $bctt_locales;

That’s it! Make sure that the path to the newly created file is correct, and you are good to go!

I have disabled comments, but if you have comments or questions, the contact form below will get to me. Thanks!

How to Switch Plugins from Click to Tweet by CoSchedule to Better Click To Tweet

So I’ve convinced you that switching plugins from Click to Tweet by the folks over at TodayMade (the makers of the top-notch content marketing editorial calendar CoSchedule) is worth it. But what about all of those tweet quotes you’ve already added to dozens (if not hundreds) of blog posts?

Going back through to switch each quote manually is a huge headache at best, or a deal-breaker at worst.

This is a tutorial for how to do it in fewer than 10 minutes, with one plugin and a few clicks.


Warning: read carefully, and you should be fine. Skip ahead and you could irreparably (translation, I can’t fix it even if I wanted to) damage the database, and mess up everything.


The first thing you’ll need to do is download and configure the Better Click To Tweet plugin. The two plugins should peacefully coexist, so don’t uninstall the old plugin until the end of this tutorial.

Next, before you do anything on WordPress (especially related to the database) always take a full backup, stored on your local computer (or some cloud backup server). I trust you understand that backups are a non-negotiable must-have for anybody who wants to keep anything they’ve ever said on their website, so this is more fundamental than the scope of this tutorial.

There are several solutions out there for backups, the most respected being VaultPress (made by the folks over at Automattic, the step-parent of WordPress).

I have also used BackupBuddy from iThemes, and have heard great stuff about Migrate DB pro. I don’t care how you back everything up, just that you DO back everything up. (shameless plug: I offer that as a service) Also, it’s worth having a test site to make sure you know how to restore from that backup.

Please don’t skip this step, because I won’t be able to help you get back everything if you do something even just slightly wrong.

::climbs down off of soapbox::

Now, for a bit of a basic lesson on how WordPress works. The database stores all of the words on your site, including pages, posts, and other content. For our purposes today, we are looking to find every instance of the old Click To Tweet code that looks like this:

[Tweet "Some tweetable quote..."]

And replace it with our nice new Better Click To Tweet WordPress shortcode:

[bctt tweet="Some tweetable quote..."]

Note that all we need to replace is the beginning portion of the old pseudo-shortcode. Everything after (and including) the first quotation mark can remain unchanged.

To make that change, we need to do what is appropriately called a “search and replace” on the database. There are several plugins in the official WordPress.org repository that claim to be able to make the changes. The one I have used and recommend (despite the fact that it has the ominous WordPress warning “this plugin has not been tested with your version of WordPress”) is Search Regex.

Install the plugin, make sure you’ve gotten a full backup that you can confidently restore from, and configure the plugin like so (this page can be found under the “Tools” menu in your admin area):

You can't see it, but I did put the space in the first box after the word "Tweet." I don't know if it matters or not.
You can’t see it, but I did put the space in the first box after the word “Tweet.” I don’t know if it matters or not.

The first time around, click the replace button, and scroll down to see the proposed changes. If those look right (make sure that the spacing is correct in the new shortcodes!), scroll back to the top and click “Replace and Save.”

As they say in France, “Voila!” You have upgraded your Click To Tweet experience, and future-proofed your WordPress site!

You may now (after you verify that everything looks satisfactory on the front end of your site) safely deactivate and uninstall the Click to Tweet plugin by TodayMade.

If you run into any issues, restore from the backup I insisted you make above, start a thread on the support forums (so that everyone can benefit from our back-and-forth), and I will happily help you get switched over!

Welcome to the Better Click To Tweet family. Why not let others know how great it is:

I just switched to Better Click To Tweet with the help of this tutorial! Share on X

What the Marine Radio Taught Me About WordPress Development

“I don’t even turn the thing on. Too many commercial charter captains yammering on about nothing” my uncle said, motioning toward the CB radio tucked under the dash of his fishing boat.

That day, we caught 5 Mahi-mahi, the longest of which clocked in at over 45 inches.

<img class="wp-image-347011458 size-full" src="https://benandjacq.s3.us-west-2.amazonaws.com/wp-content/uploads/2015/06/16110000/Featured-image-benandjacq-8.png" alt="That was a fun day on the water. Yes, I really caught those fish." width="500" height="500" srcset="https://s3-us-west-2.amazonaws.com/benandjacq/wp-content/uploads/2015/06/16110000/Featured-image-benandjacq-8 try here.png 500w, https://benandjacq.s3.us-west-2.amazonaws.com/wp-content/uploads/2015/06/16110000/Featured-image-benandjacq-8-150×150.png 150w, https://benandjacq.s3.us-west-2.amazonaws.com/wp-content/uploads/2015/06/16110000/Featured-image-benandjacq-8-300×300.png 300w, https://benandjacq.s3.us-west-2.amazonaws.com/wp-content/uploads/2015/06/16110000/Featured-image-benandjacq-8-50×50.png 50w” sizes=”(max-width: 500px) 100vw, 500px” />
That was a fun day on the water. Yes, I really caught those fish.

Fast forward two days. My uncle decided to pay a professional to take us out fishing for Cobia. “That’s how you learn” he said to me, winking.

On the charter boat the CB radio was featured prominently, with our captain contributing to the banter about where the good spots were, and where to avoid. Much of the back-and-forth was punctuated by our captain telling us—off-air—how full of sh** the guy on the other end of the radio was.

We went on to catch exactly zero Cobia that day, with a pro. An insider.

There are insiders and outsiders in every field.

I’ll take being a CB radio outsider with a cooler full of Mahi-mahi any day.

As a old-enough-to-know-better WordPress developer, I find myself approaching communities like the core development Slack channel and the Advanced WordPress Facebook group with a certain level of intimidation, knowing that my piping up there is akin to the rookie fisherman weighing in over the marine radio on the best brand of spinning reel–marginally helpful at best.

So I mostly just keep my head down, and keep reeling in the Mahi-mahi of engaged, happy users and raving five-star reviews.

There’s a place for contributing and collaborating, some day. But until I’ve got a few more fish in the cooler, it’s best for me to focus on fishing.

The 2 Broken Yardsticks in Most DIY WordPress Users’ Toolbox

Original Image licensed under Creative Commons.
Original Image licensed under Creative Commons.

Which WordPress theme you choose has the ability to make or break you.

  1. A good theme can’t help you nearly as much as a bad theme will hurt you.
  2. A good theme makes WordPress a stable, scalable, and cost-effective way to run your business.
  3. A bad theme makes WordPress a slow-loading joke in the developer community, full of security holes and inefficient code.

So have I convinced you yet that picking the right theme is not just window dressing?

If so, keep reading for how to pick a good theme.

Where most novices go wrong is picking the theme using two broken yardsticks: Looks and Popularity.

The first broken yardstick is looks. Like a supermodel with no ability to carry on a conversation, people will leave a website that loads too slowly or doesn’t look right on their device.

“It’s pretty, buuuut…“

The second and more tragic yardstick beginners use is popularity. Novice users flock to cheap prices, and to more features. It sounds great to say “160 color options” or “drag and drop customization,” but if those “features” are adding bloat to your website, making it load slowly or confusing your readers, they are not worth the price, no matter how cheap.

Repeat after me: just because 9,000,000 others have downloaded the theme doesn’t mean you should too. Your mother’s advice about jumping off of a bridge works well here.

This is not an indictment of cheap themes, or even popular themes. I recently recommended and installed a $100 theme on a client site. (yes, $100 is cheap) There are great themes out there for $50-$100, but the most popular ones out there are often the ones so loaded with “features” that you can forget about performance.

So, apart from a personal recommendation of a developer, how does a newbie pick a good theme?

For starters, that personal recommendation is not out of the question. It might be worth asking a developer you respect for their opinion. I am more than happy to make a recommendation before you spend $50 and commit to a theme that doesn’t do what you want in an efficient way. I’ve yet to find a theme I didn’t like officially recommended by the folks at StudioPress. They use the Genesis framework, which is a clean, lean way to build a WordPress site. If you are looking for my affiliate link, that would be http://benlikes.us/genesis (but read the rest of this article before you go buy even a StudioPress theme.)

I’ve spent too many hours trying to fix bad code on slow, bloated themes. I’d rather you not have to pay me $100 per hour to fix your $50 theme.

Second, if a theme is seeking to be one-size-fits-all, it’s probably a red flag. Look for a theme designed specifically for the niche you are in. Real estate professionals need different things from their website than do video game reviewers. Their themes should reflect that.

This is so important I probably should have led with it: Before you purchase a theme, you should have a clearly defined primary goal of the website. Then find a theme that does that one thing really well. Some example of primary goals would be

  • Increasing brand awareness
  • Getting people to sign up for your product emails
  • Behind-the-scenes looks at your business
  • Communicating with existing customers
  • Providing support
  • Doing product reviews
  • Create a digital scrapbook of family memories

There are other great reasons to have a website. Here’s a bad one: because you just feel like you need a site that looks cool.

Nope. Just nope. I will no longer make a site for someone who can’t tell me their primary goal.

Finally, if all of the promo material for a theme stresses how customizable it is, and no mention is made of how lightweight, or fast loading, or efficient it is, that’s also a red flag. Good developers are very proud of how fast their designs are. They’ll likely tell you about it in the promo material.

The best marketers out there will tell you that content is king on the web. High quality content is the only thing that will keep people (and uncle Google) coming back to your site. But even if you put $10K per month into content, a slow-loading website will slow your traffic to a trickle.

So those marketers are correct, it’s the content that keeps them. Is your theme making that content consumption easier or harder? Focus on the user experience, and showcasing the content as quickly and effectively as possible.

Whatever you do, don’t focus on looks and popularity. That’s a shortcut to picking a theme that will break your heart and your wallet.