PluginProbe
Kit (formerly ConvertKit) – Email Newsletter, Email Marketing, Membership, Subscribers and Landing Pages / 1.6.4
Kit (formerly ConvertKit) – Email Newsletter, Email Marketing, Membership, Subscribers and Landing Pages v1.6.4
3.4.2 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 All 195 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.6.4, at includes/class-convertkit-api.php

541 lines 13.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * ConvertKit PI 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( 'str_get_html' ) ) {
400 require_once( dirname( __FILE__ ) . '/../lib/simple-html-dom/simple-html-dom.php' );
401 }
402
403 if ( ! function_exists( 'url_to_absolute' ) ) {
404 require_once( dirname( __FILE__ ) . '/../lib/url-to-absolute/url-to-absolute.php' );
405 }
406
407 // Maybe inflate response body.
408 // @see https://wordpress.stackexchange.com/questions/10088/how-do-i-troubleshoot-responses-with-wp-http-api
409 $inflate = @gzinflate( $response['body'] );
410 if ( $inflate ) {
411 $response['body'] = $inflate;
412 }
413
414 $body = wp_remote_retrieve_body( $response );
415
416 $html = str_get_html( $body );
417 foreach ( $html->find( 'a, link' ) as $element ) {
418 if ( isset( $element->href ) ) {
419 $element->href = url_to_absolute( $url, $element->href );
420 }
421 }
422
423 foreach ( $html->find( 'img, script' ) as $element ) {
424 if ( isset( $element->src ) ) {
425 $element->src = url_to_absolute( $url, $element->src );
426 }
427 }
428
429 foreach ( $html->find( 'form' ) as $element ) {
430 if ( isset( $element->action ) ) {
431 $element->action = url_to_absolute( $url, $element->action );
432 } else {
433 $element->action = $url;
434 }
435 }
436
437 // Check `status_code` for 200, otherwise log error.
438 if ( 200 === $response['response']['code'] ) {
439 $resource = $html->save();
440 $this->markup[ $url ] = $resource;
441 } else {
442 WP_ConvertKit::log( 'Status Code (' . $response['response']['code'] . ') for URL (' . $url . '): ' . $html->save() );
443 }
444 } else {
445 WP_ConvertKit::log( 'API Response was WP_Error (get_resource): ' .
446 'Code: ' . $response->get_error_code() . ' ' .
447 'Message: ' . $response->get_error_message()
448 );
449 } // End if().
450 } // End if().
451
452 return $resource;
453 }
454
455 /**
456 * Do a remote request.
457 *
458 * @param string $path Part of URL.
459 * @return array
460 */
461 private function _get_api_response( $path = '' ) {
462
463 $args = array(
464 'api_key' => $this->api_key,
465 );
466 $api_path = $this->api_url_base . $this->api_version;
467 $url = add_query_arg( $args, path_join( $api_path, $path ) );
468
469 $response = wp_remote_get(
470 $url,
471 array(
472 'timeout' => 10,
473 'Accept-Encoding' => 'gzip',
474 'sslverify' => false,
475 )
476 );
477
478 if ( is_wp_error( $response ) ) {
479 WP_ConvertKit::log( 'Error: ' . $response->get_error_message() );
480
481 return array(
482 'error' => $response->get_error_message(),
483 );
484 } else {
485
486 // Maybe inflate response body.
487 // @see https://wordpress.stackexchange.com/questions/10088/how-do-i-troubleshoot-responses-with-wp-http-api
488 $inflate = @gzinflate( $response['body'] );
489 if ( $inflate ) {
490 $response['body'] = $inflate;
491 }
492
493 $body = wp_remote_retrieve_body( $response );
494 $data = json_decode( $body, true );
495 }
496
497 return $data;
498 }
499
500 /**
501 * Make a request to the ConvertKit API
502 *
503 * @param string $request Request string.
504 * @param string $method HTTP Method.
505 * @param array $args Request arguments.
506 * @return object Response object
507 */
508 private function make_request( $request, $method, $args = array() ) {
509
510 WP_ConvertKit::log( 'API Request (make_request): ' . $request . ' Args: ' . wp_json_encode( $args ) );
511
512 $url = $this->api_url_base . $request;
513
514 $headers = array(
515 'Content-Type' => 'application/json; charset=utf-8',
516 );
517
518 $settings = array(
519 'headers' => $headers,
520 'method' => $method,
521 'body' => wp_json_encode( $args ),
522 );
523
524 $result = wp_remote_request( $url, $settings );
525
526 if ( is_wp_error( $result ) ) {
527 WP_ConvertKit::log( 'API Response (make_request): WPError: ' . $result->get_error_message() );
528 } elseif ( isset( $result['response']['code'] ) && '200' === $result['response']['code'] ) {
529 if ( isset( $result['body'] ) ) {
530 WP_ConvertKit::log( 'API Response (make_request): ' . $result['body'] );
531 } else {
532 WP_ConvertKit::log( 'API Response (make_request): Response code 200, but body is not set.' );
533 }
534 } else {
535 WP_ConvertKit::log( 'API Response (make_request): Result code: ' . $result['response']['code'] . ' ' . $result['response']['message'] );
536 }
537
538 }
539
540 }
541