Some More Lessons Learned From Publishing My First WordPress Plug-in

Plugging InIt’s been two months now since I published my first WordPress Plugin. Further to my last post on this subject, I am now in a position to share a few more lessons learned.

Subversion

WordPress uses Subversion (SVN) repositories to manage the code for it’s hosted plugins and themes. I use GIT to manage my own code (and I love it BTW), so SVN was a new animal for me. These are some important points to note when using the SVN repositories on wordpress.org:

  • The SVN TRUNK is equivalent to the master branch in GIT.
  • You can store your code in TRUNK and optionally TAG each version that you upload to the repository.
  • The stable tag that you refer to in your plugin’s readme.txt file is very important. As its name suggests, it points to the tag that is stable and is the version that will be downloaded by your user when they click the download button.
  • The stable tag can refer to TRUNK, so any code you upload to TRUNK immediately becomes the downloadable code.
  • A much better way to operate is to have the stable tag refer to an actual TAG (e.g. “1.23”) and then use the TRUNK to store your development version. When you are ready to do a new release simply create a new TAG from the code in TRUNK. Check all is well and then update the stable tag as a second step. This is the approach I use. I note that the SVN notes by WordPress suggest that this should be done as a single step, but I prefer the two-step approach, for safety.
  • You can update the code in a TAG in the same way that you can update the code in the TRUNK, just place your files in it and then call svn ci -m 'message'.

Here is a useful link for using SVN with WordPress.

Apply Your WordPress Filter For The Shortest Time Possible

This is a lesson learned through resolving a conflict with a theme (in beta release at the time, so we shall forgive). The said theme had placed a filter in it’s functions.php file to override the ‘from’ address for all emails sent by WordPress with the function wp_mail():

add_filter ('wp_mail_from', 'do_mail_from',10,1);

Because this filter was applied in functions.php it had a site-wide effect, and therefore had an effect on any module that also used the wp_mail() function, of which my plugin was of course one. The consequence of this is that I had a user contact me to say that all the emails he received via the contact form appeared not to come from his enquirer, but from the WordPress administrator instead, pretty useless if you want to be able to reply back!

So the moral of this story is, that in order to play nice with your fellow plugins and themes, always apply filters that don’t need to be site wide at the last moment possible, and then remove as soon as possible.

As a result, I now employ the filter method of setting the ‘from’ address, but the difference is I apply it at the latest convenience and remove it at the earliest :

//apply filters
add_filter('wp_mail_from','my_mail_from_addr',10,1);
add_filter('wp_mail_from_name','my_mail_from_name',10,1);

//send mail
wp_mail('[email protected]' , 'You Got Mail', 'Please reply asap');

//play nice and remove filters
remove_filter('wp_mail_from','my_mail_from_addr',10,1);
remove_filter('wp_mail_from_name','my_mail_from_name',10,1);

Internationalisation

WordPress has users all around the world. If you want your plugin to be used in more than one country then you need to put in a few simple changes. If you build this in at the start then it is even easier.

Here is a quick guide:

  • To mark a string in your code as translatable simply place it in __('string to translate','textdomain'); or _e('string to translate','textdomain'); if you want to echo. You obviously only need to do this for strings that are to be displayed to your user.
  • The textdomain tells WordPress that the text belongs to your plugin, I used the text domain ‘cleanandsimple‘ for my contact form plugin.
  • Don’t try to get clever (as I did and had to change it back!) by putting your text domain in a variable. You must hard-code it each time.
  • Once you have done this for all your displayable strings you need to create a POT file. If your plugin is hosted on wordpress.org you can go to the ADMIN section on your plugin page to generate it.
  • Put the POT file e.g. cleanandsimple.pot in your plugin code. A good place would be in its own folder called /languages
  • Load the text domain in your plugin:
function RegisterTextDomain() {  
     $path = '/' . CSCF_PLUGIN_NAME . '/languages'; 
     load_plugin_textdomain('cleanandsimple', false, $path ); 
}
  • That’s it.

The next thing I did was to wait until one of my users requested the plugin in their own language. All I had to do was direct them to the POT file and ask them to fill in the empty strings with their translation to produce a PO file, e.g. cleanandsimple_de_DE.po for the German language. Then compile the .PO file into a .MO file. Compilation can be done using the msgfmt utility which can be installed on an Ubuntu machine with the command sudo apt-get install gettext.

Much more information on this subject can be found here.

Use A Namespace When Registering CSS and JS Files

For those new to the term namespace, a namespace is a method used to separate the code between two modules so that naming conflicts cannot occur. PHP 5.3 allows classes to be namespaced but since WordPress advises that the minimum version is less than this, then it is best not to use this behaviour unless you can be sure that your end users are on a minimum of PHP 5.3.

So we can’t use the official namespacing behaviours of PHP, but we can implement namespacing to a point. For example, by preceding all class names with a (hopefully) unique word. For my contact form I use CSCF_ before all my class names.

The same principle applies when registering the CSS and JS files that you include with your plugin.

I made the mistake of registering my CSS file for the contact form as ‘bootstrap’:

wp_register_style('bootstrap', CSCF_PLUGIN_URL . '/css/bootstrap-forms.min.css', null, '2.3.1');

This was fine until one of my users was using a theme that registered a CSS file with that name too. Because my CSS was registered last it was the one that was enqueued instead of the theme’s version and ended up causing the site to break.

The situation was resolved by namespacing:

wp_register_style('cscf-bootstrap', CSCF_PLUGIN_URL . '/css/bootstrap-forms.min.css', null, '2.3.1');