Custom Generators

Digital License Manager provides a way for developers to extend the default Generators algorithm for generating the license keys.

To implement your own Generator class you need to hook into the dlm_generator_class, for more details follow the guide below:

1. Custom Generator Class

Create a PHP class somewhere that will hold your Generator’s logic, this class should extend the base Generator class IdeoLogix\DigitalLicenseManager\Abstracts\AbstractGenerator.

The following implementation is the exact same StandardGenerator class but with additional error_log() call that will output the generated license in the error log stack (debug.log) for demonstration purposes.

<?php

use IdeoLogix\DigitalLicenseManager\Abstracts\AbstractGenerator;

class MyCustomGenerator extends AbstractGenerator {

	/**
	 * Generate list of licenses needed.
	 *
	 * @param $amount - Needed amount of licenses
	 * @param array $licenses - List of existing licenses
	 *
	 * @return WP_Error|array
	 */
	public function generate( $amount, $licenses = [] ) {
		// check if it's possible to create as many combinations using the input args
		$uniqueCharacters = count( array_unique( str_split( $this->generator->getCharset() ) ) );
		$maxPossibleKeys  = pow( $uniqueCharacters, $this->generator->getChunks() * $this->generator->getChunkLength() );

		if ( $amount > $maxPossibleKeys ) {
			return new WP_Error( 'data_error', __( 'It\'s not possible to generate that many keys with the given parameters, there are not enough combinations. Please review your inputs.', 'digital-license-manager' ), array( 'code' => 422 ) );
		}

		// Generate the license strings
		for ( $i = 0; $i < $amount; $i ++ ) {
			$licenses[] = $this->generate_licenses(
				$this->generator->getCharset(),
				$this->generator->getChunks(),
				$this->generator->getChunkLength(),
				$this->generator->getSeparator(),
				$this->generator->getPrefix(),
				$this->generator->getSuffix()
			);
		}

		// Remove duplicate entries from the array
		$licenses = array_unique( $licenses );

		// check if any licenses have been removed
		if ( count( $licenses ) < $amount ) {
			// regenerate removed license keys, repeat until there are no duplicates
			while ( count( $licenses ) < $amount ) {
				$licenses = $this->generate( ( $amount - count( $licenses ) ), $licenses );
			}
		}

		// Reindex and return the array
		return array_values( $licenses );
	}

	/**
	 * The algorithm for generating licenses based on the generator options
	 *
	 * @param $charset
	 * @param $chunks
	 * @param $chunkLength
	 * @param $separator
	 * @param $prefix
	 * @param $suffix
	 *
	 * @return string
	 */
	private function generate_licenses( $charset, $chunks, $chunkLength, $separator, $prefix, $suffix ) {

		$charsetLength = strlen( $charset );
		$licenseString = $prefix;

		// loop through the chunks
		for ( $i = 0; $i < $chunks; $i ++ ) {
			// add n random characters from $charset to chunk, where n = $chunkLength
			for ( $j = 0; $j < $chunkLength; $j ++ ) {
				$licenseString .= $charset[ rand( 0, $charsetLength - 1 ) ];
			}
			// do not add the separator on the last iteration
			if ( $i < $chunks - 1 ) {
				$licenseString .= $separator;
			}
		}

		$licenseString .= $suffix;

		error_log( 'Generated License: ' . $licenseString );

		return $licenseString;
	}
}

2. Register the generator class with a filter

Once you set up your logic, now it’s a time to put our new Generator class to a good use. For that purpose we will hook into the filter called dlm_generator_class

The below code is just a very simple / minimum code on how this should look, feel free to set up your own logic, you can even conditionally use different Generator by manipulating with the generator, order, product parameters.

<?php
/**
 * This is a custom generator class that overrides the default DLM functionality.
 *
 * This is just a very simple example, but you can also use the parameters to set up
 * your logic and conditionally change the generator.
 *
 * @param string $className
 * @param \IdeoLogix\DigitalLicenseManager\Database\Models\Resources\Generator $generator
 * @param \WC_Order|null $order
 * @param \WC_Product|null $product
 *
 * @return string
 */
function dlm_custom_generator_class( $className, $generator, $order, $product ) {
	require_once get_template_directory() . '/includes/dlm-custom-generator.php';

	return MyCustomGenerator::class;
}
add_filter( 'dlm_generator_class', 'dlm_custom_generator_class', 10, 4 );

Once this is done, the generator class should be used, to test that, try to invoke the Generator by placing a new order or generating licenses from the Generator edit page in the admin screen.