Crimes Against WordPress: Avoid Being a Jerk with Themes & Plugins

    Andrew Tetlaw
    Andrew Tetlaw

    Want to develop a sense of deep contempt for your fellow web developers and designers? Then try managing a multi-site WordPress install that uses SSL.

    Some would have you believe that the WordPress ecosystem is a veritable Shangri-La of themes and plugins. I want to destroy this illusion: it’s not. If you’ve had to manage a WordPress site or two, you’ll know what I mean when I say WordPress themes and plugins can be a labyrinth of compatibility problems and a morass of bad programming practices;  full of empty promises. This article is my small contribution to making the world a better place; making my life have meaning; and assuaging the pain.

    This is a list of crimes against WordPress. I found all of these questionable practices in themes and plugins that made my life a living hell.

    Including Your Own Out-of-date Version of jQuery

    I discovered this in a theme:

    $my_jquery = get_bloginfo('template_url'). "/js/jquery.old.version.js";
    wp_deregister_script( 'jquery' );
    wp_register_script( 'jquery', $my_jquery, false, '' );

    WordPress comes with jQuery included; please make sure your plugin or theme is compatible with the jQuery version WordPress includes. Never include jQuery with your plugin or theme. What do you think happens when your version of jQuery is a step or two behind the version included by WordPress, hmmm?

    Adding code like that above feels like you’re invading my personal space. If your JavaScript code requires jQuery then simply do this:


    Uneditable Template Text

    Ever known someone who finishes all your sentences for you? Themes and plugins that output page text that you can’t change feel the same way.

    Here’s an example:  if you’re a theme maker and you want to show a page submenu in the side column, avoid hard-coding it into your template; make it a widget. Allow the site owner to position it and add a custom title. The site owner may dislike the title “Sub Navigation” and prefer “In This Section.” Why do you assume you have the right to make all the decisions?

    At least provide an options panel.


    This is just plain cruel; you may as well start throwing rusty nails into my eyes, because that’d be more fun than tracking down the cause of the CSS bugs that arise because of this:

    <meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7">

    I found that in a theme I actually paid for. If you’re a theme maker and you’re unable to make your CSS work in IE unless it emulates IE7, you need to go back to the drawing board. Seriously bad form.

    Adding Superfluous Theme Features

    A WordPress theme is all about presentation. Providing features like Google Analytics support is unnecessary and just adds to the clutter of your theme options page, like a colleague who never shuts up.

    If I want to use Analytics, I can get a plugin for that. Besides, what if I want to use a site stats service other than Google Analytics?

    Not Cleaning Up After Yourself

    If the site owner wants to remove your plugin or theme, don’t begrudge them the option to do so; it’s their site, after all. Leaving all your data lying around is like being a bad tenant who trashes the joint when they leave.

    Plugin authors, make sure sure you add actions for the deactivation of your plugin. For example:

    function my_plugin_deactivation()
      //get rid of stored data here

    It’s simple to add and you can read all about it on the WordPress Codex.

    There’s currently no official method for themes to assign actions to a deregistration event,  but here’s an approach that looks promising.

    Neglecting to Make a Call to wp_footer in Your Theme

    If you’re not going to add a call to wp_footer in your theme you may as well steal my shoes. This is the most basic no-no—so many plugins depend upon this happening—and yet you still find themes, even commercial ones, that fail to call wp_footer.

    You need to place <?php wp_footer(); ?> just before the closing </body> tag.

    There are no arguments here. Just do it.

    Performing Initialization inside wp_head

    Comparable to turning up late to your best friend’s wedding, I’ve noticed theme and plugin makers sometimes initialize important global variables or constants inside a function that is bound to wp_head. For example:

    function my_init() {
    define('REALLY_IMPORTANT_CONSTANT', 'really_important_value');
    add_action('wp_head', 'my_init');

    Simply put, the wp_head action should only be used to output tags into the HTML head. If you ignore this rule you’re binding code logic with HTML output, and that’s generally bad.

    Promising Custom Menus without Using WordPress Custom Menus

    Would you promise to bring a van to help your friend move house and then turn up on a motorbike? So why would you promise the feature of custom menus, but not use the WordPress custom menu feature? I recently paid for a theme that provided a field into which the site owner is supposed to enter a comma separated list of page IDs:

    Enter the query string of the pages you want to display in the main menu (top left corner of the page). Example: include=9,10,20,21,32 (this would display 5 menu items for the pages with the id 9,10,20,21,32).

    If you offer custom menus in your theme, define menu positions and allow the site owner to use the WordPress custom menu maker; available in WordPress 3.0. it’s flexible and easy to use for the site owner; and the code to add custom menu slots to your theme is so simple. The Codex has all the code you need.

    Thumbnails without Using Post Thumbnails

    Here’s a great way to sentence the site owner to a life of hard labor. WordPress has had the post thumbnail feature since version 2.9, but you still find themes and plugins that force site-owners to manually paste image URLs into custom post fields.

    Instead create a few custom image sizes an then use the Post thumbnail feature. It turns hard labor into a set-and-forget option:

    add_theme_support( 'post-thumbnails');
    if ( function_exists( 'add_image_size' ) ) {
      add_image_size( 'frontpage-news-thumb', 75, 45, true );
      add_image_size( 'frontpage-news-large', 570, 300, true );
      add_image_size( 'portfolio-page-thumb', 44, 30, true );

    With the above code, whenever an editor uploads an image, the additional sizes will be generated automatically. All the editor then needs to do is select the image as the feature image for the post.

    In your theme or plugin you can output the appropriate image tag with the the_post_thumbnail function:

    <?php the_post_thumbnail( 'frontpage-news-thumb' ); ?>

    Read all about it on the Codex. Please.

    Inserting Custom Post Boxes without Using add_meta_box

    The add_meta_box function has been available since WordPress 2.5, but I still see the following:

    add_action('edit_page_form', custom_write_panel);
    function custom_write_panel() {
      //echo lots of form HTML

    The example custom_write_panel function above echos form HTML into the post edit form. This is equivalent to throwing up into the urn your best friend keeps her mother’s ashes in.

    The add_meta_box function adds your custom write panel to the global $wp_meta_boxes array. Once there it can be accessed, overridden—generally managed by other code or a plugin. It’s the polite way to do it.

    Read the function’s reference on the Codex for details and links to easy tutorials

    Failing to Support HTTPS

    If you run a WordPress site under HTTPS, constant browser mixed content security warnings are almost inevitable, requiring you to modify the plugins and themes manually. This is because many theme and plugin authors hard-code ‘http’ when they include page resources like JavaScript files and Images. It feels like being conned into buying a brand new suit and realizing only the front half of the mannequin was covered. And now your butt’s hanging out in the breeze while you deliver your big speech to the shareholders.

    Since version 2.6 WordPress has had the is_ssl function:

    $scheme = ( is_ssl() ? 'https' : 'http' );

    Just use it before someone gets hurt.

    Hardcoding aside, there are times where you can’t really blame plugin and theme creators. After all many of them have simple copied code from WordPress itself. In WordPress 3.0.4, default-constants.php, line 77, we find:

    if ( !defined('WP_CONTENT_URL') )
    define( 'WP_CONTENT_URL', get_option('siteurl') . '/wp-content');

    Using get_option('siteurl') simply retrieves the value from the database without any SSL check. A better way is to use the site_url / get_site_url functions as these perform the appropriate check.

    Alternatively you can do what I did and patch this yourself:

    function fix_ssl_siteurl($url) {
      if ( 0 === strpos($url, 'http') && is_ssl() )
        $url = str_replace( 'http://', 'https://', $url );
      return $url;
    add_filter('option_siteurl', 'fix_ssl_siteurl');
    add_filter('option_home', 'fix_ssl_siteurl');
    add_filter('option_url', 'fix_ssl_siteurl');
    add_filter('option_wpurl', 'fix_ssl_siteurl');
    add_filter('option_stylesheet_url', 'fix_ssl_siteurl');
    add_filter('option_template_url', 'fix_ssl_siteurl');

    You can place the above code in a plugin, in the functions.php file in a theme or, if you run a multi-site installation,  put it in your mu-plugins folder and be done with it. Of course it’d be better if everyone just supported HTTPS properly.

    Not Supporting Multi-site WordPress

    If you claim to support WordPress 3.0 and up, then you must support multi-site WordPress installations. If you fail to do this you’re a schmuck. From my point of view the experience is like winning a family trip to Sea World, but finding out that only one of us is allowed to swim with the dolphins.

    Enabling multi-site on a  WordPress install changes the file upload path, the URL to admin forms, and the database table names are unique for each blog. Also, plugins can be activated for the whole network. Writing about this topic could fill a whole tutorial itself. But here’s a few pointers:

    In a multi-site WordPress installation the content file path depends upon a URL redirection. Often theme or plugin makers will include a supporting library, like an image manipulation library for example. If this is the case with your theme or plugin, make sure your library works with URL redirection. So many of them fail at this.

    One plugin I used wrote the options form action like this:

    <form method="post" action="<?php echo $_SERVER['PHP_SELF'] . '?page='
    . basename(__FILE__); ?>&updated=true">

    The problem with this is that with multi-site WordPress, the path to the admin forms is different for each blog and not equal to $_SERVER['PHP_SELF']. Here’s the fix I used for that plugin; it basically changes the action from a root-relative path to just a plain relative one:

    <form method="post" action="<?php echo 'options-general.php?page=' .
    basename(__FILE__); ?>&updated=true">

    If your theme or plugin need custom database tables, then don’t forget in a multi-site installation each site has a unique table name prefix. Mostly this means using the global $wpdb object for database access and the $wpdb->prefix property. It’s all explained in the Codex and in this blog post.

    The above blog post also has some useful examples for dealing with network activation and deactivation.

    Summing Up and Calming Down

    I feel a little better now that I’ve gotten that off my chest. It really comes down to this: do as little damage as you can, use existing WordPress features as much as possible, make everything customizable, and recognize that some sites need SSL or are multi-site installations.

    If site owners are forced to make edits to your code just to make it work acceptably, then you’ve failed, and the WordPress ecosystem isn’t working as it should.