Welcome to the last part of this series. If you just arrived, please check our two previous articles. We covered so far the following topics:
Tips for Best Practices in WordPress Development
- WordPress Coding standards
- Avoiding Global namespaces collisions (prefix and use of classes)
- Code commenting
- Security
More Tips for Best Practices in WordPress Development
- Correct way to add Scripts and styles (register, enqueue and localize)
- Ajax calls
- Filters and actions
In this final article, I'm going to talk about three important things that although they don't affect the plugin operation, they are essential if you want to deliver a quality plugin.
1. Debugging
The first thing you should do while coding a plugin is to enable debug mode as WordPress recommends. That way you will see all errors, warning and issues.
To enable debug mode simple place in your wp-config.php
define('WP_DEBUG', true);
Once you reload the site you will see all warning and issues along with other messages like deprecated WordPress functions notices. If you want to deliver a quality product ensure that using your plugin with debug mode enable or disable result in the same thing (no errors, warnings or notices at all).
If you want instead to save the errors to a file and not display them in the HTML you can do it by adding along with WP_DEBUG
the following lines.
// all errors will be saved to a debug.log log file inside the /wp-content/ directory define('WP_DEBUG_LOG', true); // not display errors in HTML define('WP_DEBUG_DISPLAY', false);
Another debug setting that I use a lot that saves all database queries into an array is the following:
define('SAVEQUERIES', true);
Usually I use all these ( specially the last one) with Debug Bar plugin and Debug Bar console. If you don't know them, go and grab a copy and start debugging your plugins and themes. You will see how easy it's to do it.
You can also check the lists of plugins I use for development in Wp Favs.
2. Documentation
Documenting every aspect of your plugin or theme will make your users and your life much easier. They will be able to make the plugin or theme work by following a guide or video or a combination of both and you will save lot of time with support tickets and endless emails.
I recommend to split all the documentation in categories or sections being the most important :
- Installation
- Configuration
- Quick Usage
- Common Problems
- Requirements
Then depending on your theme or plugin you can add the rest of sections or categories. If you check the documentation page of WordPress Social Invitations you will see what I mean.
If you added filters and hooks as I mentioned on the previous article it's a nice idea to create a Filter / Actions reference page explaining what they do.
Helps Tabs
Help Tabs are another way to provide help to your users directly on your plugin, instead of redirecting them to your website. They are normally used to provide info about the screen being use at that moment.
For example, on one of my plugins called Social PopUP I use a help tab to explain the available shortcodes.
If you are using a class in your plugin and you want to add the help tab into a custom post type you could do something like:
/** * Initialize the plugin by loading admin scripts & styles and adding a * settings page and menu. * * @since 1.0.0 */ function __construct(){ [...] //Help Tab add_action( 'load-post.php', array( $this, 'my_admin_add_help_tab') ); } /** * Add help tab to the spucpt post type * @since 1.0 * @return void */ function my_admin_add_help_tab () { $screen = get_current_screen(); if( 'spucpt' != $screen->id ) { return; } // Add my_help_tab if post type is spucpt $screen->add_help_tab( array( 'id' => 'my_help_tab', 'title' => __( 'Shortcodes' ), 'content' => 'Hello content goes here', ) ); }
It's very important that you check that the current screen ID matches your custom post type or the help tab will appear everywhere.
If instead you added an options page you could use the code used as example in the Codex.
<?php add_action('admin_menu', 'my_admin_add_page'); function my_admin_add_page() { $my_admin_page = add_options_page( __( 'My Admin Page', 'map' ), __( 'My Admin Page', 'map' ), 'manage_options', 'map', 'my_admin_page' ); // Adds my_help_tab when my_admin_page loads add_action( 'load-' . $my_admin_page, 'my_admin_add_help_tab' ); } function my_admin_add_help_tab () { $screen = get_current_screen(); // Add my_help_tab if current screen is My Admin Page $screen->add_help_tab( array( 'id' => 'my_help_tab', 'title' => __( 'My Help Tab' ), 'content' => '<p>' . __( 'Descriptive content that will show in My Help Tab-body goes here.' ) . '</p>', ) ); } ?>
In my opinion helps tabs are not very visible to users, and most of them they don't even know that they exists, but it's a good practice to include some help lines inside the plugin itself.
3. Internationalization
Internationalization also known as i18n (there are 18 letters between the i and n) it's the icing on the cake of a plugin or theme. As you already know WordPress it's used by people from all over the world, so at the time of delivering a plugin or theme we need to be sure that they can easily translated it to their native language.
What's the Difference Between Internationalization and Localization?
First, we should learn the meaning of these two words also knowns as i18n and i10n. Internationalization refers to the process of creating a translatable plugin or theme while localization is basically the act of doing it.
How Does WordPress Handle Translations?
WordPress uses the famous gettext library that explained in a few words, we can say that works like this:
- Developers wrap translatable strings in special gettext functions
- Special tools parse the source code files and extract the translatable strings into POT (Portable Objects Template) files
- Translators translate the POT files and the result is a PO file (POT file, but with translations inside)
- PO files are compiled to binary MO files, which give faster access to the strings at run-time.
How Do We Create Translatable Strings?
The first thing you need to do is decide a text-domain that will be used to wrap all your plugin or theme translations. The text-domain should match your plugin slug.
There are multiple ways to create the translatable strings depending if you are creating variables, echoing something, etc. The most common functions are __()
and _e( )
. Let's see some examples below:
// creating a variable $hello = __( 'Hello, Im a translatable string', 'my-text-domain' ); echo '<h2>'. __( 'Hello, Im a translatable string', 'my-text-domain' ) . '</h2>'; // to do an echo you can use _e( 'Hello, Im a translatable string', 'my-text-domain' ); // When you have variables in the string you do: printf( __( 'We deleted %d posts.', 'my-text-domain' ), $count ); // Or multiple variables printf( __( 'Your name is %1$s, and your last name is %2$s.', 'my-text-domain' ), $name, $lastname );
Another cool function that you can use is _n( )
which it's used for plurals. This functions takes 4 arguments:
- singular — the singular form of the string
- plural — the plural form of the string
- count — the number of objects, which will determine whether the singular or the plural form should be returned
- text domain - The plugin text-domain
Coming back to our previous example , with plurals will look something like:
printf( _n( 'We deleted one post.', 'We deleted %d posts.', $count, 'my-text-domain' ), $count );
If, by any chance you need to translate strings in your JavaScript, you can pass all the strings by using the wp_localize_script()
function that we discussed on the second article of this series.
wp_enqueue_script( 'script-handle', … ); wp_localize_script( 'script-handle', 'objectL10n', array( 'alert' => __( 'This is an alert message', 'my-text-domain' ), 'submit' => __( 'Submit', 'my-text-domain' ), ) );
Enabling Translations in Our Plugins
We already added all the translatable string around our plugin and now It's time to enable it. To do that you simple do:
function myplugin_init() { $plugin_dir = basename( dirname( __FILE__ ) ); load_plugin_textdomain( 'my-text-domain', false, $plugin_dir ); } add_action( 'plugins_loaded', 'myplugin_init' );
This piece of code will try to load from the root of your plugin a MO file called my-text-domain-
{locale}
.mo
. Depending on your language settings in wp-config.php the {locale} part will be replaced with your language code. For example if my wp-config.php
is configured like:
define ('WPLANG', 'es_ES');
The file that is going to be loaded is my-text-domain-es_ES.mo
. For themes is pretty similar, you just need to include in your functions.php
the following:
load_theme_textdomain( 'my_theme_textdomain' );
The main difference is that this function will look for {locale}.mo
instead of my_theme_textdomain-{locale}.mo
as we saw on the previous example.
You can read more about l18n in the WordPress Codex.
Conclusion
We are at the end of this series and I hope you enjoyed reading it as much as I did writing it. As I said earlier, I wrote this series thinking about my beginnings as a developer. I tried to collect all the information that I consider important to make a good plugin, summarizing in a large scale all that of what it's already explained in the Codex. Although I have probably left out a lot, I think it's enough to have solid foundation.
I would love to see you sharing your thoughts, tips and ideas for a solid development in the comments.
Comments