PluginProbe
Kit (formerly ConvertKit) – Email Newsletter, Email Marketing, Membership, Subscribers and Landing Pages / 1.9.0
Kit (formerly ConvertKit) – Email Newsletter, Email Marketing, Membership, Subscribers and Landing Pages v1.9.0
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.php

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

710 lines 19.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * Class WP_ConvertKit
5 */
6 class WP_ConvertKit {
7
8 const POST_META_KEY = '_wp_convertkit_post_meta';
9
10 const SETTINGS_NAME = '_wp_convertkit_settings';
11
12 const SETTINGS_PAGE_SLUG = '_wp_convertkit_settings';
13
14 /**
15 * @var ConvertKit_API
16 */
17 private static $api;
18
19 /**
20 * @var int Data Caching
21 */
22 private static $cache_period = 0;
23
24 /**
25 * @var null
26 */
27 private static $meta_defaults = null;
28
29 /**
30 * @var array
31 */
32 private static $settings_defaults = array(
33 'api_key' => '',
34 'api_secret' => '',
35 'default_form' => 0,
36 'debug' => false,
37 'no_scripts' => false,
38 );
39
40 /**
41 * @var array
42 */
43 private static $forms_markup = array();
44
45 /** @var array */
46 private static $landing_pages_markup = array();
47
48 /** @var string */
49 private static $forms_version = '6';
50
51 /**
52 * Initialize the class
53 */
54 public static function init() {
55 self::add_actions();
56 self::add_filters();
57 self::register_shortcodes();
58
59 self::$cache_period = MINUTE_IN_SECONDS * 10;
60
61 self::_api_connect();
62 }
63
64 /**
65 * Add WP Actions
66 */
67 private static function add_actions() {
68 add_action( 'plugins_loaded', array( __CLASS__, 'load_textdomain' ) );
69 if ( is_admin() ) {
70 add_action( 'add_meta_boxes_page', array( __CLASS__, 'add_meta_boxes' ) );
71 add_action( 'add_meta_boxes_post', array( __CLASS__, 'add_meta_boxes' ) );
72 add_action( 'add_meta_boxes_product', array( __CLASS__, 'add_meta_boxes' ) );
73 } else {
74 add_action( 'template_redirect', array( __CLASS__, 'append_custom_post_type_forms' ) );
75 add_action( 'template_redirect', array( __CLASS__, 'page_takeover' ) );
76 add_action( 'wp_enqueue_scripts', array( __CLASS__, 'enqueue_scripts' ) );
77 }
78
79 add_action( 'widgets_init', array( __CLASS__, 'ck_register_widgets' ) );
80
81 add_action( 'save_post', array( __CLASS__, 'save_post_meta' ), 10, 2 );
82
83 add_action( 'init', array( __CLASS__, 'upgrade' ) , 10 );
84 }
85
86 /**
87 * Load plugin textdomain
88 */
89 public static function load_textdomain() {
90 load_plugin_textdomain( 'convertkit', false, basename( dirname( __FILE__ ) ) . '/languages/' );
91 }
92
93 /**
94 * Add WP Filters
95 */
96 private static function add_filters() {
97 if ( ! is_admin() ) {
98 add_filter( 'the_content', array( __CLASS__, 'append_form' ) );
99 }
100
101 add_filter( 'plugin_action_links_' . CONVERTKIT_PLUGIN_FILE, array( __CLASS__, 'add_settings_page_link' ) );
102 }
103
104 /**
105 * Register ConvertKit shortcodes
106 */
107 private static function register_shortcodes() {
108 add_shortcode( 'convertkit', array( __CLASS__, 'shortcode' ) );
109 }
110
111 /**
112 * Plugin action links callback
113 *
114 * @param $links
115 * @return array
116 */
117 public static function add_settings_page_link( $links ) {
118 $settings_link = sprintf( '<a href="%s">%s</a>', self::_get_settings_page_link(), __( 'Settings', 'convertkit' ) );
119
120 return array_merge( array( 'settings' => $settings_link ), $links );
121 }
122
123 /**
124 * Add Meta Boxes callback
125 *
126 * @param WP_Post $post The current post.
127 */
128 public static function add_meta_boxes( $post ) {
129 add_meta_box( 'wp-convertkit-meta-box', __( 'ConvertKit', 'convertkit' ), array( __CLASS__, 'display_meta_box' ), $post->post_type, 'normal' );
130 }
131
132 /**
133 * Metabox callback
134 *
135 * @param $post
136 */
137 public static function display_meta_box( $post ) {
138
139 $forms = get_option( 'convertkit_forms' );
140 $landing_pages = get_option( 'convertkit_landing_pages' );
141 $tags = get_option( 'convertkit_tags' );
142
143 /**
144 * Alphabetize
145 */
146 usort( $forms, function( $a, $b ) {
147 return strcmp( $a['name'], $b['name'] );
148 });
149
150 usort( $landing_pages, function( $a, $b ) {
151 return strcmp( $a['name'], $b['name'] );
152 });
153
154 usort( $tags, function( $a, $b ) {
155 return strcmp( $a['name'], $b['name'] );
156 });
157
158 $meta = self::_get_meta( $post->ID );
159 $settings_link = self::_get_settings_page_link();
160
161 include( CONVERTKIT_PLUGIN_PATH . '/views/backend/meta-boxes/meta-box.php' );
162 }
163
164 /**
165 * Save post meta callback
166 *
167 * @param int $post_id Post id.
168 * @param WP_Post $post The post.
169 */
170 public static function save_post_meta( $post_id, $post ) {
171 if ( wp_is_post_autosave( $post_id )
172 || wp_is_post_revision( $post_id )
173 || ! isset( $_POST['wp-convertkit-save-meta-nonce'] ) // WPCS input var okay.
174 || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['wp-convertkit-save-meta-nonce'] ) ), 'wp-convertkit-save-meta' ) ) { // WPCS input var okay.
175 return;
176 }
177 if ( isset( $_POST['wp-convertkit'] ) ) { // WPCS input var okay.
178 $form = '';
179 if ( isset( $_POST['wp-convertkit']['form'] ) ) { // WPCS input var okay.
180 $form = sanitize_text_field( wp_unslash( $_POST['wp-convertkit']['form'] ) ); // WPCS input var okay.
181 }
182 $landing_page = '';
183 if ( isset( $_POST['wp-convertkit']['landing_page'] ) ) { // WPCS input var okay.
184 $landing_page = sanitize_text_field( wp_unslash( $_POST['wp-convertkit']['landing_page'] ) ); // WPCS input var okay.
185 }
186 $tag = '';
187 if ( isset( $_POST['wp-convertkit']['tag'] ) ) { // WPCS input var okay.
188 $tag = sanitize_text_field( wp_unslash( $_POST['wp-convertkit']['tag'] ) ); // WPCS input var okay.
189 }
190
191 $meta = array(
192 'form' => $form,
193 'landing_page' => $landing_page,
194 'tag' => $tag,
195 );
196 update_post_meta( $post_id, self::POST_META_KEY, $meta );
197 }
198 }
199
200 /**
201 * Page/Post display callback
202 * In the future, other post types that use the_content can be handled here with conditional cases
203 *
204 * @param string $content The post content.
205 * @return string
206 */
207 public static function append_form( $content ) {
208
209 if ( is_singular( array( 'post' ) ) || is_page() ) {
210 $content .= self::get_form_for_post( get_the_ID(), 'default_form' );
211 }
212
213 return $content;
214 }
215
216 /**
217 * Handle custom post types that don't reliably use the_content
218 */
219 public static function append_custom_post_type_forms() {
220 add_action( 'woocommerce_after_single_product_summary', array( __CLASS__, 'append_woocommerce_product_form' ) );
221 }
222
223 /**
224 * Append form to WooCommerce products
225 */
226 public static function append_woocommerce_product_form() {
227 $form = self::get_form_for_post( get_the_ID(), 'product_form' );
228 echo $form;
229 }
230
231 /**
232 * @param integer $post_id
233 * @param string $settings_key The settings key used for the post type on the ConvertKit plugin settings page
234 * Usually of the form {post_type_name}_form
235 *
236 * @return string
237 */
238 public static function get_form_for_post( $post_id, $settings_key ) {
239 $form = '';
240 $attributes = self::_get_meta( $post_id );
241
242 // Get post/page form setting
243 // If post form id is 0, then it's "None", and we need to stop here completely
244 if ( isset( $attributes['form'] ) && ( 0 <= $attributes['form'] ) ) {
245 $form_id = $attributes['form'];
246 } else {
247 // Get category form
248 $form_id = self::get_category_form( $post_id );
249
250
251 if ( 0 === $form_id || 'default' === $form_id ) {
252 // Get default form for post type
253 if ( '-1' === $attributes['form'] ) {
254 $form_id = self::_get_settings( $settings_key );
255 }
256 }
257 }
258
259 if ( 0 < $form_id && ! is_array( $form_id ) ) {
260
261 $forms = get_option( 'convertkit_forms' );
262
263 if ( isset( $forms[ $form_id ]['uid'] ) ) {
264 // new form
265 $tag = '<script async data-uid="' . $forms[ $form_id ]['uid'] . '" src="' . $forms[ $form_id ]['embed_js'] . '"></script>';
266 $form = $tag;
267 } else {
268 // old form
269 $url = add_query_arg(
270 array(
271 'api_key' => self::_get_settings( 'api_key' ),
272 'v' => self::$forms_version,
273 ),
274 'https://forms.convertkit.com/' . $form_id . '.html'
275 );
276
277 $form_markup = self::$api->get_resource( $url );
278 $form = $form_markup;
279 }
280 }
281
282 return $form;
283 }
284
285 /**
286 * Replace page content if a landing_page is set
287 */
288 public static function page_takeover() {
289 $queried_object = get_queried_object();
290 if ( isset( $queried_object->post_type )
291 && 'page' === $queried_object->post_type ) {
292
293 $landing_page_id = self::_get_meta( $queried_object->ID, 'landing_page' );
294
295 if ( '0' === $landing_page_id || empty( $landing_page_id ) ) {
296 // Set to None
297 return;
298 }
299
300 if ( strstr( $landing_page_id, 'http') ) {
301 // Old landing page
302 $landing_page = self::$api->get_resource( $landing_page_id );
303 if ( ! empty( $landing_page ) ) {
304 $script = WP_ConvertKit::get_ck_script();
305 $script .= "</head>";
306 $landing_page = str_replace( '</head>', $script, $landing_page );
307 echo $landing_page; // WPCS: XSS ok.
308 exit;
309 }
310 } else {
311 // New landing page
312 $landing_pages = get_option( 'convertkit_landing_pages' );
313 $landing_page = self::$api->get_resource( $landing_pages[$landing_page_id]['embed_url'] );
314 if ( ! empty( $landing_page ) ) {
315 $script = WP_ConvertKit::get_ck_script( true );
316 $script .= "</head>";
317 $landing_page = str_replace( '</head>', $script, $landing_page );
318 echo $landing_page; // WPCS: XSS ok.
319 exit;
320 }
321 }
322 }
323 }
324
325 /**
326 * Generate HTML for including ConvertKit JS in a landing page.
327 *
328 * During the landing page takeover the normal WordPress enqueue routine is not run so we need to add these
329 * javascript if we want subscribers tagged correctly.
330 *
331 * @since 1.5.2
332 * @param bool $include_jquery
333 * @return string
334 */
335 public static function get_ck_script( $include_jquery = false) {
336 $script = '';
337 if ( $include_jquery ) {
338 $scripts = new WP_Scripts();
339 $script .= "<script type='text/javascript' src='" . trailingslashit( $scripts->base_url ) . "wp-includes/js/jquery/jquery.js?ver=1.4.0'></script>";
340 }
341 $script .= "<script type='text/javascript' src='" . CONVERTKIT_PLUGIN_URL . "resources/frontend/jquery.cookie.min.js?ver=1.4.0'></script>";
342 $script .= "<script type='text/javascript' src='" . CONVERTKIT_PLUGIN_URL . 'resources/frontend/wp-convertkit.js?ver=' . CONVERTKIT_PLUGIN_VERSION . "'></script>";
343 $script .= "<script type='text/javascript'>/* <![CDATA[ */var ck_data = {\"ajaxurl\":\"" . admin_url( 'admin-ajax.php' ) . '"};/* ]]> */</script>';
344 return $script;
345 }
346
347 /**
348 * Enqueue scripts
349 */
350 public static function enqueue_scripts() {
351
352 // Only check for tags if we're on a singular post; otherwise, no tags
353 $has_tag = is_singular() ? self::post_has_tag( get_post() ) : false;
354
355 // Only load scripts if no scripts setting is not checked
356 $no_scripts = self::_get_settings( 'no_scripts' );
357 if ( ! $no_scripts ) {
358 wp_register_script(
359 'jquery-cookie',
360 CONVERTKIT_PLUGIN_URL . 'resources/frontend/jquery.cookie.min.js',
361 array( 'jquery' ),
362 '1.4.0'
363 );
364
365 wp_register_script(
366 'convertkit-js',
367 CONVERTKIT_PLUGIN_URL . 'resources/frontend/wp-convertkit.js',
368 array( 'jquery-cookie' ),
369 CONVERTKIT_PLUGIN_VERSION
370 );
371
372 wp_localize_script(
373 'convertkit-js',
374 'ck_data',
375 array(
376 'ajaxurl' => admin_url( 'admin-ajax.php' ),
377 'post_has_tag' => $has_tag,
378 )
379 );
380
381 wp_enqueue_script( 'convertkit-js' );
382 }
383 }
384
385 /**
386 * Register widget.
387 */
388 public static function ck_register_widgets() {
389 register_widget( 'CK_Widget_Form' );
390 }
391
392 /**
393 * Shortcode callback
394 *
395 * @param array $attributes Shortcode attributes.
396 * @param null $content
397 * @return string
398 */
399 public static function shortcode( $attributes, $content = null ) {
400
401 if ( isset( $attributes['id'] ) ) {
402 $form_id = $attributes['id'];
403 $forms = get_option( 'convertkit_forms' );
404
405 if ( isset( $forms[ $form_id ]['uid'] ) ) {
406 // new form
407 $form_markup = '<script async data-uid="' . $forms[ $form_id ]['uid'] . '" src="' . $forms[ $form_id ]['embed_js'] . '"></script>';
408 return apply_filters( 'wp_convertkit_get_form_embed', $form_markup, $attributes );
409 } else {
410 // old form
411 $url = add_query_arg(
412 array(
413 'api_key' => self::_get_settings( 'api_key' ),
414 'v' => self::$forms_version,
415 ),
416 'https://forms.convertkit.com/' . $form_id . '.html'
417 );
418 }
419 } elseif ( isset( $attributes['form'] ) ) {
420 $form_id = $attributes['form'];
421 $forms = get_option( 'convertkit_forms' );
422
423 if ( isset( $forms[ $form_id ]['uid'] ) ) {
424 // new form
425 $form_markup = '<script async data-uid="' . $forms[ $form_id ]['uid'] . '" src="' . $forms[ $form_id ]['embed_js'] . '"></script>';
426 return apply_filters( 'wp_convertkit_get_form_embed', $form_markup, $attributes );
427 } else {
428 $url = add_query_arg(
429 array(
430 'k' => self::_get_settings( 'api_key' ),
431 'v' => '2',
432 ),
433 'https://api.convertkit.com/forms/' . $form_id . '/embed'
434 );
435 }
436 } else {
437 $form_id = self::_get_settings( 'default_form' );
438 $url = add_query_arg(
439 array(
440 'api_key' => self::_get_settings( 'api_key' ),
441 'v' => self::$forms_version,
442 ),
443 'https://forms.convertkit.com/' . $form_id . '.html'
444 );
445 }
446
447 if ( 0 < $form_id ) {
448 $form_markup = self::$api->get_resource( $url );
449 } else {
450 $form_markup = '';
451 }
452
453 return apply_filters( 'wp_convertkit_get_form_embed', $form_markup, $attributes );
454 }
455
456 /**
457 * Retrieve meta
458 *
459 * @return array|null
460 */
461 private static function _get_meta_defaults() {
462 if ( is_null( self::$meta_defaults ) ) {
463 self::$meta_defaults = array(
464 'form' => '-1',
465 'landing_page' => '',
466 'tag' => '',
467 );
468 }
469
470 return self::$meta_defaults;
471 }
472
473 /**
474 * Get selected post meta
475 *
476 * @param int $post_id Post ID.
477 * @param null $meta_key Key string to get.
478 *
479 * @return array|bool
480 */
481 private static function _get_meta( $post_id, $meta_key = null ) {
482 $post_id = empty( $post_id ) ? get_the_ID() : $post_id;
483
484 $meta = get_post_meta( $post_id, self::POST_META_KEY, true );
485 $meta_defaults = self::_get_meta_defaults();
486
487 if ( empty( $meta ) ) {
488 $meta = $meta_defaults;
489
490 $old_value = intval( get_post_meta( $post_id, '_convertkit_convertkit_form', true ) );
491 if ( 0 !== $old_value ) {
492 $meta['form'] = $old_value;
493 }
494 }
495
496 $meta = shortcode_atts( $meta_defaults, $meta );
497
498 return is_null( $meta_key ) ? $meta : ( isset( $meta[ $meta_key ] ) ? $meta[ $meta_key ] : false );
499 }
500
501 /**
502 * Get plugin settings
503 *
504 * @param null $settings_key
505 * @return mixed|null
506 */
507 public static function _get_settings( $settings_key = null ) {
508 $settings = get_option( self::SETTINGS_NAME, self::$settings_defaults );
509
510 return is_null( $settings_key ) ? $settings : ( isset( $settings[ $settings_key ] ) ? $settings[ $settings_key ] : null);
511 }
512
513 /**
514 * Get instance of ConvertKitAPI
515 */
516 private static function _api_connect() {
517 $api_key = self::_get_settings( 'api_key' );
518 $api_secret = self::_get_settings( 'api_secret' );
519 $debug = self::_get_settings( 'debug' );
520
521 self::$api = new ConvertKit_API( $api_key, $api_secret, $debug );
522 }
523
524 /**
525 * Get instance of the CK API
526 *
527 * @return ConvertKit_API
528 */
529 public static function get_api() {
530 return self::$api;
531 }
532
533 /**
534 * Get ConvertKit API key
535 *
536 * @return mixed|null|void
537 */
538 public static function get_api_key() {
539 return self::_get_settings( 'api_key' );
540 }
541
542 /**
543 * Get ConvertKit API secret
544 *
545 * @return mixed|null|void
546 */
547 public static function get_api_secret() {
548 return self::_get_settings( 'api_secret' );
549 }
550
551 /**
552 * @return string
553 */
554 public static function get_forms_version() {
555 return self::$forms_version;
556 }
557
558 /**
559 * Get link to the plugin settings page
560 *
561 * @param array $query_args Args to add to URL.
562 * @return string
563 */
564 private static function _get_settings_page_link( $query_args = array() ) {
565 $query_args = array(
566 'page' => self::SETTINGS_PAGE_SLUG,
567 ) + $query_args;
568
569 return add_query_arg( $query_args, admin_url( 'options-general.php' ) );
570 }
571
572 /**
573 * Get default form for the post's categories.
574 * If there are multiple set the last one found will be returned.
575 *
576 * @param int $id
577 * @return int $form_id
578 */
579 private static function get_category_form( $id ) {
580 $categories = wp_get_post_categories( $id );
581
582 $form_id = 0;
583 foreach ( $categories as $category ) {
584
585 $id = get_term_meta( $category, 'ck_default_form', true );
586 if ( $id ) {
587 $form_id = $id;
588 }
589 }
590
591 return $form_id;
592 }
593
594 /**
595 * Output data to log file
596 *
597 * @param string $message String to add to log.
598 */
599 static function log( $message ) {
600
601 if ( 'on' === self::_get_settings( 'debug' ) ) {
602 $dir = CONVERTKIT_PLUGIN_PATH;
603 $handle = fopen( trailingslashit( $dir ) . 'log.txt', 'a' );
604 if ( $handle ) {
605 $time = date_i18n( 'm-d-Y @ H:i:s -' );
606 fwrite( $handle, $time . ' ' . $message . "\n" );
607 fclose( $handle );
608 }
609 }
610
611 }
612
613 /**
614 * Run version specific upgrade.
615 */
616 public static function upgrade() {
617
618 $current_version = get_option( 'convertkit_version' );
619 $convertkit_user_history_table = get_option( 'convertkit_user_history_table' );
620
621 if ( ! $current_version ) {
622 // Run 1.4.1 upgrade.
623 $settings = self::_get_settings();
624
625 if ( isset( $settings['api_key'] ) ) {
626 // Get all posts and pages to track what has been updated.
627 $posts = get_option( '_wp_convertkit_upgrade_posts' );
628
629 if ( ! $posts ) {
630
631 $args = array(
632 'post_type' => array( 'post', 'page' ),
633 'fields' => 'ids',
634 );
635
636 $result = new WP_Query( $args );
637 if ( ! is_wp_error( $result ) ) {
638 $posts = $result->posts;
639 update_option( '_wp_convertkit_upgrade_posts', $posts );
640 }
641 }
642
643 // Get form mappings.
644 $mappings = self::$api->get_resources( 'subscription_forms' );
645
646 // 1. Update global form. Set 'api_version' so this is only done once.
647 if ( ! isset( $settings['api_version'] ) ) {
648 $old_form_id = $settings['default_form'];
649 $settings['default_form'] = isset( $mappings[ $old_form_id ] ) ? $mappings[ $old_form_id ] : 0;
650 $settings['api_version'] = 'v3';
651 update_option( self::SETTINGS_NAME, $settings );
652 }
653
654 // 2. Scan posts/pages for _wp_convertkit_post_meta and update IDs
655 // Scan content for shortcode and update
656 // Remove page_id from posts array after page is updated.
657 foreach ( $posts as $key => $post_id ) {
658 $post_settings = get_post_meta( $post_id, '_wp_convertkit_post_meta', true );
659
660 if ( isset( $post_settings['form'] ) && ( 0 < $post_settings['form'] ) ) {
661 $post_settings['form'] = isset( $mappings[ $post_settings['form'] ] ) ? $mappings[ $post_settings['form'] ] : 0;
662 }
663 if ( isset( $post_settings['landing_page'] ) && ( 0 < $post_settings['landing_page'] ) ) {
664 $post_settings['landing_page'] = isset( $mappings[ $post_settings['landing_page'] ] ) ? $mappings[ $post_settings['landing_page'] ] : 0;
665 }
666 update_post_meta( $post_id, '_wp_convertkit_post_meta', $post_settings );
667 unset( $posts[ $key ] );
668 update_option( '_wp_convertkit_upgrade_posts', $posts );
669 }
670
671 // Done scanning posts, upgrade complete.
672 if ( empty( $posts ) ) {
673 update_option( 'convertkit_version', CONVERTKIT_PLUGIN_VERSION );
674 delete_option( '_wp_convertkit_upgrade_posts' );
675 }
676 } else {
677 update_option( 'convertkit_version', CONVERTKIT_PLUGIN_VERSION );
678 } // End if().
679 } elseif ( version_compare( $current_version, '1.5.0', '<' ) || ! $convertkit_user_history_table ) {
680
681 // Create User History table
682 ConvertKit_Custom_Content::create_table();
683 update_option( 'convertkit_version', CONVERTKIT_PLUGIN_VERSION );
684
685 } elseif ( version_compare( $current_version, '1.6.1', '<' ) ) {
686 // Refresh the forms meta to get new forms builder settings
687 $api_key = self::_get_settings( 'api_key' );
688 if ( ! empty( $api_key ) ) {
689 self::$api->update_resources( $api_key );
690 }
691 update_option( 'convertkit_version', CONVERTKIT_PLUGIN_VERSION );
692 }// End if().
693 }
694
695
696 /**
697 * @param $post WP_Post
698 *
699 * @return boolean
700 */
701 public static function post_has_tag( $post ) {
702 $meta = get_post_meta( $post->ID, '_wp_convertkit_post_meta', true );
703
704 if ( isset( $meta['tag'] ) ) {
705 return ( $meta['tag'] == 0 ) ? false : true;
706 }
707 return false;
708 }
709 }
710