PluginProbe
Kit (formerly ConvertKit) – Email Newsletter, Email Marketing, Membership, Subscribers and Landing Pages / 3.4.6
Kit (formerly ConvertKit) – Email Newsletter, Email Marketing, Membership, Subscribers and Landing Pages v3.4.6
3.4.6 3.4.5 3.4.4 3.4.3 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 All 199 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 3.4.6, at admin/section/class-convertkit-admin-section-general.php

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