PluginProbe
Kit (formerly ConvertKit) – Email Newsletter, Email Marketing, Membership, Subscribers and Landing Pages / 2.5.1
Kit (formerly ConvertKit) – Email Newsletter, Email Marketing, Membership, Subscribers and Landing Pages v2.5.1
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-settings-general.php

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

663 lines 19.6 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 > ConvertKit > General.
11 *
12 * @package ConvertKit
13 * @author ConvertKit
14 */
15 class ConvertKit_Settings_General extends ConvertKit_Settings_Base {
16
17 /**
18 * Holds the API instance.
19 *
20 * @since 1.9.6
21 *
22 * @var ConvertKit_API_V4
23 */
24 private $api;
25
26 /**
27 * Holds the ConvertKit Account Name.
28 *
29 * @since 1.9.6
30 *
31 * @var bool|WP_Error|array
32 */
33 private $account = false;
34
35 /**
36 * Holds the ConvertKit Forms Resource.
37 *
38 * @since 1.9.6
39 *
40 * @var bool|ConvertKit_Resource_Forms;
41 */
42 private $forms = false;
43
44 /**
45 * Constructor.
46 */
47 public function __construct() {
48
49 // Define the class that reads/writes settings.
50 $this->settings = new ConvertKit_Settings();
51
52 // Define the settings key.
53 $this->settings_key = $this->settings::SETTINGS_NAME;
54
55 // Define the programmatic name, Title and Tab Text.
56 $this->name = 'general';
57 $this->title = __( 'General Settings', 'convertkit' );
58 $this->tab_text = __( 'General', 'convertkit' );
59
60 // Register and maybe output notices for this settings screen.
61 if ( $this->on_settings_screen( $this->name ) ) {
62 add_filter( 'convertkit_settings_base_register_notices', array( $this, 'register_notices' ) );
63 add_action( 'convertkit_settings_base_render_before', array( $this, 'maybe_output_notices' ) );
64 }
65
66 // Enqueue scripts and CSS.
67 add_action( 'convertkit_admin_settings_enqueue_scripts', array( $this, 'enqueue_scripts' ) );
68 add_action( 'convertkit_admin_settings_enqueue_styles', array( $this, 'enqueue_styles' ) );
69
70 parent::__construct();
71
72 $this->check_credentials();
73 $this->maybe_disconnect();
74
75 }
76
77 /**
78 * Registers success and error notices for the General screen, to be displayed
79 * depending on the action.
80 *
81 * @since 2.5.1
82 *
83 * @param array $notices Regsitered success and error notices.
84 * @return array
85 */
86 public function register_notices( $notices ) {
87
88 return array_merge(
89 $notices,
90 array(
91 'oauth2_success' => __( 'Successfully authorized with ConvertKit.', 'convertkit' ),
92 )
93 );
94
95 }
96
97 /**
98 * Test the access token, if it exists.
99 * If the access token has been revoked or is invalid, remove it from the settings now.
100 *
101 * @since 2.5.0
102 */
103 private function check_credentials() {
104
105 // Bail if we're not on the settings screen.
106 if ( ! $this->on_settings_screen( $this->name ) ) {
107 return;
108 }
109
110 // Bail if no access and refresh token exist.
111 if ( ! $this->settings->has_access_and_refresh_token() ) {
112 return;
113 }
114
115 // Initialize the API.
116 $this->api = new ConvertKit_API_V4(
117 CONVERTKIT_OAUTH_CLIENT_ID,
118 CONVERTKIT_OAUTH_CLIENT_REDIRECT_URI,
119 $this->settings->get_access_token(),
120 $this->settings->get_refresh_token(),
121 $this->settings->debug_enabled(),
122 'settings'
123 );
124
125 // Get Account Details, which we'll use in account_name_callback(), but also lets us test
126 // whether the API credentials are valid.
127 $this->account = $this->api->get_account();
128
129 // If the request succeeded, no need to perform further actions.
130 if ( ! is_wp_error( $this->account ) ) {
131 // Remove any existing persistent notice.
132 WP_ConvertKit()->get_class( 'admin_notices' )->delete( 'authorization_failed' );
133
134 return;
135 }
136
137 // Depending on the error code, maybe persist a notice in the WordPress Administration until the user
138 // fixes the problem.
139 switch ( $this->account->get_error_data( $this->account->get_error_code() ) ) {
140 case 401:
141 // Access token either expired or was revoked in ConvertKit.
142 // Remove from settings.
143 $this->settings->delete_credentials();
144
145 // Display a site wide notice.
146 WP_ConvertKit()->get_class( 'admin_notices' )->add( 'authorization_failed' );
147
148 // Redirect to General screen, which will now show the ConvertKit_Settings_OAuth screen, because
149 // the Plugin has no access token.
150 wp_safe_redirect(
151 add_query_arg(
152 array(
153 'page' => $this->settings_key,
154 ),
155 'options-general.php'
156 )
157 );
158 exit();
159 }
160
161 // Output a non-401 error now.
162 $this->output_error( $this->account->get_error_message() );
163
164 }
165
166 /**
167 * Deletes the OAuth Access Token, Refresh Token and Expiry from the Plugin's settings, if the user
168 * clicked the Disconnect button.
169 *
170 * @since 2.5.0
171 */
172 private function maybe_disconnect() {
173
174 // Bail if we're not on the settings screen.
175 if ( ! $this->on_settings_screen( $this->name ) ) {
176 return;
177 }
178
179 // Bail if nonce verification fails.
180 if ( ! isset( $_REQUEST['_convertkit_settings_oauth_disconnect'] ) ) {
181 return;
182 }
183 if ( ! wp_verify_nonce( sanitize_key( $_REQUEST['_convertkit_settings_oauth_disconnect'] ), 'convertkit-oauth-disconnect' ) ) {
184 return;
185 }
186
187 // Delete Access Token.
188 $settings = new ConvertKit_Settings();
189 $settings->delete_credentials();
190
191 // Delete cached resources.
192 $creator_network = new ConvertKit_Resource_Creator_Network_Recommendations();
193 $forms = new ConvertKit_Resource_Forms();
194 $landing_pages = new ConvertKit_Resource_Landing_Pages();
195 $posts = new ConvertKit_Resource_Posts();
196 $products = new ConvertKit_Resource_Products();
197 $tags = new ConvertKit_Resource_Tags();
198 $creator_network->delete();
199 $forms->delete();
200 $landing_pages->delete();
201 $posts->delete();
202 $products->delete();
203 $tags->delete();
204
205 // Redirect to General screen, which will now show the ConvertKit_Settings_OAuth screen, because
206 // the Plugin has no access token.
207 wp_safe_redirect(
208 add_query_arg(
209 array(
210 'page' => $this->settings_key,
211 ),
212 'options-general.php'
213 )
214 );
215 exit();
216
217 }
218
219 /**
220 * Enqueues scripts for the Settings > General screen.
221 *
222 * @since 2.2.4
223 *
224 * @param string $section Settings section / tab (general|tools|restrict-content).
225 */
226 public function enqueue_scripts( $section ) {
227
228 // Bail if we're not on the general section.
229 if ( $section !== $this->name ) {
230 return;
231 }
232
233 // Enqueue Select2 JS.
234 convertkit_select2_enqueue_scripts();
235
236 // Enqueue Preview Output JS.
237 wp_enqueue_script( 'convertkit-admin-preview-output', CONVERTKIT_PLUGIN_URL . 'resources/backend/js/preview-output.js', array( 'jquery' ), CONVERTKIT_PLUGIN_VERSION, true );
238
239 }
240
241 /**
242 * Enqueues styles for the Settings > General screen.
243 *
244 * @since 2.2.4
245 *
246 * @param string $section Settings section / tab (general|tools|restrict-content).
247 */
248 public function enqueue_styles( $section ) {
249
250 // Bail if we're not on the general section.
251 if ( $section !== $this->name ) {
252 return;
253 }
254
255 // Enqueue Select2 CSS.
256 convertkit_select2_enqueue_styles();
257
258 }
259
260 /**
261 * Registers settings fields for this section.
262 */
263 public function register_fields() {
264
265 add_settings_field(
266 'account_name',
267 __( 'Account Name', 'convertkit' ),
268 array( $this, 'account_name_callback' ),
269 $this->settings_key,
270 $this->name
271 );
272
273 foreach ( convertkit_get_supported_post_types() as $supported_post_type ) {
274 // Get Post Type's Label.
275 $post_type = get_post_type_object( $supported_post_type );
276
277 // Skip if the Post Type doesn't exist.
278 if ( ! $post_type ) {
279 continue;
280 }
281
282 // Add Settings Field.
283 add_settings_field(
284 $supported_post_type . '_form',
285 sprintf(
286 /* translators: Post Type Name */
287 __( 'Default Form (%s)', 'convertkit' ),
288 $post_type->label
289 ),
290 array( $this, 'custom_post_types_callback' ),
291 $this->settings_key,
292 $this->name,
293 array(
294 'label_for' => '_wp_convertkit_settings_' . $supported_post_type . '_form',
295 'post_type' => $supported_post_type,
296 'post_type_object' => $post_type,
297 )
298 );
299 }
300
301 add_settings_field(
302 'non_inline_form',
303 __( 'Default Form (Site Wide)', 'convertkit' ),
304 array( $this, 'non_inline_form_callback' ),
305 $this->settings_key,
306 $this->name,
307 array(
308 'label_for' => 'non_inline_form',
309 )
310 );
311
312 add_settings_field(
313 'debug',
314 __( 'Debug', 'convertkit' ),
315 array( $this, 'debug_callback' ),
316 $this->settings_key,
317 $this->name,
318 array(
319 'label_for' => 'debug',
320 )
321 );
322
323 add_settings_field(
324 'no_scripts',
325 __( 'Disable JavaScript', 'convertkit' ),
326 array( $this, 'no_scripts_callback' ),
327 $this->settings_key,
328 $this->name,
329 array(
330 'label_for' => 'no_scripts',
331 )
332 );
333
334 add_settings_field(
335 'no_css',
336 __( 'Disable CSS', 'convertkit' ),
337 array( $this, 'no_css_callback' ),
338 $this->settings_key,
339 $this->name,
340 array(
341 'label_for' => 'no_css',
342 )
343 );
344
345 }
346
347 /**
348 * Prints help info for this section
349 */
350 public function print_section_info() {
351
352 ?>
353 <p><?php esc_html_e( 'Choosing a default form will embed it at the bottom of every post or page (in single view only) across your site.', 'convertkit' ); ?></p>
354 <p><?php esc_html_e( 'If you wish to turn off form embedding or select a different form for an individual post or page, you can do so using the ConvertKit meta box on the edit page.', 'convertkit' ); ?></p>
355 <p>
356 <?php
357 printf(
358 /* translators: [convertkit] shortcode, wrapped in <code> tags */
359 esc_html__( 'The default form can be inserted into the middle of post or page content by using the %s shortcode.', 'convertkit' ),
360 '<code>[convertkit]</code>'
361 );
362 ?>
363 </p>
364 <?php
365
366 }
367
368 /**
369 * Returns the URL for the ConvertKit documentation for this setting section.
370 *
371 * @since 2.0.8
372 *
373 * @return string Documentation URL.
374 */
375 public function documentation_url() {
376
377 return 'https://help.convertkit.com/en/articles/2502591-the-convertkit-wordpress-plugin';
378
379 }
380
381 /**
382 * Outputs the Account Name
383 *
384 * @since 1.9.6
385 */
386 public function account_name_callback() {
387
388 // Output Account Name.
389 $html = sprintf(
390 '<code>%s</code>',
391 isset( $this->account['account']['name'] ) ? esc_attr( $this->account['account']['name'] ) : esc_html__( '(Not specified)', 'convertkit' )
392 );
393
394 // Display an option to disconnect.
395 $html .= sprintf(
396 '<p><a href="%1$s" class="button button-primary">%2$s</a></p>',
397 esc_url(
398 add_query_arg(
399 array(
400 'page' => '_wp_convertkit_settings',
401 '_convertkit_settings_oauth_disconnect' => wp_create_nonce( 'convertkit-oauth-disconnect' ),
402 ),
403 'options-general.php'
404 )
405 ),
406 esc_html__( 'Disconnect', 'convertkit' )
407 );
408
409 // Output has already been run through escaping functions above.
410 echo $html; // phpcs:ignore WordPress.Security.EscapeOutput
411 }
412
413 /**
414 * Renders the input for the Default Form setting for the given Post Type.
415 *
416 * @since 1.9.6
417 *
418 * @param array $args Field arguments.
419 */
420 public function custom_post_types_callback( $args ) {
421
422 // Refresh Forms.
423 if ( ! $this->forms ) {
424 $this->forms = new ConvertKit_Resource_Forms( 'settings' );
425 $this->forms->refresh();
426
427 // Also refresh Landing Pages, Tags and Posts. Whilst not displayed in the Plugin Settings, this ensures up to date
428 // lists are stored for when editing e.g. Pages.
429 $landing_pages = new ConvertKit_Resource_Landing_Pages( 'settings' );
430 $landing_pages->refresh();
431
432 remove_all_actions( 'convertkit_resource_refreshed_posts' );
433 $posts = new ConvertKit_Resource_Posts( 'settings' );
434 $posts->refresh();
435
436 $products = new ConvertKit_Resource_Products( 'settings' );
437 $products->refresh();
438
439 $tags = new ConvertKit_Resource_Tags( 'settings' );
440 $tags->refresh();
441 }
442
443 // Bail if no Forms exist.
444 if ( ! $this->forms->exist() ) {
445 esc_html_e( 'No Forms exist in ConvertKit.', 'convertkit' );
446 echo '<br /><a href="' . esc_url( convertkit_get_new_form_url() ) . '" target="_blank">' . esc_html__( 'Click here to create your first form', 'convertkit' ) . '</a>';
447 return;
448 }
449
450 // Build description with preview link.
451 $description = false;
452 $preview_url = WP_ConvertKit()->get_class( 'preview_output' )->get_preview_form_url( $args['post_type'] );
453 if ( $preview_url ) {
454 // Include a preview link in the description.
455 $description = sprintf(
456 '%s %s %s',
457 sprintf(
458 /* translators: Post Type name, plural */
459 esc_html__( 'Select a form above to automatically output below all %s.', 'convertkit' ),
460 $args['post_type_object']->label
461 ),
462 '<a href="' . esc_url( $preview_url ) . '" id="convertkit-preview-form-' . esc_attr( $args['post_type'] ) . '" target="_blank">' . esc_html__( 'Click here', 'convertkit' ) . '</a>',
463 esc_html__( 'to preview how this will display.', 'convertkit' )
464 );
465 } else {
466 // Just output the field's description.
467 $description = sprintf(
468 /* translators: Post Type name, plural */
469 esc_html__( 'Select a form above to automatically output below all %s.', 'convertkit' ),
470 $args['post_type_object']->label
471 );
472 }
473
474 // Build field.
475 $select_field = $this->forms->get_select_field_all(
476 $this->settings_key . '[' . $args['post_type'] . '_form]',
477 $this->settings_key . '_' . $args['post_type'] . '_form',
478 array(
479 'convertkit-select2',
480 'convertkit-preview-output-link',
481 ),
482 $this->settings->get_default_form( $args['post_type'] ),
483 array(
484 'default' => esc_html__( 'None', 'convertkit' ),
485 ),
486 array(
487 'data-target' => '#convertkit-preview-form-' . esc_attr( $args['post_type'] ),
488 'data-link' => esc_attr( $preview_url ) . '&convertkit_form_id=',
489 ),
490 $description
491 );
492
493 // Output field.
494 echo '<div class="convertkit-select2-container">' . $select_field . '</div>'; // phpcs:ignore WordPress.Security.EscapeOutput
495
496 }
497
498
499 /**
500 * Renders the input for the Non-inline Form setting.
501 *
502 * @since 2.2.3
503 *
504 * @param array $args Field arguments.
505 */
506 public function non_inline_form_callback( $args ) {
507
508 // Bail if no non-inline Forms exist.
509 if ( ! $this->forms->non_inline_exist() ) {
510 esc_html_e( 'No non-inline Forms exist in ConvertKit.', 'convertkit' );
511 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>';
512 return;
513 }
514
515 // Build description with preview link.
516 $preview_url = WP_ConvertKit()->get_class( 'preview_output' )->get_preview_form_home_url();
517 $description = sprintf(
518 '%s %s %s',
519 esc_html__( 'Select a non-inline modal, slide in or sticky bar form to automatically display site wide. Ignored if a non-inline form is specified in Default Form settings above, individual Post / Page settings, or any block / shortcode.', 'convertkit' ),
520 '<a href="' . esc_url( $preview_url ) . '" id="convertkit-preview-non-inline-form" target="_blank">' . esc_html__( 'Click here', 'convertkit' ) . '</a>',
521 esc_html__( 'to preview how this will display.', 'convertkit' )
522 );
523
524 // Build field.
525 $select_field = $this->forms->get_select_field_non_inline(
526 $this->settings_key . '[non_inline_form]',
527 $this->settings_key . '_non_inline_form',
528 array(
529 'convertkit-select2',
530 'convertkit-preview-output-link',
531 ),
532 $this->settings->get_non_inline_form(),
533 array(
534 '' => esc_html__( 'None', 'convertkit' ),
535 ),
536 array(
537 'data-target' => '#convertkit-preview-non-inline-form',
538 'data-link' => esc_attr( $preview_url ) . '&convertkit_form_id=',
539 ),
540 $description
541 );
542
543 // Output field.
544 echo '<div class="convertkit-select2-container">' . $select_field . '</div>'; // phpcs:ignore WordPress.Security.EscapeOutput
545
546 }
547
548 /**
549 * Renders the input for the Debug setting.
550 *
551 * @since 1.9.6
552 */
553 public function debug_callback() {
554
555 // Output field.
556 echo $this->get_checkbox_field( // phpcs:ignore WordPress.Security.EscapeOutput
557 'debug',
558 'on',
559 $this->settings->debug_enabled(), // phpcs:ignore WordPress.Security.EscapeOutput
560 esc_html__( 'Log requests to file and output browser console messages.', 'convertkit' ),
561 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' )
562 );
563
564 }
565
566 /**
567 * Renders the input for the Disable Javascript setting.
568 *
569 * @since 1.9.6
570 */
571 public function no_scripts_callback() {
572
573 // Output field.
574 echo $this->get_checkbox_field( // phpcs:ignore WordPress.Security.EscapeOutput
575 'no_scripts',
576 'on',
577 $this->settings->scripts_disabled(), // phpcs:ignore WordPress.Security.EscapeOutput
578 esc_html__( 'Prevent plugin from loading JavaScript files. This will disable the custom content and tagging features of the plugin. Does not apply to landing pages. Use with caution!', 'convertkit' )
579 );
580
581 }
582
583 /**
584 * Renders the input for the Disable CSS setting.
585 *
586 * @since 1.9.6.9
587 */
588 public function no_css_callback() {
589
590 // Output field.
591 echo $this->get_checkbox_field( // phpcs:ignore WordPress.Security.EscapeOutput
592 'no_css',
593 'on',
594 $this->settings->css_disabled(), // phpcs:ignore WordPress.Security.EscapeOutput
595 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' ),
596 array(
597 sprintf(
598 '%s <a href="%s" target="_blank">%s</a>',
599 esc_html__( 'To customize forms and their styling, use the', 'convertkit' ),
600 esc_url( convertkit_get_form_editor_url() ),
601 esc_html__( 'ConvertKit form editor', 'convertkit' )
602 ),
603 sprintf(
604 '%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',
605 esc_html__( 'For developers who require custom form designs through use of CSS, consider using the', 'convertkit' ),
606 esc_html__( 'or', 'convertkit' ),
607 esc_html__( 'integrations.', 'convertkit' )
608 ),
609 )
610 );
611
612 }
613
614 /**
615 * Sanitizes the settings prior to being saved.
616 *
617 * @since 2.4.3
618 *
619 * @param array $settings Submitted Settings Fields.
620 * @return array Sanitized Settings with Defaults
621 */
622 public function sanitize_settings( $settings ) {
623
624 // If no Access Token, Refresh Token or Token Expiry keys were specified in the settings
625 // prior to save, don't overwrite them with the blank setting from get_defaults().
626 // This ensures we only blank these values if we explicitly do so via $settings,
627 // as they won't be included in the Settings screen for security.
628 if ( ! array_key_exists( 'disconnect', $_REQUEST ) ) { // phpcs:ignore WordPress.Security.NonceVerification
629 if ( ! array_key_exists( 'access_token', $settings ) ) {
630 $settings['access_token'] = $this->settings->get_access_token();
631 }
632 if ( ! array_key_exists( 'refresh_token', $settings ) ) {
633 $settings['refresh_token'] = $this->settings->get_refresh_token();
634 }
635 if ( ! array_key_exists( 'token_expires', $settings ) ) {
636 $settings['token_expires'] = $this->settings->get_token_expiry();
637 }
638 }
639
640 // Call parent class to merge settings with defaults.
641 $settings = parent::sanitize_settings( $settings );
642
643 // If a Form or Landing Page was specified that isn't the default,
644 // request a review.
645 // Since switching to OAuth means the settings screen will only display
646 // settings if the access token is valid, the Default Forms options will
647 // always be submitted. Previously, if no API Key/Secret was specified,
648 // no Default Forms options would render.
649 // This can safely be called multiple times, as the review request
650 // class will ensure once a review request is dismissed by the user,
651 // it is never displayed again.
652 if ( ( isset( $settings['page_form'] ) && $settings['page_form'] !== 'default' ) ||
653 ( isset( $settings['post_form'] ) && $settings['post_form'] !== 'default' ) ) {
654 WP_ConvertKit()->get_class( 'review_request' )->request_review();
655 }
656
657 // Return settings to be saved.
658 return $settings;
659
660 }
661
662 }
663