2016 WordPress Business Review

2016 brought a lot of change in the WordPress product space, and lots more is coming in 2017.

Companies are getting bigger and more mature, hosts are pushing their weight around with acquisitions, and new players are entering the game. Established products are still doing well, but new products by old companies are gaining momentum. Many plugin authors have their eyes on SaaS for 2017, because of it’s superior business model.

Acquisitions

GoDaddy acquired ManageWP and WP Curve, and these won’t likely be the last.

Hosts are getting interested in products that can add value to their infrastructure, and offer a differentiation from their competitors. ManageWP’s new dashboard fits the bill, and WP Curve brings a team that can help GoDaddy bring in extra revenue through custom development.

There was a great interview at Publish about this topic between Steve Lee and Josh Strebel. The main takeaway I got from that is getting acquired can be very different than what you see in the media.

It takes a lot of time, effort, and money to make an acquisition happen. Many of the valuations you see in larger transactions (i.e. Instagram) don’t apply to smaller companies. The valuations mentioned for some of GoDaddy’s purchases were 1.x. Meaning 1 year of revenue times 1.x. That would be a nice payday for a founder, but it doesn’t make much sense unless you are doing a lot of revenue.

Even a 1M/yr company would be a disappointing payday in my opinion. Let’s say you get 1.2x revenue, some cash and some stock, and you are a 50% partner. You end up with around $500K, minus taxes it’s more like $325k. That would be nice if you really want out, but you aren’t going to retire on $325k.

Hosts as Competitors

Hosts like GoDaddy have a lot more money to throw around than the average WordPress product company, and with their entry into this space, they become a competitor.

The more features that hosts add to their platform, the less room there will be for WordPress products that do the same thing. For example, if your host has nightly backups, do you really need a backup plugin?

If your host offers free security scanning and cleanup, do you need to pay for a separate product that does the same thing?

You could argue that the individual products are better at their job than the host, and they can certainly retain some customers because of that. The point is that if you have a product that works well with hosting infrastructure, you should be aware of this threat.

Will your plugin get acquired?

Another topic discussed at Publish was that plugins are not in a good position to be acquired. Since they are all GPL code, it’s difficult to explain to a buyer what they are paying for. Acquiring a company that owns several products makes sense, but if you have a small plugin business I wouldn’t hold your breath for an offer.

ManageWP has a proprietary SaaS, and it’s easy to see how that fits into GoDaddy’s business model. It’s much easier to sell a SaaS product, it’s something tangible and predictable.

Many product creators have their eyes on SaaS for 2017, but it’s not an attempt to get acquired.

SaaS All the Things

AppPresser is moving to a SaaS model in 2017 with AppPresser 3, and I know of at least 2 other popular products moving that direction. There will most likely be many more than that.

Why? Because a SaaS model is superior in many ways, including customer experience and revenue model.

Customer Experience

The customer experience is a huge one. A SaaS allows customers to experience your product without having to setup their own WordPress site. This is huge.

Squarespace and Shopify are popular because they are so easy to use. We need to bring this type of experience to WordPress.

For a long time WordPress plugins have been all about “build X inside WordPress.” You pay $29/mo for accounting software? I’ll make a plugin that does it for $49 one-time payment, and you host it yourself! We’ve done the same for a CRM, a/b testing, invoicing, eCommerce, and even mobile apps.

The problem is that building anything and everything into WordPress is not always a good thing. If you have a tiny business and a low-traffic site, it’s cool to put everything in WordPress. A business that has thousands of clients, invoices, products, and sales will not have a good experience doing everything in WordPress.

I’m not knocking any single product, just the idea that building every feature a business needs into WordPress is a good thing. I would rather use an external SaaS for almost everything not directly related to site content, such as accounting, a/b testing, and anything related to email. A SaaS can provide a superior experience because it is focused on one thing, and it does it really well.

Revenue Models

The revenue models are superior in a SaaS because we have the option of monthly billing. You can’t do that with a plugin. I don’t think that monthly billing is the holy grail, in fact if you do it wrong you will lose money.

For example, if I divided up our Agency Bundle payment of $499 to a monthly payment of $41.50, my lifetime customer value might go down. This would be due to the fact that most people won’t make 12 or more payments because of churn.

The biggest appeal is not the monthly billing, but the fact that you are providing a service, and customers will lose it if they stop paying. It should increase renewal rates, which are notoriously low in the WordPress plugin space.

Innovate or Die

Some companies, such as iThemes, have been around for 9 years.

As the businesses in our space mature, they are not coasting on the success of older products, they are innovating new ones. For example, BackupBuddy has long been iThemes’ flagship product, but they have continued to drive growth with Sync and Security.

