302 lines
10 KiB
PHP
302 lines
10 KiB
PHP
<?php
|
|
/**
|
|
* Handle WPForms submissions and trigger Mailjet actions.
|
|
*
|
|
* @package WPFMJ
|
|
* @subpackage WPFMJ/includes
|
|
*/
|
|
|
|
class WPFMJ_Form_Handler {
|
|
|
|
/**
|
|
* Maximum retry attempts (configurable via filter).
|
|
*/
|
|
private $max_retries;
|
|
|
|
/**
|
|
* Constructor.
|
|
*/
|
|
public function __construct() {
|
|
// Allow filtering of max retry attempts (default 3, min 1, max 5)
|
|
$this->max_retries = apply_filters('wpfmj_max_retry_attempts', 3);
|
|
$this->max_retries = max(1, min(5, absint($this->max_retries)));
|
|
}
|
|
|
|
/**
|
|
* Handle form submission.
|
|
*/
|
|
public function handle_submission($fields, $entry, $form_data, $entry_id) {
|
|
$form_id = $form_data['id'];
|
|
|
|
// Find all active automations for this form
|
|
$automations = $this->get_active_automations($form_id);
|
|
|
|
if (empty($automations)) {
|
|
return;
|
|
}
|
|
|
|
foreach ($automations as $automation) {
|
|
$this->process_automation($automation, $fields, $entry_id);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get active automations for a form.
|
|
*/
|
|
private function get_active_automations($form_id) {
|
|
$args = array(
|
|
'post_type' => 'wpfmj_automation',
|
|
'post_status' => 'publish',
|
|
'posts_per_page' => -1,
|
|
'meta_query' => array(
|
|
array(
|
|
'key' => '_wpfmj_form_id',
|
|
'value' => $form_id,
|
|
'compare' => '='
|
|
)
|
|
)
|
|
);
|
|
|
|
return get_posts($args);
|
|
}
|
|
|
|
/**
|
|
* Process a single automation.
|
|
*/
|
|
private function process_automation($automation, $fields, $entry_id) {
|
|
$automation_id = $automation->ID;
|
|
|
|
// Get automation settings
|
|
$config = get_post_meta($automation_id, '_wpfmj_config', true);
|
|
|
|
if (empty($config)) {
|
|
$this->log_error($automation_id, $entry_id, 'missing_config', 'Automation configuration is empty');
|
|
return;
|
|
}
|
|
|
|
// Validate config structure for data integrity
|
|
$required_keys = array('field_mapping', 'trigger_field_id', 'api_key', 'api_secret', 'list_mappings');
|
|
foreach ($required_keys as $key) {
|
|
if (!isset($config[$key])) {
|
|
$this->log_error($automation_id, $entry_id, 'invalid_config', "Missing required config key: {$key}");
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (!isset($config['field_mapping']['email'])) {
|
|
$this->log_error($automation_id, $entry_id, 'invalid_config', 'Email field mapping is missing');
|
|
return;
|
|
}
|
|
|
|
if (!is_array($config['list_mappings']) || empty($config['list_mappings'])) {
|
|
$this->log_error($automation_id, $entry_id, 'invalid_config', 'List mappings are empty or invalid');
|
|
return;
|
|
}
|
|
|
|
// Extract form data
|
|
$email = $this->get_field_value($fields, $config['field_mapping']['email']);
|
|
$firstname = $this->get_field_value($fields, $config['field_mapping']['firstname']);
|
|
$lastname = $this->get_field_value($fields, $config['field_mapping']['lastname']);
|
|
$trigger_value = $this->get_field_value($fields, $config['trigger_field_id']);
|
|
|
|
// Validate email address
|
|
if (empty($email)) {
|
|
$this->log_error($automation_id, $entry_id, 'missing_email', 'Email field is empty');
|
|
return;
|
|
}
|
|
|
|
// Sanitize and validate email format
|
|
$email = sanitize_email($email);
|
|
if (!is_email($email)) {
|
|
$this->log_error($automation_id, $entry_id, 'invalid_email', 'Email address is not valid: ' . sanitize_text_field($email));
|
|
return;
|
|
}
|
|
|
|
// Determine which lists to add the contact to based on trigger value
|
|
$lists_to_add = $this->get_lists_for_trigger_value($trigger_value, $config['list_mappings']);
|
|
|
|
if (empty($lists_to_add)) {
|
|
// No matching lists, this is normal behavior
|
|
return;
|
|
}
|
|
|
|
// Prepare contact properties
|
|
$properties = array();
|
|
if (!empty($firstname)) {
|
|
$properties['firstname'] = $firstname;
|
|
}
|
|
if (!empty($lastname)) {
|
|
$properties['lastname'] = $lastname;
|
|
}
|
|
|
|
// Add to Mailjet with retry logic
|
|
$this->add_to_mailjet_with_retry($automation_id, $entry_id, $email, $lists_to_add, $properties, $config['api_key'], $config['api_secret']);
|
|
}
|
|
|
|
/**
|
|
* Get field value from fields array.
|
|
*/
|
|
private function get_field_value($fields, $field_id) {
|
|
if (!isset($fields[$field_id])) {
|
|
return '';
|
|
}
|
|
|
|
$value = $fields[$field_id]['value'];
|
|
|
|
// Handle arrays (checkboxes, multi-select)
|
|
if (is_array($value)) {
|
|
return $value;
|
|
}
|
|
|
|
return sanitize_text_field($value);
|
|
}
|
|
|
|
/**
|
|
* Get lists for trigger value.
|
|
*/
|
|
private function get_lists_for_trigger_value($trigger_value, $mappings) {
|
|
$lists = array();
|
|
|
|
// Handle array values (checkboxes, multi-select)
|
|
if (is_array($trigger_value)) {
|
|
foreach ($trigger_value as $value) {
|
|
if (isset($mappings[$value])) {
|
|
$lists[] = $mappings[$value];
|
|
}
|
|
}
|
|
} else {
|
|
// Single value (radio, dropdown)
|
|
if (isset($mappings[$trigger_value])) {
|
|
$lists[] = $mappings[$trigger_value];
|
|
}
|
|
}
|
|
|
|
return array_unique(array_filter($lists));
|
|
}
|
|
|
|
/**
|
|
* Add to Mailjet with retry logic.
|
|
*/
|
|
private function add_to_mailjet_with_retry($automation_id, $entry_id, $email, $lists, $properties, $api_key, $api_secret) {
|
|
$decrypted_key = WPFMJ_Encryption::decrypt($api_key);
|
|
$decrypted_secret = WPFMJ_Encryption::decrypt($api_secret);
|
|
|
|
// Check for decryption failures (can happen if encryption key changed)
|
|
if ($decrypted_key === false || $decrypted_secret === false || empty($decrypted_key) || empty($decrypted_secret)) {
|
|
$this->log_error(
|
|
$automation_id,
|
|
$entry_id,
|
|
'decryption_failed',
|
|
'Failed to decrypt API credentials. The encryption key may have changed. Please re-save this automation with valid API credentials.'
|
|
);
|
|
$this->notify_admin_of_failure($automation_id, $entry_id, 'API credential decryption failed');
|
|
return;
|
|
}
|
|
|
|
$api = new WPFMJ_Mailjet_API($decrypted_key, $decrypted_secret);
|
|
|
|
$attempt = 0;
|
|
$success = false;
|
|
|
|
while ($attempt < $this->max_retries && !$success) {
|
|
$result = $api->add_contact_to_lists($email, $lists, $properties);
|
|
|
|
if (!is_wp_error($result)) {
|
|
$success = true;
|
|
|
|
// Log success
|
|
do_action('wpfmj_automation_success', $automation_id, $entry_id, $email, $lists);
|
|
} else {
|
|
$attempt++;
|
|
|
|
if ($attempt < $this->max_retries) {
|
|
// Exponential backoff: 1s, 2s, 4s
|
|
sleep(pow(2, $attempt - 1));
|
|
} else {
|
|
// Max retries reached, log error
|
|
$this->log_error(
|
|
$automation_id,
|
|
$entry_id,
|
|
'mailjet_api_error',
|
|
$result->get_error_message(),
|
|
$attempt
|
|
);
|
|
|
|
// Notify admin
|
|
$this->notify_admin_of_failure($automation_id, $entry_id, $result->get_error_message());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Log error.
|
|
*/
|
|
private function log_error($automation_id, $entry_id, $error_type, $error_message, $retry_count = 0) {
|
|
$logger = new WPFMJ_Error_Logger();
|
|
$logger->log($automation_id, $entry_id, $error_type, $error_message, $retry_count);
|
|
}
|
|
|
|
/**
|
|
* Notify admin of failure.
|
|
*/
|
|
private function notify_admin_of_failure($automation_id, $entry_id, $error_message) {
|
|
// Check if notifications are disabled
|
|
if (apply_filters('wpfmj_disable_failure_notifications', false)) {
|
|
return;
|
|
}
|
|
|
|
// Get notification recipients (filterable)
|
|
$default_email = get_option('admin_email');
|
|
$recipients = apply_filters('wpfmj_failure_notification_emails', array($default_email));
|
|
|
|
// Ensure recipients is an array
|
|
if (!is_array($recipients)) {
|
|
$recipients = array($default_email);
|
|
}
|
|
|
|
// Remove invalid emails
|
|
$recipients = array_filter($recipients, function($email) {
|
|
return is_email($email);
|
|
});
|
|
|
|
if (empty($recipients)) {
|
|
error_log('WPFMJ: No valid email recipients for failure notification');
|
|
return;
|
|
}
|
|
|
|
$automation_title = get_the_title($automation_id);
|
|
$site_name = get_bloginfo('name');
|
|
|
|
// Sanitize all data for email
|
|
$automation_title = sanitize_text_field($automation_title);
|
|
$site_name = sanitize_text_field($site_name);
|
|
$error_message = sanitize_textarea_field($error_message);
|
|
$entry_id = intval($entry_id);
|
|
|
|
$subject = sprintf(
|
|
'[%s] Mailjet Automation Failed',
|
|
$site_name
|
|
);
|
|
|
|
$message = sprintf(
|
|
"A Mailjet automation has failed after %d retry attempts.\n\nAutomation: %s\nEntry ID: %d\nError: %s\n\nPlease check the error logs in your WordPress admin.",
|
|
$this->max_retries,
|
|
$automation_title,
|
|
$entry_id,
|
|
$error_message
|
|
);
|
|
|
|
// Use wp_mail with proper headers
|
|
$headers = array('Content-Type: text/plain; charset=UTF-8');
|
|
|
|
// Send to all recipients
|
|
foreach ($recipients as $recipient) {
|
|
$sent = wp_mail($recipient, $subject, $message, $headers);
|
|
|
|
if (!$sent) {
|
|
error_log("WPFMJ: Failed to send notification email to {$recipient}");
|
|
}
|
|
}
|
|
}
|
|
}
|