PluginProbe
Kit (formerly ConvertKit) – Email Newsletter, Email Marketing, Membership, Subscribers and Landing Pages / 1.9.7.9
Kit (formerly ConvertKit) – Email Newsletter, Email Marketing, Membership, Subscribers and Landing Pages v1.9.7.9
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 / lib / class-convertkit-api.php

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

1,596 lines 43.2 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 *
12 * @package ConvertKit
13 * @author ConvertKit
14 */
15 class ConvertKit_API {
16
17 /**
18 * ConvertKit API Key
19 *
20 * @var bool|string
21 */
22 protected $api_key = false;
23
24 /**
25 * ConvertKit API Secret
26 *
27 * @var bool|string
28 */
29 protected $api_secret = false;
30
31 /**
32 * Save debug data to log
33 *
34 * @var bool
35 */
36 protected $debug = false;
37
38 /**
39 * The plugin name.
40 *
41 * @var bool|string
42 */
43 protected $plugin_name;
44
45 /**
46 * The plugin path.
47 *
48 * @var bool|string
49 */
50 protected $plugin_path;
51
52 /**
53 * The plugin URL.
54 *
55 * @var bool|string
56 */
57 protected $plugin_url;
58
59 /**
60 * The plugin version.
61 *
62 * @var bool|string
63 */
64 protected $plugin_version;
65
66 /**
67 * Version of ConvertKit API
68 *
69 * @var string
70 */
71 protected $api_version = 'v3';
72
73 /**
74 * ConvertKit API URL
75 *
76 * @var string
77 */
78 protected $api_url_base = 'https://api.convertkit.com/';
79
80 /**
81 * Holds the log class for writing to the log file
82 *
83 * @var bool|ConvertKit_Log
84 */
85 public $log = false;
86
87 /**
88 * Holds an array of error messages, localized to the plugin
89 * using this API class.
90 *
91 * @var bool|array
92 */
93 public $error_messages = false;
94
95 /**
96 * Sets up the API with the required credentials.
97 *
98 * @since 1.9.6
99 *
100 * @param bool|string $api_key ConvertKit API Key.
101 * @param bool|string $api_secret ConvertKit API Secret.
102 * @param bool|object $debug Save data to log.
103 */
104 public function __construct( $api_key = false, $api_secret = false, $debug = false ) {
105
106 // Set API credentials, debugging and logging class.
107 $this->api_key = $api_key;
108 $this->api_secret = $api_secret;
109 $this->debug = $debug;
110 $this->plugin_name = ( defined( 'CONVERTKIT_PLUGIN_NAME' ) ? CONVERTKIT_PLUGIN_NAME : false );
111 $this->plugin_path = ( defined( 'CONVERTKIT_PLUGIN_PATH' ) ? CONVERTKIT_PLUGIN_PATH : false );
112 $this->plugin_url = ( defined( 'CONVERTKIT_PLUGIN_URL' ) ? CONVERTKIT_PLUGIN_URL : false );
113 $this->plugin_version = ( defined( 'CONVERTKIT_PLUGIN_VERSION' ) ? CONVERTKIT_PLUGIN_VERSION : false );
114
115 // Setup logging class if the required parameters exist.
116 if ( $this->debug && $this->plugin_path !== false ) {
117 $this->log = new ConvertKit_Log( $this->plugin_path );
118 }
119
120 // Define translatable / localized error strings.
121 // WordPress requires that the text domain be a string (e.g. 'woocommerce-convertkit') and not a variable,
122 // otherwise localization won't work.
123 // phpcs:disable
124 $this->error_messages = array(
125 // form_subscribe().
126 'form_subscribe_form_id_empty' => __( 'form_subscribe(): the form_id parameter is empty.', 'convertkit' ),
127 'form_subscribe_email_empty' => __( 'form_subscribe(): the email parameter is empty.', 'convertkit' ),
128
129 // sequence_subscribe().
130 'sequence_subscribe_sequence_id_empty' => __( 'sequence_subscribe(): the sequence_id parameter is empty.', 'convertkit' ),
131 'sequence_subscribe_email_empty' => __( 'sequence_subscribe(): the email parameter is empty.', 'convertkit' ),
132
133 // tag_subscribe().
134 'tag_subscribe_tag_id_empty' => __( 'tag_subscribe(): the tag_id parameter is empty.', 'convertkit' ),
135 'tag_subscribe_email_empty' => __( 'tag_subscribe(): the email parameter is empty.', 'convertkit' ),
136
137 // get_subscriber_by_email().
138 'get_subscriber_by_email_email_empty' => __( 'get_subscriber_by_email(): the email parameter is empty.', 'convertkit' ),
139 /* translators: Email Address */
140 'get_subscriber_by_email_none' => __( 'No subscriber(s) exist in ConvertKit matching the email address %s.', 'convertkit' ),
141
142 // get_subscriber_by_id().
143 'get_subscriber_by_id_subscriber_id_empty' => __( 'get_subscriber_by_id(): the subscriber_id parameter is empty.', 'convertkit' ),
144
145 // get_subscriber_tags().
146 'get_subscriber_tags_subscriber_id_empty' => __( 'get_subscriber_tags(): the subscriber_id parameter is empty.', 'convertkit' ),
147
148 // unsubscribe_email().
149 'unsubscribe_email_empty' => __( 'unsubscribe(): the email parameter is empty.', 'convertkit' ),
150
151 // get_all_posts().
152 'get_all_posts_posts_per_request_bound_too_low' => __( 'get_all_posts(): the posts_per_request parameter must be equal to or greater than 1.', 'convertkit' ),
153 'get_all_posts_posts_per_request_bound_too_high' => __( 'get_all_posts(): the posts_per_request parameter must be equal to or less than 50.', 'convertkit' ),
154
155 // get_posts().
156 'get_posts_page_parameter_bound_too_low' => __( 'get_posts(): the page parameter must be equal to or greater than 1.', 'convertkit' ),
157 'get_posts_per_page_parameter_bound_too_low' => __( 'get_posts(): the per_page parameter must be equal to or greater than 1.', 'convertkit' ),
158 'get_posts_per_page_parameter_bound_too_high' => __( 'get_posts(): the per_page parameter must be equal to or less than 50.', 'convertkit' ),
159
160 // request().
161 /* translators: HTTP method */
162 'request_method_unsupported' => __( 'API request method %s is not supported in ConvertKit_API class.', 'convertkit' ),
163 'request_rate_limit_exceeded' => __( 'Rate limit hit.', 'convertkit' ),
164 'response_type_unexpected' => __( 'The response from the API is not of the expected type array.', 'convertkit' ),
165 );
166 // phpcs:enable
167
168 }
169
170 /**
171 * Gets account information from the API.
172 *
173 * @since 1.9.6
174 *
175 * @return WP_Error|array
176 */
177 public function account() {
178
179 $this->log( 'API: account()' );
180
181 return $this->get(
182 'account',
183 array(
184 'api_secret' => $this->api_secret,
185 )
186 );
187
188 }
189
190 /**
191 * Gets all subscription forms from the API.
192 *
193 * @since 1.9.6
194 *
195 * @return WP_Error|array
196 */
197 public function get_subscription_forms() {
198
199 $this->log( 'API: get_subscription_forms()' );
200
201 // Send request.
202 return $this->get(
203 'subscription_forms',
204 array(
205 'api_key' => $this->api_key,
206 )
207 );
208
209 }
210
211 /**
212 * Gets all forms from the API.
213 *
214 * @since 1.9.6
215 *
216 * @return WP_Error|array
217 */
218 public function get_forms() {
219
220 $this->log( 'API: get_forms()' );
221
222 // Get all forms and landing pages from the API.
223 $forms = $this->get_forms_landing_pages();
224
225 // If an error occured, log and return it now.
226 if ( is_wp_error( $forms ) ) {
227 $this->log( 'API: get_forms(): Error: ' . $forms->get_error_message() );
228 return $forms;
229 }
230
231 return $forms['forms'];
232
233 }
234
235 /**
236 * Subscribes an email address to a form.
237 *
238 * @since 1.9.6
239 *
240 * @param int $form_id Form ID.
241 * @param string $email Email Address.
242 * @param string $first_name First Name.
243 * @param mixed $fields Custom Fields (false|array).
244 * @param mixed $tag_ids Tags (false|array).
245 * @return WP_Error|array
246 */
247 public function form_subscribe( $form_id, $email, $first_name = '', $fields = false, $tag_ids = false ) {
248
249 // Backward compat. if $email is an array comprising of email and name keys.
250 if ( is_array( $email ) ) { // @phpstan-ignore-line.
251 _deprecated_function( __FUNCTION__, '1.2.1', 'form_subscribe( $form_id, $email, $first_name )' );
252 $first_name = $email['name'];
253 $email = $email['email'];
254 }
255
256 $this->log( 'API: form_subscribe(): [ form_id: ' . $form_id . ', email: ' . $email . ', first_name: ' . $first_name . ' ]' );
257
258 // Sanitize some parameters.
259 $form_id = absint( $form_id );
260 $email = trim( $email );
261 $first_name = trim( $first_name );
262
263 // Return error if no Form ID or email address is specified.
264 if ( empty( $form_id ) ) {
265 return new WP_Error( 'convertkit_api_error', $this->get_error_message( 'form_subscribe_form_id_empty' ) );
266 }
267 if ( empty( $email ) ) {
268 return new WP_Error( 'convertkit_api_error', $this->get_error_message( 'form_subscribe_email_empty' ) );
269 }
270
271 // Build request parameters.
272 $params = array(
273 'api_key' => $this->api_key,
274 'email' => $email,
275 'first_name' => $first_name,
276 );
277 if ( $fields ) {
278 $params['fields'] = $fields;
279 }
280 if ( $tag_ids ) {
281 $params['tags'] = $tag_ids;
282 }
283
284 // Send request.
285 $response = $this->post( 'forms/' . $form_id . '/subscribe', $params );
286
287 // If an error occured, log and return it now.
288 if ( is_wp_error( $response ) ) {
289 $this->log( 'API: form_subscribe(): Error: ' . $response->get_error_message() );
290 return $response;
291 }
292
293 /**
294 * Runs actions immediately after the email address was successfully subscribed to the form.
295 *
296 * @since 1.2.1
297 *
298 * @param array $response API Response
299 * @param int $form_id Form ID
300 * @param string $email Email Address
301 * @param string $first_name First Name
302 * @param mixed $fields Custom Fields (false|array)
303 * @param mixed $tag_ids Tags (false|array)
304 */
305 do_action( 'convertkit_api_form_subscribe_success', $response, $form_id, $email, $first_name, $fields, $tag_ids );
306
307 return $response;
308
309 }
310
311 /**
312 * Gets all landing pages from the API.
313 *
314 * @since 1.9.6
315 *
316 * @return WP_Error|array
317 */
318 public function get_landing_pages() {
319
320 $this->log( 'API: get_landing_pages()' );
321
322 // Get all forms and landing pages from the API.
323 $forms = $this->get_forms_landing_pages();
324
325 // If an error occured, log and return it now.
326 if ( is_wp_error( $forms ) ) {
327 $this->log( 'API: get_landing_pages(): Error: ' . $forms->get_error_message() );
328 return $forms;
329 }
330
331 return $forms['landing_pages'];
332
333 }
334
335 /**
336 * Fetches all sequences from the API.
337 *
338 * @since 1.9.6
339 *
340 * @return WP_Error|array
341 */
342 public function get_sequences() {
343
344 $this->log( 'API: get_sequences()' );
345
346 $sequences = array();
347
348 // Send request.
349 $response = $this->get(
350 'sequences',
351 array(
352 'api_key' => $this->api_key,
353 )
354 );
355
356 // If an error occured, log and return it now.
357 if ( is_wp_error( $response ) ) {
358 $this->log( 'API: get_sequences(): Error: ' . $response->get_error_message() );
359 return $response;
360 }
361
362 // If the response isn't an array as we expect, log that no sequences exist and return a blank array.
363 if ( ! is_array( $response['courses'] ) ) {
364 $this->log( 'API: get_sequences(): Error: No sequences exist in ConvertKit.' );
365 return new WP_Error( 'convertkit_api_error', $this->get_error_message( 'response_type_unexpected' ) );
366 }
367
368 // If no sequences exist, log that no sequences exist and return a blank array.
369 if ( ! count( $response['courses'] ) ) {
370 $this->log( 'API: get_sequences(): Error: No sequences exist in ConvertKit.' );
371 return $sequences;
372 }
373
374 foreach ( $response['courses'] as $sequence ) {
375 $sequences[] = $sequence;
376 }
377
378 return $sequences;
379
380 }
381
382 /**
383 * Subscribes an email address to a sequence.
384 *
385 * @since 1.9.6
386 *
387 * @param int $sequence_id Sequence ID.
388 * @param string $email Email Address.
389 * @param string $first_name First Name.
390 * @param mixed $fields Custom Fields (false|array).
391 * @return WP_Error|array
392 */
393 public function sequence_subscribe( $sequence_id, $email, $first_name = '', $fields = false ) {
394
395 $this->log( 'API: sequence_subscribe(): [ sequence_id: ' . $sequence_id . ', email: ' . $email . ']' );
396
397 // Sanitize some parameters.
398 $sequence_id = absint( $sequence_id );
399 $email = trim( $email );
400 $first_name = trim( $first_name );
401
402 // Return error if no Sequence ID or email address is specified.
403 if ( empty( $sequence_id ) ) {
404 return new WP_Error( 'convertkit_api_error', $this->get_error_message( 'sequence_subscribe_sequence_id_empty' ) );
405 }
406 if ( empty( $email ) ) {
407 return new WP_Error( 'convertkit_api_error', $this->get_error_message( 'sequence_subscribe_email_empty' ) );
408 }
409
410 // Build request parameters.
411 $params = array(
412 'api_key' => $this->api_key,
413 'email' => $email,
414 'first_name' => $first_name,
415 );
416 if ( $fields ) {
417 $params['fields'] = $fields;
418 }
419
420 // Send request.
421 $response = $this->post( 'sequences/' . $sequence_id . '/subscribe', $params );
422
423 // If an error occured, log and return it now.
424 if ( is_wp_error( $response ) ) {
425 $this->log( 'API: sequence_subscribe(): Error: ' . $response->get_error_message() );
426 return $response;
427 }
428
429 /**
430 * Runs actions immediately after the email address was successfully subscribed to the sequence.
431 *
432 * @since 1.9.6
433 *
434 * @param array $response API Response
435 * @param int $sequence_id Sequence ID
436 * @param string $email Email Address
437 * @param mixed $fields Custom Fields (false|array)
438 */
439 do_action( 'convertkit_api_sequence_subscribe_success', $response, $sequence_id, $email, $fields );
440
441 return $response;
442
443 }
444
445 /**
446 * Fetches all tags from the API.
447 *
448 * @since 1.9.6
449 *
450 * @return WP_Error|array
451 */
452 public function get_tags() {
453
454 $this->log( 'API: get_tags()' );
455
456 $tags = array();
457
458 // Send request.
459 $response = $this->get(
460 'tags',
461 array(
462 'api_key' => $this->api_key,
463 )
464 );
465
466 // If an error occured, log and return it now.
467 if ( is_wp_error( $response ) ) {
468 $this->log( 'API: get_tags(): Error: ' . $response->get_error_message() );
469 return $response;
470 }
471
472 // If the response isn't an array as we expect, log that no tags exist and return a blank array.
473 if ( ! is_array( $response['tags'] ) ) {
474 $this->log( 'API: get_tags(): Error: No tags exist in ConvertKit.' );
475 return new WP_Error( 'convertkit_api_error', $this->get_error_message( 'response_type_unexpected' ) );
476 }
477
478 // If no tags exist, log that no tags exist and return a blank array.
479 if ( ! count( $response['tags'] ) ) {
480 $this->log( 'API: get_tags(): Error: No tags exist in ConvertKit.' );
481 return $tags;
482 }
483
484 foreach ( $response['tags'] as $tag ) {
485 $tags[] = $tag;
486 }
487
488 return $tags;
489
490 }
491
492 /**
493 * Subscribes an email address to a tag.
494 *
495 * @since 1.9.6
496 *
497 * @param int $tag_id Tag ID.
498 * @param string $email Email Address.
499 * @param string $first_name First Name.
500 * @param mixed $fields Custom Fields (false|array).
501 * @return WP_Error|array
502 */
503 public function tag_subscribe( $tag_id, $email, $first_name = '', $fields = false ) {
504
505 $this->log( 'API: tag_subscribe(): [ tag_id: ' . $tag_id . ', email: ' . $email . ']' );
506
507 // Sanitize some parameters.
508 $tag_id = absint( $tag_id );
509 $email = trim( $email );
510 $first_name = trim( $first_name );
511
512 // Return error if no Tag ID or email address is specified.
513 if ( empty( $tag_id ) ) {
514 return new WP_Error( 'convertkit_api_error', $this->get_error_message( 'tag_subscribe_tag_id_empty' ) );
515 }
516 if ( empty( $email ) ) {
517 return new WP_Error( 'convertkit_api_error', $this->get_error_message( 'tag_subscribe_email_empty' ) );
518 }
519
520 // Build request parameters.
521 $params = array(
522 'api_key' => $this->api_key,
523 'email' => $email,
524 'first_name' => $first_name,
525 );
526 if ( $fields ) {
527 $params['fields'] = $fields;
528 }
529
530 // Send request.
531 $response = $this->post( 'tags/' . $tag_id . '/subscribe', $params );
532
533 // If an error occured, log and return it now.
534 if ( is_wp_error( $response ) ) {
535 $this->log( 'API: tag_subscribe(): Error: ' . $response->get_error_message() );
536 return $response;
537 }
538
539 /**
540 * Runs actions immediately after the email address was successfully subscribed to the tag.
541 *
542 * @since 1.9.6
543 *
544 * @param array $response API Response
545 * @param int $tag_id Tag ID
546 * @param string $email Email Address
547 * @param mixed $fields Custom Fields (false|array).
548 */
549 do_action( 'convertkit_api_tag_subscribe_success', $response, $tag_id, $email, $fields );
550
551 return $response;
552
553 }
554
555 /**
556 * Gets a subscriber by their email address.
557 *
558 * @since 1.9.6
559 *
560 * @param string $email Email Address.
561 * @return WP_Error|array
562 */
563 public function get_subscriber_by_email( $email ) {
564
565 $this->log( 'API: get_subscriber_by_email(): [ email: ' . $email . ']' );
566
567 // Sanitize some parameters.
568 $email = trim( $email );
569
570 // Return error if email address is specified.
571 if ( empty( $email ) ) {
572 return new WP_Error( 'convertkit_api_error', $this->get_error_message( 'get_subscriber_by_email_email_empty' ) );
573 }
574
575 // Send request.
576 $response = $this->get(
577 'subscribers',
578 array(
579 'api_secret' => $this->api_secret,
580 'email_address' => $email,
581 )
582 );
583
584 // If an error occured, log and return it now.
585 if ( is_wp_error( $response ) ) {
586 $this->log( 'API: get_subscriber_by_email(): Error: ' . $response->get_error_message() );
587 return $response;
588 }
589
590 // If no matching subscribers exist, log that no matching subscribers exist and return a blank array.
591 if ( (int) $response['total_subscribers'] === 0 ) {
592 $error = new WP_Error(
593 'convertkit_api_error',
594 sprintf(
595 $this->get_error_message( 'get_subscriber_by_email_none' ),
596 $email
597 )
598 );
599
600 $this->log( 'API: get_subscriber_by_email(): Error: ' . $error->get_error_message() );
601 return $error;
602 }
603
604 // Return subscriber.
605 return $response['subscribers'][0];
606
607 }
608
609 /**
610 * Gets a subscriber by their ConvertKit subscriber ID.
611 *
612 * @since 1.9.6
613 *
614 * @param int $subscriber_id Subscriber ID.
615 * @return WP_Error|array
616 */
617 public function get_subscriber_by_id( $subscriber_id ) {
618
619 $this->log( 'API: get_subscriber_by_id(): [ subscriber_id: ' . $subscriber_id . ']' );
620
621 // Sanitize some parameters.
622 $subscriber_id = absint( $subscriber_id );
623
624 // Return error if no Subscriber ID is specified.
625 if ( empty( $subscriber_id ) ) {
626 return new WP_Error( 'convertkit_api_error', $this->get_error_message( 'get_subscriber_by_id_subscriber_id_empty' ) );
627 }
628
629 // Send request.
630 $response = $this->get(
631 'subscribers/' . $subscriber_id,
632 array(
633 'api_secret' => $this->api_secret,
634 )
635 );
636
637 // If an error occured, log and return it now.
638 if ( is_wp_error( $response ) ) {
639 $this->log( 'API: get_subscriber_by_id(): Error: ' . $response->get_error_message() );
640 return $response;
641 }
642
643 return $response['subscriber'];
644
645 }
646
647 /**
648 * Gets a list of tags for the given ConvertKit subscriber ID.
649 *
650 * @since 1.9.6
651 *
652 * @param int $subscriber_id Subscriber ID.
653 * @return WP_Error|array
654 */
655 public function get_subscriber_tags( $subscriber_id ) {
656
657 $this->log( 'API: get_subscriber_tags(): [ subscriber_id: ' . $subscriber_id . ']' );
658
659 // Sanitize some parameters.
660 $subscriber_id = absint( $subscriber_id );
661
662 // Return error if no Subscriber ID is specified.
663 if ( empty( $subscriber_id ) ) {
664 return new WP_Error( 'convertkit_api_error', $this->get_error_message( 'get_subscriber_tags_subscriber_id_empty' ) );
665 }
666
667 // Send request.
668 $response = $this->get(
669 'subscribers/' . $subscriber_id . '/tags',
670 array(
671 'api_key' => $this->api_key,
672 )
673 );
674
675 // If an error occured, log and return it now.
676 if ( is_wp_error( $response ) ) {
677 $this->log( 'API: get_subscriber_tags(): Error: ' . $response->get_error_message() );
678 return $response;
679 }
680
681 return $response['tags'];
682
683 }
684
685 /**
686 * Returns the subscriber's ID by their email address.
687 *
688 * @since 1.9.6
689 *
690 * @param string $email_address Email Address.
691 * @return WP_Error|int
692 */
693 public function get_subscriber_id( $email_address ) {
694
695 // Get subscriber.
696 $subscriber = $this->get_subscriber_by_email( $email_address );
697
698 // If an error occured, log and return it now.
699 if ( is_wp_error( $subscriber ) ) {
700 return $subscriber;
701 }
702
703 // Return ID.
704 return $subscriber['id'];
705
706 }
707
708 /**
709 * Unsubscribes an email address.
710 *
711 * @since 1.9.6
712 *
713 * @param string $email Email Address.
714 * @return WP_Error|array
715 */
716 public function unsubscribe( $email ) {
717
718 $this->log( 'API: unsubscribe(): [ email: ' . $email . ']' );
719
720 // Sanitize some parameters.
721 $email = trim( $email );
722
723 // Return error if no email address is specified.
724 if ( empty( $email ) ) {
725 return new WP_Error( 'convertkit_api_error', $this->get_error_message( 'unsubscribe_email_empty' ) );
726 }
727
728 // Send request.
729 $response = $this->put(
730 'unsubscribe',
731 array(
732 'api_secret' => $this->api_secret,
733 'email' => $email,
734 )
735 );
736
737 // If an error occured, log and return it now.
738 if ( is_wp_error( $response ) ) {
739 $this->log( 'API: unsubscribe(): Error: ' . $response->get_error_message() );
740 return $response;
741 }
742
743 /**
744 * Runs actions immediately after the email address was successfully unsubscribed.
745 *
746 * @since 1.9.6
747 *
748 * @param array $response API Response
749 * @param string $email Email Address
750 */
751 do_action( 'convertkit_api_form_unsubscribe_success', $response, $email );
752
753 return $response;
754
755 }
756
757 /**
758 * Gets all custom fields from the API.
759 *
760 * @since 1.9.6.9
761 *
762 * @return WP_Error|array
763 */
764 public function get_custom_fields() {
765
766 $this->log( 'API: get_custom_fields()' );
767
768 $custom_fields = array();
769
770 // Send request.
771 $response = $this->get(
772 'custom_fields',
773 array(
774 'api_key' => $this->api_key,
775 )
776 );
777
778 // If an error occured, return WP_Error.
779 if ( is_wp_error( $response ) ) {
780 $this->log( 'API: get_custom_fields(): Error: ' . $response->get_error_message() );
781 return $response;
782 }
783
784 // If the response isn't an array as we expect, log that no tags exist and return a blank array.
785 if ( ! is_array( $response['custom_fields'] ) ) {
786 $this->log( 'API: get_custom_fields(): Error: No custom fields exist in ConvertKit.' );
787 return new WP_Error( 'convertkit_api_error', $this->get_error_message( 'response_type_unexpected' ) );
788 }
789
790 // If no custom fields exist, log that no custom fields exist and return a blank array.
791 if ( ! count( $response['custom_fields'] ) ) {
792 $this->log( 'API: get_custom_fields(): Error: No custom fields exist in ConvertKit.' );
793 return $custom_fields;
794 }
795
796 foreach ( $response['custom_fields'] as $custom_field ) {
797 $custom_fields[] = $custom_field;
798 }
799
800 return $custom_fields;
801
802 }
803
804 /**
805 * Gets all posts from the API.
806 *
807 * @since 1.9.7.6
808 *
809 * @param int $posts_per_request Number of Posts to fetch in each request.
810 * @return WP_Error|array
811 */
812 public function get_all_posts( $posts_per_request = 50 ) {
813
814 $this->log( 'API: get_all_posts()' );
815
816 // Sanitize some parameters.
817 $posts_per_request = absint( $posts_per_request );
818
819 // Sanity check that parameters aren't outside of the bounds as defined by the API.
820 if ( $posts_per_request < 1 ) {
821 return new WP_Error( 'convertkit_api_error', $this->get_error_message( 'get_all_posts_posts_per_request_bound_too_low' ) );
822 }
823 if ( $posts_per_request > 50 ) {
824 return new WP_Error( 'convertkit_api_error', $this->get_error_message( 'get_all_posts_posts_per_request_bound_too_high' ) );
825 }
826
827 // Define an array to store the posts in.
828 $posts = array();
829
830 // Mock the response to start the while loop.
831 $response = array(
832 'page' => 0, // Start on page zero, as the below loop will add 1 to this.
833 'total_pages' => 1, // We always know there will be one page of posts.
834 );
835
836 // Iterate through each page of posts.
837 while ( absint( $response['total_pages'] ) >= absint( $response['page'] ) + 1 ) {
838 // Fetch posts.
839 $response = $this->get_posts( absint( $response['page'] ) + 1, $posts_per_request );
840
841 // Bail if an error occured.
842 if ( is_wp_error( $response ) ) {
843 return $response;
844 }
845
846 // Exit loop if no posts exist.
847 if ( ! count( $response ) ) {
848 break;
849 }
850
851 // Append posts to array.
852 foreach ( $response['posts'] as $post ) {
853 $posts[] = $post;
854 }
855 }
856
857 // If no posts exist, log an error.
858 if ( ! count( $posts ) ) {
859 $this->log( 'API: get_posts(): Error: No broadcasts exist in ConvertKit.' );
860 }
861
862 // Return posts.
863 return $posts;
864
865 }
866
867 /**
868 * Gets posts from the API.
869 *
870 * @since 1.9.7.4
871 *
872 * @param int $page Page number.
873 * @param int $per_page Number of Posts to return.
874 * @return WP_Error|array
875 */
876 public function get_posts( $page = 1, $per_page = 10 ) {
877
878 $this->log( 'API: get_posts()' );
879
880 // Sanitize some parameters.
881 $page = absint( $page );
882 $per_page = absint( $per_page );
883
884 // Sanity check that parameters aren't outside of the bounds as defined by the API.
885 if ( $page < 1 ) {
886 return new WP_Error( 'convertkit_api_error', $this->get_error_message( 'get_posts_page_parameter_bound_too_low' ) );
887 }
888 if ( $per_page < 1 ) {
889 return new WP_Error( 'convertkit_api_error', $this->get_error_message( 'get_posts_per_page_parameter_bound_too_low' ) );
890 }
891 if ( $per_page > 50 ) {
892 return new WP_Error( 'convertkit_api_error', $this->get_error_message( 'get_posts_per_page_parameter_bound_too_high' ) );
893 }
894
895 $posts = array();
896
897 // Send request.
898 $response = $this->get(
899 'posts',
900 array(
901 'api_key' => $this->api_key,
902 'api_secret' => $this->api_secret,
903 'page' => $page,
904 'per_page' => $per_page,
905 )
906 );
907
908 // If an error occured, return WP_Error.
909 if ( is_wp_error( $response ) ) {
910 $this->log( 'API: get_posts(): Error: ' . $response->get_error_message() );
911 return $response;
912 }
913
914 // If the response isn't an array as we expect, log that no posts exist and return a blank array.
915 if ( ! is_array( $response['posts'] ) ) {
916 $this->log( 'API: get_posts(): Error: No broadcasts exist in ConvertKit.' );
917 return new WP_Error( 'convertkit_api_error', $this->get_error_message( 'response_type_unexpected' ) );
918 }
919
920 // If no posts exist, log that no posts exist and return a blank array.
921 if ( ! count( $response['posts'] ) ) {
922 $this->log( 'API: get_posts(): Error: No broadcasts exist in ConvertKit.' );
923 return $posts;
924 }
925
926 return $response;
927
928 }
929
930 /**
931 * Get HTML from ConvertKit for the given Legacy Form ID.
932 *
933 * This isn't specifically an API function, but for now it's best suited here.
934 *
935 * @param int $id Form ID.
936 * @return WP_Error|string HTML
937 */
938 public function get_form_html( $id ) {
939
940 // Define Legacy Form URL.
941 $url = add_query_arg(
942 array(
943 'k' => $this->api_key,
944 'v' => 2,
945 ),
946 'https://api.convertkit.com/forms/' . $id . '/embed'
947 );
948
949 // Get HTML.
950 $body = $this->get_html( $url );
951
952 return $body;
953
954 }
955
956 /**
957 * Get HTML from ConvertKit for the given Landing Page URL.
958 *
959 * This isn't specifically an API function, but for now it's best suited here.
960 *
961 * @param string $url URL of Landing Page.
962 * @return string HTML
963 */
964 public function get_landing_page_html( $url ) {
965
966 // Get HTML.
967 $body = $this->get_html( $url, false );
968
969 // Inject JS for subscriber forms to work.
970 $scripts = new WP_Scripts();
971 $script = "<script type='text/javascript' src='" . trailingslashit( $scripts->base_url ) . "wp-includes/js/jquery/jquery.js?ver=1.4.0'></script>"; // phpcs:ignore
972 $script .= "<script type='text/javascript' src='" . $this->plugin_url . 'resources/frontend/js/convertkit.js?ver=' . $this->plugin_version . "'></script>"; // phpcs:ignore
973 $script .= "<script type='text/javascript'>/* <![CDATA[ */var convertkit = {\"ajaxurl\":\"" . admin_url( 'admin-ajax.php' ) . '"};/* ]]> */</script>'; // phpcs:ignore
974
975 $body = str_replace( '</head>', '</head>' . $script, $body );
976
977 return $body;
978
979 }
980
981 /**
982 * Create a Purchase.
983 *
984 * @since 1.9.6.9
985 *
986 * @param array $purchase Purchase Data.
987 * @return WP_Error|array
988 */
989 public function purchase_create( $purchase ) {
990
991 $this->log( 'API: purchase_create(): [ purchase: ' . print_r( $purchase, true ) . ']' ); // phpcs:ignore
992
993 $response = $this->post(
994 'purchases',
995 array(
996 'api_secret' => $this->api_secret,
997 'purchase' => $purchase,
998 )
999 );
1000
1001 if ( is_wp_error( $response ) ) {
1002 $this->log( 'API: purchase_create(): Error: ' . $response->get_error_message() );
1003 }
1004
1005 /**
1006 * Runs actions immediately after the purchase data address was successfully created.
1007 *
1008 * @since 1.9.6.9
1009 *
1010 * @param array $response API Response
1011 * @param array $purchase Purchase Data
1012 */
1013 do_action( 'convertkit_api_purchase_create_success', $response, $purchase );
1014
1015 return $response;
1016
1017 }
1018
1019 /**
1020 * Backward compat. function for updating Forms, Landing Pages and Tags in WordPress options table.
1021 *
1022 * @since 1.0.0
1023 *
1024 * @param string $api_key API Key.
1025 * @param string $api_secret API Secret.
1026 */
1027 public function update_resources( $api_key, $api_secret ) { // phpcs:ignore
1028
1029 // Warn the developer that they shouldn't use this function.
1030 _deprecated_function( __FUNCTION__, '1.9.6', 'refresh() in ConvertKit_Resource_Forms, ConvertKit_Resource_Landing_Pages and ConvertKit_Resource_Tags classes.' );
1031
1032 // Initialize resource classes.
1033 $forms = new ConvertKit_Resource_Forms();
1034 $landing_pages = new ConvertKit_Resource_Landing_Pages();
1035 $tags = new ConvertKit_Resource_Tags();
1036
1037 // Refresh resources by calling the API and storing the results.
1038 $forms->refresh();
1039 $landing_pages->refresh();
1040 $tags->refresh();
1041
1042 }
1043
1044 /**
1045 * Backward compat. function for getting a ConvertKit subscriber by their ID.
1046 *
1047 * @since 1.9.6
1048 *
1049 * @param int $id Subscriber ID.
1050 * @return WP_Error|array
1051 */
1052 public function get_subscriber( $id ) {
1053
1054 // Warn the developer that they shouldn't use this function.
1055 _deprecated_function( __FUNCTION__, '1.9.6', 'get_subscriber_by_id()' );
1056
1057 // Pass request to new function.
1058 return $this->get_subscriber_by_id( $id );
1059
1060 }
1061
1062 /**
1063 * Backward compat. function for subscribing a ConvertKit subscriber to the given Tag.
1064 *
1065 * @since 1.9.6
1066 *
1067 * @param int $tag Tag ID.
1068 * @param array $args Arguments.
1069 * @return WP_Error|array
1070 */
1071 public function add_tag( $tag, $args ) {
1072
1073 // Warn the developer that they shouldn't use this function.
1074 _deprecated_function( __FUNCTION__, '1.9.6', 'tag_subscribe( $tag_id, $email_address )' );
1075
1076 // Pass request to new function.
1077 return $this->tag_subscribe( $tag, $args['email'] );
1078
1079 }
1080
1081 /**
1082 * Backward compat. function for fetching Legacy Form or Landing Page markup for the given URL.
1083 *
1084 * @since 1.9.6
1085 *
1086 * @param string $url URL.
1087 * @return WP_Error|string
1088 */
1089 public function get_resource( $url ) {
1090
1091 // Warn the developer that they shouldn't use this function.
1092 _deprecated_function( __FUNCTION__, '1.9.6', 'get_form_html( $form_id ) or get_landing_page_html( $url )' );
1093
1094 // Pass request to new function.
1095 return $this->get_landing_page_html( $url );
1096
1097 }
1098
1099 /**
1100 * Backward compat. function for fetching Legacy Form or Landing Page markup for the given URL.
1101 *
1102 * @since 1.9.6
1103 *
1104 * @param array $args Arguments (single email key).
1105 * @return WP_Error|array
1106 */
1107 public function form_unsubscribe( $args ) {
1108
1109 // Warn the developer that they shouldn't use this function.
1110 _deprecated_function( __FUNCTION__, '1.9.6', 'unsubscribe( $email_address )' );
1111
1112 // Pass request to new function.
1113 return $this->unsubscribe( $args['email'] );
1114
1115 }
1116
1117 /**
1118 * Adds the given entry to the log file, if debugging is enabled.
1119 *
1120 * @since 1.9.6
1121 *
1122 * @param string $entry Log Entry.
1123 */
1124 public function log( $entry ) {
1125
1126 // Don't log this entry if debugging is disabled.
1127 if ( ! $this->debug ) {
1128 return;
1129 }
1130
1131 // Don't log this entry if the logging class was not initialized.
1132 if ( ! $this->log ) {
1133 return;
1134 }
1135
1136 // Pass the request to the ConvertKit_Log class.
1137 $this->log->add( $entry );
1138
1139 }
1140
1141 /**
1142 * Get HTML for the given URL.
1143 *
1144 * This isn't specifically an API function, but for now it's best suited here.
1145 *
1146 * @param string $url URL of Form or Landing Page.
1147 * @param bool $body_only Return HTML between <body> and </body> tags only.
1148 * @return WP_Error|string
1149 */
1150 private function get_html( $url, $body_only = true ) {
1151
1152 // Get HTML from URL.
1153 $result = wp_remote_get(
1154 $url,
1155 array(
1156 'Accept-Encoding' => 'gzip',
1157 'timeout' => $this->get_timeout(),
1158 'user-agent' => $this->get_user_agent(),
1159 )
1160 );
1161
1162 // If an error occured, log and return it now.
1163 if ( is_wp_error( $result ) ) {
1164 return $result;
1165 }
1166
1167 // Fetch HTTP response code and body.
1168 $http_response_code = wp_remote_retrieve_response_code( $result );
1169 $body = wp_remote_retrieve_body( $result );
1170
1171 // If the body appears to be JSON containing an error, the request for a Legacy Form
1172 // through api.convertkit.com failed, so return a WP_Error now.
1173 if ( $this->is_json( $body ) ) {
1174 $json = json_decode( $body );
1175 return new WP_Error(
1176 'convertkit_api_error',
1177 sprintf(
1178 'ConvertKit: %s',
1179 $json->error_message
1180 )
1181 );
1182 }
1183
1184 // Get just the scheme and host from the URL.
1185 $url_scheme = wp_parse_url( $url );
1186 $url_scheme_host_only = $url_scheme['scheme'] . '://' . $url_scheme['host'];
1187
1188 // Load the landing page HTML into a DOMDocument.
1189 libxml_use_internal_errors( true );
1190 $html = new DOMDocument();
1191 if ( $body_only ) {
1192 // Prevent DOMDocument from including a doctype on saveHTML().
1193 // We don't use LIBXML_HTML_NOIMPLIED, as it requires a single root element, which Legacy Forms don't have.
1194 $html->loadHTML( mb_convert_encoding( $body, 'HTML-ENTITIES', 'UTF-8' ), LIBXML_HTML_NODEFDTD );
1195 } else {
1196 $html->loadHTML( mb_convert_encoding( $body, 'HTML-ENTITIES', 'UTF-8' ) );
1197 }
1198
1199 // Convert any relative URLs to absolute URLs in the HTML DOM.
1200 $this->convert_relative_to_absolute_urls( $html->getElementsByTagName( 'a' ), 'href', $url_scheme_host_only );
1201 $this->convert_relative_to_absolute_urls( $html->getElementsByTagName( 'link' ), 'href', $url_scheme_host_only );
1202 $this->convert_relative_to_absolute_urls( $html->getElementsByTagName( 'img' ), 'src', $url_scheme_host_only );
1203 $this->convert_relative_to_absolute_urls( $html->getElementsByTagName( 'script' ), 'src', $url_scheme_host_only );
1204 $this->convert_relative_to_absolute_urls( $html->getElementsByTagName( 'form' ), 'action', $url_scheme_host_only );
1205
1206 // If the entire HTML needs to be returned, return it now.
1207 if ( ! $body_only ) {
1208 return $html->saveHTML();
1209 }
1210
1211 // Remove some HTML tags that DOMDocument adds, returning the output.
1212 // We do this instead of using LIBXML_HTML_NOIMPLIED in loadHTML(), because Legacy Forms are not always contained in
1213 // a single root / outer element, which is required for LIBXML_HTML_NOIMPLIED to correctly work.
1214 return $this->strip_html_head_body_tags( $html->saveHTML() );
1215
1216 }
1217
1218 /**
1219 * Determines if the given string is JSON.
1220 *
1221 * @since 1.9.6.4
1222 *
1223 * @param string $string Possible JSON String.
1224 * @return bool Is JSON String.
1225 */
1226 private function is_json( $string ) {
1227
1228 json_decode( $string );
1229 return json_last_error() === JSON_ERROR_NONE;
1230
1231 }
1232
1233 /**
1234 * Converts any relative URls to absolute, fully qualified HTTP(s) URLs for the given
1235 * DOM Elements.
1236 *
1237 * @since 1.9.6
1238 *
1239 * @param DOMNodeList<DOMElement> $elements Elements.
1240 * @param string $attribute HTML Attribute.
1241 * @param string $url Absolute URL to prepend to relative URLs.
1242 */
1243 private function convert_relative_to_absolute_urls( $elements, $attribute, $url ) {
1244
1245 // Anchor hrefs.
1246 foreach ( $elements as $element ) {
1247 // Skip if the attribute's value is empty.
1248 if ( empty( $element->getAttribute( $attribute ) ) ) {
1249 continue;
1250 }
1251
1252 // Skip if the attribute's value is a fully qualified URL.
1253 if ( filter_var( $element->getAttribute( $attribute ), FILTER_VALIDATE_URL ) ) {
1254 continue;
1255 }
1256
1257 // Skip if this is a Google Font CSS URL.
1258 if ( strpos( $element->getAttribute( $attribute ), '//fonts.googleapis.com' ) !== false ) {
1259 continue;
1260 }
1261
1262 // If here, the attribute's value is a relative URL, missing the http(s) and domain.
1263 // Prepend the URL to the attribute's value.
1264 $element->setAttribute( $attribute, $url . $element->getAttribute( $attribute ) );
1265 }
1266
1267 }
1268
1269 /**
1270 * Strips <html>, <head> and <body> opening and closing tags from the given markup.
1271 *
1272 * @since 1.9.6.5
1273 *
1274 * @param string $markup HTML Markup.
1275 * @return string HTML Markup
1276 * */
1277 private function strip_html_head_body_tags( $markup ) {
1278
1279 $markup = str_replace( '<html>', '', $markup );
1280 $markup = str_replace( '</html>', '', $markup );
1281 $markup = str_replace( '<head>', '', $markup );
1282 $markup = str_replace( '</head>', '', $markup );
1283 $markup = str_replace( '<body>', '', $markup );
1284 $markup = str_replace( '</body>', '', $markup );
1285
1286 return $markup;
1287
1288 }
1289
1290 /**
1291 * Gets all forms and landing pages from the API.
1292 *
1293 * @since 1.9.6
1294 *
1295 * @return WP_Error|array
1296 */
1297 private function get_forms_landing_pages() {
1298
1299 // Send request.
1300 $response = $this->get(
1301 'forms',
1302 array(
1303 'api_key' => $this->api_key,
1304 )
1305 );
1306
1307 // If an error occured, log and return it now.
1308 if ( is_wp_error( $response ) ) {
1309 return $response;
1310 }
1311
1312 // Iterate through forms, determining if each form is a form or landing page.
1313 $forms = array();
1314 $landing_pages = array();
1315 foreach ( $response['forms'] as $form ) {
1316 // Skip archived forms.
1317 if ( isset( $form['archived'] ) && $form['archived'] ) {
1318 continue;
1319 }
1320
1321 switch ( $form['type'] ) {
1322 case 'hosted':
1323 $landing_pages[ $form['id'] ] = $form;
1324 break;
1325
1326 default:
1327 $forms[ $form['id'] ] = $form;
1328 break;
1329 }
1330 }
1331
1332 return array(
1333 'forms' => $forms,
1334 'landing_pages' => $landing_pages,
1335 );
1336
1337 }
1338
1339 /**
1340 * Performs a GET request.
1341 *
1342 * @since 1.9.6
1343 *
1344 * @param string $endpoint API Endpoint.
1345 * @param array $params Params.
1346 * @return WP_Error|array
1347 */
1348 private function get( $endpoint, $params ) {
1349
1350 return $this->request( $endpoint, 'get', $params, true );
1351
1352 }
1353
1354 /**
1355 * Performs a POST request.
1356 *
1357 * @since 1.9.6
1358 *
1359 * @param string $endpoint API Endpoint.
1360 * @param array $params Params.
1361 * @return WP_Error|array
1362 */
1363 private function post( $endpoint, $params ) {
1364
1365 return $this->request( $endpoint, 'post', $params, true );
1366
1367 }
1368
1369 /**
1370 * Performs a PUT request.
1371 *
1372 * @since 1.9.7.8
1373 *
1374 * @param string $endpoint API Endpoint.
1375 * @param array $params Params.
1376 * @return WP_Error|array
1377 */
1378 private function put( $endpoint, $params ) {
1379
1380 return $this->request( $endpoint, 'put', $params, true );
1381
1382 }
1383
1384 /**
1385 * Main function which handles sending requests to the API using WordPress functions.
1386 *
1387 * @since 1.9.6
1388 *
1389 * @param string $endpoint API Endpoint (required).
1390 * @param string $method HTTP Method (optional).
1391 * @param mixed $params Params (array|boolean|string).
1392 * @param bool $retry_if_rate_limit_hit Retry request if rate limit hit.
1393 * @return WP_Error|array
1394 */
1395 private function request( $endpoint, $method = 'get', $params = array(), $retry_if_rate_limit_hit = true ) {
1396
1397 // Send request.
1398 switch ( $method ) {
1399 case 'get':
1400 $result = wp_remote_get(
1401 $this->add_params_to_url( $this->get_api_url( $endpoint ), $params ),
1402 array(
1403 'Accept-Encoding' => 'gzip',
1404 'timeout' => $this->get_timeout(),
1405 'user-agent' => $this->get_user_agent(),
1406 )
1407 );
1408 break;
1409
1410 case 'post':
1411 $result = wp_remote_post(
1412 $this->get_api_url( $endpoint ),
1413 array(
1414 'Accept-Encoding' => 'gzip',
1415 'headers' => array(
1416 'Content-Type' => 'application/json; charset=utf-8',
1417 ),
1418 'body' => wp_json_encode( $params ),
1419 'timeout' => $this->get_timeout(),
1420 'user-agent' => $this->get_user_agent(),
1421 )
1422 );
1423 break;
1424
1425 case 'put':
1426 $result = wp_remote_request(
1427 $this->get_api_url( $endpoint ),
1428 array(
1429 'method' => 'PUT',
1430 'Accept-Encoding' => 'gzip',
1431 'headers' => array(
1432 'Content-Type' => 'application/json; charset=utf-8',
1433 ),
1434 'body' => wp_json_encode( $params ),
1435 'timeout' => $this->get_timeout(),
1436 'user-agent' => $this->get_user_agent(),
1437 )
1438 );
1439 break;
1440
1441 default:
1442 $result = new WP_Error(
1443 'convertkit_api_error',
1444 sprintf(
1445 $this->get_error_message( 'request_method_unsupported' ),
1446 $method
1447 )
1448 );
1449 break;
1450 }
1451
1452 // If an error occured, log and return it now.
1453 if ( is_wp_error( $result ) ) {
1454 $this->log( 'API: Error: ' . $result->get_error_message() );
1455 return $result;
1456 }
1457
1458 // Fetch HTTP response code and body.
1459 $http_response_code = wp_remote_retrieve_response_code( $result );
1460 $body = wp_remote_retrieve_body( $result );
1461 $response = json_decode( $body, true );
1462
1463 // If the HTTP response code is 429, we've hit the API's rate limit of 120 requests over 60 seconds.
1464 if ( $http_response_code === 429 ) {
1465 // If retry on rate limit hit is disabled, return a WP_Error.
1466 if ( ! $retry_if_rate_limit_hit ) {
1467 return new WP_Error( 'convertkit_api_error', $this->get_error_message( 'request_rate_limit_exceeded' ) );
1468 }
1469
1470 // Retry the request a final time, waiting 2 seconds before.
1471 sleep( 2 );
1472 return $this->request( $endpoint, $method, $params, false );
1473 }
1474
1475 // If an error message or code exists in the response, return a WP_Error.
1476 if ( isset( $response['error'] ) ) {
1477 $this->log( 'API: Error: ' . $response['error'] . ': ' . $response['message'] );
1478 return new WP_Error( 'convertkit_api_error', $response['error'] . ': ' . $response['message'] );
1479 }
1480
1481 return $response;
1482
1483 }
1484
1485 /**
1486 * Returns the maximum amount of time to wait for
1487 * a response to the request before exiting.
1488 *
1489 * @since 1.9.6
1490 *
1491 * @return int Timeout, in seconds.
1492 */
1493 private function get_timeout() {
1494
1495 $timeout = 10;
1496
1497 /**
1498 * Defines the maximum time to allow the API request to run.
1499 *
1500 * @since 2.2.9
1501 *
1502 * @param int $timeout Timeout, in seconds.
1503 */
1504 $timeout = apply_filters( 'convertkit_api_get_timeout', $timeout );
1505
1506 return $timeout;
1507
1508 }
1509
1510 /**
1511 * Gets a customized version of the WordPress default user agent; includes WP Version, PHP version, and ConvertKit plugin version.
1512 *
1513 * @since 1.9.6
1514 *
1515 * @return string User Agent
1516 */
1517 private function get_user_agent() {
1518
1519 global $wp_version;
1520
1521 // Include an unmodified $wp_version.
1522 require ABSPATH . WPINC . '/version.php';
1523
1524 return sprintf(
1525 'WordPress/%1$s;PHP/%2$s;%3$s/%4$s;%5$s',
1526 $wp_version,
1527 phpversion(),
1528 $this->plugin_name,
1529 $this->plugin_version,
1530 home_url( '/' )
1531 );
1532
1533 }
1534
1535 /**
1536 * Returns the full API URL for the given endpoint.
1537 *
1538 * @since 1.9.6
1539 *
1540 * @param string $endpoint Endpoint.
1541 * @return string API URL
1542 */
1543 private function get_api_url( $endpoint ) {
1544
1545 // For the /posts endpoint, the API base is https://api.convertkit.com/api/v3/$endpoint.
1546 if ( $endpoint === 'posts' ) {
1547 return path_join( $this->api_url_base . 'api/' . $this->api_version, $endpoint );
1548 }
1549
1550 // For all other endpoints, it's https://api.convertkit.com/v3/$endpoint.
1551 return path_join( $this->api_url_base . $this->api_version, $endpoint );
1552
1553 }
1554
1555 /**
1556 * Adds the supplied array of parameters as query arguments to the URL.
1557 *
1558 * @since 1.9.6.9
1559 *
1560 * @param string $url URL.
1561 * @param array $params Parameters for request.
1562 * @return string URL with API Key or API Secret
1563 */
1564 private function add_params_to_url( $url, $params ) {
1565
1566 return add_query_arg( $params, $url );
1567
1568 }
1569
1570 /**
1571 * Returns the localized/translated error message for the given error key.
1572 *
1573 * @since 1.9.7.8
1574 *
1575 * @param string $key Key.
1576 * @return string Error message
1577 */
1578 private function get_error_message( $key ) {
1579
1580 // Return a blank string if no error messages have been defined.
1581 if ( ! is_array( $this->error_messages ) ) {
1582 return '';
1583 }
1584
1585 // Return a blank string if the error message isn't defined.
1586 if ( ! array_key_exists( $key, $this->error_messages ) ) {
1587 return '';
1588 }
1589
1590 // Return error message.
1591 return $this->error_messages[ $key ];
1592
1593 }
1594
1595 }
1596