Drop-in Single File

WPLF_Licensing is a single-file alternative to the 3-class system. It bundles license operations, an admin page, and automatic updates into one file with a static API -- ideal for quick integrations where the defaults are acceptable.

File

Copy a single file into your plugin or theme:

File Class
wplf-licensing.php WPLF_Licensing

Initialization

Call the static init() method from your plugin's main file or your theme's functions.php:

require_once __DIR__ . '/includes/wplf-licensing.php';

WPLF_Licensing::init( 'my-plugin', 'https://licences.example.com', __FILE__ );

Method signature

WPLF_Licensing::init( string $slug, string $api_url, string $file, array $args = [] )
Parameter Type Description
$slug string Product slug as defined in your LicenceForge dashboard.
$api_url string Base URL of your LicenceForge server (no trailing slash).
$file string Full path to the main plugin file or theme's functions.php. Pass __FILE__.
$args array Optional configuration overrides (see below).

Optional arguments

WPLF_Licensing::init( 'my-plugin', 'https://licences.example.com', __FILE__, [
    'cache_duration' => 43200,           // Default: 43200 (12 hours)
    'api_key'        => 'lf_pk_abc123',  // Optional. Required if server enforces API key auth.
] );
Key Type Default Description
cache_duration int 43200 Seconds to cache the validation result. Default is 12 hours.
api_key string null Public API key sent as X-LicenceForge-Key header.

Note

The drop-in defaults to a 12-hour cache (43200 seconds), compared to 1 hour (3600 seconds) in the 3-class system. This reduces API traffic for simpler products that do not need rapid revocation detection.

Singleton pattern

WPLF_Licensing uses a singleton pattern keyed by product slug. Calling init() a second time with the same slug returns the existing instance without reinitialising:

// First call: creates and returns the instance
WPLF_Licensing::init( 'my-plugin', 'https://licences.example.com', __FILE__ );

// Second call: returns the same instance (arguments are ignored)
WPLF_Licensing::init( 'my-plugin', 'https://other-url.com', __FILE__ );

This allows multiple files within the same plugin to safely call init() without side effects. The first call wins.

Static helper methods

After initialisation, use these static methods anywhere in your code without holding a reference to the instance:

Method Returns Description
WPLF_Licensing::get( $slug ) WPLF_Licensing|null Returns the instance for the given slug, or null if not initialised.
WPLF_Licensing::is_active( $slug ) bool Returns true if the license for the given slug is valid and active.
WPLF_Licensing::feature_available( $feature, $slug ) bool Returns true if the specified feature is available on the current tier.
// Check license status from anywhere in your codebase
if ( WPLF_Licensing::is_active( 'my-plugin' ) ) {
    // Licensed functionality
}

// Gate a specific feature
if ( WPLF_Licensing::feature_available( 'advanced-export', 'my-plugin' ) ) {
    // Show advanced export UI
}

Instance methods

WPLF_Licensing exposes the same methods as WPLF_Client on the instance object. Retrieve the instance with WPLF_Licensing::get() and call methods directly:

$licensing = WPLF_Licensing::get( 'my-plugin' );

$licensing->activate();
$licensing->deactivate();
$licensing->validate( true );       // Force fresh validation
$licensing->is_active();
$licensing->has_feature( 'slug' );
$licensing->get_features();
$licensing->get_tier_label();
$licensing->is_trial();
$licensing->get_trial_end();
$licensing->get_trial_days_remaining();
$licensing->get_license_key();
$licensing->set_license_key( $key );
$licensing->check_update();
$licensing->clear_cache();
$licensing->get_license_info();
$licensing->get_plugin_file();
$licensing->get_product_slug();
$licensing->get_version();
$licensing->mask_key( $key );

For detailed descriptions of each method, see the WPLF_Client methods reference.

Plugin vs. theme auto-detection

WPLF_Licensing automatically detects whether the $file path resides inside wp-content/plugins/ or wp-content/themes/ and adjusts its behaviour accordingly:

Behaviour Plugin Theme
Admin menu location Under Settings Under Appearance
Update hook pre_set_site_transient_update_plugins pre_set_site_transient_update_themes
Version source Plugin headers (get_plugin_data()) Theme headers (wp_get_theme())

No configuration flags are needed -- the detection is automatic based on the file path.

Built-in admin page

The drop-in automatically registers an admin page with:

  • License key input with Activate, Deactivate, and Refresh buttons.
  • Status display (active, expired, trial with countdown).
  • Tier name and feature list.
  • Masked key display after activation.

Unlike the 3-class system, the built-in admin page does not support custom branding options (brand_name, brand_color, brand_logo) or custom parent_slug placement.

Complete example

<?php
/**
 * Plugin Name: Simple Gallery
 * Version:     1.0.3
 * Description: A lightweight image gallery plugin.
 * Author:      Example Inc
 * Requires PHP: 7.4
 */

defined( 'ABSPATH' ) || exit;

require_once __DIR__ . '/includes/wplf-licensing.php';

// Initialize licensing -- one line is all you need
WPLF_Licensing::init( 'simple-gallery', 'https://licences.example.com', __FILE__, [
    'api_key' => 'lf_pk_gallery_xxxxxxxxxxxx',
] );

// Gate a premium feature elsewhere in the plugin
add_action( 'init', function () {
    if ( WPLF_Licensing::feature_available( 'lightbox', 'simple-gallery' ) ) {
        require_once __DIR__ . '/includes/lightbox.php';
    }
} );

Tradeoffs

Advantages

  • Single file to include -- fewer files to manage and ship.
  • Two lines of code to get started.
  • Auto-detects plugin vs. theme context.
  • Static helpers eliminate the need to pass an instance around.

Limitations

  • Less customisable admin page -- no branding or custom menu placement.
  • Larger single file compared to any individual class in the 3-class system.
  • All-or-nothing: you cannot use the updater without the admin page, or vice versa.

Tip

You can migrate from the drop-in to the 3-class system at any time without server-side changes. The stored license key and activation records are compatible between both approaches. Simply replace the file and update your bootstrap code.

Next steps