Taking a new product from concept to launch
When you launch a new project there’s always a buzz of excitement, hope, and relief, but also that of fear of failure and disappointment.
This is something I’ve experienced for all the projects I’ve been part of over the past eight years, to the point that I’m actively looking forward to the first failed launch.
Nothing reflects this sentiment more than the feedback received from our few users.
Hope: “We’re using your free plugin already. We would like to buy it later.”
Fear of Failure: “If it works with the plugin that handles the booking on our site.”
Then there’s the abysmal number of active installs after sending over 7,000 emails to previous clients: fewer than ten for the first two weeks.
But this is not a story of something that looks like a failed product launch (more on that later).
Instead, I’m going back to December 2016 to explain almost everything we’ve gone through over the past eight months, from initial concept to a brand new plugin that allows you to translate a WordPress website in more languages.
I’m going to cover the following topics:
- Why create a new translation plugin? How we came up with the idea.
- Allocating development resources and deciding on a time-frame.
- Why we exceeded our time-frame by almost 2.5 times.
- Quickly oming up with a logo and something that resembles a brand.
- Deciding how the plugin will be monetized.
- Implementing a brand new site, setting up payments and licenses.
- Beta launching the plugin and working on a new feature.
- Our conclusions.
Let’s build a plugin, they said! It will be fun, they said!
At the end of every year, we have a meeting with the rest of the team over at Cozmoslabs. We talk about the things that worked, what completely failed, and the things we’re looking forward to in the next year.
My colleague Razvan Mocanu wanted to work on a brand new project: a new plugin. So we wrote the idea down, went on our Christmas holiday, and came back in January with a single good idea we actually wanted to work on: a translation plugin for WordPress.
While this looks somewhat arbitrary, it’s really not.
As plugin developers, we’ve always had to deal with translation plugins. (Right now we have support for WPML in all our plugins.) Before we switched to plugin development, we were a custom development agency that implemented WPML for various clients. It worked for us as developers but almost never for the end user.
We really didn’t like the translation workflow of almost all existing translation plugins on the market. The interfaces are mostly non-visual, out-of-context, and spread out over multiple locations. We knew we didn’t want to do a WPML clone or work with multisite installations.
The only other existing plugin on the market that did something different was WeGlot –a SaaS implementation that offers automatic and manual translation. Basically, the translation of your site gets loaded from their servers.
From the combination of the plugins and ideas above we came up with a concept similar to WeGlot, but quite different in its implementation:
Translate the entire page. No more switching between the editor, string translation interfaces, or badly translated plugins. You can now translate the final rendered page.
The main difference is our implementation:
- Support for dynamic strings. (gettext strings)
- Everything is stored locally in your database. (You own your translation.)
- GPL. (Access to the codebase in case you need something different.)
- A desire to make our plugin work with any WordPress plugin or theme and not the other way around, where developers need to support translation plugins.
In January, my colleague Madalin Ungureanu started testing the core of the plugin, a PHP DOM parser class to see if we could work with it. It worked fairly well. We could do string search and replace from the database without slowing down the test site, so we moved forward and started the project. Razvan was to be the lead developer, and he would be 100% in charge to deliver the alpha/beta versions at which point we would allocate more resources to the project. While not ideal, it was all we could do without hiring more people.
We gave ourselves three months. We said, “Let’s have an alpha/beta version in April.”
In July we started testing internally and pushed for a beta launch. On July 31st we made the beta available for download. The final launch was September 4th, more than five months over our estimate.
I’ve come to expect software development tasks to take longer than expected. There are some exceptions to that rule, but they are usually at the end of a development cycle when the problem was already well-defined, it didn’t require further research, and all that remained was to write the code.
So why did it take longer than we estimated?
- Obviously, we underestimated the time needed. We really didn’t know how long it would take.
- The three-month timeframe was selected for practical reasons. We didn’t want to push the project into the summer holiday season. (We did.)
- Razvan is still a junior developer and this was his first big project at the company. While there were quite a lot of discussions regarding development direction and implementation, there was very little actual code written by anyone else from the team in the first stages of the project. So progress was slow.
- Once I started testing the plugin in June, nothing worked (On my install anyway). While Razvan tried to generalize the problem as much as possible (fast string replace), it quickly became clear to us: there are a lot more edge cases than we realized and budgeted for.
Fast logo design
While the plugin was being developed, I focused my attention on the design of a new logo and color scheme for our future website.
By no means am I a graphic designer, but I’m okay at pushing pixels around in Photoshop. I allocated a few hours and came up with four suggestions that I showed to the rest of the team.
We decided on the last one and moved forward with the site design.
All in all, there were probably three to four actual work days distributed over a few months to get all the graphics and design we needed for launch. The theme was a clone of the same custom theme we’ve used over at Cozmoslabs so we’ve spent as little time as possible getting this out.
While the design is important, finishing the website with the minimum time investment meant more to us. The Cozmoslabs design had taken a combination of four months of working with a designer and another two months of implementing it in its entirety. We simply could not afford to do that again. So we did just enough and moved forward.
We decided early on take the fremium route. Our own previous experiences, as well as those of other plugin developers in the WordPress community, made it clear this was the way forward.
What wasn’t so clear is how we should differentiate the versions. Things we considered to be part of the Pro versions were:
- Translation of Custom Post Types
- Multiple languages
- Google Translate API
- SEO Module (Slug, page title and description translation.)
What we finally decided was to include the SEO Module and Multiple Languages in the Pro versions with a differentiation based on the number of active installs. Additionally, we decided:
- Each pricing tier is valid for one year with automatic renewal.
- Only the Pro versions contain the Advanced Addons.
Brand new site, setting up payments and licenses
To sell our new plugin, we’ve tried to keep it as simple as possible. We used Easy Digital Downloads and Digital Licenses for EDD.
Unfortunately, for our setup to work we needed some customization:
- Our payment gateway Avangate had to be custom coded because the Avangate API is weird.
- Automatic renewals from Avangate can’t use EDD, so we needed something custom coded.
- Digital licenses for a bundled product so one license works with all add-ons from the bundle (This doesn’t work with EDD).
We wanted to use the All Access Pass Add-on for EDD to solve the digital licenses for bundles, but that didn’t work for us because:
- If you have an All Access Pass, you can’t buy another, You can only increase the license period.
- It broke our custom automatic renewals because of the way Avangate deals with automatic renewals.
- It also broke upgrades due to Avangate.
We ended up custom coding an add-on for EDD that sort of works like All Access Pass (the code is basically taken from the add-on), but without the All Access part.
Other than that, we used our own Profile Builder Pro plugin for the login / edit profile / password reset functionality.
One way of building momentum for a product is a beta launch. While there are other reasons for a beta launch (bug reporting), what I’ve experienced with other plugins in the past is that the main benefit is the possibility to talk about your product even if it doesn’t work perfectly yet.
While somewhat shallow in its pursuit, it’s just another marketing tool one can use. And as a bonus, we’ve also got a couple of proper bug/feature reports that made it clearer we were missing something critical with the beta version: there was no support for gettext fields.
Support for gettext fields was one of the big features we wanted to introduce after launch. However, while playing more and more with the plugin and hearing what our beta users had to say about it, we bit the bullet and started working on this feature right after beta launching the plugin.
This is one of the biggest mistakes we could have done from a development point of view and one of the reasons why it took us so long to ship version 1.0. We delayed support for gettext because it was hard to implement.
After the beta launch, we had a one-hour power failure at the office. While I waited for power to come back on, I started cleaning my keyboard. There was nothing better to do anyway, so I took a picture of the keyboard, removed all keycaps and proceed to clean them one by one with a little bit of rubbing alcohol and a rag.
For the next 2 hours, I cleaned my keyboard and created a mental mindmap of the gettext implementation in WordPress, how our plugin was translating strings, and how we could combine the two without getting into performance issues further down the line.
After that, I had a quick discussion with Madalin about gettext, decided we should do it now – before our 1.0 launch – and he got to work on it.
There are a couple of lessons to take away from this story:
- It’s a bad idea to delay complicated features without a good reason. We knew it was going to be complicated, and that’s the reasons why we delayed it for so long.
- While the two hours I spent thinking about gettext did absolutely nothing in terms of actual development time, it was infinitely better than not thinking about it at all. It was what we needed to decide and get unstuck. It took Madalin a month to get it working and he’s since then also been able to tackle wp_ajax and gettext.
For promoting the beta we:
- Wrote an article that’s SEO optimized for “WordPress in More Languages.” (There's no point writing 2,000+ words without hoping for a bit of SEO traffic in the future. )
- Sent a newsletter to our existing clients at Cozmoslabs about the new plugin.
- Put proper “Signup for Beta” forms on the TranslatePress website.
- Asked the 100 people who signed up for the beta for feedback via Mailchimp two weeks into the beta.
- For another two weeks, we ran Facebook ads that increased our beta testers to 160.
It took us a month of develop -> test -> fix cycles to get the gettext implementation working for strings rendered by PHP in normal page templates.
We still didn’t have gettext support for wp_ajax calls (we do now), but it was important to launch now and not later for the following reasons:
- If we had waited to get everything done before launching, we would have lost time for marketing. If there is no product we can’t talk about the product.
- We could have lost the opportunity to sponsor WordCamp Bucharest that’s happening in October.
- Once the website, payment gateway, licenses, support and documentation are all set up, all we’re left with is working on the product.
Ever since the beta launch, we started thinking about marketing the plugin.
A freemium business model means we’re dependent on a large number of non-paying users and active installs.
Promoting a new free plugin is harder than you might think, particularly with the new WordPress directory that takes into account active installs, reviews, number of answered questions on the forums, and other things we don’t control.
Our efforts were directed towards getting in front of as many WordPress admins as possible:
- We added cross-promotion in our other plugins. TranslatePress can translate our other plugins, so we’ve listed it in our recommended plugins sections for those products.
- We added the free download to the account page for all our clients over at Cozmoslabs.
- We got in touch with ThemeIsle to add TranslatePress to a recommended plugin list as it works very well to translate their complex themes. (We’re using Hestia for our demo site.)
- We are sponsoring WordCamp Bucharest and will get to talk to potential users face to face.
All this effort is particularly important at the beginning to get a bit of traction so TranslatePress appears in the WordPress plugin directory search results.
We tried to be as non-spammy as possible. We didn’t use notices that appear on all backend pages or send newsletter after newsletter to our existing clients. We sent two emails to existing clients: one for the beta and one for the version 1.0 launch.
Future marketing plans:
- We plan to create tutorials for a lot of popular themes and how to translate them. (Thanks, Ionut.)
- Continue our outreach efforts towards plugin and theme developers. We want to add support for plugins, not have plugin developers add support for us.
- Content marketing for multilingual is hard because we won’t rank high in search engines. Not at first anyway. So while we’ll be active on this front, it’s not highly important for us now.
The main thing I want to highlight about this eight-month process is that it’s not the end of the line. Lack of interest at the beginning is normal. Few downloads are normal. Little to no feedback is normal.
Instead of worrying about all this, I’ve come to see initial launches for what they really are: a structure on which the company can build the product and market it in the future.
The real success or failure comes at a much later time.
It’s been almost comical for me to see how poorly our initial launches have historically been and to make bets with the our team that are almost always way more optimistic.
Finally, here’s a list of the things we’ve learned these past eight months:
- Rethink product launches as a way to create the structure of the project. Once it's released you can work on marketing and improving the product.
- Don’t delay thinking about complicated parts of the project. You can decide whether or not to include them in version 1.0, but never, ever simply refuse to think about them.
- Ask for feedback from other people in the community. I’ve had some really interesting technical discussions with the Post Status community. I've had productive conversations about features with local WordPress people who implement multilingual websites and actual users who love the simple interface (If only the plugin worked for all strings!). Other WordPress product people have been great sounding boards for marketing issues. Our future features, technical decisions, and marketing are influenced by this feedback.
- Spend the necessary amount of time on important features. We’ve spent a lot of time on the gettext implementation and continue to do so. It’s the one thing that makes the entire plugin so versatile, so it has to work.
- Unless you’re selling actual design work, don’t spend a lot of time on website design. Focus instead on making the content clear and structured so it’s not overly complicated for non-technical readers. If you’re not sure where to start, just go over to AffiliateWP and steal their content structure. No one will notice 🙂
- Everything you can set up and forget should be done early on. If you can’t use off the shelf tools to sell your plugin, custom code them now if you know how. With the infrastructure in place, we can focus on the plugin completely for the next year or more without worrying about changing the pricing structure, renewals, accounts, etc.
So this is the beginning of our TranslatePress adventure.
If you managed to read all of this, thank you for your time! And try TranslatePress, even if it’s just to play with it. It’s cool like that!