Below you will find the coding best practices and standards that the AppThemes development team uses. It’s a continuously evolving document and will improve over time.
WordPress Core
The Automattic team put together their own Coding Standards manual which is a great place to start. It’s the de-facto standard used in the WordPress product code so we highly recommend following it (we certainly do).
Source Code Repository
We never start a new theme or plugin without having first setup a repository in a version control system. Our tool of choice is Git and hosted on Github.
Another popular web-based Git repository hosting service is BitBucket, although we highly recommend Github so you can interact directly with our repos (if you’re a Marketplace seller).
Theme Development
Before beginning any theme development, it’s important to make sure your theme includes all the necessary templates, styles, functions, and other items. The WordPress Codex has a great page on these theme standards so we always start here.
We also recommend starting with an existing theme like Underscore S (_s), which is a starter theme provided by Automattic. It’s a great theme to get you going and to help speed up development time.
Debugging
Ensuring that our themes are properly tested before they are rolled out is crucial. While you are developing it is recommended to have the WordPress Debug mode turned on. This allows you to see and fix any PHP errors, notices, and/or warnings. To enable debug mode, enter the following constant declaration in your wp-config.php file.
define('WP_DEBUG', true); |
We also recommend installing a couple of useful developer plugins (written and used by WordPress core contributors) to aide in debugging and optimization.
- Debug Bar – Adds a debug menu to the admin bar that shows query, cache, and other helpful debugging information.
- Debug Bar Console – Adds a PHP/MySQL console to the debug bar. Requires the debug bar plugin.
- Log Deprecated Notices – Logs the usage of deprecated files, functions, and function arguments. Then offers the alternative if available and identifies where the deprecated functionality is being used. You’ll also need to add these constant declarations in your wp-config.php file for them to work properly.
define('WP_DEBUG_DISPLAY', false); define('SAVEQUERIES', true); |
You should now see a new button in the top right corner of your admin bar called “Debug”.
Unit Testing
It’s important to unit test your entire theme before making it available to the public. Most theme developers fail to do this and it later comes back to bite them in the butt. Unit testing allows you run through a pre-defined list of items that need to be tested.
WordPress graciously provides the steps and data to import and test against. Read the instructions on the theme unit testing Codex page to get started.
Theme Review
After going through the theme unit testing above, it’s time to run down the theme review checklist. This guide lists out everything that should be included in your theme.
After you check off everything on that list, the next steps is to send your theme through the theme meat grinder. The Theme Check plugin is the perfect tool just for that. It searches your theme for things like deprecated functions, notices, missing functions/declarations, etc. A summary is then provided so you can go back and fix/tweak as needed.
Actual Code Examples
Below you will find example code and how to use it.
Conditional Statements
If Else
When writing if….else statements, always make sure to indent the code to be executed between each section. Also don’t use {} if you don’t need to. Note the spacing between the parentheses and after the “if”.
if ( condition ) echo 'true'; // code to be executed if condition is true else echo 'false'; // code to be executed if condition is false |
Loops
Make sure to always use brackets {} (instead of : and endif;) when setting up loops. This makes it much easier to see what’s happening inside the code block. It can easily get messy when you have if statements and other logic within the loop.
// foreach loop foreach ( $results as $key => $value ) { // do something here } //while loop $i = 1; while ( $i <= 5 ) { // do something here } |
Data Escaping & Sanitation
Making sure our themes are secure is top priority. All data input and output needs to be escaped and sanitized. Escape as late as possible, ideally right before it’s displayed on the screen. Here are the WordPress functions that should be wrapped around variables.
Escape any text that appears within html
esc_html( $text )
Example
echo '<h1>' . esc_html( 'Blog Posts', 'appthemes' ) . '</h1>'; |
Echo and escape any text that appears within html
esc_html_e( $text )
Example
<label for="nav-menu"><?php esc_html_e( 'Select Menu:', 'appthemes' ); ?></label> |
Encode text for use inside a textarea element
esc_textarea( $text )
Example
<textarea rows="5" cols="5"><?php echo esc_textarea( $comment->comment_content ); ?></textarea> |
Escape values that are html attributes
esc_attr( $text )
Example
<input type="submit" name="Submit" value="<?php esc_attr_e( 'Activate', 'appthemes' ) ?>" /> |
Echo and escape values that are html attributes
esc_attr_e( $text )
Example
<a href="http://www.appthemes.com" title="<?php esc_attr_e( 'Visit Site', 'appthemes' ) ?>"><?php esc_html_e( 'Visit Site', 'appthemes' ); ?></a> |
Sanitize URLs
esc_url( $url )
Example
$img = '<img src="' . esc_url( admin_url( 'images/comment-grey-bubble.png' ) ) . '" />'; |
Escape javascript strings
esc_js( $text )
Example
<script type='text/javascript'> /* <![CDATA[ */ var pwsL10n = { empty: "<?php echo esc_js( __( 'Strength indicator', 'appthemes' ) ); ?>", short: "<?php echo esc_js( __( 'Very weak', 'appthemes' ) ); ?>", }; try{convertEntities(pwsL10n);}catch(e){}; /* ]]> */ </script> |
See the WordPress Codex for more details and a list of all data validation functions.
Database Escaping
To prevent SQL injections into the database, you always want to wrap your sql statement with “$wpdb->prepare” This escapes the data so malicious users cannot compromise the server. This is probably one of the most overlooked security issues when it comes to plugin and theme developers.
Here’s an example of how you would use the built-in WordPress escape function:
$thepost = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $wpdb->posts WHERE ID = 1" ) ); echo $thepost->post_title; |
Post Types & Taxonomies
Any time a custom post type or taxonomy is used, a CONSTANT needs to be defined in theme-functions.php. There should never be a hardcoded post type or taxonomy anywhere else in the code. This makes it easy for other developers or non-native English speakers to change.
It also needs to be setup to allow customers to override it. Adding the !defined check before the constant is defined will allow them to do this.
// defined in theme-functions.php if (!defined('APP_POST_TYPE')) define('APP_POST_TYPE', 'ad_listing'); if (!defined('APP_TAX_CAT')) define('APP_TAX_CAT', 'ad_cat'); if (!defined('APP_TAX_TAG')) define('APP_TAX_TAG', 'ad_tag'); An example of when you'd call this constant is a page: // get all custom taxonomy category terms echo get_the_term_list($post->ID, APP_TAX_CAT, '', ', ', ''); |
Code Comments
We all know that most developers hate writing documentation. We also know how annoying it is trying to reverse engineer a function that doesn’t have comments. Comment your code. Comment your code. Comment your code. It will help you the next time you come back and work on it and it’ll help others too.
Here’s an example of how you should write comments in your code. Notice the main description, variable declaration, and comment within the actual function. This format is recognized by some IDEs and it also makes automatically generating docs with software like phpDocumentor a snap.
/** * This is the description of the function. * * @global string $app_edition */ function appthemes_cool_function() { global $app_edition; // this will print out the $app_edition value echo $app_edition . ' is such a cool function!'; } |
jQuery Code Standards
In order to use the default jQuery shortcut of $, we need to set the $ as an alias like such:
jQuery(document).ready(function($) { // $() enter your normal jQuery code here using $ instead of jQuery declaration each time }); |
If you want the code to execute immediately (instead of waiting for the DOM ready event), then you can use this wrapper method instead:
(function($) { // $() enter your normal jQuery code here using $ instead of jQuery declaration each time })(jQuery); |
Localization Standards
All text throughout the theme files need to be wrapped in localization tags. The standard name we use is, appthemes.
// echo out the text on the page <?php _e('Here is some text', 'appthemes') ?> // return the text instead of echoing <?php __('Here is some text', 'appthemes') ?> |
Variable Placeholders
In some cases you will have variables within sentences. Instead of having to breakup the sentence and create multiple _e strings, you can use a couple of nifty php functions, sprintf() and printf() which allow variable placeholders. The difference between the two functions is that sprintf returns a string and printf() echos it on screen.
When you have just one variable within a text string you’ll want to substitute it was a placeholder. In this case it’s a digit so we’ll use the %d.
$count = 30; printf( __( "There are a total of %d coupons available.", 'appthemes' ), $count ); |
This would output, “There are a total of 30 coupons available.”.
$sitename = 'Widgets'; printf( __( "Welcome to the %s website.", 'appthemes' ), $sitename ); |
This would output, “Welcome to the Widgets website.”.
Here’s an example of how to use two variables within a text string called argument swapping. Notice that the text string is wrapped in single quotes instead of double quotes. This is required otherwise it won’t work.
$post_id = 30; $address = '123 Main St'; printf( __( 'Your post id is: %1$s. Your address is: %2$s.', 'appthemes' ), $post_id, $address ); |
This will output, “Your post id is: 30. Your address is: 123 Main St.
Now what about those cases when you have plurals? The most common occurrence, is with the comments text in WordPress themes. Fortunately WordPress contains a special function _n to handle this. The function accepts four arguments: singular string text, plural string text, variable, and text domain.
printf( _n( "We deleted %d spam message.", "We deleted %d spam messages.", $count ), 'appthemes' ); |
For a full list of formats allowed, see the PHP sprintf manual. The most commonly used formats are %s and %d.
JavaScript
Text strings within Javascript also need to be translated but the above method won’t work. In this case, you’ll want to use a specifically designed WordPress function called wp_localize_script to handle these.
For example, we have two files called theme-scripts.js and functions.php. The text we want to translate using this function is in theme-scripts.js.
Here’s the line of code in the .js function we changed. It includes a special javascript variable called theme_scripts_loc.sendEmailTrue which we declared in cp_theme_scripts_localization php function. Since php executes before Javascript, the wp_localize_script will declare those variables in the head so the included theme-scripts.js file loaded afterwards can reference them later.
$('.comments').append('<p>' + theme_scripts_loc.sendEmailTrue + ': ' + val.recipient + '</p>'); |
Here’s the wp_localize_script function that we added to our functions.php file.
// localized text for the theme-scripts.js file function cp_theme_scripts_localization() { wp_localize_script( 'theme-scripts', 'theme_scripts_loc', array( 'sendEmailTrue' => __('This coupon was successfully shared with', 'appthemes'), 'sendEmailFalse' => __('There was a problem sharing this coupon with', 'appthemes') ) ); } add_filter( 'wp_print_scripts', 'cp_theme_scripts_localization' ); |
So the next time you have another text string within your Javascript file that you need to translate, just add it to the cp_theme_scripts_localization function and the new variable name to your .js file. Done.
Displaying Numbers & Dates
When echoing out numbers and dates to the screen, it’s important to wrap them with special WordPress functions. These functions are number_format_i18n and date_i18n. This ensures that the number and date gets correctly displayed based on the localization (native language format) of the site.
echo 'Total Customers Today:' . number_format_i18n( $customers_today ); |
Total Customers Today: 1,035
echo 'Member Since:' . date_i18n( get_option('date_format') ); |
Member Since: 3/16/2015
When saving dates in the database, the easiest way is to use the WordPress built-in function, current_time(). This automatically factors in the time offset of the current blog’s setting.
echo current_time('mysql'); |
2014-07-09 12:58:51