Activations

Activations track which sites are using a given license. Each activation record represents a single site that has registered itself against a license key, and LicenceForge enforces per-license limits to control concurrent usage.

Activations table schema

All activation records are stored in the wplf_activations table. The following columns make up the schema:

Column Type Description
id BIGINT UNSIGNED Auto-incrementing primary key.
license_id BIGINT UNSIGNED Foreign key referencing wplf_licenses.id. Identifies which license this activation belongs to.
site_origin VARCHAR(255) The normalized origin URL of the client site (scheme + host). Derived from the site's home_url().
user_agent VARCHAR(500) The User-Agent string sent by the client site during activation. Used for diagnostics and identifying the WordPress version and server environment.
server_fingerprint VARCHAR(64) A SHA-256 hash of server environment attributes. Nullable—only populated when device fingerprinting is enabled for the product.
activated_at DATETIME Timestamp of when the site was activated. Set automatically on creation.
last_seen_at DATETIME Timestamp of the most recent validation request from this site. Updated on each successful validation call.
deactivated_at DATETIME Timestamp of when the activation was deactivated. NULL indicates the activation is still active.

Site origin normalization

The site_origin value is derived from the client site's home_url() and normalized before storage to ensure consistent matching. The normalization process:

  1. Parses the URL and extracts the scheme and host components.
  2. Converts the host to lowercase.
  3. Strips trailing slashes and path components.
  4. Removes the www. prefix if present (configurable via the wplf_strip_www filter).
  5. Removes default port numbers (:80 for HTTP, :443 for HTTPS).

For example, all of the following inputs would normalize to https://example.com:

https://example.com/
https://www.example.com
https://Example.COM:443/
https://www.example.com/wp/

Note

The normalization ensures that a site is not counted twice against the activation limit due to minor URL variations. If you need to preserve www. as a distinct origin, return false from the wplf_strip_www filter.

Activation limits

Each license has an activation_limit that defines the maximum number of concurrently active sites. This value is typically inherited from the price tier when the license is created, but can be overridden on individual licenses.

The active activation count is calculated as the number of rows in wplf_activations for the given license_id where deactivated_at IS NULL. When a new activation request arrives:

  1. The system checks whether the site_origin already has an active activation for this license.
  2. If yes, the existing activation is returned (idempotent). The last_seen_at timestamp is updated.
  3. If no, the active count is compared against activation_limit.
  4. If the limit has been reached, the activation is rejected with error code wplf_activation_limit_reached.
  5. If capacity is available, a new activation row is inserted.
$active_count = $wpdb->get_var( $wpdb->prepare(
    "SELECT COUNT(*) FROM {$this->activations_table}
     WHERE license_id = %d AND deactivated_at IS NULL",
    $license_id
) );

if ( $active_count >= $license->activation_limit ) {
    return new WP_Error(
        'wplf_activation_limit_reached',
        sprintf( 'Activation limit of %d reached.', $license->activation_limit ),
        [ 'status' => 403 ]
    );
}

Deactivation

Deactivating a site sets the deactivated_at timestamp on the activation record. The row is not deleted—it is preserved for audit purposes. Deactivation frees up one slot against the activation limit.

Deactivation can occur through several channels:

Client-initiated deactivation

The client library can call the POST /wplf/v1/licenses/deactivate endpoint, passing the license key and site origin. This is typically triggered when a customer deactivates the plugin from within their WordPress admin panel.

Admin deactivation

Administrators can deactivate individual sites from the license detail page in the WordPress admin. Each activation row displays a Deactivate button.

License detail page showing the activations section with site limit and activation status
The activations list on a license detail page, showing two active sites and one previously deactivated site.

Automatic deactivation

When a license transitions to an expired or cancelled state and the wplf_auto_deactivate option is enabled, all active activations for that license are deactivated automatically. See Auto-deactivation for details.

Last seen tracking

Every time a client site sends a successful validation request, the last_seen_at column on the corresponding activation record is updated. This provides administrators with visibility into which sites are actively using a license versus sites that were activated but may no longer be in use.

The last_seen_at value is displayed in the admin panel on the license detail page and can be used to identify stale activations. LicenceForge does not automatically deactivate stale sites, but administrators can do so manually or build custom logic using the wplf_activation_last_seen action hook.

API endpoints

Activations are managed through the following REST API endpoints:

Method Endpoint Description
POST /wplf/v1/licenses/activate Activate a site against a license key. Requires license_key and site_url in the request body.
POST /wplf/v1/licenses/deactivate Deactivate a site. Requires license_key and site_url.
GET /wplf/v1/admin/licenses/{id}/activations List all activations for a license (admin only). Returns both active and deactivated records.

See the REST API documentation for full request and response schemas.