api_key = $api_key; $this->api_secret = $api_secret; } /** * Test API connection. */ public function test_connection() { $response = $this->request('GET', '/contact'); return !is_wp_error($response); } /** * Get all contact lists. */ public function get_lists() { $response = $this->request('GET', '/contactslist?Limit=1000'); if (is_wp_error($response)) { return $response; } return isset($response['Data']) ? $response['Data'] : array(); } /** * Add contact to list(s). */ public function add_contact_to_lists($email, $lists, $properties = array()) { // Validate inputs if (empty($email) || !is_email($email)) { return new WP_Error('invalid_email', 'Invalid email address provided'); } if (!is_array($lists) || empty($lists)) { return new WP_Error('invalid_lists', 'Lists must be a non-empty array'); } // First, ensure contact exists $contact = $this->get_or_create_contact($email, $properties); if (is_wp_error($contact)) { return $contact; } // Validate contact response structure if (!isset($contact['ID'])) { return new WP_Error('invalid_contact_response', 'Contact response missing ID field'); } $contact_id = $contact['ID']; $results = array(); // Add contact to each list foreach ($lists as $list_id) { // Validate list ID $list_id = absint($list_id); if ($list_id === 0) { $results['invalid'] = new WP_Error('invalid_list_id', 'Invalid list ID'); continue; } $result = $this->add_contact_to_list($contact_id, $list_id); $results[$list_id] = $result; } return $results; } /** * Get or create a contact. */ private function get_or_create_contact($email, $properties = array()) { // Try to get existing contact $response = $this->request('GET', '/contact/' . rawurlencode($email)); if (!is_wp_error($response) && isset($response['Data'][0])) { // Contact exists, update properties if provided if (!empty($properties)) { $this->update_contact($email, $properties); } return $response['Data'][0]; } // Create new contact $data = array('Email' => $email); if (!empty($properties)) { $data['Properties'] = $properties; } $response = $this->request('POST', '/contact', $data); if (is_wp_error($response)) { return $response; } return isset($response['Data'][0]) ? $response['Data'][0] : new WP_Error('contact_creation_failed', 'Failed to create contact'); } /** * Update contact properties. */ private function update_contact($email, $properties) { $data = array('Data' => $properties); return $this->request('PUT', '/contactdata/' . rawurlencode($email), $data); } /** * Add contact to a specific list. */ private function add_contact_to_list($contact_id, $list_id) { $data = array( 'ContactID' => $contact_id, 'ListID' => $list_id, 'IsActive' => true ); return $this->request('POST', '/contactslist/' . $list_id . '/managecontact', $data); } /** * Make API request with rate limiting. */ private function request($method, $endpoint, $data = array()) { // Rate limiting: configurable via filter, default 60 requests per minute $rate_limit = apply_filters('wpfmj_api_rate_limit', 60); $rate_limit = max(10, min(300, absint($rate_limit))); // Clamp between 10-300 $rate_limit_key = 'wpfmj_api_rate_' . md5($this->api_key); $requests = get_transient($rate_limit_key); if ($requests === false) { $requests = 0; } if ($requests >= $rate_limit) { return new WP_Error('rate_limit_exceeded', sprintf( 'API rate limit exceeded (%d requests per minute). Please wait a moment and try again.', $rate_limit )); } // Increment request count set_transient($rate_limit_key, $requests + 1, 60); $url = $this->api_url . $endpoint; $args = array( 'method' => $method, 'headers' => array( 'Content-Type' => 'application/json', 'Authorization' => 'Basic ' . base64_encode($this->api_key . ':' . $this->api_secret) ), 'timeout' => 30, 'sslverify' => true ); if ($method === 'POST' || $method === 'PUT') { $args['body'] = wp_json_encode($data); } $response = wp_remote_request($url, $args); if (is_wp_error($response)) { return $response; } $code = wp_remote_retrieve_response_code($response); $body = wp_remote_retrieve_body($response); // Validate JSON response $json = json_decode($body, true); if (json_last_error() !== JSON_ERROR_NONE) { return new WP_Error( 'mailjet_json_error', sprintf('Invalid JSON response from Mailjet API: %s', json_last_error_msg()), array('status' => $code, 'body' => substr($body, 0, 200)) ); } if ($code >= 400) { $message = isset($json['ErrorMessage']) ? sanitize_text_field($json['ErrorMessage']) : 'API request failed'; return new WP_Error('mailjet_api_error', $message, array('status' => $code)); } return $json; } }