Pippin Williamson of Easy Digital Downloads has been involved with two new projects, AffiliateWP and Restrict Content Pro. These two projects combined are now more profitable than Easy Digital Downloads, which he has publicly noted is not profitable right now. (EDD is still a very healthy company, and they plan to be profitable in 2017.)

It’s not easy to create more than one successful product, and even guys like Cory Miller and Pippin Williamson have failures. Innovation is key, it truly seems like if you aren’t growing, you’re dying.

I think the innovation in 2017 is going to be in moving towards SaaS. We seem to be running out of broad product categories that don’t have a couple dominant players, so we will have to get more creative within those categories.

What trends do you foresee in 2017? Let me know in the comments.

Some WP-API Tips for WordPress 4.7+

Now that the WP-API is in core, here are some useful tips for you.

Filtering Posts

Filtering posts was a bit confusing for me at first, because the documentation seems to suggest you would visit an endpoint like /posts/category/40 to get posts from a certain category.

Instead, you are supposed to use arguments in your request. For example, to show a certain category, you would make a GET request to this url:

https://yoursite.com/wp-json/wp/v2/posts?categories=40

The ’40’ at the end is the category term ID. You can do the same for tags by changing the parameter to ?tags=XX.

There are other parameters available, such as author, orderby, exclude, and more. For a full list, please see the “Arguments” section here.

You can string parameters like this:

https://yoursite.com/wp-json/wp/v2/posts?categories=40&author=1&exclude=214

?filter

There is no longer an option for ?filter, which was really handy for custom taxonomies. I would guess this will be added back at some point, but for now you can use this plugin.

That allows you to use WP Query arguments in your request, for example:

https://example.com/wp-json/wp/v2/posts?filter[name]=the-slug

Custom Post Type Support

I’ve covered this before, but the WP-API won’t show CPTs by default. To add them:

add_action( 'init', 'sb_post_type_rest_support', 999 );
function sb_post_type_rest_support() {
	global $wp_post_types;
	//be sure to set this to the name of your post type!
	$post_type_name = 'product';
	if( isset( $wp_post_types[ $post_type_name ] ) ) {
		$wp_post_types[$post_type_name]->show_in_rest = true;
		$wp_post_types[$post_type_name]->rest_base = $post_type_name;
		$wp_post_types[$post_type_name]->rest_controller_class = 'WP_REST_Posts_Controller';
	}
}

In the example above, your products would then show at the url wp-json/wp/v2/product.

You can also set ‘show_in_rest’ to true when registering the post type instead.

Custom Endpoints

The documentation covers this fairly well, but if you want to add your own endpoint it looks like this:

add_action( 'rest_api_init', function () {
	register_rest_route( 'sb/v1', '/author/(?P<id>\d+)', array(
		'methods' => 'GET',
		'callback' => 'my_awesome_func',
	) );
} );

/**
 * Grab latest post title by an author!
 *
 * @param array $data Options for the function.
 * @return string|null Post title for the latest,? * or null if none.
 */
function my_awesome_func( $data ) {
	$posts = get_posts( array(
		'author' => $data['id'],
	) );

	if ( empty( $posts ) ) {
		return null;
	}

	return $posts[0]->post_title;
}

You can then send a GET request to http://example.com/wp-json/sb/v1/author/1 and get all the posts by the author with an ID of 1.

Post Meta

Post meta doesn’t show up by default, you have to add it. Here’s an example for adding the WooCommerce price:

add_action( 'rest_api_init', 'sb_register_post_meta' );
function sb_register_post_meta() {
    register_rest_field( 'product', // any post type registered with API
        '_price', // this needs to match meta key
        array(
            'get_callback'    => 'sb_get_meta',
            'update_callback' => null,
            'schema'          => null,
        )
    );
}

function sb_get_meta( $object, $field_name, $request ) {
    return get_post_meta( $object[ 'id' ], $field_name, true );
}

CORS Errors

If you are getting CORS errors from your API requests, you can try adding this header to your site:

add_action('send_headers', function() {
  header("Access-Control-Allow-Origin: *");
});

CORS is there for safety, so adding this may be unsafe. Please consult a security professional before using this code on your site.

That’s all I’ve got for now, leave your tips in the comments.

EDD Metrics Plugin Released

I’ve been working on a new plugin for Easy Digital Downloads called EDD Metrics, it’s now released on the WordPress plugin repository.

This plugin gives you valuable metrics on your business with comparisons to previous periods. If you are familiar with Baremetrics, this is basically a copy of that.  I love Baremetrics, but it just doesn’t work for the type of business I have.

WordPress based businesses like mine use a mix of payment gateways, recurring and one-time payments, discounts, renewals, and more. The gateway itself does not provide enough details to get the metrics I wanted, you have to get those from EDD itself.

Download the Plugin

