Available on the regular plugin since version 1.5.0.
The API Validator loads additional API data into the request (like the License Key model) and applies endpoint validations.
WooCommerce License Keys allows you to customize and replace the validator class with your own, allowing you to replace entirely what data is loaded and validated by the API.
The following examples will replace the default validator with a custom one that will load the license key based on the customer email instead of the license key code.
Extend wc_find_license_key
The first thing needed, will be to extend the function wc_find_license_key()
and allow it to search a license key if an email
is passed as search arguments. We use filter woocommerce_license_key_find
to achieve this:
add_filter( 'woocommerce_license_key_find', function( $license_key, $args ) { // Search first license key found by email if ( array_key_exists( 'email', $args ) && filter_var( $args['email'], FILTER_VALIDATE_EMAIL ) ) { $license_keys = \LicenseKeys\Models\LicenseKey::base_builder_with_meta( 'find_by_email' ) ->join( 'postmeta as `customer`', [ [ 'key_a' => 'customer.post_id', 'key_b' => 'items.order_id', ], [ 'key' => 'customer.meta_key', 'value' => '_customer_user', ], ] ) ->join( 'users as `users`', [ [ 'key_a' => 'customer.meta_value', 'key_b' => 'users.ID', ], [ 'key' => 'users.user_email', 'value' => $args['email'], ], ] ) ->order_by( 'items.order_id', 'DESC' ) // Latest order ->group_by( 'items.order_id' ) ->limit( 1 ) ->get( OBJECT, 'wc_license_key_builder_mapping' ); $license_keys = array_filter( $license_keys, 'wc_license_key_array_filter' ); return empty( $license_keys ) ? null : $license_keys[0]; } // Returns license key return $license_key; }, 10, 2 );
The customization above, will allow to search a license key like this:
$license_key = wc_find_license_key( ['email' => 'customer@email.com'] );
Add email parameter to request
You will need to add the email
as part of the parameters available for the API.
add_filter( 'woocommerce_license_keys_activate_request', function( $request ) { $request['email'] = \WPMVC\Request::input( 'email', false ); return $request; } );
The hook above needs to be added to the validation and deactivation requests as well.
If you plan to use WordPress REST API as the handler, then you will need to filter the whitelisted arguments as well.
add_filter( 'woocommerce_license_key_wp_rest_activate_args', function( $args ) { // Add email param $args['email'] = [ 'required' => true, 'sanitize_callback' => 'sanitize_text_field', ]; // Remove license key param unset( $args['license_key'] ); return $args; } );
The hook above needs to be applied for the validate and deactivate endpoints as well.
The validator
The API validator needs to be a class that implements the interface LicenseKeys\Interfaces\Validatable
. You can also extend the existing validator class and add your validations.
use WPMVC\Response; use LicenseKeys\Core\ValidationException; use LicenseKeys\Validators\ApiValidator; /** * Custom validator. */ class MyApiValidator extends ApiValidator { /** * Function triggered only for the activation API endpoint. * Called after common validation has run. * * @param array &$request * @param \WPMVC\Response &$response * @param array $args */ public function activate( &$request, Response &$response, $args ) { // Breakable validations if ( ! $this->is_valid( 'empty_store_code', $request, $response, $args ) ) throw new ValidationException(); if ( ! $this->is_valid( 'empty_email', $request, $response, $args ) ) throw new ValidationException(); if ( ! $this->is_valid( 'store_code', $request, $response, $args ) ) throw new ValidationException(); if ( ! $this->is_valid( 'email', $request, $response, $args ) ) throw new ValidationException(); if ( ! $this->get_license_key( $request, $response, $args ) ) throw new ValidationException(); // Non-breakable validations $this->is_valid( 'license_key_expire', $request, $response, $args ); $this->is_valid( 'license_key_limit', $request, $response, $args ); } /** * Returns flag indicating if validation was successful. * * @param string $validation Validation to make. * @param array &$request Request data. * @param object &$response Response. * @param array &$args Additional arguments. * * @return bool */ public function is_valid( $validation, &$request, &$response, $args = [] ) { $is_code = isset( $args['error_format'] ) && $args['error_format'] === 'code'; switch ( $validation ) { case 'empty_email': if ( empty( $request['email'] ) ) { $response->error( ( $is_code ? 1001 : 'email' ), __( 'Required.', 'my-text-domain' ) ); return false; } break; case 'email': $user = get_user_by( 'email', $request['email'] ); if ( empty( $user ) ) { $response->error( ( $is_code ? 1002 : 'email' ), __( 'Unknown email.', 'my-text-domain' ) ); return false; } break; } return parent::is_valid( $validation, $request, $response, $args ); } }
The example above, extends from the default validator, add custom validations to check if the email passed is valid, validates and loads license key to the request.
In the example above, the license_key
parameter and validation is removed entirely, for the endpoint activate, and it is replaced with the email
parameter instead.
The validator will use function wc_find_license_key()
to obtain the license key and will pass the $request
as search arguments; the function will search the license key because the email
parameter is present.
You will need to customize the methods validate()
and deactivate()
as well, so it supports the email
parameter across all endpoints.
Register custom validator
Custom validator needs to be registered using the hook woocommerce_license_keys_api_validator_class
.
add_filter( 'woocommerce_license_keys_api_validator_class', function() { return MyApiValidator::class; } );
The example above will replace the default validator with custom one, enabling all the custom functionality above.