Phase 09: Key Generator
Implement a configurable key generator that produces keys in any format (e.g., XXXX-XXXX-XXXX-XXXX), with support for sequential generation, random generation, and batch creation.
Files Written
Section titled “Files Written”src/Models/Generator.phpsrc/Services/GeneratorService.phpsrc/Repositories/GeneratorRepository.php
Generator Model
Section titled “Generator Model”A Generator record defines the format template for a batch of keys:
$generator->pattern // e.g. "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"$generator->character_set // e.g. "ABCDEFGHJKLMNPQRSTUVWXYZ23456789"$generator->separator // e.g. "-"$generator->prefix // e.g. "ACME-"$generator->max_activations // default seats for keys from this generator$generator->valid_for_days // default expiry window$generator->product_id // WooCommerce product this generator is linked toWhy exclude I, O, 1, 0? The default character set removes characters that are visually ambiguous when a customer reads a key from an email. This reduces support requests.
GeneratorService
Section titled “GeneratorService”Key generation algorithm
Section titled “Key generation algorithm”1. Load the Generator record.2. Walk the pattern left-to-right: - 'X' → pick random character from character_set (random_int for CSPRNG). - Other characters → use as literal separator.3. Prepend prefix if set.4. Check uniqueness against the database (license_key_hash lookup).5. Retry up to 10 times on collision before returning WP_Error.$key = $generator_svc->generate($generator_id); // single key string$keys = $generator_svc->generate_batch($generator_id, 50); // array of 50Circular dependency avoidance
Section titled “Circular dependency avoidance”GeneratorService::generate_batch() accepts an optional ?callable $create_fn parameter:
$svc->generate_batch($gen_id, 50, fn($key) => $license_svc->create($key, $attrs));When provided, the callable is invoked to persist each key rather than GeneratorService calling LicenseService directly. This avoids the GeneratorService → LicenseService → GeneratorService circular dependency. The REST controller supplies the callable.
REST Endpoint
Section titled “REST Endpoint”POST /wplm/v1/generators/{id}/generate
{ "count": 50 }Response: array of created license objects (keys excluded by default, visible to write-scoped API keys only).