PluginProbe
Kit (formerly ConvertKit) – Email Newsletter, Email Marketing, Membership, Subscribers and Landing Pages / trunk
Kit (formerly ConvertKit) – Email Newsletter, Email Marketing, Membership, Subscribers and Landing Pages vtrunk
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 / admin / section / class-convertkit-admin-section-general.php

class-convertkit-admin-section-general.php in Kit (formerly ConvertKit) – Email Newsletter, Email Marketing, Membership, Subscribers and Landing Pages trunk, at admin/section/class-convertkit-admin-section-general.php

1,298 lines 38.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * ConvertKit Settings General class.
4 *
5 * @package ConvertKit
6 * @author ConvertKit
7 */
8
9 /**
10 * Registers General Settings that can be edited at Settings > Kit > General.
11 *
12 * @package ConvertKit
13 * @author ConvertKit
14 */
15 class ConvertKit_Admin_Section_General extends ConvertKit_Admin_Section_Base {
16
17 /**
18 * Holds the ConvertKit Account Name.
19 *
20 * @since 1.9.6
21 *
22 * @var bool|WP_Error|array
23 */
24 private $account = false;
25
26 /**
27 * Holds the ConvertKit Forms Resource.
28 *
29 * @since 1.9.6
30 *
31 * @var bool|ConvertKit_Resource_Forms
32 */
33 private $forms = false;
34
35 /**
36 * Constructor.
37 */
38 public function __construct() {
39
40 // Define the class that reads/writes settings.
41 $this->settings = new ConvertKit_Settings();
42
43 // Define the settings key.
44 $this->settings_key = $this->settings::SETTINGS_NAME;
45
46 // Define the programmatic name, Title and Tab Text.
47 $this->name = $this->settings->get_name();
48 $this->title = $this->settings->get_title();
49 $this->tab_text = __( 'General', 'convertkit' );
50
51 // Define settings sections.
52 $this->settings_sections = array(
53 'general' => array(
54 'title' => $this->title,
55 'callback' => array( $this, 'print_section_info' ),
56 'wrap' => true,
57 ),
58 'site-wide' => array(
59 'title' => __( 'Non-inline Forms', 'convertkit' ),
60 'callback' => array( $this, 'print_section_info_site_wide' ),
61 'wrap' => true,
62 ),
63 'spam-protection' => array(
64 'title' => __( 'Spam Protection', 'convertkit' ),
65 'callback' => array( $this, 'print_section_info_spam_protection' ),
66 'wrap' => true,
67 ),
68 'advanced' => array(
69 'title' => __( 'Advanced', 'convertkit' ),
70 'callback' => array( $this, 'print_section_info_advanced' ),
71 'wrap' => true,
72 ),
73 );
74
75 $this->maybe_disconnect();
76
77 // Register and maybe output notices for this settings screen, and the Intercom messenger.
78 if ( $this->on_settings_screen( $this->name ) ) {
79 add_filter( 'convertkit_settings_base_register_notices', array( $this, 'register_notices' ) );
80 add_action( 'convertkit_settings_base_render_before', array( $this, 'maybe_output_notices' ) );
81 add_action( 'convertkit_settings_base_render_before', array( $this, 'maybe_output_legacy_form_notice' ) );
82 }
83
84 // Enqueue scripts and CSS.
85 add_action( 'convertkit_admin_settings_enqueue_scripts', array( $this, 'enqueue_scripts' ) );
86 add_action( 'convertkit_admin_settings_enqueue_styles', array( $this, 'enqueue_styles' ) );
87
88 parent::__construct();
89
90 $this->check_credentials();
91
92 }
93
94 /**
95 * Registers success and error notices for the General screen, to be displayed
96 * depending on the action.
97 *
98 * @since 2.5.1
99 *
100 * @param array $notices Regsitered success and error notices.
101 * @return array
102 */
103 public function register_notices( $notices ) {
104
105 return array_merge(
106 $notices,
107 array(
108 'oauth2_success' => __( 'Successfully authorized with Kit.', 'convertkit' ),
109 )
110 );
111
112 }
113
114 /**
115 * Outputs a non-dismissible warning when one or more Default Form settings
116 * reference Legacy Forms.
117 *
118 * @since 3.3.9
119 */
120 public function maybe_output_legacy_form_notice() {
121
122 // Get warnings.
123 $warnings = WP_ConvertKit()->get_class( 'admin_legacy_resource_notice' )->get_legacy_warnings_for_plugin_settings( $this->settings->get() );
124
125 // Bail if no warnings are found.
126 if ( empty( $warnings ) ) {
127 return;
128 }
129
130 // Output warnings.
131 ?>
132 <div id="convertkit-legacy-settings-warning" class="notice notice-warning">
133 <p>
134 <strong><?php esc_html_e( 'Kit', 'convertkit' ); ?>:</strong>
135 <?php esc_html_e( 'Your Default Form settings reference Legacy Forms. They still work, but should be migrated:', 'convertkit' ); ?>
136 </p>
137 <ul>
138 <?php
139 foreach ( $warnings as $warning ) {
140 echo '<li>' . esc_html( $warning ) . '</li>';
141 }
142 ?>
143 </ul>
144 </div>
145 <?php
146
147 }
148
149 /**
150 * Test the access token, if it exists.
151 * If the access token has been revoked or is invalid, remove it from the settings now.
152 *
153 * @since 2.5.0
154 */
155 private function check_credentials() {
156
157 // Bail if we're not on the settings screen.
158 if ( ! $this->on_settings_screen( $this->name ) ) {
159 return;
160 }
161
162 // Bail if no access and refresh token exist.
163 if ( ! $this->settings->has_access_and_refresh_token() ) {
164 // Redirect to General screen, which will now show the ConvertKit_Admin_Section_OAuth screen, because
165 // the Plugin has no access token.
166 wp_safe_redirect(
167 add_query_arg(
168 array(
169 'page' => $this->settings_key,
170 ),
171 'options-general.php'
172 )
173 );
174 exit();
175 }
176
177 // Get Account Details, which we'll use in account_name_callback(), but also lets us test
178 // whether the API credentials are valid.
179 $account = new ConvertKit_Resource_Account();
180 $this->account = $account->refresh();
181
182 // If the request succeeded, no need to perform further actions.
183 if ( ! is_wp_error( $this->account ) ) {
184 return;
185 }
186
187 // Depending on the error code, display an error notice in the settings screen until the user
188 // fixes the problem.
189 $this->output_error( $this->account->get_error_message() );
190
191 }
192
193 /**
194 * Deletes the OAuth Access Token, Refresh Token and Expiry from the Plugin's settings, if the user
195 * clicked the Disconnect button.
196 *
197 * @since 2.5.0
198 */
199 private function maybe_disconnect() {
200
201 // Bail if we're not on the settings screen.
202 if ( ! $this->on_settings_screen( $this->name ) ) {
203 return;
204 }
205
206 // Bail if nonce verification fails.
207 if ( ! isset( $_REQUEST['_convertkit_settings_oauth_disconnect'] ) ) {
208 return;
209 }
210 if ( ! wp_verify_nonce( sanitize_key( $_REQUEST['_convertkit_settings_oauth_disconnect'] ), 'convertkit-oauth-disconnect' ) ) {
211 return;
212 }
213
214 // Get Settings class.
215 $settings = new ConvertKit_Settings();
216
217 // Setup API.
218 $api = new ConvertKit_API_V4(
219 CONVERTKIT_OAUTH_CLIENT_ID,
220 CONVERTKIT_OAUTH_CLIENT_REDIRECT_URI,
221 $settings->get_access_token(),
222 $settings->get_refresh_token(),
223 $settings->debug_enabled(),
224 'settings'
225 );
226
227 // Check that we're using the Kit WordPress Libraries 2.1.4 or higher.
228 // If another Kit Plugin is active and out of date, its libraries might
229 // be loaded that don't have this method.
230 if ( ! method_exists( $api, 'revoke_tokens' ) ) { // @phpstan-ignore-line Older WordPress Libraries won't have this function.
231 $this->output_error( __( 'The Kit WordPress Libraries is missing the `revoke_tokens` method. Please update all Kit WordPress Plugins to their latest versions, and click Disconnect again.', 'convertkit' ) );
232 return;
233 }
234
235 // Revoke Access and Refresh Tokens.
236 // See convertkit_delete_credentials() method in functions.php, which is called
237 // by the `convertkit_api_revoke_tokens` action and deletes credentials from the Plugin's settings.
238 $result = $api->revoke_tokens();
239 if ( is_wp_error( $result ) ) {
240 $this->output_error( $result->get_error_message() );
241 return;
242 }
243
244 // Delete cached resources.
245 $account = new ConvertKit_Resource_Account();
246 $creator_network = new ConvertKit_Resource_Creator_Network_Recommendations();
247 $custom_fields = new ConvertKit_Resource_Custom_Fields();
248 $forms = new ConvertKit_Resource_Forms();
249 $landing_pages = new ConvertKit_Resource_Landing_Pages();
250 $posts = new ConvertKit_Resource_Posts();
251 $products = new ConvertKit_Resource_Products();
252 $sequences = new ConvertKit_Resource_Sequences();
253 $tags = new ConvertKit_Resource_Tags();
254 $account->delete();
255 $creator_network->delete();
256 $custom_fields->delete();
257 $forms->delete();
258 $landing_pages->delete();
259 $posts->delete();
260 $products->delete();
261 $sequences->delete();
262 $tags->delete();
263
264 // Redirect to General screen, which will now show the ConvertKit_Settings_OAuth screen, because
265 // the Plugin has no access token.
266 wp_safe_redirect(
267 add_query_arg(
268 array(
269 'page' => $this->settings_key,
270 ),
271 'options-general.php'
272 )
273 );
274 exit();
275
276 }
277
278 /**
279 * Enqueues scripts for the Settings > General screen.
280 *
281 * @since 2.2.4
282 *
283 * @param string $section Settings section / tab (general|tools|restrict-content).
284 */
285 public function enqueue_scripts( $section ) {
286
287 // Bail if we're not on the general section.
288 if ( $section !== $this->name ) {
289 return;
290 }
291
292 // Enqueue Select2 JS.
293 convertkit_select2_enqueue_scripts();
294
295 // Enqueue JS.
296 wp_enqueue_script( 'convertkit-admin-preview-output', CONVERTKIT_PLUGIN_URL . 'resources/backend/js/preview-output.js', array( 'jquery' ), CONVERTKIT_PLUGIN_VERSION, true );
297 wp_enqueue_script( 'convertkit-admin-settings-conditional-display', CONVERTKIT_PLUGIN_URL . 'resources/backend/js/settings-conditional-display.js', array( 'jquery' ), CONVERTKIT_PLUGIN_VERSION, true );
298
299 }
300
301 /**
302 * Enqueues styles for the Settings > General screen.
303 *
304 * @since 2.2.4
305 *
306 * @param string $section Settings section / tab (general|tools|restrict-content).
307 */
308 public function enqueue_styles( $section ) {
309
310 // Bail if we're not on the general section.
311 if ( $section !== $this->name ) {
312 return;
313 }
314
315 // Enqueue Select2 CSS.
316 convertkit_select2_enqueue_styles();
317
318 }
319
320 /**
321 * Registers settings fields for this section.
322 */
323 public function register_fields() {
324
325 // Initialize resource classes.
326 $this->maybe_initialize_and_refresh_resources();
327
328 add_settings_field(
329 'account_name',
330 __( 'Account Name', 'convertkit' ),
331 array( $this, 'account_name_callback' ),
332 $this->settings_key,
333 $this->name
334 );
335
336 // Initialize resource classes and perform a refresh if this hasn't yet been done.
337 foreach ( convertkit_get_supported_post_types() as $supported_post_type ) {
338 // Get Post Type's Label.
339 $post_type = get_post_type_object( $supported_post_type );
340
341 // Skip if the Post Type doesn't exist.
342 if ( ! $post_type ) {
343 continue;
344 }
345
346 // Add Settings Fields.
347 add_settings_field(
348 $supported_post_type . '_form',
349 sprintf(
350 /* translators: Post Type Name, plural */
351 __( 'Default Form (%s)', 'convertkit' ),
352 $post_type->label
353 ),
354 array( $this, 'default_form_callback' ),
355 $this->settings_key,
356 $this->name,
357 array(
358 'label_for' => '_wp_convertkit_settings_' . $supported_post_type . '_form',
359 'post_type' => $supported_post_type,
360 'post_type_object' => $post_type,
361 )
362 );
363
364 if ( $this->forms->exist() ) {
365 add_settings_field(
366 $supported_post_type . '_form_position',
367 sprintf(
368 /* translators: Post Type Name, plural */
369 __( 'Form Position (%s)', 'convertkit' ),
370 $post_type->label
371 ),
372 array( $this, 'default_form_position_callback' ),
373 $this->settings_key,
374 $this->name,
375 array(
376 'label_for' => '_wp_convertkit_settings_' . $supported_post_type . '_form_position',
377 'post_type' => $supported_post_type,
378 'post_type_object' => $post_type,
379 )
380 );
381
382 add_settings_field(
383 $supported_post_type . '_form_position_element',
384 '',
385 array( $this, 'default_form_position_element_callback' ),
386 $this->settings_key,
387 $this->name,
388 array(
389 'label_for' => '_wp_convertkit_settings_' . $supported_post_type . '_form_position_element',
390 'post_type' => $supported_post_type,
391 'post_type_object' => $post_type,
392 )
393 );
394 }
395 }
396
397 // Site Wide.
398 add_settings_field(
399 'non_inline_form',
400 __( 'Default Forms (Site Wide)', 'convertkit' ),
401 array( $this, 'non_inline_form_callback' ),
402 $this->settings_key,
403 $this->name . '-site-wide',
404 array(
405 'label_for' => 'non_inline_form',
406 )
407 );
408
409 add_settings_field(
410 'non_inline_form_honor_none_setting',
411 __( 'Behavior', 'convertkit' ),
412 array( $this, 'non_inline_form_honor_none_setting_callback' ),
413 $this->settings_key,
414 $this->name . '-site-wide',
415 array(
416 'label_for' => 'non_inline_form_honor_none_setting',
417 )
418 );
419
420 // Non-inline Form Limit per Session.
421 add_settings_field(
422 'non_inline_form_limit_per_session',
423 __( 'Limit Display', 'convertkit' ),
424 array( $this, 'non_inline_form_limit_per_session_callback' ),
425 $this->settings_key,
426 $this->name . '-site-wide',
427 array(
428 'label_for' => 'non_inline_form_limit_per_session',
429 )
430 );
431
432 // Spam Protection.
433 add_settings_field(
434 'spam_protection_provider',
435 __( 'Provider', 'convertkit' ),
436 array( $this, 'spam_protection_provider_callback' ),
437 $this->settings_key,
438 $this->name . '-spam-protection',
439 array(
440 'label_for' => 'spam_protection_provider',
441 'description' => array(
442 __( 'Select which spam protection service to use for the Member Content signup form and Form Builder block.', 'convertkit' ),
443 ),
444 )
445 );
446
447 // reCAPTCHA.
448 add_settings_field(
449 'recaptcha_site_key',
450 __( 'reCAPTCHA: Site Key', 'convertkit' ),
451 array( $this, 'recaptcha_site_key_callback' ),
452 $this->settings_key,
453 $this->name . '-spam-protection',
454 array(
455 'label_for' => 'recaptcha_site_key',
456 'class' => 'convertkit-spam-protection-recaptcha',
457 'description' => array(
458 __( 'Enter your Google reCAPTCHA v3 Site Key. When specified, this will be used to reduce spam signups.', 'convertkit' ),
459 ),
460 )
461 );
462 add_settings_field(
463 'recaptcha_secret_key',
464 __( 'reCAPTCHA: Secret Key', 'convertkit' ),
465 array( $this, 'recaptcha_secret_key_callback' ),
466 $this->settings_key,
467 $this->name . '-spam-protection',
468 array(
469 'label_for' => 'recaptcha_secret_key',
470 'class' => 'convertkit-spam-protection-recaptcha',
471 'description' => array(
472 __( 'Enter your Google reCAPTCHA v3 Secret Key. When specified, this will be used to reduce spam signups.', 'convertkit' ),
473 ),
474 )
475 );
476 add_settings_field(
477 'recaptcha_minimum_score',
478 __( 'reCAPTCHA: Minimum Score', 'convertkit' ),
479 array( $this, 'recaptcha_minimum_score_callback' ),
480 $this->settings_key,
481 $this->name . '-spam-protection',
482 array(
483 'label_for' => 'recaptcha_minimum_score',
484 'class' => 'convertkit-spam-protection-recaptcha',
485 'min' => 0,
486 'max' => 1,
487 'step' => 0.01,
488 'description' => array(
489 __( 'Enter the minimum threshold for a subscriber to pass Google reCAPTCHA. A higher number will reduce spam signups (1.0 is very likely a good interaction, 0.0 is very likely a bot).', 'convertkit' ),
490 ),
491 )
492 );
493
494 // Cloudflare Turnstile.
495 add_settings_field(
496 'cloudflare_turnstile_site_key',
497 __( 'Cloudflare Turnstile: Site Key', 'convertkit' ),
498 array( $this, 'cloudflare_turnstile_site_key_callback' ),
499 $this->settings_key,
500 $this->name . '-spam-protection',
501 array(
502 'label_for' => 'cloudflare_turnstile_site_key',
503 'class' => 'convertkit-spam-protection-cloudflare_turnstile',
504 'description' => array(
505 __( 'Enter your Cloudflare Turnstile Site Key. When specified, this will be used to reduce spam signups.', 'convertkit' ),
506 ),
507 )
508 );
509 add_settings_field(
510 'cloudflare_turnstile_secret_key',
511 __( 'Cloudflare Turnstile: Secret Key', 'convertkit' ),
512 array( $this, 'cloudflare_turnstile_secret_key_callback' ),
513 $this->settings_key,
514 $this->name . '-spam-protection',
515 array(
516 'label_for' => 'cloudflare_turnstile_secret_key',
517 'class' => 'convertkit-spam-protection-cloudflare_turnstile',
518 'description' => array(
519 __( 'Enter your Cloudflare Turnstile Secret Key. When specified, this will be used to reduce spam signups.', 'convertkit' ),
520 ),
521 )
522 );
523
524 // Advanced.
525 add_settings_field(
526 'debug',
527 __( 'Debug', 'convertkit' ),
528 array( $this, 'debug_callback' ),
529 $this->settings_key,
530 $this->name . '-advanced',
531 array(
532 'label_for' => 'debug',
533 )
534 );
535
536 add_settings_field(
537 'no_scripts',
538 __( 'Disable JavaScript', 'convertkit' ),
539 array( $this, 'no_scripts_callback' ),
540 $this->settings_key,
541 $this->name . '-advanced',
542 array(
543 'label_for' => 'no_scripts',
544 )
545 );
546
547 add_settings_field(
548 'no_css',
549 __( 'Disable CSS', 'convertkit' ),
550 array( $this, 'no_css_callback' ),
551 $this->settings_key,
552 $this->name . '-advanced',
553 array(
554 'label_for' => 'no_css',
555 )
556 );
557
558 add_settings_field(
559 'no_add_new_button',
560 __( 'Disable Add New Landing Page / Member Content Button', 'convertkit' ),
561 array( $this, 'no_add_new_button_callback' ),
562 $this->settings_key,
563 $this->name . '-advanced',
564 array(
565 'label_for' => 'no_add_new_button',
566 )
567 );
568
569 add_settings_field(
570 'usage_tracking',
571 __( 'Usage Tracking', 'convertkit' ),
572 array( $this, 'usage_tracking_callback' ),
573 $this->settings_key,
574 $this->name . '-advanced',
575 array(
576 'label_for' => 'usage_tracking',
577 )
578 );
579
580 }
581
582 /**
583 * Prints help info for this section
584 */
585 public function print_section_info() {
586
587 ?>
588 <p><?php esc_html_e( 'Forms can be embedded before and/or after (or following number of elements) on every post or page (in single view only) across your site by using the settings below.', 'convertkit' ); ?>
589 <p><?php esc_html_e( 'You can also configure non-inline forms to display site wide under the "Non-inline Forms" section below.', 'convertkit' ); ?></p>
590 <p><?php esc_html_e( 'These default form settings can be overridden using the Kit meta box on a page or post\'s edit screen. For site wide non-inline forms to respect when a post/page has forms disabled, enable the "Behavior" option in the "Non-inline Forms" section below.', 'convertkit' ); ?></p>
591 <p>
592 <?php
593 printf(
594 /* translators: [convertkit] shortcode, wrapped in <code> tags */
595 esc_html__( 'The default form can be inserted into the middle of post or page content by using either the %s shortcode or block.', 'convertkit' ),
596 '<code>[convertkit]</code>'
597 );
598 ?>
599 </p>
600 <?php
601
602 }
603
604 /**
605 * Prints help info for the site wide section of the settings screen.
606 *
607 * @since 2.7.3
608 */
609 public function print_section_info_site_wide() {
610
611 ?>
612 <p class="description"><?php esc_html_e( 'Defines non-inline forms to display site wide, and if these forms should display on Pages / Posts that have the Kit Form setting = None.', 'convertkit' ); ?></p>
613 <?php
614
615 }
616
617 /**
618 * Prints help info for the spam protection section of the settings screen.
619 *
620 * @since 3.3.7
621 */
622 public function print_section_info_spam_protection() {
623 ?>
624 <p class="description"><?php esc_html_e( 'Configure a spam protection service to protect the Member Content signup form and Form Builder block from spam and abuse. Choose a provider below, then enter the corresponding site and secret keys.', 'convertkit' ); ?></p>
625 <?php
626 }
627
628 /**
629 * Prints help info for the advanced section of the settings screen.
630 *
631 * @since 2.7.1
632 */
633 public function print_section_info_advanced() {
634
635 ?>
636 <p class="description"><?php esc_html_e( 'Defines advanced configuration settings, usually when working with support or needing to disable JS or CSS.', 'convertkit' ); ?></p>
637 <?php
638
639 }
640
641 /**
642 * Returns the URL for the ConvertKit documentation for this setting section.
643 *
644 * @since 2.0.8
645 *
646 * @return string Documentation URL.
647 */
648 public function documentation_url() {
649
650 return 'https://help.kit.com/en/articles/2502591-how-to-set-up-the-kit-plugin-on-your-wordpress-website';
651
652 }
653
654 /**
655 * Outputs the Account Name
656 *
657 * @since 1.9.6
658 */
659 public function account_name_callback() {
660
661 // Output Account Name.
662 // If account is an error, check_credentials() will output an error above the settings section.
663 $html = sprintf(
664 '<p>%s</p>',
665 ! is_wp_error( $this->account ) && isset( $this->account['account']['name'] ) ? esc_attr( $this->account['account']['name'] ) : esc_html__( '(Not specified)', 'convertkit' )
666 );
667
668 // Display an option to disconnect.
669 $html .= sprintf(
670 '<p><a href="%1$s" class="button button-secondary">%2$s</a></p>',
671 esc_url(
672 add_query_arg(
673 array(
674 'page' => '_wp_convertkit_settings',
675 '_convertkit_settings_oauth_disconnect' => wp_create_nonce( 'convertkit-oauth-disconnect' ),
676 ),
677 'options-general.php'
678 )
679 ),
680 esc_html__( 'Disconnect', 'convertkit' )
681 );
682
683 echo wp_kses( $html, convertkit_kses_allowed_html() );
684
685 }
686
687 /**
688 * Initialize resource classes and perform a and refresh of resources,
689 * if initialization has not yet taken place.
690 *
691 * @since 2.5.9
692 */
693 public function maybe_initialize_and_refresh_resources() {
694
695 // If the Forms resource class is initialized, this has already been done.
696 if ( $this->forms !== false ) {
697 return;
698 }
699
700 // Initialize forms resource class.
701 $this->forms = new ConvertKit_Resource_Forms( 'settings' );
702
703 // Don't refresh resources if we're not on the settings screen, as
704 // it's a resource intense process that can take several seconds.
705 // We don't want to block other parts of the admin UI.
706 if ( ! $this->on_settings_screen( $this->name ) ) {
707 return;
708 }
709
710 // Refresh Forms.
711 $result = $this->forms->refresh();
712
713 // Bail if an error occured.
714 if ( is_wp_error( $result ) ) {
715 return;
716 }
717
718 // Also refresh other resources. Whilst not displayed in the Plugin Settings, this ensures up to date
719 // lists are stored for when editing e.g. Pages.
720
721 // Refresh Custom Fields.
722 $custom_fields = new ConvertKit_Resource_Custom_Fields( 'settings' );
723 $result = $custom_fields->refresh();
724
725 // Bail if an error occured.
726 if ( is_wp_error( $result ) ) {
727 return;
728 }
729
730 // Refresh Landing Pages.
731 $landing_pages = new ConvertKit_Resource_Landing_Pages( 'settings' );
732 $result = $landing_pages->refresh();
733
734 // Bail if an error occured.
735 if ( is_wp_error( $result ) ) {
736 return;
737 }
738
739 // Refresh Posts.
740 remove_all_actions( 'convertkit_resource_refreshed_posts' );
741 $posts = new ConvertKit_Resource_Posts( 'settings' );
742 $result = $posts->refresh();
743
744 // Bail if an error occured.
745 if ( is_wp_error( $result ) ) {
746 return;
747 }
748
749 // Refresh Products.
750 $products = new ConvertKit_Resource_Products( 'settings' );
751 $result = $products->refresh();
752
753 // Bail if an error occured.
754 if ( is_wp_error( $result ) ) {
755 return;
756 }
757
758 // Refresh Sequences.
759 $sequences = new ConvertKit_Resource_Sequences( 'settings' );
760 $result = $sequences->refresh();
761
762 // Bail if an error occured.
763 if ( is_wp_error( $result ) ) {
764 return;
765 }
766
767 // Refresh Tags.
768 $tags = new ConvertKit_Resource_Tags( 'settings' );
769 $result = $tags->refresh();
770
771 // Bail if an error occured.
772 if ( is_wp_error( $result ) ) {
773 return;
774 }
775
776 }
777
778 /**
779 * Renders the input for the Default Form setting for the given Post Type.
780 *
781 * @since 1.9.6
782 *
783 * @param array $args Field arguments.
784 */
785 public function default_form_callback( $args ) {
786
787 // Bail if no Forms exist.
788 if ( ! $this->forms->exist() ) {
789 esc_html_e( 'No Forms exist in Kit.', 'convertkit' );
790 echo '<br /><a href="' . esc_url( convertkit_get_new_form_url() ) . '" target="_blank">' . esc_html__( 'Click here to create your first form', 'convertkit' ) . '</a>';
791 return;
792 }
793
794 // Build description with preview link.
795 $description = false;
796 $preview_url = WP_ConvertKit()->get_class( 'preview_output' )->get_preview_form_url( $args['post_type'] );
797 if ( $preview_url ) {
798 // Include a preview link in the description.
799 $description = sprintf(
800 '%s %s %s',
801 sprintf(
802 /* translators: Post Type name, plural */
803 esc_html__( 'Select a form above to automatically output below all %s.', 'convertkit' ),
804 $args['post_type_object']->label
805 ),
806 '<a href="' . esc_url( $preview_url ) . '" id="convertkit-preview-form-' . esc_attr( $args['post_type'] ) . '" target="_blank">' . esc_html__( 'Click here', 'convertkit' ) . '</a>',
807 esc_html__( 'to preview how this will display.', 'convertkit' )
808 );
809 } else {
810 // Just output the field's description.
811 $description = sprintf(
812 /* translators: Post Type name, plural */
813 esc_html__( 'Select a form above to automatically output below all %s.', 'convertkit' ),
814 $args['post_type_object']->label
815 );
816 }
817
818 // Output field.
819 echo '<div class="convertkit-select2-container">';
820 $this->forms->output_select_field_all(
821 $this->settings_key . '[' . $args['post_type'] . '_form]',
822 $this->settings_key . '_' . $args['post_type'] . '_form',
823 array(
824 'convertkit-select2',
825 'convertkit-preview-output-link',
826 ),
827 $this->settings->get_default_form( $args['post_type'] ),
828 array(
829 'default' => esc_html__( 'None', 'convertkit' ),
830 ),
831 array(
832 'data-target' => '#convertkit-preview-form-' . esc_attr( $args['post_type'] ),
833 'data-link' => esc_attr( $preview_url ) . '&convertkit_form_id=',
834 ),
835 $description
836 );
837 echo '</div>';
838
839 }
840
841 /**
842 * Renders the input for the Default Form Position setting for the given Post Type.
843 *
844 * @since 2.5.8
845 *
846 * @param array $args Field arguments.
847 */
848 public function default_form_position_callback( $args ) {
849
850 $this->output_select_field(
851 $args['post_type'] . '_form_position',
852 esc_attr( $this->settings->get_default_form_position( $args['post_type'] ) ),
853 array(
854 'before_content' => sprintf(
855 /* translators: Post type singular name */
856 esc_attr__( 'Before %s content', 'convertkit' ),
857 esc_attr( $args['post_type_object']->labels->singular_name )
858 ),
859 'after_content' => sprintf(
860 /* translators: Post type singular name */
861 esc_attr__( 'After %s content', 'convertkit' ),
862 esc_attr( $args['post_type_object']->labels->singular_name )
863 ),
864 'before_after_content' => sprintf(
865 /* translators: Post type singular name */
866 esc_attr__( 'Before and after %s content', 'convertkit' ),
867 esc_attr( $args['post_type_object']->labels->singular_name )
868 ),
869 'after_element' => esc_html__( 'After element', 'convertkit' ),
870 ),
871 sprintf(
872 /* translators: Post Type name, plural */
873 esc_html__( 'Where forms should display relative to the %s content', 'convertkit' ),
874 esc_html( $args['post_type_object']->labels->singular_name )
875 ),
876 array( 'convertkit-conditional-display' ),
877 array(
878 'data-conditional-value' => 'after_element',
879 'data-conditional-element' => esc_attr( $args['post_type'] ) . '_form_position_element_index',
880 )
881 );
882
883 }
884
885 /**
886 * Renders the input for the Default Form Position Index setting for the given Post Type.
887 *
888 * @since 2.6.1
889 *
890 * @param array $args Field arguments.
891 */
892 public function default_form_position_element_callback( $args ) {
893
894 $this->output_number_field(
895 $args['post_type'] . '_form_position_element_index',
896 esc_attr( (string) $this->settings->get_default_form_position_element_index( $args['post_type'] ) ),
897 1,
898 999,
899 1,
900 false,
901 array( 'after_element' )
902 );
903
904 $this->output_select_field(
905 $args['post_type'] . '_form_position_element',
906 esc_attr( $this->settings->get_default_form_position_element( $args['post_type'] ) ),
907 array(
908 'p' => esc_html__( 'Paragraphs', 'convertkit' ),
909 'h2' => esc_html__( 'Headings <h2>', 'convertkit' ),
910 'h3' => esc_html__( 'Headings <h3>', 'convertkit' ),
911 'h4' => esc_html__( 'Headings <h4>', 'convertkit' ),
912 'h5' => esc_html__( 'Headings <h5>', 'convertkit' ),
913 'h6' => esc_html__( 'Headings <h6>', 'convertkit' ),
914 'img' => esc_html__( 'Images', 'convertkit' ),
915 ),
916 esc_html__( 'The number of elements before outputting the form.', 'convertkit' ),
917 array( 'after_element' )
918 );
919
920 }
921
922 /**
923 * Renders the input for the Non-inline Form setting.
924 *
925 * @since 2.2.3
926 *
927 * @param array $args Field arguments.
928 */
929 public function non_inline_form_callback( $args ) {
930
931 // Bail if no non-inline Forms exist.
932 if ( ! $this->forms->non_inline_exist() ) {
933 esc_html_e( 'No non-inline Forms exist in Kit.', 'convertkit' );
934 echo '<br /><a href="' . esc_url( convertkit_get_new_form_url() ) . '" target="_blank">' . esc_html__( 'Click here to create your first modal, slide in or sticky bar form', 'convertkit' ) . '</a>';
935 return;
936 }
937
938 // Build description with preview link.
939 $preview_url = WP_ConvertKit()->get_class( 'preview_output' )->get_preview_form_home_url();
940 $description = sprintf(
941 '%s %s %s',
942 esc_html__( 'Automatically display one or more modal, slide-in, or sticky bar forms across your site. This setting is overridden if a default non-inline form is set above, a specific non-inline form or "None" option is chosen for a post/page, or a non-inline form is specified in a block/shortcode.', 'convertkit' ),
943 '<a href="' . esc_url( $preview_url ) . '" id="convertkit-preview-non-inline-form" target="_blank">' . esc_html__( 'Click here', 'convertkit' ) . '</a>',
944 esc_html__( 'to preview how this will display.', 'convertkit' )
945 );
946
947 // Output field.
948 echo '<div class="convertkit-select2-container">';
949 $this->forms->output_select_field_non_inline(
950 $this->settings_key . '[non_inline_form]',
951 $this->settings_key . '_non_inline_form',
952 array(
953 'convertkit-select2',
954 'convertkit-preview-output-link',
955 ),
956 $this->settings->get_non_inline_form(),
957 false,
958 array(
959 'data-target' => '#convertkit-preview-non-inline-form',
960 'data-link' => esc_attr( $preview_url ) . '&convertkit_form_id=',
961 ),
962 $description
963 );
964 echo '</div>';
965
966 }
967
968 /**
969 * Renders the input for the Non-inline Form override setting.
970 *
971 * @since 2.7.3
972 */
973 public function non_inline_form_honor_none_setting_callback() {
974
975 // Output field.
976 $this->output_checkbox_field(
977 'non_inline_form_honor_none_setting',
978 'on',
979 $this->settings->non_inline_form_honor_none_setting(),
980 esc_html__( 'If checked, do not display the site wide form(s) above on Pages / Posts that have their Kit Form setting = None.', 'convertkit' )
981 );
982
983 }
984
985
986 /**
987 * Renders the input for the Modal Form Limit per Session setting.
988 *
989 * @since 3.0.0
990 *
991 * @param array $args Setting field arguments (name,description).
992 */
993 public function non_inline_form_limit_per_session_callback( $args ) {
994
995 // Output field.
996 $this->output_checkbox_field(
997 'non_inline_form_limit_per_session',
998 'on',
999 $this->settings->non_inline_form_limit_per_session(),
1000 esc_html__( 'If checked, one non-inline form will be displayed per session. This applies to all non-inline forms defined on this screen, Page / Post / Category settings, and any Form blocks or shortcodes specifying a non-inline form.', 'convertkit' )
1001 );
1002
1003 }
1004
1005 /**
1006 * Renders the dropdown for choosing the active spam protection provider.
1007 *
1008 * @since 3.3.7
1009 *
1010 * @param array $args Setting field arguments (name,description).
1011 */
1012 public function spam_protection_provider_callback( $args ) {
1013
1014 $this->output_select_field(
1015 'spam_protection_provider',
1016 esc_attr( $this->settings->spam_protection_provider() ),
1017 array(
1018 'recaptcha' => esc_html__( 'Google reCAPTCHA v3', 'convertkit' ),
1019 'cloudflare_turnstile' => esc_html__( 'Cloudflare Turnstile', 'convertkit' ),
1020 ),
1021 $args['description'],
1022 array( 'convertkit-conditional-display' ),
1023 array( 'data-conditional-class-prefix' => 'convertkit-spam-protection-' )
1024 );
1025
1026 }
1027
1028 /**
1029 * Renders the input for the reCAPTCHA Site Key setting.
1030 *
1031 * @since 3.0.0
1032 *
1033 * @param array $args Setting field arguments (name,description).
1034 */
1035 public function recaptcha_site_key_callback( $args ) {
1036
1037 // Output field.
1038 $this->output_text_field(
1039 'recaptcha_site_key',
1040 esc_attr( $this->settings->recaptcha_site_key() ),
1041 $args['description'],
1042 array(
1043 'widefat',
1044 )
1045 );
1046
1047 }
1048
1049 /**
1050 * Renders the input for the reCAPTCHA Secret Key setting.
1051 *
1052 * @since 3.0.0
1053 *
1054 * @param array $args Setting field arguments (name,description).
1055 */
1056 public function recaptcha_secret_key_callback( $args ) {
1057
1058 // Output field.
1059 $this->output_text_field(
1060 'recaptcha_secret_key',
1061 esc_attr( $this->settings->recaptcha_secret_key() ),
1062 $args['description'],
1063 array(
1064 'widefat',
1065 )
1066 );
1067
1068 }
1069
1070 /**
1071 * Renders the input for the reCAPTCHA Minimum Score setting.
1072 *
1073 * @since 3.0.0
1074 *
1075 * @param array $args Setting field arguments (name,description).
1076 */
1077 public function recaptcha_minimum_score_callback( $args ) {
1078
1079 // Output field.
1080 $this->output_number_field(
1081 'recaptcha_minimum_score',
1082 esc_attr( (string) $this->settings->recaptcha_minimum_score() ),
1083 $args['min'],
1084 $args['max'],
1085 $args['step'],
1086 $args['description'],
1087 array(
1088 'widefat',
1089 )
1090 );
1091
1092 }
1093
1094 /**
1095 * Renders the input for the Cloudflare Turnstile Site Key setting.
1096 *
1097 * @since 3.3.7
1098 *
1099 * @param array $args Setting field arguments (name,description).
1100 */
1101 public function cloudflare_turnstile_site_key_callback( $args ) {
1102
1103 $this->output_text_field(
1104 'cloudflare_turnstile_site_key',
1105 esc_attr( $this->settings->cloudflare_turnstile_site_key() ),
1106 $args['description'],
1107 array(
1108 'widefat',
1109 )
1110 );
1111
1112 }
1113
1114 /**
1115 * Renders the input for the Cloudflare Turnstile Secret Key setting.
1116 *
1117 * @since 3.3.7
1118 *
1119 * @param array $args Setting field arguments (name,description).
1120 */
1121 public function cloudflare_turnstile_secret_key_callback( $args ) {
1122
1123 $this->output_text_field(
1124 'cloudflare_turnstile_secret_key',
1125 esc_attr( $this->settings->cloudflare_turnstile_secret_key() ),
1126 $args['description'],
1127 array(
1128 'widefat',
1129 )
1130 );
1131
1132 }
1133
1134 /**
1135 * Renders the input for the Debug setting.
1136 *
1137 * @since 1.9.6
1138 */
1139 public function debug_callback() {
1140
1141 // Output field.
1142 $this->output_checkbox_field(
1143 'debug',
1144 'on',
1145 $this->settings->debug_enabled(),
1146 esc_html__( 'Log requests to file and output browser console messages.', 'convertkit' ),
1147 esc_html__( 'You can ignore this unless you\'re working with our support team to resolve an issue. Decheck this option to improve performance.', 'convertkit' )
1148 );
1149
1150 }
1151
1152 /**
1153 * Renders the input for the Disable Javascript setting.
1154 *
1155 * @since 1.9.6
1156 */
1157 public function no_scripts_callback() {
1158
1159 // Output field.
1160 $this->output_checkbox_field(
1161 'no_scripts',
1162 'on',
1163 $this->settings->scripts_disabled(),
1164 esc_html__( 'Prevent plugin JavaScript files loading on the frontend site. This will disable the custom content and tagging features of the plugin. Does not apply to embedding forms or landing pages. Use with caution!', 'convertkit' )
1165 );
1166
1167 }
1168
1169 /**
1170 * Renders the input for the Disable CSS setting.
1171 *
1172 * @since 1.9.6.9
1173 */
1174 public function no_css_callback() {
1175
1176 // Output field.
1177 $this->output_checkbox_field(
1178 'no_css',
1179 'on',
1180 $this->settings->css_disabled(),
1181 esc_html__( 'Prevents loading plugin CSS files. This will disable styling on broadcasts, form trigger buttons, product buttons and member\'s content. Use with caution!', 'convertkit' ),
1182 array(
1183 sprintf(
1184 '%s <a href="%s" target="_blank">%s</a>',
1185 esc_html__( 'To customize forms and their styling, use the', 'convertkit' ),
1186 esc_url( convertkit_get_form_editor_url() ),
1187 esc_html__( 'Kit form editor', 'convertkit' )
1188 ),
1189 esc_html__( 'For creators who require form designs to follow their WordPress theme, use the Kit Form Builder block in the block editor.', 'convertkit' ),
1190 sprintf(
1191 '%s <a href="https://wordpress.org/plugins/contact-form-7/" target="_blank">Contact Form 7</a>, <a href="https://wordpress.org/plugins/convertkit-gravity-forms/" target="_blank">Gravity Forms</a> %s <a href="https://wordpress.org/plugins/integrate-convertkit-wpforms/" target="_blank">WPForms</a> %s',
1192 esc_html__( 'For developers who require custom form designs through use of CSS, consider using the', 'convertkit' ),
1193 esc_html__( 'or', 'convertkit' ),
1194 esc_html__( 'integrations.', 'convertkit' )
1195 ),
1196 )
1197 );
1198
1199 }
1200
1201 /**
1202 * Renders the input for the Disable Add New Landing Page / Member Content setting.
1203 *
1204 * @since 3.2.0
1205 */
1206 public function no_add_new_button_callback() {
1207
1208 // Output field.
1209 $this->output_checkbox_field(
1210 'no_add_new_button',
1211 'on',
1212 $this->settings->add_new_button_disabled(),
1213 esc_html__( 'Hide the "Add New" button on Pages for creating Landing Pages and Member Content.', 'convertkit' )
1214 );
1215
1216 }
1217
1218 /**
1219 * Renders the input for the Usage Tracking setting.
1220 *
1221 * @since 3.0.4
1222 */
1223 public function usage_tracking_callback() {
1224
1225 // Output field.
1226 $this->output_checkbox_field(
1227 'usage_tracking',
1228 'on',
1229 $this->settings->usage_tracking(),
1230 esc_html__( 'By allowing us to collect usage data, we can better understand which WordPress configurations, themes and plugins we should test.', 'convertkit' ),
1231 array(
1232 sprintf(
1233 '%s <a href="%s" target="_blank">%s</a>',
1234 esc_html__( 'Complete documentation on usage tracking can be found', 'convertkit' ),
1235 $this->documentation_url(),
1236 esc_html__( 'here', 'convertkit' )
1237 ),
1238 )
1239 );
1240
1241 }
1242
1243 /**
1244 * Sanitizes the settings prior to being saved.
1245 *
1246 * @since 2.4.3
1247 *
1248 * @param null|array $settings Submitted Settings Fields.
1249 * @return array Sanitized Settings with Defaults
1250 */
1251 public function sanitize_settings( $settings ) {
1252
1253 // If no Access Token, Refresh Token or Token Expiry keys were specified in the settings
1254 // prior to save, don't overwrite them with the blank setting from get_defaults().
1255 // This ensures we only blank these values if we explicitly do so via $settings,
1256 // as they won't be included in the Settings screen for security.
1257 if ( ! filter_has_var( INPUT_GET, 'disconnect' ) ) {
1258 // If settings are null, no checkboxes were ticked and no other form elements
1259 // were submitted i.e. the Kit account has no forms.
1260 if ( is_null( $settings ) ) {
1261 $settings = array();
1262 }
1263
1264 if ( ! array_key_exists( 'access_token', $settings ) ) {
1265 $settings['access_token'] = $this->settings->get_access_token();
1266 }
1267 if ( ! array_key_exists( 'refresh_token', $settings ) ) {
1268 $settings['refresh_token'] = $this->settings->get_refresh_token();
1269 }
1270 if ( ! array_key_exists( 'token_expires', $settings ) ) {
1271 $settings['token_expires'] = $this->settings->get_token_expiry();
1272 }
1273 }
1274
1275 // Call parent class to merge settings with defaults.
1276 $settings = parent::sanitize_settings( $settings );
1277
1278 // If a Form or Landing Page was specified that isn't the default,
1279 // request a review.
1280 // Since switching to OAuth means the settings screen will only display
1281 // settings if the access token is valid, the Default Forms options will
1282 // always be submitted. Previously, if no API Key/Secret was specified,
1283 // no Default Forms options would render.
1284 // This can safely be called multiple times, as the review request
1285 // class will ensure once a review request is dismissed by the user,
1286 // it is never displayed again.
1287 if ( ( isset( $settings['page_form'] ) && $settings['page_form'] !== 'default' ) ||
1288 ( isset( $settings['post_form'] ) && $settings['post_form'] !== 'default' ) ) {
1289 WP_ConvertKit()->get_class( 'review_request' )->request_review();
1290 }
1291
1292 // Return settings to be saved.
1293 return $settings;
1294
1295 }
1296
1297 }
1298