Files
WooNooW/VALIDATION_HOOKS.md
Dwindi Ramadhana 0b2c8a56d6 feat: Newsletter system improvements and validation framework
- Fix: Marketing events now display in Staff notifications tab
- Reorganize: Move Coupons to Marketing/Coupons for better organization
- Add: Comprehensive email/phone validation with extensible filter hooks
  - Email validation with regex pattern (xxxx@xxxx.xx)
  - Phone validation with WhatsApp verification support
  - Filter hooks for external API integration (QuickEmailVerification, etc.)
- Fix: Newsletter template routes now use centralized notification email builder
- Add: Validation.php class for reusable validation logic
- Add: VALIDATION_HOOKS.md documentation with integration examples
- Add: NEWSLETTER_CAMPAIGN_PLAN.md architecture for future campaign system
- Fix: API delete method call in Newsletter.tsx (delete -> del)
- Remove: Duplicate EmailTemplates.tsx (using notification system instead)
- Update: Newsletter controller to use centralized Validation class

Breaking changes:
- Coupons routes moved from /routes/Coupons to /routes/Marketing/Coupons
- Legacy /coupons routes maintained for backward compatibility
2025-12-26 10:59:48 +07:00

8.3 KiB

Validation Filter Hooks

WooNooW provides extensible validation filter hooks that allow addons to integrate external validation services for emails and phone numbers.

Email Validation

Filter: woonoow/validate_email

Validates email addresses with support for external API integration.

Parameters:

  • $is_valid (bool|WP_Error): Initial validation state (default: true)
  • $email (string): The email address to validate
  • $context (string): Context of validation (e.g., 'newsletter_subscribe', 'checkout', 'registration')

Returns: true if valid, WP_Error if invalid

Built-in Validation:

  1. WordPress is_email() check
  2. Regex pattern validation: xxxx@xxxx.xx format
  3. Extensible via filter hook

Example: QuickEmailVerification.com Integration

add_filter('woonoow/validate_email', function($is_valid, $email, $context) {
    // Only validate for newsletter subscriptions
    if ($context !== 'newsletter_subscribe') {
        return $is_valid;
    }
    
    $api_key = get_option('my_addon_quickemail_api_key');
    if (!$api_key) {
        return $is_valid; // Skip if no API key configured
    }
    
    // Call QuickEmailVerification API
    $response = wp_remote_get(
        "https://api.quickemailverification.com/v1/verify?email={$email}&apikey={$api_key}",
        ['timeout' => 5]
    );
    
    if (is_wp_error($response)) {
        // Fallback to basic validation on API error
        return $is_valid;
    }
    
    $data = json_decode(wp_remote_retrieve_body($response), true);
    
    // Check validation result
    if (isset($data['result']) && $data['result'] !== 'valid') {
        return new WP_Error(
            'email_verification_failed',
            sprintf('Email verification failed: %s', $data['reason'] ?? 'Unknown'),
            ['status' => 400]
        );
    }
    
    return true;
}, 10, 3);

Example: Hunter.io Email Verification

add_filter('woonoow/validate_email', function($is_valid, $email, $context) {
    $api_key = get_option('my_addon_hunter_api_key');
    if (!$api_key) return $is_valid;
    
    $response = wp_remote_get(
        "https://api.hunter.io/v2/email-verifier?email={$email}&api_key={$api_key}"
    );
    
    if (is_wp_error($response)) return $is_valid;
    
    $data = json_decode(wp_remote_retrieve_body($response), true);
    
    if ($data['data']['status'] !== 'valid') {
        return new WP_Error('email_invalid', 'Email address is not deliverable');
    }
    
    return true;
}, 10, 3);

Phone Validation

Filter: woonoow/validate_phone

Validates phone numbers with support for external API integration and WhatsApp verification.

Parameters:

  • $is_valid (bool|WP_Error): Initial validation state (default: true)
  • $phone (string): The phone number to validate (cleaned, no formatting)
  • $context (string): Context of validation (e.g., 'checkout', 'registration', 'shipping')
  • $country_code (string): Country code if available (e.g., 'ID', 'US')

Returns: true if valid, WP_Error if invalid

Built-in Validation:

  1. Format check: 8-15 digits, optional + prefix
  2. Removes common formatting characters
  3. Extensible via filter hook

Example: WhatsApp Number Verification