To use EDD Metrics, login to your WordPress admin area, go to Plugins->Add New, and search for EDD Metrics. You can also download straight from the repo here.

Find the metrics under the Downloads side menu, under Metrics.

If you find any bugs, please report them on Github here, not on wordpress.org. Also feel free to contribute!

Screenshots

The Metrics Dashboard

screenshot-1

The revenue detail view

screenshot-2

Videos

Here’s a couple of animated gifs if you want to see it in action.

EDD Metrics Dashboard

EDD Metrics Revenue Detail

Included metrics

  • Revenue
  • Sales
  • Average revenue per customer
  • Estimated yearly revenue
  • Estimated monthly revenue
  • Refunds
  • Discounts
  • Renewals, and renewal rate (if EDD Software Licensing is active)
  • Subscriptions (if EDD Recurring Payments is active)
  • Earnings by download
  • Earnings by gateway
  • New customers

All metrics can be viewed for any time period by using the date picker in the top right corner of either screen. It’s all ajax based, and there is a 15 minute cache to speed things up. This plugin doesn’t work great for long time periods if you have a lot of sales, but should be fine for most shops. If you’d like it to work better feel free to contribute 😉

Have fun, post issues on Github, and share on Twitter!

Cheers!

It would be better if your product didn’t exist

It’s true.

No one wants to use your product, and it would be better if they didn’t have to. This is not just about crappy products, it’s about great ones too.

Using your product is a necessary evil, because a better way doesn’t exist yet.

It would be better if I didn’t have to use Google to look stuff up, I just had the information accessible in my brain already. It would be better if I didn’t have to use my phone to text, I could just communicate with my thoughts. It would be better if I didn’t have to use your website builder, I could just magically have the site of my dreams.

I’ve taken the title and most of these thoughts from this awesome Smashing Magazine article. I highly recommend reading it.

Maybe this thinking isn’t new, but it’s not how I think about building my product. I focus on designing great app building tools, and making sure there are enough features. I try to write clean code and design a sleek product, but what if I focused on getting out of the way instead?

Nobody wants to build an app, they want an app in the app store. I focus on making my tools great, but what if I focused on getting out of the way?

Instead of adding settings and features, I should focus on reducing complexity. I could reduce the amount of steps it takes to get an app into the app store. I could make it easier to add my plugins, use better default settings, and automatically compile the app.

I could help people use my product less, and get the same result.

Are you helping people use your product less?

My Javascript Tools and Workflow Tips

It’s important for a modern front-end developer to have good tools and workflow that is going to survive the perpetually changing land of frameworks, ES specs, Typescript, and slightlybetterthanwhatyoudidyesterday.js craziness.

I’ve been working with modern JavaScript tools and frameworks for long enough to have nailed down a pretty good workflow, which I’ll share today. The tools I’ll talk about here work with different frameworks, even though I prefer Angular. These are especially important for working with teams using git.

I’ve mostly stolen it from better developers than me, so I take no credit for any of this. Let’s start with the essentials, Node and npm.

Continue reading

Javascript, APIs, and the Future of WordPress

Automattic just announced Calypso, which is a radical new interface for WordPress.com.

It replaces the old WordPress.com admin experience with a faster, more modern approach. It uses a Javascript framework called React, which was developed by Facebook. The main advantage of React is that it’s supposed to allow development of web and mobile apps using a similar codebase.

WordPress.com now uses an API to communicate with a Node server, instead of processing with PHP. The advantage of this is that it’s much faster and more interactive, and there are no page refreshes. It’s the same approach that makes many mobile and web apps tick, and it has the performance many users have come to expect these days.

This is a huge shift for WordPress.com, and it’s a major milestone for WordPress in general. Even though many sites and apps have already been taking this API driven approach, this marks a huge shift in WordPress development philosophy.

The question I’m wondering is, where is this all going? What does this shift mean for developers, products, and WordPress core?

I’ve been working with Javascript apps and WordPress APIs for over a year now, and I have a lot of thoughts on the subject.

Continue reading

Dealing with Custom Taxonomies in the WP-API

Update: this article focuses on the WP-API v1. Click here for an article on filtering with the WP-API v2 in WordPress 4.7+.

I have recently started working on a mobile app for a WordPress site that relies heavily on custom taxonomies.

The app needs to pull in posts from WordPress through the WP-API, and allow user filtering based on taxonomy. This requires some special handling, since custom taxonomies don’t appear in the WP-API by default.

What’s a custom taxonomy?

Taxonomies are for categorization. An example of a taxonomy is a category or a post tag.

For example, this post is in the ‘category’ of ‘wp-api.’ We can have lots of terms like wp-api, tutorial, blog, or personal under the name ‘category.’ A custom taxonomy could be swapping the word ‘category’ for something like ‘device.’ So we could have terms like ‘iPhone’, ‘Android’, and ‘Windows’ under our ‘device’ taxonomy.

