PHPackages                             duckdev/freemius-plugin-licensing - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Authentication &amp; Authorization](/categories/authentication)
4. /
5. duckdev/freemius-plugin-licensing

ActiveLibrary[Authentication &amp; Authorization](/categories/authentication)

duckdev/freemius-plugin-licensing
=================================

Lite version of the Freemius SDK for managing plugin licensing and updates using Freemius APIs, specifically developed for use with Duck Dev plugins.

2.0.2(1w ago)2656GPL-2.0+PHPPHP &gt;=7.4CI passing

Since Aug 3Pushed 1mo agoCompare

[ Source](https://github.com/duckdev/freemius-plugin-licensing)[ Packagist](https://packagist.org/packages/duckdev/freemius-plugin-licensing)[ Docs](https://github.com/duckdev/freemius-plugin-licensing)[ RSS](/packages/duckdev-freemius-plugin-licensing/feed)WikiDiscussions main Synced today

READMEChangelog (7)Dependencies (6)Versions (11)Used By (0)

Freemius Plugin Licensing
=========================

[](#freemius-plugin-licensing)

A lite, UI-free Freemius SDK for Duck Dev WordPress plugins. The library handles license activation, deactivation, update delivery, and addon listing by talking to the Freemius API directly. It deliberately ships no admin screens — host plugins build their own UI and call into this library for the underlying logic.

Requirements
------------

[](#requirements)

- PHP 7.4 or higher
- WordPress 5.0+
- Composer

Installation
------------

[](#installation)

```
composer require duckdev/freemius-plugin-licensing
```

The library autoloads under the `DuckDev\Freemius\` namespace via PSR-4.

Architecture
------------

[](#architecture)

The library is organised as a small dependency-injection container wired up by the entry class `DuckDev\Freemius\Freemius`. The folder layout mirrors the namespace:

```
src/
├── Freemius.php              # Container + entry point
├── Api/
│   ├── Client.php            # Unsigned HTTP client over wp_remote_request
│   ├── SignedClient.php      # Adds FS / FSP signed auth headers
│   ├── RequestSigner.php     # Pure header-signing logic
│   └── ApiFactory.php        # Builds fresh clients per call
├── Contracts/
│   ├── ServiceInterface.php
│   ├── ApiClientInterface.php
│   └── CacheInterface.php
├── Data/
│   ├── Plugin.php            # Immutable host plugin info
│   ├── Activation.php        # Value object around the persisted activation
│   └── ApiKeys.php           # Public / secret key pair
├── Storage/
│   ├── ActivationRepository.php   # Reads / writes the activation option
│   └── TransientCache.php         # Per-plugin transient cache + throttle
├── Services/
│   ├── AbstractService.php
│   ├── License.php           # activate() / deactivate()
│   ├── Update.php            # WP update hooks
│   └── Addon.php             # Addon listing
├── Support/
│   └── SiteIdentity.php      # Deterministic site UID
└── Exceptions/
    └── FreemiusException.php

```

Each service receives its collaborators by constructor injection, so they can be unit-tested without WordPress in the loop. Hook registration happens inside `boot()` (called once by the container), so simply instantiating the container has no side effects.

Usage
-----

[](#usage)

### Initialization

[](#initialization)

Initialise the container by calling `Freemius::get_instance()` with your Freemius product ID and an arguments array:

```
// Assuming Composer's autoload.php has been included.
$freemius = \DuckDev\Freemius\Freemius::get_instance(
    12345, // Your Freemius product ID.
    array(
        'slug'       => 'loggedin',              // Your plugin's unique Freemius slug.
        'main_file'  => LOGGEDIN_FILE,           // Absolute path to the plugin's main file.
        'public_key' => 'pk_XXXXXXXXXXXXXXXXX',  // Plugin public key.
        'is_premium' => true,                    // Whether this build is the premium edition.
        'has_addons' => false,                   // Whether the product has addons to list.
    )
);
```

The supported arguments are:

KeyTypeDescription`slug``string`Unique Freemius slug for the plugin.`main_file``string`Absolute path to the plugin's main file (used for `plugin_basename()` and `get_plugin_data()`).`public_key``string`Freemius public key (`pk_…`). Required for plugin-scoped endpoints (addons, info).`is_premium``bool`Whether this build is the premium edition. Update hooks only register when `true`. Default false.`has_addons``bool`Whether the product has addons to list. Default false.The first call to `get_instance()` creates the container and registers WordPress hooks. Subsequent calls for the same plugin ID return the existing instance (the second argument is ignored after the first call).

### License Activation

[](#license-activation)

```
$result = $freemius->license()->activate( 'XXXX-XXXX-XXXX' );

if ( is_wp_error( $result ) ) {
    // $result->get_error_message() — show to the user.
}
```

`activate()` returns `true` / `false` from the option update on success, or a `WP_Error` when the key is empty, the plugin is not the premium build, the API call fails, or the response does not include an install ID.

### License Deactivation

[](#license-deactivation)

```
$result = $freemius->license()->deactivate();
```

`deactivate()` refuses to proceed when the stored UID does not match the current site — that means the activation was moved to another host, and we let the new host appear unlicensed rather than silently freeing the original seat.

### Reading the Current Activation

[](#reading-the-current-activation)

```
$activation = $freemius->license()->get_activation();

if ( $activation->is_active() ) {
    // $activation->license_key(), $activation->install_id(), …
}
```

`get_activation()` always returns an `Activation` value object — use `is_empty()` to detect the no-activation case.

### Updates

[](#updates)

Update hooks are registered automatically during `boot()` for premium builds. There is no manual integration needed — WordPress will check for, display, and apply updates through its standard pipeline.

To force a refresh from the host plugin's UI:

```
$freemius->update()->get_update_data( true );
```

### Addons

[](#addons)

```
$addons = $freemius->addon()->get_addons();              // Cached for 24h.
$addons = $freemius->addon()->get_addons( true );        // Force refresh.
```

Each entry is enriched with a `link` field (Freemius checkout URL) and an `is_premium` boolean. Use the `duckdev_freemius_format_addon_data` filter to add or rewrite fields per addon.

Hooks
-----

[](#hooks)

### Actions

[](#actions)

HookArgumentsWhen`duckdev_freemius_license_activated``array $activation, bool $success`After a successful activation.`duckdev_freemius_license_deactivated``array $activation, bool $success`After a successful deactivation.### Filters

[](#filters)

HookArgumentsUse`duckdev_freemius_api_request_args``array $args, string $method, string $url, array $data, array $headers`Tweak the request arguments before they reach `wp_remote_request()`.`duckdev_freemius_api_request_verify_ssl``bool $verify, Client $client`Disable SSL verification (typically only in local dev).`duckdev_freemius_format_addon_data``array $addon, Addon $service`Rewrite or augment each addon entry before it is returned.Security Notes
--------------

[](#security-notes)

- The library does **not** verify nonces or capabilities. Host plugins MUST do that before forwarding form input to `License::activate()` / `License::deactivate()`.
- The license key is stored in the `duckdev_freemius_activation_data` option (an autoload-safe option keyed by plugin ID). It is blanked from storage on deactivation.

License
-------

[](#license)

GPL-2.0+

###  Health Score

44

↑

FairBetter than 90% of packages

Maintenance96

Actively maintained with recent releases

Popularity22

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity43

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~46 days

Recently: every ~57 days

Total

8

Last Release

8d ago

Major Versions

1.0.0 → 2.0.02026-06-03

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/17586?v=4)[Schmidt](/maintainers/Jo)[@jo](https://github.com/jo)

---

Top Contributors

[![Joel-James](https://avatars.githubusercontent.com/u/7510463?v=4)](https://github.com/Joel-James "Joel-James (36 commits)")

---

Tags

freemiuslicense-managementpluginwordpresswordpress-pluginupdatespluginsfreemiuslicensing

###  Code Quality

TestsPHPUnit

Code StylePHP\_CodeSniffer

### Embed Badge

![Health badge](/badges/duckdev-freemius-plugin-licensing/health.svg)

```
[![Health](https://phpackages.com/badges/duckdev-freemius-plugin-licensing/health.svg)](https://phpackages.com/packages/duckdev-freemius-plugin-licensing)
```

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