add_filter('woonoow/validate_phone', function($is_valid, $phone, $context, $country_code) {
    // Only validate for checkout
    if ($context !== 'checkout') {
        return $is_valid;
    }
    
    $api_token = get_option('my_addon_whatsapp_api_token');
    if (!$api_token) return $is_valid;
    
    // Check if number is registered on WhatsApp
    $response = wp_remote_post('https://api.whatsapp.com/v1/contacts', [
        'headers' => [
            'Authorization' => 'Bearer ' . $api_token,
            'Content-Type' => 'application/json',
        ],
        'body' => json_encode([
            'blocking' => 'wait',
            'contacts' => [$phone],
        ]),
        'timeout' => 10,
    ]);
    
    if (is_wp_error($response)) {
        return $is_valid; // Fallback on API error
    }
    
    $data = json_decode(wp_remote_retrieve_body($response), true);
    
    // Check if WhatsApp ID exists
    if (!isset($data['contacts'][0]['wa_id'])) {
        return new WP_Error(
            'phone_not_whatsapp',
            'Phone number must be registered on WhatsApp for order notifications',
            ['status' => 400]
        );
    }
    
    return true;
}, 10, 4);

Example: Numverify Phone Validation

add_filter('woonoow/validate_phone', function($is_valid, $phone, $context, $country_code) {
    $api_key = get_option('my_addon_numverify_api_key');
    if (!$api_key) return $is_valid;
    
    $url = sprintf(
        'http://apilayer.net/api/validate?access_key=%s&number=%s&country_code=%s',
        $api_key,
        urlencode($phone),
        urlencode($country_code)
    );
    
    $response = wp_remote_get($url, ['timeout' => 5]);
    
    if (is_wp_error($response)) return $is_valid;
    
    $data = json_decode(wp_remote_retrieve_body($response), true);
    
    if (!$data['valid']) {
        return new WP_Error(
            'phone_invalid',
            sprintf('Invalid phone number: %s', $data['error'] ?? 'Unknown error')
        );
    }
    
    // Store carrier info for later use
    update_post_meta(get_current_user_id(), '_phone_carrier', $data['carrier'] ?? '');
    
    return true;
}, 10, 4);

Filter: woonoow/validate_phone_whatsapp

Convenience filter specifically for WhatsApp registration checks.

Parameters:

  • $is_registered (bool|WP_Error): Initial state (default: true)
  • $phone (string): The phone number (cleaned)
  • $context (string): Context of validation
  • $country_code (string): Country code if available

Returns: true if registered on WhatsApp, WP_Error if not


Usage in Code

Email Validation

use WooNooW\Core\Validation;

// Validate email for newsletter
$result = Validation::validate_email('user@example.com', 'newsletter_subscribe');

if (is_wp_error($result)) {
    // Handle error
    echo $result->get_error_message();
} else {
    // Email is valid
    // Proceed with subscription
}

Phone Validation

use WooNooW\Core\Validation;

// Validate phone for checkout
$result = Validation::validate_phone('+628123456789', 'checkout', 'ID');

if (is_wp_error($result)) {
    // Handle error
    echo $result->get_error_message();
} else {
    // Phone is valid
    // Proceed with order
}

Phone + WhatsApp Validation

use WooNooW\Core\Validation;

// Validate phone and check WhatsApp registration
$result = Validation::validate_phone_whatsapp('+628123456789', 'checkout', 'ID');

if (is_wp_error($result)) {
    // Phone invalid or not registered on WhatsApp
    echo $result->get_error_message();
} else {
    // Phone is valid and registered on WhatsApp
    // Proceed with order
}

Validation Contexts

Common contexts used throughout WooNooW:

  • newsletter_subscribe - Newsletter subscription form
  • checkout - Checkout process
  • registration - User registration
  • shipping - Shipping address validation
  • billing - Billing address validation
  • general - General validation (default)

Addons can filter based on context to apply different validation rules for different scenarios.


Best Practices

  1. Always fallback gracefully - If external API fails, return $is_valid to use basic validation
  2. Use timeouts - Set reasonable timeouts (5-10 seconds) for API calls
  3. Cache results - Cache validation results to avoid repeated API calls
  4. Provide clear error messages - Return descriptive WP_Error messages
  5. Check context - Only apply validation where needed to avoid unnecessary API calls
  6. Handle API keys securely - Store API keys in options, never hardcode
  7. Log errors - Log API errors for debugging without blocking users

Error Codes

Email Validation Errors

  • invalid_email - Basic format validation failed
  • invalid_email_format - Regex pattern validation failed
  • email_verification_failed - External API verification failed
  • email_validation_failed - Generic validation failure

Phone Validation Errors

  • invalid_phone - Basic format validation failed
  • phone_not_whatsapp - Phone not registered on WhatsApp
  • phone_invalid - External API validation failed
  • phone_validation_failed - Generic validation failure