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
This commit is contained in:
293
VALIDATION_HOOKS.md
Normal file
293
VALIDATION_HOOKS.md
Normal file
@@ -0,0 +1,293 @@
|
||||
# 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
|
||||
|
||||
```php
|
||||
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
|
||||
|
||||
```php
|
||||
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
|
||||
|
||||
```php
|
||||
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
|
||||
|
||||
```php
|
||||
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
|
||||
|
||||
```php
|
||||
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
|
||||
|
||||
```php
|
||||
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
|
||||
|
||||
```php
|
||||
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
|
||||
Reference in New Issue
Block a user