The freemium WordPress plugin is one of the best small software businesses a solo developer can run: a free plugin on WordPress.org brings you free, search-driven installs, and a paid Pro upgrade turns a slice of those installs into recurring revenue. The catch is that most of the work isn't your plugin's actual feature — it's the plumbing every freemium plugin needs, and the WordPress.org rules you have to get right or your submission bounces.

This is the architecture that works, the compliance gotcha that trips people up, and the reusable pieces you should never write more than once.

The model: free on wp.org, Pro sold off-site

WordPress.org is the discovery engine. Millions of people search the plugin directory (and Google surfaces its pages), so a free plugin that solves a real problem gets installs you didn't pay for. That's the top of your funnel. The paid tier is where the money is — but here's the rule that catches everyone:

Your free plugin on WordPress.org may not contain paid code, and may not lock features behind a payment. The directory is GPL and forbids "trialware." So you cannot ship a paid feature disabled in the free download.

The compliant pattern is two plugins:

  • The free plugin ships on wp.org. It contains the free features and a gate — an "if Pro, do more" check — plus "Get Pro" links. No paid code.
  • A separate Pro add-on is sold on your own store (Gumroad, Freemius, Lemon Squeezy). When the buyer installs and licenses it, it answers a filter — say myplugin_is_pro — with true, and registers the paid features on the hooks the free plugin already exposes.

The gate: one function you'll reuse forever

The whole freemium mechanism comes down to a single, dependency-free class. The free plugin defines it; the Pro add-on flips it on:

class Freemium {
    const IS_PRO_FILTER = 'myplugin_is_pro';

    // Features the free tier includes. Everything else is Pro-only.
    private static function free_features() {
        return array( 'core' );
    }

    public static function is_pro() {
        return (bool) apply_filters( self::IS_PRO_FILTER, false );
    }

    public static function allows( $feature ) {
        return self::is_pro() || in_array( $feature, self::free_features(), true );
    }
}

Now you gate any feature with one call, and it always degrades cleanly to the free behaviour instead of erroring:

if ( Freemium::allows( 'bulk_export' ) ) {
    // Pro path
} else {
    // free path, or a "Get Pro" nudge at the moment of need
}

The Pro add-on, once licensed, is a two-line file: add_filter( 'myplugin_is_pro', '__return_true' ); after its license check. That's it. The gate does the rest.

The boring 80% you keep rewriting

Every freemium plugin needs the same scaffolding before you write a single line of your actual feature:

  • A settings framework — one serialized option row, typed defaults, sanitized writes, and an allow-list so a crafted POST can't smuggle values in.
  • The license gate above, plus an admin "Get Pro" call-to-action that shows the upsell at the moment a user hits a locked feature (the highest-converting spot in the whole funnel).
  • A wp.org-format readme.txt — with the exact headers, tags, and "Stable tag" the directory requires.
  • A build script that produces a clean distributable zip, excluding your dev files (tests, .git, build tooling) via a dist-ignore list.
  • An uninstall routine that removes your options — but keeps anything that's a real record.

None of that is your product. It's the same every time, and it's a day or two of fiddly work before you even start. It's also where wp.org rejections come from — a missing readme header, a permission not nonce-checked, a fatal on a missing dependency.

Don't fatal the site

One rule that saves you a one-star review: never let a missing dependency crash a site. If your plugin needs WooCommerce and it isn't active, show an admin notice and return — don't call a class that doesn't exist. The same goes for any optional library: check, degrade, continue.

if ( ! class_exists( 'WooCommerce' ) ) {
    add_action( 'admin_notices', function () {
        echo '<div class="notice notice-error"><p>My Plugin needs WooCommerce active.</p></div>';
    } );
    return;
}

How the money actually reaches you

WordPress.org never touches money — it only distributes the free plugin. The payment happens on the external store, which acts as merchant of record: it charges the card, handles global sales tax/VAT, and pays out to your bank. Your free plugin's "Get Pro" button sends the buyer there; they get the Pro add-on plus a license key; the key flips the gate. Keep one store as the license authority so you're not reconciling two key formats.

Or skip the boring 80%

I got tired of rebuilding the same license gate, settings framework, readme and build script for every plugin, so I packaged them into a boilerplate with a one-command scaffolder: run it, and you get a complete, activation-ready freemium plugin — namespace, constants, settings screen and license gate already wired. You add your feature and ship. It's GPL, so you can use it in unlimited commercial plugins.

See the Freemium Plugin Boilerplate →

The part nobody automates for you

Building the plugin is the easy half. The hard half is distribution: getting installs (wp.org search rankings, which reviews and active installs compound), and converting a few of them to Pro. Ship the free plugin, earn the installs, then build the Pro tier for the users who ask for more — not before. A paywall for zero users is wasted work.

Related reading: How to build a SaaS platform and who pays for open source.