PluginProbe
Kit (formerly ConvertKit) – Email Newsletter, Email Marketing, Membership, Subscribers and Landing Pages / 1.7.0
Kit (formerly ConvertKit) – Email Newsletter, Email Marketing, Membership, Subscribers and Landing Pages v1.7.0
3.4.1 3.4.0 3.3.9 3.3.8 3.3.7 3.3.6 3.3.5 3.3.4 3.3.3 3.3.2 3.3.1 2.2.0 2.2.1 2.2.2 2.2.3 2.2.4 2.2.5 2.2.6 2.2.7 2.2.8 2.2.9 2.3.0 2.3.1 2.3.2 2.3.3 All 194 releases
convertkit / includes / class-convertkit-api.php

class-convertkit-api.php in Kit (formerly ConvertKit) – Email Newsletter, Email Marketing, Membership, Subscribers and Landing Pages 1.7.0, at includes/class-convertkit-api.php

538 lines 13.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * ConvertKit API class
4 *
5 * @package ConvertKit
6 * @author ConvertKit
7 */
8
9 /**
10 * ConvertKit_API Class
11 * Establishes API connection to ConvertKit App
12 */
13 class ConvertKit_API {
14
15 /**
16 * ConvertKit API Key
17 *
18 * @var string
19 */
20 protected $api_key;
21
22 /**
23 * ConvertKit API Secret
24 *
25 * @var string
26 */
27 protected $api_secret;
28
29 /**
30 * Save debug data to log
31 *
32 * @var string
33 */
34 protected $debug;
35
36 /**
37 * Version of ConvertKit API
38 *
39 * @var string
40 */
41 protected $api_version = 'v3';
42
43 /**
44 * ConvertKit API URL
45 *
46 * @var string
47 */
48 protected $api_url_base = 'https://api.convertkit.com/';
49
50 /**
51 * API resources
52 *
53 * @var array
54 */
55 protected $resources = array();
56
57 /**
58 * Additional markup
59 *
60 * @var array
61 */
62 protected $markup = array();
63
64 /**
65 * Constructor for ConvertKitAPI instance
66 *
67 * @param string $api_key ConvertKit API Key.
68 * @param string $api_secret ConvertKit API Secret.
69 * @param string $debug Save data to log.
70 */
71 public function __construct( $api_key, $api_secret, $debug ) {
72 $this->api_key = $api_key;
73 $this->api_secret = $api_secret;
74 $this->debug = $debug;
75 }
76
77 /**
78 * Adds a tag to a subscriber
79 *
80 * @param int $tag Tag ID
81 * @param array $options Array of user data
82 * @return object
83 */
84 public function add_tag( $tag, $options ) {
85 $request = $this->api_version . sprintf( '/tags/%s/subscribe', $tag );
86
87 $args = array(
88 'api_key' => $this->api_key,
89 'email' => $options['email'],
90 );
91
92 return $this->make_request( $request, 'POST', $args );
93 }
94
95 /**
96 * Update resources in local options table.
97 *
98 * @param string $api_key
99 */
100 public function update_resources( $api_key ) {
101
102 $this->api_key = $api_key;
103
104 $forms = array();
105 $landing_pages = array();
106 $tags = array();
107
108 WP_ConvertKit::log( 'Updating resource with API key: ' . $api_key );
109 // Forms and Landing Pages
110 $api_response = $this->_get_api_response( 'forms' );
111 WP_ConvertKit::log( 'API Response: ' . print_r( $api_response, true ) );
112
113 if ( is_null( $api_response )
114 || is_wp_error( $api_response )
115 || isset( $api_response['error'] )
116 || isset( $api_response['error_message'] ) ) {
117 $error_message = isset( $api_response['error'] ) ? $api_response['error'] : 'unknown error';
118 $error_message .= is_wp_error( $api_response ) ? $api_response->get_error_message() : '';
119 WP_ConvertKit::log( 'Error contacting API: ' . $error_message );
120
121 $forms[0] = array(
122 'id' => '-2',
123 'name' => 'Error contacting API',
124 );
125 update_option( 'convertkit_forms', $forms );
126 update_option( 'convertkit_landing_pages', $landing_pages );
127 update_option( 'convertkit_tags', $tags );
128
129 } else {
130
131 $response = isset( $api_response['forms'] ) ? $api_response['forms'] : array();
132 foreach ( $response as $form ) {
133 if ( isset( $form['archived'] ) && $form['archived'] ) {
134 continue;
135 }
136
137 if ( 'hosted' === $form['type'] ) {
138 $landing_pages[ $form['id'] ] = $form;
139 } else {
140 $forms[ $form['id'] ] = $form;
141 }
142 }
143 update_option( 'convertkit_forms', $forms );
144 update_option( 'convertkit_landing_pages', $landing_pages );
145
146 // Tags
147 $api_response = $this->_get_api_response( 'tags' );
148 $response = isset( $api_response['tags'] ) ? $api_response['tags'] : array();
149 foreach ( $response as $tag ) {
150 $tags[] = $tag;
151 }
152 update_option( 'convertkit_tags', $tags );
153 }
154 }
155
156 /**
157 * Gets a resource index
158 *
159 * GET /{$resource}/
160 *
161 * @param string $resource Resource type.
162 * @return object API response
163 */
164 public function get_resources( $resource ) {
165
166 if ( ! array_key_exists( $resource, $this->resources ) ) {
167
168 if ( 'landing_pages' === $resource ) {
169 $api_response = $this->_get_api_response( 'forms' );
170 } else {
171 $api_response = $this->_get_api_response( $resource );
172 }
173
174 if ( is_null( $api_response ) || is_wp_error( $api_response ) || isset( $api_response['error'] ) || isset( $api_response['error_message'] ) ) {
175 $this->resources[ $resource ] = array(
176 array(
177 'id' => '-2',
178 'name' => 'Error contacting API',
179 ),
180 );
181 } else {
182 $_resource = array();
183
184 if ( 'forms' === $resource ) {
185 $response = isset( $api_response['forms'] ) ? $api_response['forms'] : array();
186 $forms = array();
187 foreach ( $response as $form ) {
188 if ( isset( $form['archived'] ) && $form['archived'] ) {
189 continue;
190 }
191 $_resource[] = $form;
192 $forms[ $form['id'] ] = $form;
193
194 }
195 update_option( 'convertkit_forms', $forms );
196 } elseif ( 'landing_pages' === $resource ) {
197
198 $response = isset( $api_response['forms'] ) ? $api_response['forms'] : array();
199 foreach ( $response as $landing_page ) {
200 if ( 'hosted' === $landing_page['type'] ) {
201 if ( isset( $landing_page['archived'] ) && $landing_page['archived'] ) {
202 continue;
203 }
204 $_resource[] = $landing_page;
205 }
206 }
207 update_option( 'convertkit_landing_pages', $_resource );
208 } elseif ( 'subscription_forms' === $resource ) {
209 foreach ( $api_response as $mapping ) {
210 if ( isset( $mapping['archived'] ) && $mapping['archived'] ) {
211 continue;
212 }
213 $_resource[ $mapping['id'] ] = $mapping['form_id'];
214 }
215 update_option( 'convertkit_subscription_forms', $_resource );
216 } elseif ( 'tags' === $resource ) {
217 $response = isset( $api_response['tags'] ) ? $api_response['tags'] : array();
218 foreach ( $response as $tag ) {
219 $_resource[] = $tag;
220 }
221 update_option( 'convertkit_tags', $_resource );
222 }
223
224 $this->resources[ $resource ] = $_resource;
225 } // End if().
226 } // End if().
227
228 return $this->resources[ $resource ];
229 }
230
231 /**
232 * Adds a subscriber to a form.
233 *
234 * @param string $form_id Form ID.
235 * @param array $options Array of user data.
236 */
237 public function form_subscribe( $form_id, $options ) {
238 $request = $this->api_version . sprintf( '/forms/%s/subscribe', $form_id );
239
240 $args = array(
241 'api_key' => $this->api_key,
242 'email' => $options['email'],
243 'name' => $options['name'],
244 );
245
246 $this->make_request( $request, 'POST', $args );
247 }
248
249 /**
250 * Remove subscription from a form
251 *
252 * @param array $options Array of user data.
253 */
254 public function form_unsubscribe( $options ) {
255 $request = $this->api_version . '/unsubscribe';
256
257 $args = array(
258 'api_secret' => $this->api_secret,
259 'email' => $options['email'],
260 );
261
262 $this->make_request( $request, 'PUT', $args );
263 }
264
265 /**
266 * Get the ConvertKit subscriber ID associated with email address if it exists.
267 * Return 0 if subscriber not found.
268 *
269 * @param $email_address
270 * @return int $subscriber_id
271 */
272 public function get_subscriber_id( $email_address ) {
273
274 $url = add_query_arg(
275 array(
276 'api_secret' => WP_ConvertKit::get_api_secret(),
277 'email_address' => $email_address,
278 'status' => 'all',
279 ),
280 'https://api.convertkit.com/v3/subscribers'
281 );
282
283 WP_ConvertKit::log( 'get_subscriber_id for: ' . $email_address );
284
285 $result = $this->get_resource( $url );
286 if ( is_wp_error( $result ) ) {
287 WP_ConvertKit::log( 'Error getting resource for: ' . $url . '. Error: ' . $result->get_error_messages() );
288 return 0;
289 }
290
291 $subs = json_decode( $result );
292
293 $subscribers = is_array( $subs->subscribers ) ? $subs->subscribers : array();
294 if ( $subscribers ) {
295 $subscriber = array_pop( $subscribers );
296 WP_ConvertKit::log( 'Found ' . count( $subscribers ) . ' subscribers' );
297 WP_ConvertKit::log( 'ID (' . $subscriber->id . ') ' . $subscriber->email_address );
298 return $subscriber->id;
299 }
300 WP_ConvertKit::log( 'Subscriber not found with email ' . $email_address );
301 // subscriber not found
302 return 0;
303
304 }
305
306 /**
307 * @param $subscriber_id
308 *
309 * @return int
310 */
311 public function get_subscriber( $subscriber_id ) {
312 $url = add_query_arg(
313 array(
314 'api_secret' => WP_ConvertKit::get_api_secret(),
315 ),
316 'https://api.convertkit.com/v3/subscribers/' . $subscriber_id
317 );
318
319 WP_ConvertKit::log( 'get_subscriber info for id: ' . $subscriber_id );
320
321 $result = $this->get_resource( $url );
322 if ( is_wp_error( $result ) ) {
323 WP_ConvertKit::log( 'Error getting resource for: ' . $url . '. Error: ' . $result->get_error_messages() );
324 return 0;
325 }
326
327 $result = json_decode( $result );
328
329 if ( isset( $result->subscriber ) ) {
330 $subscriber = $result->subscriber;
331 WP_ConvertKit::log( 'Found: (' . $subscriber->id . ') ' . $subscriber->email_address );
332 return $subscriber;
333 }
334
335 // subscriber not found
336 return 0;
337 }
338
339 /**
340 * Get a list of the tags for a subscriber.
341 *
342 * @param $subscriber_id
343 * @return array $subscriber_tags Array of tags for customer with key of tag_id
344 */
345 public function get_subscriber_tags( $subscriber_id ) {
346
347 $url = add_query_arg(
348 array(
349 'api_key' => WP_ConvertKit::get_api_key(),
350 ),
351 'https://api.convertkit.com/v3/subscribers/' . $subscriber_id . '/tags'
352 );
353
354 WP_ConvertKit::log( 'get_subscriber_tags for: ' . $subscriber_id );
355
356 $result = $this->get_resource( $url );
357 if ( is_wp_error( $result ) ) {
358 WP_ConvertKit::log( 'Error getting resource for: ' . $url . '. Error: ' . $result->get_error_messages() );
359 return array();
360 }
361 $result = json_decode( $result );
362 $tags = isset( $result->tags ) ? $result->tags : array();
363
364 if ( empty( $tags ) ) {
365 WP_ConvertKit::log( 'No tags found for customer.' );
366 } else {
367 WP_ConvertKit::log( 'Found ' . count( $tags ) . 'tags for subscriber' );
368 $tags = wp_list_pluck( $tags, 'name', 'id' );
369 }
370
371 return $tags;
372
373 }
374
375 /**
376 * Get markup from ConvertKit for the provided $url
377 *
378 * @param string $url URL of API action.
379 * @return string
380 */
381 public function get_resource( $url ) {
382 $resource = '';
383
384 if ( ! empty( $url ) && isset( $this->markup[ $url ] ) ) {
385 $resource = $this->markup[ $url ];
386 } elseif ( ! empty( $url ) ) {
387 WP_ConvertKit::log( 'API Request (get_resource): ' . $url );
388
389 $response = wp_remote_get(
390 $url,
391 array(
392 'timeout' => 10,
393 'Accept-Encoding' => 'gzip',
394 )
395 );
396
397 if ( ! is_wp_error( $response ) ) {
398
399 if ( ! function_exists( 'url_to_absolute' ) ) {
400 require_once( CONVERTKIT_PLUGIN_PATH . '/lib/url-to-absolute/url-to-absolute.php' );
401 }
402
403 // Maybe inflate response body.
404 // @see https://wordpress.stackexchange.com/questions/10088/how-do-i-troubleshoot-responses-with-wp-http-api
405 $inflate = @gzinflate( $response['body'] );
406 if ( $inflate ) {
407 $response['body'] = $inflate;
408 }
409
410 $body = wp_remote_retrieve_body( $response );
411
412 /** @var \simple_html_dom\simple_html_dom $html */
413 $html = \KubAT\PhpSimple\HtmlDomParser::str_get_html( $body );
414 foreach ( $html->find( 'a, link' ) as $element ) {
415 if ( isset( $element->href ) ) {
416 $element->href = url_to_absolute( $url, $element->href );
417 }
418 }
419
420 foreach ( $html->find( 'img, script' ) as $element ) {
421 if ( isset( $element->src ) ) {
422 $element->src = url_to_absolute( $url, $element->src );
423 }
424 }
425
426 foreach ( $html->find( 'form' ) as $element ) {
427 if ( isset( $element->action ) ) {
428 $element->action = url_to_absolute( $url, $element->action );
429 } else {
430 $element->action = $url;
431 }
432 }
433
434 // Check `status_code` for 200, otherwise log error.
435 if ( 200 === $response['response']['code'] ) {
436 $resource = $html->save();
437 $this->markup[ $url ] = $resource;
438 } else {
439 WP_ConvertKit::log( 'Status Code (' . $response['response']['code'] . ') for URL (' . $url . '): ' . $html->save() );
440 }
441 } else {
442 WP_ConvertKit::log( 'API Response was WP_Error (get_resource): ' .
443 'Code: ' . $response->get_error_code() . ' ' .
444 'Message: ' . $response->get_error_message()
445 );
446 } // End if().
447 } // End if().
448
449 return $resource;
450 }
451
452 /**
453 * Do a remote request.
454 *
455 * @param string $path Part of URL.
456 * @return array
457 */
458 private function _get_api_response( $path = '' ) {
459
460 $args = array(
461 'api_key' => $this->api_key,
462 );
463 $api_path = $this->api_url_base . $this->api_version;
464 $url = add_query_arg( $args, path_join( $api_path, $path ) );
465
466 $response = wp_remote_get(
467 $url,
468 array(
469 'timeout' => 10,
470 'Accept-Encoding' => 'gzip',
471 'sslverify' => false,
472 )
473 );
474
475 if ( is_wp_error( $response ) ) {
476 WP_ConvertKit::log( 'Error: ' . $response->get_error_message() );
477
478 return array(
479 'error' => $response->get_error_message(),
480 );
481 } else {
482
483 // Maybe inflate response body.
484 // @see https://wordpress.stackexchange.com/questions/10088/how-do-i-troubleshoot-responses-with-wp-http-api
485 $inflate = @gzinflate( $response['body'] );
486 if ( $inflate ) {
487 $response['body'] = $inflate;
488 }
489
490 $body = wp_remote_retrieve_body( $response );
491 $data = json_decode( $body, true );
492 }
493
494 return $data;
495 }
496
497 /**
498 * Make a request to the ConvertKit API
499 *
500 * @param string $request Request string.
501 * @param string $method HTTP Method.
502 * @param array $args Request arguments.
503 * @return object Response object
504 */
505 private function make_request( $request, $method, $args = array() ) {
506
507 WP_ConvertKit::log( 'API Request (make_request): ' . $request . ' Args: ' . wp_json_encode( $args ) );
508
509 $url = $this->api_url_base . $request;
510
511 $headers = array(
512 'Content-Type' => 'application/json; charset=utf-8',
513 );
514
515 $settings = array(
516 'headers' => $headers,
517 'method' => $method,
518 'body' => wp_json_encode( $args ),
519 );
520
521 $result = wp_remote_request( $url, $settings );
522
523 if ( is_wp_error( $result ) ) {
524 WP_ConvertKit::log( 'API Response (make_request): WPError: ' . $result->get_error_message() );
525 } elseif ( isset( $result['response']['code'] ) && '200' === $result['response']['code'] ) {
526 if ( isset( $result['body'] ) ) {
527 WP_ConvertKit::log( 'API Response (make_request): ' . $result['body'] );
528 } else {
529 WP_ConvertKit::log( 'API Response (make_request): Response code 200, but body is not set.' );
530 }
531 } else {
532 WP_ConvertKit::log( 'API Response (make_request): Result code: ' . $result['response']['code'] . ' ' . $result['response']['message'] );
533 }
534
535 }
536
537 }
538