For more on custom taxonomies, check out these references.

Creating custom taxonomies

Creating custom taxonomies uses the register taxonomy function. It’s similar to creating a custom post type, and just like a CPT, it won’t show up the WP-API unless we add show_in_rest = true.

To create a custom taxonomy that shows up in the WP-API, we could do something like this:

<?php
// hook into the init action and call create_book_taxonomies when it fires
add_action( 'init', 'create_book_taxonomies', 0 );

// create two taxonomies, genres and writers for the post type "book"
function create_book_taxonomies() {
	// Add new taxonomy, make it hierarchical (like categories)
	$labels = array(
		'name'              => _x( 'Genres', 'taxonomy general name' ),
		// more labels here...
	);

	$args = array(
		'hierarchical'      => true,
		'labels'            => $labels,
		'show_ui'           => true,
                'show_in_rest'      => true,
		'show_admin_column' => true,
		'query_var'         => true,
		'rewrite'           => array( 'slug' => 'genre' ),
	);

	register_taxonomy( 'genre', array( 'book' ), $args );

The main thing to notice is the ‘show_in_rest’ argument, set to true.

Adding current taxonomies to the WP-API

If the taxonomy has already been created, or you don’t have access to the registration function, you can add the show_in_rest argument like this.

For a single taxonomy:

<?php
function sb_add_tax_to_api() {
    $mytax = get_taxonomy( 'genre' );
    $mytax->show_in_rest = true;
}
add_action( 'init', 'sb_add_tax_to_api', 30 );

For multiple taxonomies, something like this:

<?php
function sb_add_taxes_to_api() {
    $taxonomies = get_taxonomies( '', 'objects' );
    
    foreach( $taxonomies as $taxonomy ) {
	    $taxonomy->show_in_rest = true;
    }
}
add_action( 'init', 'sb_add_taxes_to_api', 30 );

WP-API endpoint for custom taxonomies

After you’ve added your custom taxonomy to the WP-API using show_in_rest, you can navigate to the taxonomies or terms endpoint to see it in action.

For example, using the example of ‘genre’ from above, we could go to mysite.com/wp-json/wp/v2/terms/genre to see all of our genres. Let’s say we had a genre called ‘fiction’ with an ID of 212. To see information about only the fiction genre, we could visit mysite.com/wp-json/wp/v2/terms/genre/212

If we just wanted the structural information about the taxonomy, we could visit mysite.com/wp-json/wp/v2/taxonomies/genre

If we wanted to get only the posts in a certain term (like fiction), we could make a GET request to mysite.com/wp-json/wp/v2/posts?filter[genre]=fiction. You could do the same for a custom post type (assuming you’ve added show_in_rest = true for the post type) by using the CPT’s endpoint: mysite.com/wp-json/wp/v2/mycptslug?filter[genre]=fiction

I hope that helps! Let me know if you have any additional tips or questions in the comments.

4 Ways to Make Your Ionic App Feel Native

Recent developments in the hybrid world are blurring the lines between hybrid and native.

You can now use native transitions and native scrolling, along with a fast framework like Ionic. In many cases, it’s impossible to tell any difference between hybrid and native, since many fully native apps use WebViews.

The exciting thing is that hybrid apps are improving at breakneck speed, and it’s never been a better time to be in this field. There are 4 things that can drastically improve your apps and make them feel more native, let’s look at them now.

Continue reading

Working with Custom Post Types in WP-API v2

If you worked with the first version of the WP-API, you know that getting custom post types was really easy.

To get all posts, I could send a GET request to http://scottbolinger.com/wp-json/posts. To get a specific type, I could send my request to http://scottbolinger.com/wp-json/posts?type=event.

There have been some pretty big changes in version 2, which is the version that will (hopefully) be in WordPress core sometime soon.

Custom post types are now hidden from the API by default. I can see why they did this, many themes and plugins added post types that they never intended to be public. Making those public would cause more problems than it would solve.

However, that now means we can’t just add the ‘type’ flag to our request, and expect to get post types back.

Continue reading

Basic Authentication with the WP-API (v2) and AngularJS

Working on the WP-App Project, we need to use authentication to do certain things in the app. Deleting/approving comments, or listing users for example.

Basic Authentication is handy for testing code, but it should only be used in development, since you send the user/pass with every request. For production, you’ll want to use OAuth from an external client like a mobile app. I haven’t dug into OAuth yet, but it’s documented a little bit here.

We are using the Ionic Framework for the WP-App Project, which is based on AngularJS. Basic authentication requires sending the username and password, base64 encoded, in the request header. Here’s what that looks like.

Continue reading