Plugin Coding Guidelines

Code Standards

Documentation

Installation Location

  • The primary expected install location for all plugins should be the /plugins/ folder. If it is a multisite plugin and needs to be activated network wide, you should add the “Network: true” header line to it. The plugin should be packaged in a self-contained folder that goes in /plugins/. The only exception to this rule are very specialized plugins that must run from the /mu-plugins/ folder and can’t be designed to work via network activation, like Domain Mapping, Multi-Domains, or a multi-network type plugin.
  • It is important to follow these directions so plugins can be uploaded via the zip file uploader in WP, and via our forthcoming auto-install plugin.

Internationalization

  • Please fully internationalize every plugin with a text domain and the load_plugin_textdomain() or load_muplugin_textdomain() depending where the plugin detects it is installed.
  • Your plugin should include a /languages/ directory and you should keep an updated “TEXTDOMAIN-default.po file. Make sure to update it whenever text strings change.
  • Follow the best practice guidelines http://codex.wordpress.org/I18n_for_WordPress_Developers, especially using sprintf/printf, etc.
  • To translate strings for JS use wp_localize_script(). http://codex.wordpress.org/Function_Reference/wp_localize_script
  • Don’t forget to i18n the plugin header lines! http://jacobsantos.com/2008/general/translate-plugin-headers-in-wordpress-27/

Data Storage

  • For per-blog data, always carefully decide whether you really need to create db tables. In the vast majority of cases, you can get away with using a custom post type/meta and blog option arrays for data storage. You should avoid creating per-blog DB tables at all costs.
  • If custom DB tables are required in a multisite plugin, consider storing all data in a global table using a blog_id and site_id column to segment data.
  • Options – Whenever possible always store options in an array as one blog option. Clogging the options table with 20 options is no good. Also when the plugin is installing be mindful of whether autoload should be set or not. http://codex.wordpress.org/Function_Reference/add_option

Javascript

  • Always use wp_enqueue_script() to add an external script rather than printing via the wp_head/admin_head actions. When enqueueing scripts, be very careful to do it only on the admin or frontend pages where it’s needed. For example for frontend script enqueue with the template_redirect action. For a script needed on a plugin’s admin page(s), use the admin_print_scripts-PAGE hook. http://codex.wordpress.org/Function_Reference/wp_enqueue_script
  • If you need to access dynamic variables in your script use wp_localize_script(). Do not load a dynamic JS script via a php file. http://ottopress.com/tag/wp_localize_script/
  • We try to standardize all our development on the built in jQuery framework, so please enqueue that and use any jQuery plugins for that if needed. Only use other JS frameworks if their is no jQuery alternative.
  • AJAX should use jQuery and always use WP’s built in AJAX handler, admin-ajax.php. http://codex.wordpress.org/AJAX_in_Plugins

CSS

  • Just like javascript, css should be external and added with wp_enqueue_style() only on the pages it’s needed. http://codex.wordpress.org/Function_Reference/wp_enqueue_style
  • For frontend CSS that is enqueued, wrap it in a theme supports conditional so a theme can notify that it includes it’s own css. if ( !current_theme_supports( 'qa_style' ) )
    wp_enqueue_style(xxx);

Security

  • Check Permissions – Always check for a user’s permissions for saving/processing user initiated actions or settings changes. Either via checking current_user_can() with the proper permissions type, or is_super_admin().
  • Check Intent – Always use the Nonce API for saving/processing user initiated actions or settings changes. http://codex.wordpress.org/Wordpress_Nonce_Implementation
  • Filtering Input/Output – You should always validate data input from admin pages. Data output in admin pages should use the esc_attr() or esc_html() functions. In WordPress and especially multisite, you must be very careful to filter anything that will be outputted to avoid XSS vulnerabilities. For content areas, check for the current_user_can(‘unfiltered_html’) permission, and if they can’t, run it through the wp_filter_post_kses($data) function.
  • SQL Injection – When running SQL queries, always use the $wpdb methods, $wpdb->prepare() and $wpdb->escape(), or use the built in insert() or update() methods. http://codex.wordpress.org/Function_Reference/wpdb_Class