PluginProbe
UiCore Elements – Free widgets and templates for Elementor / 1.3.18
UiCore Elements – Free widgets and templates for Elementor v1.3.18
1.3.18 1.3.17 1.3.16 trunk 1.0.0 1.0.1 1.0.10 1.0.11 1.0.12 1.0.13 1.0.14 1.0.15 1.0.16 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.0.7 1.0.8 1.0.9 1.2.0 1.2.1 1.2.2 1.2.3 All 42 releases
uicore-elements / includes / utils / newsletter-services.php

newsletter-services.php in UiCore Elements – Free widgets and templates for Elementor 1.3.18, at includes/utils/newsletter-services.php

370 lines 13.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace UiCoreElements\Utils;
4
5 defined('ABSPATH') || exit();
6
7 /**
8 * Email and Form service providers methods
9 *
10 * Fields expected structure:
11 * array(
12 * 'email' => '[email protected]', // *required
13 * 'name' => 'Thomas',
14 * 'last_name' => 'Sankara',
15 * 'phone' => '+55 21 9999-9999',
16 * 'birthday' => '1990-01-01',
17 * )
18 *
19 * Custom Fields expected structure:
20 * array(
21 * 'country' => array(
22 * 'value' => 'Burkina Faso',
23 * 'method' => 'sanitize_text_field', // `sanitize_phone` and `sanitize_birthday` are custom methods available within this class.
24 * ),
25 * 'website' => array(
26 * 'value' => 'https://www.website.gov',
27 * 'method' => 'sanitize_url'
28 * ),
29 * )
30 *
31 * List Expected structure:
32 * array( 'abjm194', 'kmlrmg9482903-30' )
33 *
34 *
35 * @param string $api_key - API key for the service provider.
36 * @param array $data - Data to be sent to the service provider.
37 */
38
39 class Newsletter_Services
40 {
41
42 protected $api_key, $fields, $list, $custom_fields, $headers;
43
44 public function __construct(string $api_key, array $fields, array $list, array $custom_fields = [])
45 {
46 $this->api_key = $api_key;
47 $this->fields = $fields;
48 $this->list = $list;
49 $this->custom_fields = $custom_fields;
50
51 $this->headers = [
52 'Content-Type' => 'application/json',
53 ];
54 }
55
56 /**
57 * Handle the requested newsletter service.
58 * You must pass the service api key and the data in the class constructor before calling this method.
59 */
60 public function handle(string $service)
61 {
62 if (empty($this->api_key)) {
63 throw new Newsletter_Service_Exception(esc_html__('Your API key is missing.', 'uicore-elements'));
64 }
65
66 if (empty($this->list)) {
67 throw new Newsletter_Service_Exception(esc_html__("You haven't set any list; group; form or audience ID.", 'uicore-elements'));
68 }
69
70 if (!method_exists($this, $service)) {
71 throw new \Exception(esc_html__('Unsupported service provider.', 'uicore-elements'));
72 }
73
74 return call_user_func([$this, $service]);
75 }
76
77 /**
78 * Returns the list of available services.
79 *
80 * @param mixed $filter - Let you return only the service keys, if set to 'keys',
81 * or only the service names, if set to 'names'. Default is
82 * false, which returns the full array.
83 *
84 * @return array - An associative array of service keys and values or a simple array of keys or values
85 */
86 public static function get_services_list($filter = false)
87 {
88 $services = [
89 'brevo' => esc_html__('Brevo', 'uicore-elements'),
90 'getresponse' => esc_html__('GetResponse', 'uicore-elements'),
91 'kit' => esc_html__('Kit', 'uicore-elements'),
92 'mailchimp' => esc_html__('MailChimp', 'uicore-elements'),
93 'moosend' => esc_html__('Moosend', 'uicore-elements'),
94 'mailerlite' => esc_html__('MailerLite', 'uicore-elements'),
95 ];
96
97 if ($filter === 'keys') {
98 return array_keys($services);
99 } else if ($filter === 'names') {
100 return array_values($services);
101 }
102
103 return $services;
104 }
105
106 /**
107 * Services
108 */
109 protected function mailchimp()
110 {
111 $server = explode('-', $this->api_key)[1]; // Server value can be found on API key after the dash
112
113 $map = [
114 'name' => 'FNAME',
115 'last_name' => 'LNAME',
116 'phone' => 'PHONE',
117 'birthday' => 'BIRTHDAY',
118 ];
119
120 $this->headers['Authorization'] = 'Basic ' . base64_encode('anystring:' . sanitize_text_field($this->api_key));
121
122 $body = [
123 "email_address" => sanitize_email($this->fields['email']),
124 "status" => 'subscribed',
125 "merge_fields" => $this->build_fields($this->fields, $map, $this->custom_fields), // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
126 ];
127
128 $result = [];
129 foreach ($this->list as $list) {
130 $url = sanitize_url('https://' . $server . '.api.mailchimp.com/3.0/lists/' . $list . '/members/');
131 $result[] = $this->submit($url, $this->headers, $body);
132 }
133 return $result;
134 }
135 protected function brevo()
136 {
137 $map = [
138 'name' => 'FIRSTNAME',
139 'last_name' => 'LASTNAME',
140 'phone' => 'SMS',
141 'birthday' => 'BIRTHDAY'
142 ];
143
144 $this->headers['api-key'] = sanitize_text_field($this->api_key);
145
146 $body = [
147 'email' => sanitize_email($this->fields['email']),
148 'attributes' => $this->build_fields($this->fields, $map, $this->custom_fields), // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
149 'listIds' => array_map('intval', $this->list),
150 'updateEnabled' => true
151 ];
152
153 // Brevo doesn't accepts empty attributes object
154 if (empty($body['attributes'])) {
155 unset($body['attributes']);
156 }
157
158 $result = $this->submit('https://api.brevo.com/v3/contacts', $this->headers, $body);
159 return $result;
160 }
161 protected function kit()
162 {
163 $map = [
164 'last_name' => 'last_name',
165 'phone' => 'phone',
166 'birthday' => 'birthday',
167 ];
168
169 $body = [
170 'email' => sanitize_email($this->fields['email']),
171 'api_key' => sanitize_text_field($this->api_key),
172 'fields' => $this->build_fields($this->fields, $map, $this->custom_fields), // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
173 ];
174
175 if (isset($this->fields['name'])) {
176 $body['first_name'] = sanitize_text_field($this->fields['name']);
177 }
178
179 $result = [];
180 foreach ($this->list as $list) {
181 $url = sanitize_url('https://api.convertkit.com/v3/forms/' . $list . '/subscribe');
182 $result[] = $this->submit($url, $this->headers, $body);
183 }
184 return $result;
185 }
186 protected function moosend()
187 {
188 $body = [
189 'Email' => sanitize_email($this->fields['email']),
190 'api_key' => sanitize_text_field($this->api_key),
191 ];
192
193 if (isset($this->fields['name']) && !empty($this->fields['name'])) {
194 $body['Name'] = sanitize_text_field($this->fields['name']);
195 }
196
197 // Moosend has a different custom fields structure, compared to the other services, so we built it in here
198 foreach ($this->custom_fields as $key => $values) {
199 if (!empty($values['value'] && !empty($values['method']))) {
200 $body['CustomFields'][] = [
201 sanitize_text_field($key) . '=' . $this->get_sanitized_value($values['method'], $values['value']) // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
202 ];
203 }
204 }
205
206 $result = [];
207 foreach ($this->list as $list) {
208 $url = sanitize_url('https://api.moosend.com/v3/subscribers/' . $list . '/subscribe.json?apikey=' . $this->api_key);
209 $result[] = $this->submit($url, $this->headers, $body);
210 }
211 return $result;
212 }
213 protected function getresponse()
214 {
215 $body = ['email' => sanitize_email($this->fields['email'])];
216
217 if (isset($fields['name']) && !empty($fields['name'])) {
218 $body['name'] = sanitize_text_field($fields['name']);
219 }
220
221 // Getresponse has a different custom fields structure, compared to the other services, so we built it in here
222 foreach ($this->custom_fields as $key => $values) {
223 if (!empty($values['value']) && !empty($values['method'])) {
224 $body['customFieldValues'][] = [
225 'customFieldId' => sanitize_text_field($key),
226 'value' => [$this->get_sanitized_value($values['method'], $values['value'])] // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
227 ];
228 }
229 }
230
231 $result = [];
232 foreach ($this->list as $list) {
233 $this->headers['X-Auth-Token'] = 'api-key ' . sanitize_text_field($this->api_key);
234 $body['campaign'] = ['campaignId' => sanitize_text_field($list)];
235 $result[] = $this->submit('https://api.getresponse.com/v3/contacts', $this->headers, $body);
236 }
237 return $result;
238 }
239 protected function mailerlite()
240 {
241 $map = [
242 'name' => 'name',
243 'last_name' => 'last_name',
244 'phone' => 'phone',
245 ];
246
247 $this->headers['Authorization'] = 'Bearer ' . sanitize_text_field($this->api_key);
248
249 $body = [
250 'email' => sanitize_email($this->fields['email']),
251 'resubscribe' => true,
252 'autoresponders' => true,
253 'type' => 'active',
254 'groups' => $this->list, // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
255 'fields' => $this->build_fields($this->fields, $map, $this->custom_fields), // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
256 ];
257 return $this->submit('https://connect.mailerlite.com/api/subscribers', $this->headers, $body);
258 }
259
260 /**
261 * Send the post request to the service provider.
262 *
263 * @param string $url - The URL to send the request to.
264 * @param array $headers - The post request header.
265 * @param array $body - The post request body.
266 * @param int $timeout - The request timeout in seconds. Default is 15 seconds.
267 *
268 * @return array - The response from the service provider.
269 */
270 protected function submit($url, $headers, $body, $timeout = 15)
271 {
272 $response = wp_remote_post($url, [
273 'headers' => array_map('sanitize_text_field', $headers),
274 'body' => json_encode($body),
275 'timeout' => (int) $timeout,
276 ]);
277
278 if (is_wp_error($response)) {
279 return [
280 'status' => 'error',
281 'message' => $response->get_error_message()
282 ];
283 }
284
285 $body = wp_remote_retrieve_body($response);
286 $result = json_decode($body, true);
287
288 return $result;
289 }
290
291 /**
292 * Translate, sanitize and parse field values to be used in the request body.
293 *
294 * @param array $data - The array of default fields
295 * @param array $map - The reference map with the provider correspondent key for each default field available.
296 * @param array $custom_fields - An array of custom fields to merged to the fields stack. Default is empty.
297 *
298 * @return array - An array with each available data, sanitized and prepared to be added to the body request.
299 */
300 protected function build_fields(array $data, array $map, array $custom_fields = []): array
301 {
302 $fields = [];
303
304 // Default fields
305 foreach ($map as $reference => $key) {
306 if (isset($data[$reference]) && !empty($data[$reference])) {
307
308 $slug = sanitize_text_field($key);
309 $value = $data[$reference];
310
311 switch ($reference) {
312 case 'birthday':
313 $fields[$slug] = $this->sanitize_birthday($value);
314 break;
315 case 'phone':
316 $fields[$slug] = $this->sanitize_phone($value);
317 break;
318 default:
319 $fields[$slug] = sanitize_text_field($value);
320 }
321 }
322 }
323
324 // Merge custom fields using the provided sanitization method
325 if (isset($custom_fields)) {
326 foreach ($custom_fields as $key => $values) {
327 if (!empty($values['value'] && !empty($values['method']))) {
328 $fields[sanitize_text_field($key)] = $this->get_sanitized_value($values['method'], $values['value']); //call_user_func([$this, $values['method']], $values['value']);
329 }
330 }
331 }
332
333 return $fields;
334 }
335 /**
336 * Check if the provided sanitization method is available before sanitizing the value.
337 *
338 * @param @string $method - The sanitization method to call.
339 * @param mixed $value - The value to sanitize.
340 *
341 * @return mixed - The sanitized value or the original value if the method does not exist.
342 */
343 protected function get_sanitized_value(string $method, string $value)
344 {
345 if (method_exists($this, $method)) {
346 return call_user_func([$this, $method], $value); // methods within this class
347 } else if (function_exists($method)) {
348 return call_user_func($method, $value); // global functions
349 }
350 return $value;
351 }
352
353 /**
354 * Sanitizers
355 */
356 protected function sanitize_birthday(string $date, string $format = 'd/m')
357 {
358 $date = trim($date);
359 $timestamp = strtotime($date);
360 if (!$timestamp) {
361 return '';
362 }
363 return date($format, $timestamp);
364 }
365 protected function sanitize_phone(string $number)
366 {
367 return preg_replace('/[^\d+]/', '', $number ?? '');
368 }
369 }
370