PluginProbe
Kit (formerly ConvertKit) – Email Newsletter, Email Marketing, Membership, Subscribers and Landing Pages / 3.2.3
Kit (formerly ConvertKit) – Email Newsletter, Email Marketing, Membership, Subscribers and Landing Pages v3.2.3
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-setup.php

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

692 lines 19.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Plugin activation, update and deactivation class.
4 *
5 * @package ConvertKit
6 * @author ConvertKit
7 */
8
9 /**
10 * Runs any steps required on plugin activation, update and deactivation.
11 *
12 * @package ConvertKit
13 * @author ConvertKit
14 * @version 1.9.7.4
15 */
16 class ConvertKit_Setup {
17
18 /**
19 * Runs routines when the Plugin is activated.
20 *
21 * @since 1.9.7.4
22 */
23 public function activate() {
24
25 // Call any functions to e.g. schedule WordPress Cron events now.
26 $this->schedule_cron_events();
27
28 // Install entries database table.
29 $entries = new ConvertKit_Form_Entries();
30 $entries->create_database_table();
31
32 }
33
34 /**
35 * Runs routines on every Plugin request e.g.
36 * ensuring WordPress Cron events are scheduled.
37 *
38 * @since 2.6.6
39 */
40 public function initialize() {
41
42 // Call any functions to e.g. schedule WordPress Cron events now.
43 $this->schedule_cron_events();
44
45 }
46
47 /**
48 * Runs routines if the Plugin version has been updated.
49 *
50 * @since 1.9.7.4
51 */
52 public function update() {
53
54 // Get installed Plugin version.
55 $current_version = get_option( 'convertkit_version' );
56
57 // If the version number matches the plugin version, no update routines
58 // need to run.
59 if ( $current_version === CONVERTKIT_PLUGIN_VERSION ) {
60 return;
61 }
62
63 /**
64 * 3.0.4: Add form_id to entries database table.
65 */
66 if ( version_compare( $current_version, '3.0.4', '<' ) ) {
67 $this->add_form_id_column_and_key_to_form_entries_database_table();
68 }
69
70 /**
71 * 3.0.0: Migrate reCAPTCHA settings from Restrict Content to General settings.
72 * Install entries database table.
73 */
74 if ( version_compare( $current_version, '3.0.0', '<' ) ) {
75 $this->migrate_recaptcha_settings();
76
77 // Install entries database table.
78 $entries = new ConvertKit_Form_Entries();
79 $entries->create_database_table();
80 }
81
82 /**
83 * 2.6.6: Migrate 'Default' Form value in _wp_convertkit_term_meta[form] from 0 to -1,
84 * to match Posts.
85 */
86 if ( version_compare( $current_version, '2.6.6', '<' ) ) {
87 $this->migrate_term_default_form_settings();
88 }
89
90 /**
91 * 2.5.4: Migrate WishList Member to ConvertKit Form Mappings
92 */
93 if ( ! $current_version || version_compare( $current_version, '2.5.4', '<' ) ) {
94 $this->migrate_wlm_none_setting();
95 $this->migrate_wlm_form_tag_mapping_settings();
96 }
97
98 /**
99 * 2.5.3: Migrate Third Party Form integrations' 'None' option values from `default` to blank.
100 */
101 if ( ! $current_version || version_compare( $current_version, '2.5.3', '<' ) ) {
102 $this->migrate_contact_form_7_none_setting();
103 $this->migrate_forminator_none_setting();
104 $this->migrate_wlm_none_setting();
105 }
106
107 /**
108 * 2.5.2: Migrate Forminator to ConvertKit Form Mappings
109 */
110 if ( ! $current_version || version_compare( $current_version, '2.5.2', '<' ) ) {
111 $this->migrate_forminator_form_mapping_settings();
112 }
113
114 /**
115 * 2.5.2: Migrate Contact Form 7 to ConvertKit Form Mappings
116 */
117 if ( ! $current_version || version_compare( $current_version, '2.5.2', '<' ) ) {
118 $this->migrate_contact_form_7_form_mapping_settings();
119 }
120
121 /**
122 * 2.5.0: Get Access token for API version 4.0 using a v3 API Key and Secret.
123 */
124 if ( ! $current_version || version_compare( $current_version, '2.5.0', '<' ) ) {
125 $this->maybe_get_access_token_by_api_key_and_secret();
126 }
127
128 /**
129 * 2.4.9.1+: Migrate ck_default_form to _wp_convertkit_term_meta[form], as Term settings
130 * support multiple options (form, position etc).
131 */
132 if ( version_compare( $current_version, '2.4.9.1', '<' ) ) {
133 $this->migrate_term_form_settings();
134 }
135
136 /**
137 * 1.9.6+: Migrate _wp_convertkit_settings[default_form] to _wp_convertkit_settings[page_form] and
138 * _wp_convertkit_settings[post_form], now that each Post Type has its own Default Form setting
139 * in Settings > Kit > General.
140 */
141 if ( version_compare( $current_version, '1.9.6', '<' ) ) {
142 $this->migrate_default_form_settings();
143 }
144
145 /**
146 * 1.9.7.4+: Schedule Post Resources' Cron event to refresh Posts cache hourly,
147 * as the activate() routine won't pick this up for existing active installations.
148 */
149 if ( version_compare( $current_version, '1.9.7.4', '<' ) ) {
150 $posts = new ConvertKit_Resource_Posts( 'cron' );
151 $posts->schedule_cron_event();
152 }
153
154 // Update the installed version number in the options table.
155 update_option( 'convertkit_version', CONVERTKIT_PLUGIN_VERSION );
156
157 }
158
159 /**
160 * Adds form_id column and key to form entries database table.
161 *
162 * @since 3.0.4
163 */
164 private function add_form_id_column_and_key_to_form_entries_database_table() {
165
166 global $wpdb;
167
168 // Check if the column exists.
169 $exists = $wpdb->get_var(
170 $wpdb->prepare(
171 'SELECT COLUMN_NAME
172 FROM INFORMATION_SCHEMA.COLUMNS
173 WHERE table_name = %s
174 AND table_schema = %s
175 AND column_name = %s',
176 $wpdb->prefix . 'kit_form_entries',
177 $wpdb->dbname,
178 'form_id'
179 )
180 );
181
182 // If the column exists, don't add it again.
183 if ( $exists === 'form_id' ) {
184 return;
185 }
186
187 // Add the form_id column and key.
188 $wpdb->query(
189 $wpdb->prepare( 'ALTER TABLE %i ADD COLUMN `form_id` int(11) NOT NULL AFTER `custom_fields`', $wpdb->prefix . 'kit_form_entries' )
190 );
191 $wpdb->query(
192 $wpdb->prepare( 'ALTER TABLE %i ADD KEY `form_id` (`form_id`)', $wpdb->prefix . 'kit_form_entries' )
193 );
194
195 }
196
197 /**
198 * 3.0.0: Migrate reCAPTCHA settings from Restrict Content settings to General settings.
199 *
200 * @since 3.0.0
201 */
202 private function migrate_recaptcha_settings() {
203
204 // Read Restrict Content settings directly from options table,
205 // as Convertkit_Settings_Restrict_Content won't have helper
206 // methods to return the specific settings.
207 $settings = get_option( '_wp_convertkit_settings_restrict_content' );
208
209 // If no reCAPTCHA settings exist, bail.
210 if ( ! isset( $settings['recaptcha_site_key'] ) || ! isset( $settings['recaptcha_secret_key'] ) || ! isset( $settings['recaptcha_minimum_score'] ) ) {
211 return;
212 }
213
214 // Load settings class, saving the reCAPTCHA settings to the General settings.
215 $convertkit_settings = new ConvertKit_Settings();
216 $convertkit_settings->save(
217 array(
218 'recaptcha_site_key' => $settings['recaptcha_site_key'],
219 'recaptcha_secret_key' => $settings['recaptcha_secret_key'],
220 'recaptcha_minimum_score' => $settings['recaptcha_minimum_score'],
221 )
222 );
223
224 // Remove reCAPTCHA settings from Restrict Content settings.
225 unset( $settings['recaptcha_site_key'] );
226 unset( $settings['recaptcha_secret_key'] );
227 unset( $settings['recaptcha_minimum_score'] );
228 update_option( '_wp_convertkit_settings_restrict_content', $settings );
229
230 }
231
232 /**
233 * Change the Default value of 0 to -1 in wp_convertkit_term_meta[form], to
234 * match how the Default value is stored in Posts.
235 *
236 * @since 2.6.6
237 */
238 private function migrate_term_default_form_settings() {
239
240 // Get all Terms that have ConvertKit settings defined.
241 $query = new WP_Term_Query(
242 array(
243 'taxonomy' => 'category',
244 'hide_empty' => false,
245 'fields' => 'ids',
246 'meta_query' => array(
247 array(
248 'key' => '_wp_convertkit_term_meta',
249 'comparison' => 'EXISTS',
250 ),
251 ),
252 )
253 );
254
255 // Bail if no Terms exist.
256 if ( ! $query->terms ) {
257 return;
258 }
259
260 // Iterate through Terms, mapping settings.
261 foreach ( $query->terms as $term_id ) {
262 $term_settings = new ConvertKit_Term( $term_id );
263
264 // If the Form setting is Default i.e. it does not have a formchange it from 0 to -1.
265 if ( ! $term_settings->has_form() ) {
266 $term_settings->save(
267 array(
268 'form' => -1,
269 )
270 );
271 }
272 }
273
274 }
275
276 /**
277 * 2.5.4: Migrate WLM settings:
278 * - Prefix any WishList Member to ConvertKit Form ID mappings with `form:`,
279 * - Prefix any WishList Member to ConvertKit Tag ID mappings with `tag:`,
280 * - Standardise the settings keys to the format {wlm_level_id}_subscribe
281 * and {wlm_level_id}_unsubscribe.
282 *
283 * @since 2.5.4
284 */
285 private function migrate_wlm_form_tag_mapping_settings() {
286
287 $convertkit_wlm_settings = new ConvertKit_Wishlist_Settings();
288
289 // Bail if no settings exist.
290 if ( ! $convertkit_wlm_settings->has_settings() ) {
291 return;
292 }
293
294 // Define new array for settings.
295 $settings = array();
296
297 // Iterate through settings.
298 foreach ( $convertkit_wlm_settings->get() as $key => $convertkit_form_or_tag_id ) {
299 // Split the settings key.
300 list( $wlm_level_id, $type ) = explode( '_', $key );
301
302 switch ( $type ) {
303 case 'form':
304 // This is the action to perform when the user is added to the WLM Level.
305 // Use a new name for the setting key to reflect this.
306 // < 2.5.4, forms were the only option here, so prefix the resource ID with `form:`.
307 $settings[ $wlm_level_id . '_add' ] = ( empty( $convertkit_form_or_tag_id ) ? '' : 'form:' . $convertkit_form_or_tag_id );
308 break;
309
310 case 'unsubscribe':
311 // This is the action to perform when the user is removed from the WLM Level.
312 // Use a new name for the setting key to reflect this.
313 // < 2.5.4, tags were the only option here, so prefix the resource ID with `tag:`.
314 $settings[ $wlm_level_id . '_remove' ] = ( empty( $convertkit_form_or_tag_id ) ? '' : 'tag:' . $convertkit_form_or_tag_id );
315 break;
316 }
317 }
318
319 // Update settings.
320 update_option( $convertkit_wlm_settings::SETTINGS_NAME, $settings );
321
322 }
323
324 /**
325 * 2.5.3: Migrate Third Party Form integrations' 'None' option values from `default` to blank.
326 *
327 * 2.4.9 changed the 'None' label's value from `default` to a blank string, as the v4 API's
328 * `add_subscriber_to_form()` method introduces type declarations, which would result in
329 * an uncaught TypeError when passing a non integer value.
330 *
331 * The PR for that (https://github.com/ConvertKit/convertkit-wordpress/pull/655) didn't include
332 * any tests or upgrade/migration routines to change any existing saved settings where the 'None'
333 * label's value was stored as `default`.
334 */
335 private function migrate_contact_form_7_none_setting() {
336
337 $convertkit_contact_form_7_settings = new ConvertKit_ContactForm7_Settings();
338
339 // Bail if no settings exist.
340 if ( ! $convertkit_contact_form_7_settings->has_settings() ) {
341 return;
342 }
343
344 // Get settings.
345 $settings = $convertkit_contact_form_7_settings->get();
346
347 // Iterate through settings.
348 foreach ( $settings as $contact_form_7_form_id => $convertkit_form_id ) {
349 // Skip keys that are non-numeric e.g. `creator_network_recommendations_*`.
350 if ( ! is_numeric( $contact_form_7_form_id ) ) {
351 continue;
352 }
353
354 // Change 'default' to a blank string.
355 if ( $convertkit_form_id === 'default' ) {
356 $settings[ $contact_form_7_form_id ] = '';
357 }
358 }
359
360 // Update settings.
361 update_option( $convertkit_contact_form_7_settings::SETTINGS_NAME, $settings );
362
363 }
364
365 /**
366 * 2.5.3: Migrate Third Party Form integrations' 'None' option values from `default` to blank.
367 *
368 * 2.4.9 changed the 'None' label's value from `default` to a blank string, as the v4 API's
369 * `add_subscriber_to_form()` method introduces type declarations, which would result in
370 * an uncaught TypeError when passing a non integer value.
371 *
372 * The PR for that (https://github.com/ConvertKit/convertkit-wordpress/pull/655) didn't include
373 * any tests or upgrade/migration routines to change any existing saved settings where the 'None'
374 * label's value was stored as `default`.
375 */
376 private function migrate_forminator_none_setting() {
377
378 $convertkit_forminator_settings = new ConvertKit_Forminator_Settings();
379
380 // Bail if no settings exist.
381 if ( ! $convertkit_forminator_settings->has_settings() ) {
382 return;
383 }
384
385 // Get settings.
386 $settings = $convertkit_forminator_settings->get();
387
388 // Iterate through settings.
389 foreach ( $settings as $forminator_form_id => $convertkit_form_id ) {
390 // Skip keys that are non-numeric e.g. `creator_network_recommendations_*`.
391 if ( ! is_numeric( $forminator_form_id ) ) {
392 continue;
393 }
394
395 // Change 'default' to a blank string.
396 if ( $convertkit_form_id === 'default' ) {
397 $settings[ $forminator_form_id ] = '';
398 }
399 }
400
401 // Update settings.
402 update_option( $convertkit_forminator_settings::SETTINGS_NAME, $settings );
403
404 }
405
406 /**
407 * 2.5.3: Migrate Third Party Form integrations' 'None' option values from `default` to blank.
408 *
409 * 2.4.9 changed the 'None' label's value from `default` to a blank string, as the v4 API's
410 * `add_subscriber_to_form()` method introduces type declarations, which would result in
411 * an uncaught TypeError when passing a non integer value.
412 *
413 * The PR for that (https://github.com/ConvertKit/convertkit-wordpress/pull/655) didn't include
414 * any tests or upgrade/migration routines to change any existing saved settings where the 'None'
415 * label's value was stored as `default`.
416 */
417 private function migrate_wlm_none_setting() {
418
419 $convertkit_wlm_settings = new ConvertKit_Wishlist_Settings();
420
421 // Bail if no settings exist.
422 if ( ! $convertkit_wlm_settings->has_settings() ) {
423 return;
424 }
425
426 // Get settings.
427 $settings = $convertkit_wlm_settings->get();
428
429 // Iterate through settings.
430 foreach ( $settings as $wlm_level_id => $value ) {
431 // Change 'default' to a blank string.
432 if ( $value === 'default' ) {
433 $settings[ $wlm_level_id ] = '';
434 }
435 }
436
437 // Update settings.
438 update_option( $convertkit_wlm_settings::SETTINGS_NAME, $settings );
439
440 }
441
442 /**
443 * 2.5.2: Prefix any Forminator to ConvertKit Form ID mappings with `form:`, now that
444 * the Plugin supports adding a subscriber to a Form, Tag or Sequence.
445 *
446 * @since 2.5.2
447 */
448 private function migrate_forminator_form_mapping_settings() {
449
450 $convertkit_forminator_settings = new ConvertKit_Forminator_Settings();
451
452 // Bail if no settings exist.
453 if ( ! $convertkit_forminator_settings->has_settings() ) {
454 return;
455 }
456
457 // Get settings.
458 $settings = $convertkit_forminator_settings->get();
459
460 // Iterate through settings.
461 foreach ( $settings as $forminator_form_id => $convertkit_form_id ) {
462 // Skip keys that are non-numeric e.g. `creator_network_recommendations_*`.
463 if ( ! is_numeric( $forminator_form_id ) ) {
464 continue;
465 }
466
467 // Skip values that are blank i.e. no ConvertKit Form ID specified.
468 if ( empty( $convertkit_form_id ) ) {
469 continue;
470 }
471
472 // Skip values that are non-numeric i.e. the `form_` prefix was already added.
473 // This should never happen as this routine runs once, but this is a sanity check.
474 if ( ! is_numeric( $convertkit_form_id ) ) {
475 continue;
476 }
477
478 // Prefix the ConvertKit Form ID with `form_`.
479 $settings[ $forminator_form_id ] = 'form:' . $convertkit_form_id;
480 }
481
482 // Update settings.
483 update_option( $convertkit_forminator_settings::SETTINGS_NAME, $settings );
484
485 }
486
487 /**
488 * 2.5.2: Prefix any Contact Form 7 to ConvertKit Form ID mappings with `form:`, now that
489 * the Plugin supports adding a subscriber to a Form, Tag or Sequence.
490 *
491 * @since 2.5.2
492 */
493 private function migrate_contact_form_7_form_mapping_settings() {
494
495 $convertkit_contact_form_7_settings = new ConvertKit_ContactForm7_Settings();
496
497 // Bail if no settings exist.
498 if ( ! $convertkit_contact_form_7_settings->has_settings() ) {
499 return;
500 }
501
502 // Get settings.
503 $settings = $convertkit_contact_form_7_settings->get();
504
505 // Iterate through settings.
506 foreach ( $settings as $contact_form_7_form_id => $convertkit_form_id ) {
507 // Skip keys that are non-numeric e.g. `creator_network_recommendations_*`.
508 if ( ! is_numeric( $contact_form_7_form_id ) ) {
509 continue;
510 }
511
512 // Skip values that are blank i.e. no ConvertKit Form ID specified.
513 if ( empty( $convertkit_form_id ) ) {
514 continue;
515 }
516
517 // Skip values that are non-numeric i.e. the `form_` prefix was already added.
518 // This should never happen as this routine runs once, but this is a sanity check.
519 if ( ! is_numeric( $convertkit_form_id ) ) {
520 continue;
521 }
522
523 // Prefix the ConvertKit Form ID with `form_`.
524 $settings[ $contact_form_7_form_id ] = 'form:' . $convertkit_form_id;
525 }
526
527 // Update settings.
528 update_option( $convertkit_contact_form_7_settings::SETTINGS_NAME, $settings );
529
530 }
531
532 /**
533 * 2.5.0: Fetch an Access Token, Refresh Token and Expiry for v4 API use
534 * based on the Plugin setting's v3 API Key and Secret.
535 *
536 * @since 2.5.0
537 */
538 private function maybe_get_access_token_by_api_key_and_secret() {
539
540 $convertkit_settings = new ConvertKit_Settings();
541
542 // Bail if an Access Token exists; we don't need to fetch another one.
543 if ( $convertkit_settings->has_access_token() ) {
544 return;
545 }
546
547 // Bail if no API Key or Secret.
548 if ( empty( $convertkit_settings->get_api_key() ) ) {
549 return;
550 }
551 if ( empty( $convertkit_settings->get_api_secret() ) ) {
552 return;
553 }
554
555 // Get Access Token by API Key and Secret.
556 $api = new ConvertKit_API_V4( CONVERTKIT_OAUTH_CLIENT_ID, CONVERTKIT_OAUTH_CLIENT_REDIRECT_URI );
557 $result = $api->get_access_token_by_api_key_and_secret(
558 $convertkit_settings->get_api_key(),
559 $convertkit_settings->get_api_secret(),
560 get_site_url()
561 );
562
563 // Bail if an error occured.
564 if ( is_wp_error( $result ) ) {
565 return;
566 }
567
568 // Store the new credentials.
569 // We don't use update_credentials(), because the response
570 // includes an `expires_at`, not a `created_at` and `expires_in`.
571 $convertkit_settings->save(
572 array(
573 'access_token' => $result['oauth']['access_token'],
574 'refresh_token' => $result['oauth']['refresh_token'],
575 'token_expires' => $result['oauth']['expires_at'],
576 )
577 );
578
579 }
580
581 /**
582 * Migrate ck_default_form to _wp_convertkit_term_meta[form], as Term settings
583 * support multiple options (form, position etc).
584 *
585 * @since 2.4.9.1
586 */
587 private function migrate_term_form_settings() {
588
589 // Get all Terms that have ConvertKit settings defined.
590 $query = new WP_Term_Query(
591 array(
592 'taxonomy' => 'category',
593 'hide_empty' => false,
594 'fields' => 'ids',
595 'meta_query' => array(
596 array(
597 'key' => 'ck_default_form',
598 'comparison' => 'EXISTS',
599 ),
600 ),
601 )
602 );
603
604 // Bail if no Terms exist.
605 if ( ! $query->terms ) {
606 return;
607 }
608
609 // Iterate through Terms, mapping settings.
610 foreach ( $query->terms as $term_id ) {
611 $term_settings = new ConvertKit_Term( $term_id );
612 $term_settings->save(
613 array(
614 'form' => get_term_meta( $term_id, 'ck_default_form', true ), // Fetch form setting from old meta key.
615 'form_position' => '', // Default to no position.
616 )
617 );
618
619 // Delete old Term meta.
620 delete_term_meta( $term_id, 'ck_default_form' );
621 }
622
623 }
624
625 /**
626 * 1.9.6+: Migrate _wp_convertkit_settings[default_form] to _wp_convertkit_settings[page_form] and
627 * _wp_convertkit_settings[post_form], now that each Post Type has its own Default Form setting
628 * in Settings > Kit > General.
629 */
630 private function migrate_default_form_settings() {
631
632 $convertkit_settings = new ConvertKit_Settings();
633
634 // Bail if no default_form setting exists.
635 $settings = get_option( $convertkit_settings::SETTINGS_NAME );
636 if ( ! $settings ) {
637 return;
638 }
639 if ( ! array_key_exists( 'default_form', $settings ) ) {
640 return;
641 }
642
643 // Restructure settings.
644 $settings['page_form'] = $settings['default_form'];
645 $settings['post_form'] = $settings['default_form'];
646
647 // Remove obsolete default_form setting.
648 unset( $settings['default_form'] );
649
650 // Update.
651 update_option( $convertkit_settings::SETTINGS_NAME, $settings );
652
653 }
654
655 /**
656 * Runs routines when the Plugin is deactivated.
657 *
658 * @since 1.9.7.4
659 */
660 public function deactivate() {
661
662 // Call any functions to e.g. unschedule WordPress Cron events now.
663 $this->unschedule_cron_events();
664
665 }
666
667 /**
668 * Schedules any Plugin specific CRON events, if they do not already exist.
669 *
670 * @since 2.6.6
671 */
672 private function schedule_cron_events() {
673
674 $posts = new ConvertKit_Resource_Posts( 'cron' );
675 $posts->schedule_cron_event();
676
677 }
678
679 /**
680 * Unschedules any Plugin specific CRON events, if they exist.
681 *
682 * @since 2.6.6
683 */
684 private function unschedule_cron_events() {
685
686 $posts = new ConvertKit_Resource_Posts( 'cron' );
687 $posts->unschedule_cron_event();
688
689 }
690
691 }
692