Mistakes in WordPress plugins and how to avoid them

With great power comes great responsibility. WordPress offers a splendid base for developing plugins but from time to time, as plugins developers, we make small, honest mistakes that can have repercussions on our users. Below we’ll try to identify them hoping not to repeat and avoid them at all times.

PHP Notices

Most times they don’t really break anything but are just annoying and fill up server errors log unnecessary. Maybe not a big deal for small WordPress powered websites but for websites having a relatively large number of visitors every day, logs get crowded and server space gets wasted.

Best way to identify notices is to set WP_DEBUG true on development servers. Seems like common sense but over the time I’ve seen plenty of plugins that weren’t developed this way. By default debug is off, to enable it edit file wp-config.php and look for this piece of code:

/**
 * For developers: WordPress debugging mode.
 *
 * Change this to true to enable the display of notices during development.
 * It is strongly recommended that plugin and theme developers use WP_DEBUG
 * in their development environments.
 */
define('WP_DEBUG', false);

All that needs to be done is to define WP_DEBUG constant as true:

define('WP_DEBUG', true);

A more comprehensive article on WordPress debugging can be found in here: Debugging in WordPress.

Common scenarios

  • Array index is undefined:

    if( $array['someIndex'] ){
    // do something if index exists
    }
    

    The above will trigger a notice. To avoid it, first check that the index exists. There are various ways to do this, let’s just use isset()

    if( isset( $array['someIndex'] ) && $array['someIndex'] ){
    // do something here
    }
    

    All the above also applies to $_POST and $_GET variables. The scenario in this case would look something like this:

    // check variable from POST
    if( $_POST['someVar'] ){
    // do something here
    }
    

    A better way would be to first check that the variable is actually set (meaning for example, that the form sending the variable was submitted):

    // first, check that the variable is set
    if( isset( $_POST['someVar'] ) ){
    // process the value submitted
    }
    
  • WordPress functions with deprecated arguments will always issue a notice. Let’s take as example the functions for creating administration menu pages:

    // add an options page in WordPress administration under Settings
    add_options_page(
    	__( 'Page title' ), 
    	__( 'Menu title' ), 
    	8, // deprecated capability argument
    	'menu_slug',
    	'callback_function'
    );
    

    The above piece of code will issue a notice for the capability argument:

    Notice: has_cap was called with an argument that is deprecated since version 2.0! Usage of user levels by plugins and themes is deprecated. Use roles and capabilities instead.

    This error is very common in older plugins that weren’t recently updated or even if they were, the author didn’t updated the capabilities. The correct way to use capabilities would be:

    // add an options page in WordPress administration under Settings
    add_options_page(
    	__( 'Page title' ), 
    	__( 'Menu title' ), 
    	'manage_options', // we use manage_options capability since it's a settings page
    	'menu_slug',
    	'callback_function'
    );
    

    More details on roles and capabilities can be found on Roles and Capabilities codex page.

  • WordPress deprecated functions:

    Notice: deprecated_wp_function() is deprecated since version XX! Use new_wp_function() instead.

    Again, this is an error that happens most times in older plugins either because they they weren’t updated or the author missed to update to the new function. All deprecated functions in WordPress can be found in file wp-includes/deprecated.php.

  • Using WordPress functions the wrong way

    In this case, a WordPress function is used into the wrong context. One example would be to use conditional query tags ( is_front_page(), is_feed(), is_comment_feed(), …etc ) before the query is run.
    This will issue a notice but in this case things are a bit worse because the conditional function will return false. So, if you need to check if a page is indeed front page and do it the wrong way, is_front_page() will always return false.
    Without debug on, this error would pass undetected and your plugin would be flawed.

