Good Business Ethics

Good Business Ethics

Tired of the Woo drama? Then skip to this section.

Earlier this month WooThemes announced a price increase. For this they have been praised by some for ensuring “their sustainability” and “that their lifetime will be much longer than it would have been just days ago”. Some very high profile and well-respected developers also came out in support, to name but a few Carl Hanock,

Brian Krogsgard and Pippin Williamson (albeit with some reservations about how it was handled).

However the changes caused a furore among a vast majority of their customer base. While some were angered by the perceived opportunism, the main focus of customers’ anger was towards the following paragraph in WooThemes’ announcement:

Any purchase made before today will be grandfather-ed into the new system with access to support and updates for 2 years. All theme purchases will also now have a license, which you’ll be able to use with the WooThemes Updater once all themes have been updated.

That is the changes would be applied retrospectively: customers who had purchased a product (license) with the understanding it was unlimited with regard to both sites and duration were told that this would no longer be the case. This is compounded by the fact that the in the month preceding their changes, WooThemes ran a sale – pushing sales with conditions that would abruptly change.

As noted, however, there were some who backed the changes, pointing to the fact that if WooThemes didn’t survive, then the licenses would die anyway along with their product, and possibly even parent company. However, this potentially illegal1 and highly unpopular move forced caused such a stir that it forced WooThemes to backtrack and give customers the option of moving back to the terms they had agreed to.

Even then, you have to opt out of the new license conditions, which is dubious to say the least.

… but haven’t they got a point? What Carl says is entirely true:

A lot of businesses, making a lot of money (so we’re told) rely on WooThemes to exist and continue to provide updates and support for their products. But here’s my point: when a customer makes a purchase from you, it’s a promise. The customer pays you money, and in return you provide them the product, and any promises of updates and support that went with that purchase. In legal terms, it’s a contract.

If you’ve promised more than you can provide, then the company must bear the cost of that. The customer cannot be penalised for the mistakes the company made – that’s good business ethics.

Good Business Ethics

But I don’t want this article to be focussing on the bad. Because, at around the same time another WordPress company realised that their current business model wasn’t working. Like WooThemes they too had offered liftetime support and updates, and like WooThemes they realised that this wasn’t sustainable and needed to change. In fact, this change was the third in one year. The man behind this business admitted his mistakes, and corrected them without punishing existing customers.

In fact he went one step further. He even gave existing customers – regardless of which model was in use when they purchased the product – lifetime updates and support.

The company is Thomas Griffin Media, and the founder Thomas Griffin and the product, Soliloquy.

Thomas has written up an excellent summary of the four business models he experimented with, along with the reasoning behind the one he’s chosen to stick with. It’s an insightful analysis, but more importantly it’s a demonstration of how businesses can do the right thing.

At the heart of any business, including WooThemes, are people – who, like everyone, are prone to making mistakes. We need to bear that in mind, and have grace for that, and resist temptation to consider them faceless entities whose sole intention is to extract money from us. And it has been good to see – as I’m sure Adii will appreciate – customers stating they would be willing to pay more to see the business thrive.

But businesses though must recognise that their promises need to mean something and that they should, at the very least, treat customers fairly and honour the commitments they make. The burden of doing that cannot be imposed upon the customer.

As consumers in a relatively young, albeit fast growing, marketplace we have the opportunity to define the characteristics we want to see in businesses. Do we value low cost, or high quality products? Do we value established brands, or indie developers? Do we value profit-driven businesses, which are able to grow and invest? Personally, I think we should be encouraging characteristics such integrity, transparency and honesty in our businesses. These are not white elephants. They can be found in businesses of all sizes. And I urge you to promote such businesses.


  1. In UK law there is enough to suggest that courts would deem this ‘unfair’ and so illegal. www.oft.gov.uk/shared_oft/reports/unfair_contract_terms/oft311.pdf‎. But it’s really South African Law that applies here. Nevertheless, I would be willing to bet it is in fact illegal. 

Die query_posts()! Die!

For some it’s well known that query_posts() should never be used, but I still see it dotted around here and there, so this is my attempt to help kill it off.

Every time you use query_posts() a kitten does

Every time you use query_posts() a kitten dies. Photo by Brian Scott.

I’m going to keep this post as non-technical as I can. The ins and outs of query_posts() is best left to this video by Andrew Nacin:

