License Manager Product Validator
A WordPress plugin that provides page-level access control through license validation against the License Manager for WooCommerce API
by Thomas James Hole · github.com/stirtingale/license-manager-product-validator · website
Install
No release zip yet. The repository archive installs, but the folder name will carry the branch suffix and updates will not flow:
wp plugin install https://github.com/stirtingale/license-manager-product-validator/archive/refs/heads/main.zipA WordPress plugin that integrates with License Manager for WooCommerce to provide product-based license validation with protected content access and automatic order completion.
Developer: Thomas James Hole
Company: Stirtingale
Website: stirtingale.com
Version: 1.0.0
License: GPL v2 or later
Technical Overview
A WordPress plugin that provides page-level access control through license validation against the License Manager for WooCommerce API. Implements server-side session-based authentication with REST API integration for license verification. Additionally provides intelligent order auto-completion for products linked to protected pages, enabling seamless license delivery workflows.
Core Features
-
License-Based Page Protection
- Restrict page access to valid license holders
- Session-based authentication (1-hour TTL)
- REST API integration with License Manager
-
Automatic Order Completion
- Auto-complete orders containing products linked to protected pages
- Supports both free and paid orders
- Enables instant license delivery upon purchase
-
URL-Based License Entry
- Auto-fill license keys via URL parameters
- Direct customer access links
-
WooCommerce Integration
- Native settings tab in WooCommerce
- Page-level meta boxes
- Order notes and tracking
Architecture
Core Components
-
Session Management Layer
- PHP native sessions initialized on
inithook - Session-based access control with 1-hour TTL
- Per-page validation storage in
$_SESSION['lmfwc_validated_pages'][$page_id]
- PHP native sessions initialized on
-
API Integration
- REST API client using
wp_remote_get() - WooCommerce REST API authentication via query parameters
- Endpoint:
GET /wp-json/lmfwc/v2/licenses/{license_key} - Response parsing with JSON decode and error handling
- REST API client using
-
Content Protection
- WordPress filter hook:
the_content - Meta-based page configuration:
_lmfwc_required_product - Conditional content replacement for unauthorized access
- WordPress filter hook:
-
Admin Interface
- WooCommerce Settings API integration
- Custom settings tab:
WooCommerce → Settings → License Validator - Meta box on page edit screen for product assignment
Technical Implementation
License Validation Flow
1. User submits license key via POST form
2. PHP handler intercepts on 'init' hook
3. License key sanitized and validated
4. API request to License Manager:
- Endpoint: /wp-json/lmfwc/v2/licenses/{key}
- Authentication: consumer_key & consumer_secret
- Method: GET with SSL verification disabled (dev mode)
5. Response validation:
- HTTP 200 status check
- JSON parsing with error handling
- PHP notice/warning stripping from response body
6. License verification checks:
- Status in [1, 2, 3] (sold, delivered, active)
- Product ID match against page meta
- Expiration date validation
7. Session storage:
- Key: $_SESSION['lmfwc_validated_pages'][$page_id]
- Value: [product_id, license_key, timestamp]
8. Redirect to clean URL (remove license query param)
9. Content access granted on subsequent page load
Order Auto-Complete Flow
1. WooCommerce processes order
2. Order created with status "processing"
3. Hook: woocommerce_thankyou fires
4. Plugin checks order:
- Get all products in order
- Query: Find pages with auto-complete enabled
- Match: Does any page link to order products?
5. If match found:
- Order status → "completed"
- License Manager delivers license automatically
- Order note added with page details
6. Customer receives:
- License key email
- Immediate content access
Database Query for Auto-Complete:
-- Find pages with auto-complete enabled
SELECT post_id FROM wp_postmeta
WHERE meta_key = '_lmfwc_auto_complete_orders'
AND meta_value = '1'
-- Get product IDs for those pages
SELECT post_id, meta_value as product_id
FROM wp_postmeta
WHERE meta_key = '_lmfwc_required_product'
AND post_id IN (auto_complete_pages)
-- Match against order products
-- If match: auto_complete_order()
Database Schema
WordPress Options Table:
lmfwc_consumer_key- WooCommerce REST API consumer keylmfwc_consumer_secret- WooCommerce REST API consumer secret
WordPress Post Meta:
_lmfwc_required_product- Product ID required for page access_lmfwc_auto_complete_orders- Auto-complete flag ('1' = enabled)
PHP Session:
$_SESSION['lmfwc_validated_pages'] = [
{page_id} => [
'product_id' => int,
'license_key' => string,
'timestamp' => unix_timestamp
]
]
API Authentication
Uses WooCommerce REST API authentication with query parameter method:
GET /wp-json/lmfwc/v2/licenses/{license_key}
?consumer_key={key}
&consumer_secret={secret}
Response Structure:
{
"success": true,
"data": {
"id": 1,
"orderId": 165,
"productId": 20,
"userId": 1,
"licenseKey": "XXXX-XXXX-XXXX-XXXX",
"expiresAt": "2025-12-31 23:59:59",
"validFor": null,
"source": 2,
"status": 2,
"timesActivated": 0,
"timesActivatedMax": 500,
"createdAt": "2023-12-11 07:27:15",
"updatedAt": "2023-12-26 13:14:34"
}
}
License Status Codes
| Code | Status | Validation |
|---|---|---|
| 1 | Sold | ✅ Valid |
| 2 | Delivered/Active | ✅ Valid |
| 3 | Active | ✅ Valid |
| Other | Inactive/Expired | ❌ Invalid |
Use Case & Requirements
Intended Use Case
Content Protection for Licensed Products:
A WordPress site sells digital products (courses, software, templates) via WooCommerce with License Manager. Each product has associated premium content pages that should only be accessible to customers who have purchased and hold a valid license key.
Primary Workflow:
- Customer purchases product → receives license key
- Customer navigates to protected content page
- System prompts for license key entry
- System validates license against License Manager database
- If valid: content revealed, session created (1 hour)
- If invalid: access denied with error message
URL-based License Auto-fill: Customers can receive direct links with embedded license keys:
https://yoursite.com/premium-content/?license=XXXX-XXXX-XXXX-XXXX
System auto-fills and validates the license key.
Auto-Complete Orders: The License Delivery Problem
The Challenge:
Traditional WooCommerce workflow requires manual order completion before License Manager delivers license keys. This creates a delivery delay and poor customer experience:
Customer Purchase → Order "Processing" → Admin manually completes → License delivered
↓
Customer waits, no access
The Solution: Product-Based Auto-Completion
This plugin automatically completes orders containing products that are linked to protected pages, triggering instant license delivery:
Customer Purchase → Order "Processing" → Plugin detects linked product → Auto-completes
↓
License delivered instantly
↓
Customer gets immediate access
Why Auto-Complete Specific Products?
1. Instant Digital Delivery
- Digital products (courses, software, templates) should deliver immediately
- No physical fulfillment required
- Customer expects instant access after payment
2. Improved Customer Experience
- No waiting for manual order processing
- Immediate license key delivery via email
- Direct access to protected content
- Reduces support requests ("Where's my license?")
3. Business Logic Alignment
- Protected pages indicate digital products requiring licenses
- If a page requires a license, the order should complete automatically
- Links product catalog to content access workflow
4. Selective Auto-Completion
- Not all products should auto-complete (physical goods, services)
- Only products with protected content pages auto-complete
- Gives granular control per product/page
Configuration Workflow
Admin configures per page:
- Edit page with premium content
- Set "Required Product License" → Select product
- Check "Auto-complete orders from this page"
- Save
Result:
- Page requires license for Product A
- Any order containing Product A auto-completes
- License Manager delivers license instantly
- Customer can immediately access page content
Example Scenario:
Page: "Advanced JavaScript Course"
├── Required Product: JavaScript Masterclass ($199)
└── ☑ Auto-complete orders
Order #123:
├── Product: JavaScript Masterclass ($199)
├── Status: Processing → Completed (auto)
└── License: MASTER-JS-2024-X7Y9 (delivered instantly)
Customer receives:
✓ Order confirmation email
✓ License key email
✓ Direct access link to course content
✓ Immediate access (no waiting)
When NOT to Use Auto-Complete
Don't enable auto-complete for:
- Physical products requiring shipment
- Products needing manual review/approval
- Products with manual setup requirements
- Subscription products with delayed activation
- High-value products requiring fraud verification
Best Practice: Only enable auto-complete for digital products with protected content pages that require immediate license delivery.
System Requirements
WordPress Environment:
- WordPress 5.0+
- PHP 7.2+
- PHP session support enabled
- SSL recommended (not required for dev)
Required Plugins:
- WooCommerce 3.0+
- License Manager for WooCommerce 2.0+
Server Configuration:
session.auto_start= 0 (PHP handles session start)allow_url_fopen= On (for wp_remote_get)max_execution_time>= 30 seconds
Installation & Configuration
1. Install Plugin
wp-content/plugins/license-manager-product-validator/
├── license-manager-product-validator.php
├── README.md
├── templates/
│ └── widget-form.php
└── assets/
├── css/
│ └── style.css
└── js/
└── script.js
Activate via: Plugins → Activate License Manager Product Validator
2. Generate API Credentials
Option A: WooCommerce REST API
- Navigate to:
WooCommerce → Settings → Advanced → REST API - Click "Add key"
- Configure:
- Description: "License Validator"
- User: Admin user
- Permissions: Read
- Generate and copy Consumer Key & Secret
Option B: License Manager API
- Navigate to:
WooCommerce → Settings → License Manager → REST API - Click "Create Key"
- Same configuration as Option A
3. Configure Plugin
- Navigate to:
WooCommerce → Settings → License Validator - Paste Consumer Key (starts with
ck_) - Paste Consumer Secret (starts with
cs_) - Save Changes
- Verify green checkmark: "API credentials are configured"
4. Protect Pages & Configure Auto-Complete
Per-Page Configuration:
- Edit target page in WordPress
- Sidebar: "License Validation Settings" meta box
- Select required product from dropdown
- Optional: Check "Auto-complete orders from this page"
- Save page
Meta Box Fields:
- Required Product License: Product that users must have a valid license for
- Auto-complete orders: When enabled, any order containing this product auto-completes
Result:
- Page content replaced with license validation form until valid license provided
- Orders containing the linked product complete automatically if auto-complete enabled
Code Architecture
Class Structure
LMFWC_Product_Validator (Singleton)
├── start_session() // Initialize PHP sessions
├── handle_license_submission() // Process form POST
├── check_page_access() // Template redirect hook
├── show_access_denied() // Content filter replacement
├── get_licensed_products() // Query products with licenses
├── add_settings_tab() // WooCommerce settings integration
├── settings_tab_content() // Render settings form
└── update_settings() // Save settings handler
LMFWC_Product_Validator_Widget (WP_Widget)
├── widget() // Render widget output
├── form() // Admin widget config
└── update() // Save widget settings
Hook Implementation
// Session & Form Processing
add_action('init', 'start_session');
add_action('init', 'handle_license_submission');
// Access Control
add_action('template_redirect', 'check_page_access');
add_filter('the_content', 'show_access_denied');
// Order Auto-Complete
add_action('woocommerce_thankyou', 'auto_complete_orders');
// Admin Interface
add_filter('woocommerce_settings_tabs_array', 'add_settings_tab');
add_action('woocommerce_settings_tabs_lmfwc_validator', 'settings_tab_content');
add_action('woocommerce_update_options_lmfwc_validator', 'update_settings');
add_action('add_meta_boxes', 'lmfwc_add_page_meta_box');
add_action('save_post', 'lmfwc_save_page_meta');
// Widget
add_action('widgets_init', 'register_widget');
// AJAX
add_action('wp_ajax_lmfwc_logout', 'ajax_logout');
add_action('wp_ajax_nopriv_lmfwc_logout', 'ajax_logout');
Security Implementation
Input Sanitization:
$license_key = sanitize_text_field($_POST['license_key']);
$product_id = intval($_POST['product_id']);
$page_id = intval($_POST['page_id']);
Nonce Verification:
wp_verify_nonce($_POST['lmfwc_nonce'], 'lmfwc_validate_license');
Session Validation:
$validated = isset($_SESSION['lmfwc_validated_pages'][$page_id])
&& $_SESSION['lmfwc_validated_pages'][$page_id]['product_id'] == $required_product
&& $_SESSION['lmfwc_validated_pages'][$page_id]['timestamp'] > (time() - 3600);
Safe Redirects:
wp_safe_redirect(remove_query_arg('license', get_permalink($page_id)));
Widget Implementation
Purpose: Optional sidebar widget for license validation (alternative to inline form)
Usage:
Appearance → Widgets- Add "License Product Validator" to sidebar
- Configure title
- Displays product dropdown + license input
Note: Not required for core functionality. Inline form on protected pages is primary interface.
Debug Mode
Enabled by default for troubleshooting. Shows detailed validation flow:
$debug_mode = true; // Set to false to disable
Debug Output Includes:
- License key (masked)
- Product & Page IDs
- API URL with authentication
- HTTP response code
- Raw & decoded JSON response
- Validation checks (status, product match, expiration)
- Session storage confirmation
Location: Appears on protected pages after form submission
Production: Set $debug_mode = false in handle_license_submission() method
Performance Considerations
Session Storage
- In-memory PHP sessions (not database)
- Minimal overhead per page load
- Auto-cleanup after 1 hour TTL
API Calls
- Single GET request per validation
- No polling or background checks
- Cached in session after validation
- 15-second timeout prevents hanging
Database Queries
get_licensed_products(): Runs once per widget render- Uses
wp_cachefor repeat calls - Post meta queries optimized with indexes
Limitations & Constraints
-
PHP Sessions Required
- Will not work with object caching without session handler
- Redis/Memcached requires custom session storage
-
Single Product Per Page
- One license per page limitation
- Multiple products require separate pages
-
No License Activation
- Plugin validates but does not activate licenses
- Use License Manager's activate endpoint if needed
-
Session-Based Only
- No persistent authentication (cookies, JWT)
- User must re-validate after 1 hour
-
REST API Dependency
- Requires License Manager REST API enabled
- Breaks if License Manager plugin deactivated
Troubleshooting
Common Issues
"Consumer key or secret is missing"
- API credentials not configured
- Check:
WooCommerce → Settings → License Validator - Verify keys start with
ck_andcs_
"Invalid license key"
- License doesn't exist in database
- Check:
License Manager → Licenses - Verify license key spelling/format
"License is not active"
- License status is not 1, 2, or 3
- Check license status in License Manager admin
"This license key does not belong to the selected product"
- Product ID mismatch
- Verify page meta
_lmfwc_required_productmatches license product
Orders not auto-completing
- Verify page has auto-complete checkbox enabled
- Check order contains product linked to page
- Review order notes for "Auto-Complete Debug" details
- Check debug.log for LMFWC Auto-Complete entries
- Ensure order status is "processing" (not "pending" or "on-hold")
Sessions not persisting
- PHP sessions disabled
- Check
phpinfo()for session support - Server may be blocking session cookies
Headers already sent warning
- PHP output before session_start()
- Check for whitespace/BOM in PHP files
- Enable error_log to find source
Debug Checklist
- Enable WordPress debug mode:
define('WP_DEBUG', true);
define('WP_DEBUG_LOG', true);
- Check session ID exists:
// Add to plugin for testing
echo 'Session ID: ' . session_id();
- Test API credentials manually:
curl "https://yoursite.com/wp-json/lmfwc/v2/licenses/YOUR-KEY?consumer_key=ck_xxx&consumer_secret=cs_xxx"
- Verify license in database:
SELECT * FROM wp_lmfwc_licenses WHERE license_key = 'YOUR-KEY';
- Check page meta:
get_post_meta($page_id, '_lmfwc_required_product', true);
get_post_meta($page_id, '_lmfwc_auto_complete_orders', true);
- Test order auto-complete manually:
// Check if product should auto-complete
$order = wc_get_order(123);
$items = $order->get_items();
foreach ($items as $item) {
$product_id = $item->get_product_id();
// Check if any page links this product with auto-complete enabled
}
Extending the Plugin
Custom Validation Logic
add_filter('lmfwc_validator_before_validation', function($license_key, $product_id) {
// Custom pre-validation logic
return true; // Return false to block validation
}, 10, 2);
Custom Access Denied Message
add_filter('the_content', function($content) {
if (is_page() && !lmfwc_is_validated()) {
return '<div class="custom-denied">Your custom message</div>';
}
return $content;
}, 5); // Priority 5 to run before plugin
Additional License Checks
add_action('lmfwc_validator_after_api_call', function($license_data, $page_id) {
// Check custom license meta
// Log validation attempts
// Send notifications
}, 10, 2);
API Reference
Helper Functions
// Check if current page is validated
lmfwc_is_validated($page_id = null)
// Get validated license key for page
lmfwc_get_validated_license($page_id)
// Clear validation for page
lmfwc_clear_validation($page_id)
// Get required product for page
lmfwc_get_required_product($page_id)
JavaScript Events
// Validation success
jQuery(document).on("lmfwc_validation_success", function (e, data) {
console.log("License validated:", data.license_key);
});
// Validation failure
jQuery(document).on("lmfwc_validation_failed", function (e, error) {
console.log("Validation failed:", error.message);
});
Version History
1.0.0 (Initial Release)
- PHP session-based access control
- License Manager REST API integration
- WooCommerce settings integration
- Page-level product assignment
- URL parameter license auto-fill
- Debug mode for troubleshooting
- Widget for sidebar placement
- AJAX logout functionality
- Auto-complete orders for products linked to protected pages
- Product-based order completion logic
- Detailed order notes for auto-completion tracking
License
This plugin is licensed under GPL v2 or later.
Copyright (C) 2025 Thomas James Hole / Stirtingale
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
Support & Contact
Developer: Thomas James Hole
Company: Stirtingale
Website: https://stirtingale.com
For bug reports, feature requests, or technical support, please contact through the official website.
Credits
Built with integration for:
- License Manager for WooCommerce
- WordPress Core APIs
- WooCommerce Settings API