Plugin scripts and styles

  • Assets in administration pages

    Most plugins use stylesheets and JavaScript files for both aspect and functionality. One thing that gets overlooked though is the fact that ONLY the plugin that loads them needs them. Not to say that loading scripts in all WordPress administration can break things and end up in different plugins having compatibility issues.

    In administration, to avoid conflicts, always load scripts only where needed. One way to do this is by using custom hooks. Let’s take the following example:

    // add plugin page
    function my_menu_page(){
    	// add an options page in WordPress administration under Settings
    	$my_settings_page = add_options_page(
    		__( 'Page title' ), 
    		__( 'Menu title' ), 
    		'manage_options', 
    		'menu_slug',
    		'callback_function'
    	);
    	// add styles only on our page
    	add_action('admin_print_styles-'.$my_settings_page, 'my_styles');
    	// add scripts only on our page
    	add_action('admin_print_scripts-'.$my_settings_page, 'my_scripts');
    }
    add_action('admin_menu', 'my_menu_page');
    
    // callback function for admin_print_styles-$hook_suffix
    function my_styles(){
    	wp_enqueue_style($handle);
    }
    
    // callback function for admin_print_styles-$hook_suffix
    function my_scripts(){
    	wp_enqueue_script($handle);
    }
    

    Another very handy custom hook is load-$hook_suffix. Similar to the above example, it fires only on specified pages and can be used to cut down the number of functions. Let’s take the following scenario: we need a settings page that has some custom CSS and JavaScript and we need to save the data filled by our users.

    // add plugin page
    function my_menu_page(){
    	// add an options page in WordPress administration under Settings
    	$my_settings_page = add_options_page(
    		__( 'Page title' ), 
    		__( 'Menu title' ), 
    		'manage_options', 
    		'menu_slug',
    		'callback_function'
    	);
    	// add styles only on our page
    	add_action('load-'.$my_settings_page, 'my_page_onload');
    }
    add_action('admin_menu', 'my_menu_page');
    
    /**
     * callback function for load-$hook_suffix
     * Enqueues scripts, styles and processes data sent by user
     */ 
    function my_page_onload(){
    	// check if form was submitted
    	if( isset( $_POST['some_variable'] ) ){
    		if( wp_verify_nonce( $_POST['nonce_field'], 'nonce_action' ) ){
    			// process the data here
    			// after data processing, redirect user to our page
    			wp_redirect( menu_page_url( 'menu_slug' ) );
    			exit();
    		}
    	}
    	
    	// add a script file 
    	wp_enqueue_script($handle, $file_path, $dependencies);
    	// add a stylesheet file 
    	wp_enqueue_style($handle, $file_path, $dependencies);
    }
    
  • Assets in WordPress front-pages

    Unless needed in all pages (for example, Google Analytics tracking code needs to be used in all pages) scripts and styles should be loaded in front-end pages only where and when needed. Unfortunately, sometimes it gets tricky and some more complex solutions need to be applied. Never the less, since WordPress offers the opportunity to load scripts in header or footer, this should be used whenever necessary.

    Selective loading can be accomplished for example by using combinations of custom post types conditions or other conditional functions ( is_single(), is_archive() …etc ). Also, in case of shortcodes, loading scripts in footer can prove itself very useful since by the time WordPress code execution reaches the shortcode, the page header is already processed. There’s no best practice here, just make sure scripts don’t get loaded everywhere even when not needed at all.

  • Loading a different jQuery version

    Plugins that use JavaScript in WordPress are commonly developed using jQuery (although exceptions may happen). WordPress comes by default with its own jQuery version and it’s this version that the scripts should be developed for. There are cases though when plugin or theme authors choose to deliver their own jQuery file that is a different version than WordPress’s and even worse, the plugin loads its version as default and doesn’t use $.noConflict();

    Since by default WordPress is delivered with noConflict on, most plugins will use this approach in their scripts. A common way of coding by still using $ in this case is to wrap all code into an anonymous function.

    <script language="javascript" type="text/javascript">
    // here we can only use jQuery, not $
    jQuery('#someId');
    
    ;(function($){
    	// here we can use $
    	$('#someId');
    })(jQuery);
    </script>
    

    All is good so far but when the plugin loading its own jQuery file without $.noConflict() comes into action, all jQuery plugins that don’t use $ will break. For example, if we take Farbtastic (a color picker jQuery plugin) that is delivered by default in WordPress, when not using $.noConflict() an error pops up and the script halts:

    TypeError: jQuery(...).farbtastic is not a function

    Debugging such errors just because a plugin author doesn’t (want to) use the default WordPress jQuery version simply is a waste of time. One legitimate case would be when using the version provided by Google API but the implementation should be carefully and responsibly done.

Code commenting

This one is the most common “mistake” encountered in plugins. For some reason, there are plugin authors that use no or minimal commenting on code. Even a lousy, few words comment is better than nothing at all to help others understand what a function does or the logic of a piece of code. After all, WordPress means community, people that work together for the greater good.

Coding standards

Same as commenting, the way code is written in a theme or plugin at times makes the difference. WordPress has a great page on coding standards that we all should follow or at least follow as close as possible. Since both themes or plugins are basically extensions of WordPress, following the steps of the core development team should be a must for all of us.

Surely the list above could be continued with countless other mistakes. If you happen to have noticed other bad practices please leave a comment and help others improve their skills. Together we can be awesome.

Leave a Reply

Your email address will not be published. Required fields are marked *