Instead, I’m going to talk about what you should be using instead of query_posts() and some of the nuances of pre_get_posts that could land you in hot water. But first…

Why Is query_posts() So Bad?

Mainly, for two reasons:

Query Then Template

It’s bad because runs against WordPress’ handling of website url to page load. query_posts() is directly linked with the main query – this isn’t a handy-wavy notion – it’s a real (global) object: $wp_query. This query is formed from the url of the current page and determines what WordPress displays. But importantly WordPress performs the query first and then chooses the appropriate template.

However, when you use query_posts() in a template file you doing the opposite – you’re trying set the ‘main query’ based on the template used. This can lead to pagination issues and 404s.

It’s Linked to the Main Query

Secondly, the main query is what WordPress thinks is the main content of what it’s displaying. When you change that via query_posts() to display a list of related posts, for example, you end up changing what WordPress thinks it’s displaying. You may end up displaying the comments for the last post on that ‘related post’ section and not the page being viewed.

What’s the solution?

Nice and easy:

1. Secondary queries

For displaying posts in the sidebar / beneath content – or just generally performing ‘secondary queries’ – that is queries that does not related to the main content of the page:

<ul>
  <?php
  global $post;
  $posts = get_posts( array( 'numberposts' => 5, 'category' => 3 ) );
  if( $posts ):
     foreach( $posts as $post ) :   
        setup_postdata($post); ?>

       <li>
          <a href="<?php the_permalink(); ?>"><?php the_title(); ?></a>
       </li>

     <?php endforeach; 
     wp_reset_postdata(); 
   endif; ?>
</ul>

or

<ul>
  <?php
  $my_query = new WP_Query( array( 'numberposts' => 5, 'category' => 3 ) );
  if( $my_query->have_posts() ):
     while( $my_query->have_posts() ):
        $my_query->the_post(); ?>

       <li>
          <a href="<?php the_permalink(); ?>"><?php the_title(); ?></a>
       </li>

     <?php endwhile; 
     wp_reset_postdata(); 
   endif; ?>
</ul>

both work fine.

Note the wp_reset_postdata(); – this is important so WordPress doesn’t confuse the last post in your secondary loop for the post associated with the current page!

2. Altering the Main Query

If you wish to alter the main query, for instance to exclude a category from the search page, then the action pre_get_posts (yes it’s an action not a filter).

add_action('pre_get_posts','my_alter_query');
function my_alter_query( $query ){

      //Is $query the main query? And is the main query for a search
      if( $query->is_main_query() && is_search() ){
        //Do something to main query

        //Exclude category with ID 12.
        $query->set( 'cat', '-12' );
      }
}

That snippet should live in a plug-in, though it would also work in your theme’s functions.php.

But before you start tinkering with queries via pre_get_posts, take note of the health warnings…

pre_get_posts is triggered for every query

This includes admin and non-admin queries, for posts, navigation menu items (yes they’re post types), related post widgets. The lot. That is why if you only mean to alter the main query you check the conditional $query->is_main_query().

But this makes it incredibly powerful. Now I can not just alter the main query, but I can alter any query for a particular post type:

add_action('pre_get_posts','my_alter_query');
function my_alter_query( $query ){

      $pt = $query->get( 'post_type' );

      if( 'event' == $pt || ( is_array( $pt ) && array( 'event' == $pt )  ){                  
         //Do something to queries which are for events only
      }

      if( 'event' == $pt || ( is_array( $pt ) && in_array( 'event', $pt )  ){                  
         //Do something to queries which include events
      }

      if( $query->is_tax( 'event-category' )  ){                  
         //Is the query for an event category
      }

}

Take away point: pre_get_posts is not just for the ‘main query’

Functions vs Method

You’ll note that in the above example I used the method $query->is_main_query() and the function is_search(). What’s the difference? Quite a lot:

Functions = main query, Methods = current query

Conditional functions such as is_search() and is_tax() are wrappers for

 global $wp_query; 
 $wp_query->is_search();
 $wp_query->is_tax();

That is they apply to the ‘main query’. But since $query passed in pre_get_posts is not the always the main query, using a methods or functions are – in general – not the same thing. You’ll need to think about which you need to use: should the conditional apply to the passed $query object, or the main query object?

Lastly, Tom McFarlin has recently written a couple of articles on query_posts() and pre_get_posts. I recommend you check them out:

And also Rarst’s epic answer on WPSE: When should you use WP_Query vs query_posts() vs get_posts()?