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

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

950 lines 23.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * ConvertKit Settings Base class.
4 *
5 * @package ConvertKit
6 * @author ConvertKit
7 */
8
9 /**
10 * ConvertKit Settings class
11 *
12 * @package ConvertKit
13 * @author ConvertKit
14 */
15 abstract class ConvertKit_Admin_Section_Base {
16
17 /**
18 * Section name
19 *
20 * @var string
21 */
22 public $name;
23
24 /**
25 * Section title
26 *
27 * @var string
28 */
29 public $title;
30
31 /**
32 * Section tab text
33 *
34 * @var string
35 */
36 public $tab_text;
37
38 /**
39 * Options table key
40 *
41 * @var string
42 */
43 public $settings_key;
44
45 /**
46 * Holds the settings class for the section.
47 *
48 * @since 1.9.6
49 *
50 * @var false|ConvertKit_Settings|ConvertKit_ContactForm7_Settings|ConvertKit_Wishlist_Settings|ConvertKit_Settings_Restrict_Content|ConvertKit_Settings_Broadcasts|ConvertKit_Forminator_Settings
51 */
52 public $settings;
53
54 /**
55 * Holds the settings sections for a settings screen.
56 *
57 * @since 2.7.1
58 *
59 * @var array
60 */
61 public $settings_sections = array();
62
63 /**
64 * Holds whether this settings section is for beta functionality.
65 *
66 * @since 2.1.0
67 *
68 * @var bool
69 */
70 public $is_beta = false;
71
72 /**
73 * Holds whether the save button should be disabled e.g. there are no
74 * settings on screen to save.
75 *
76 * @since 2.4.9
77 *
78 * @var bool
79 */
80 public $save_disabled = false;
81
82 /**
83 * Constructor
84 */
85 public function __construct() {
86
87 // If tab text is not defined, use the title for the tab's text.
88 if ( empty( $this->tab_text ) ) {
89 $this->tab_text = $this->title;
90 }
91
92 // Output the Intercom messenger if we're on the Plugin's settings screen.
93 if ( $this->on_settings_screen( $this->name ) ) {
94 add_action( 'admin_footer', array( $this, 'output_intercom' ) );
95 }
96
97 // Register the settings section.
98 $this->register_section();
99
100 }
101
102 /**
103 * Helper method to determine if we're viewing the current settings screen.
104 *
105 * @since 2.5.0
106 *
107 * @param string $tab Current settings tab (general|tools|restrict-content|broadcasts).
108 * @return bool
109 */
110 public function on_settings_screen( $tab ) {
111
112 // Bail if this is an AJAX or Cron request.
113 if ( wp_doing_ajax() || wp_doing_cron() ) {
114 return false;
115 }
116
117 // Bail if we're not on the settings screen.
118 if ( ! filter_has_var( INPUT_GET, 'page' ) ) {
119 return false;
120 }
121 if ( filter_input( INPUT_GET, 'page', FILTER_SANITIZE_FULL_SPECIAL_CHARS ) !== '_wp_convertkit_settings' ) {
122 return false;
123 }
124
125 // Define current settings tab.
126 // General screen won't always be loaded with a `tab` parameter.
127 if ( filter_has_var( INPUT_GET, 'tab' ) ) {
128 $current_tab = filter_input( INPUT_GET, 'tab', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
129 } else {
130 $current_tab = 'general';
131 }
132
133 // Return whether the request is for the current settings tab.
134 return ( $current_tab === $tab );
135
136 }
137
138 /**
139 * Register settings section.
140 */
141 public function register_section() {
142
143 // Register settings sections.
144 foreach ( $this->settings_sections as $name => $settings_section ) {
145 // Determine if this settings section needs to be wrapped in its own container.
146 $wrap = array();
147 if ( $settings_section['wrap'] ) {
148 $wrap = array(
149 'before_section' => $this->get_render_container_start(),
150 'after_section' => $this->get_render_container_end(),
151 );
152 }
153
154 add_settings_section(
155 ( $name === 'general' ? $this->name : $this->name . '-' . $name ),
156 $settings_section['title'],
157 $settings_section['callback'],
158 $this->settings_key,
159 $wrap
160 );
161 }
162
163 // Register settings fields.
164 $this->register_fields();
165
166 // Register setting to store data in options table.
167 register_setting(
168 $this->settings_key,
169 $this->settings_key,
170 array( $this, 'sanitize_settings' )
171 );
172
173 }
174
175 /**
176 * Register fields for this section
177 */
178 public function register_fields() {
179 }
180
181 /**
182 * Prints help info for this section
183 */
184 abstract public function print_section_info();
185
186 /**
187 * Returns the URL for the ConvertKit documentation for this setting section.
188 */
189 abstract public function documentation_url();
190
191 /**
192 * Outputs success and/or error notices if required.
193 *
194 * @since 2.0.0
195 */
196 public function maybe_output_notices() {
197
198 // Define notices that might be displayed as a notification.
199 $notices = array();
200
201 /**
202 * Register success and error notices for settings screens.
203 *
204 * @since 2.5.1
205 *
206 * @param array $notices Regsitered success and error notices.
207 * @return array
208 */
209 $notices = apply_filters( 'convertkit_settings_base_register_notices', $notices );
210
211 // Output the verbose error description if supplied (e.g. OAuth).
212 if ( filter_has_var( INPUT_GET, 'error_description' ) ) {
213 $this->output_error( filter_input( INPUT_GET, 'error_description', FILTER_SANITIZE_FULL_SPECIAL_CHARS ) );
214 }
215
216 // Output error notification if defined.
217 if ( filter_has_var( INPUT_GET, 'error' ) ) {
218 $error = filter_input( INPUT_GET, 'error', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
219 if ( array_key_exists( $error, $notices ) ) {
220 $this->output_error( $notices[ $error ] );
221 }
222 }
223
224 // Output success notification if defined.
225 if ( filter_has_var( INPUT_GET, 'success' ) ) {
226 $success = filter_input( INPUT_GET, 'success', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
227 if ( array_key_exists( $success, $notices ) ) {
228 $this->output_success( $notices[ $success ] );
229 }
230 }
231
232 }
233
234 /**
235 * Renders the section
236 */
237 public function render() {
238
239 /**
240 * Performs actions prior to rendering the settings form.
241 *
242 * @since 1.9.6
243 */
244 do_action( 'convertkit_settings_base_render_before' );
245
246 do_settings_sections( $this->settings_key );
247
248 settings_fields( $this->settings_key );
249
250 if ( ! $this->save_disabled ) {
251 submit_button();
252 }
253
254 /**
255 * Performs actions after rendering of the settings form.
256 *
257 * @since 1.9.6
258 */
259 do_action( 'convertkit_settings_base_render_after' );
260
261 }
262
263 /**
264 * Outputs opening .metabox-holder and .postbox container div elements,
265 * used before beginning a setting screen's output.
266 *
267 * @since 2.0.0
268 */
269 public function render_container_start() {
270
271 echo wp_kses(
272 $this->get_render_container_start(),
273 convertkit_kses_allowed_html()
274 );
275
276 }
277
278 /**
279 * Outputs closing .metabox-holder and .postbox container div elements,
280 * used after finishing a setting screen's output.
281 *
282 * @since 2.0.0
283 */
284 public function render_container_end() {
285
286 echo wp_kses(
287 $this->get_render_container_end(),
288 convertkit_kses_allowed_html()
289 );
290
291 }
292
293 /**
294 * Returns opening .metabox-holder and .postbox container div elements,
295 * used before beginning a section of a settings screen output.
296 *
297 * @since 2.7.1
298 */
299 public function get_render_container_start() {
300
301 return '<div class="metabox-holder"><div class="postbox ' . sanitize_html_class( $this->is_beta ? 'convertkit-beta' : '' ) . '">';
302
303 }
304
305 /**
306 * Returns closing .metabox-holder and .postbox container div elements,
307 * used after finishing a section of a settings screen output.
308 *
309 * @since 2.7.1
310 */
311 public function get_render_container_end() {
312
313 return '</div></div>';
314
315 }
316
317 /**
318 * Redirects to the settings screen.
319 *
320 * @since 2.2.9
321 */
322 public function redirect() {
323
324 wp_safe_redirect(
325 add_query_arg(
326 array(
327 'page' => '_wp_convertkit_settings',
328 'tab' => $this->name,
329 ),
330 'options-general.php'
331 )
332 );
333 exit();
334
335 }
336
337 /**
338 * Redirects to the settings screen with an error notice key.
339 *
340 * The function maybe_output_notices() will then output the translated error notice
341 * based on the supplied key.
342 *
343 * @since 2.5.1
344 *
345 * @param string $error The error notice key, registered using `convertkit_settings_base_register_notices`.
346 */
347 public function redirect_with_error_notice( $error ) {
348
349 wp_safe_redirect(
350 add_query_arg(
351 array(
352 'page' => '_wp_convertkit_settings',
353 'tab' => $this->name,
354 'error' => $error,
355 ),
356 'options-general.php'
357 )
358 );
359 exit();
360
361 }
362
363 /**
364 * Redirects to the settings screen with the verbose error description.
365 *
366 * @since 2.5.1
367 *
368 * @param string $error_description The error description.
369 */
370 public function redirect_with_error_description( $error_description ) {
371
372 wp_safe_redirect(
373 add_query_arg(
374 array(
375 'page' => '_wp_convertkit_settings',
376 'tab' => $this->name,
377 'error_description' => $error_description,
378 ),
379 'options-general.php'
380 )
381 );
382 exit();
383
384 }
385
386 /**
387 * Redirects to the settings screen with a success notice key.
388 *
389 * The function maybe_output_notices() will then output the translated success notice
390 * based on the supplied key.
391 *
392 * @since 2.5.1
393 *
394 * @param string $success The success notice key, registered using `convertkit_settings_base_register_notices`.
395 */
396 public function redirect_with_success_notice( $success ) {
397
398 wp_safe_redirect(
399 add_query_arg(
400 array(
401 'page' => '_wp_convertkit_settings',
402 'tab' => $this->name,
403 'success' => $success,
404 ),
405 'options-general.php'
406 )
407 );
408 exit();
409
410 }
411
412 /**
413 * Outputs the given success message in an inline notice.
414 *
415 * @since 2.0.0
416 *
417 * @param string $success_message Success Message.
418 */
419 public function output_success( $success_message ) {
420
421 ?>
422 <div class="notice notice-success is-dismissible">
423 <p>
424 <?php echo esc_attr( $success_message ); ?>
425 </p>
426 </div>
427 <?php
428
429 }
430
431 /**
432 * Outputs the given error message in an inline notice.
433 *
434 * @since 1.9.6
435 *
436 * @param string $error_message Error Message.
437 */
438 public function output_error( $error_message ) {
439
440 ?>
441 <div class="notice notice-error is-dismissible">
442 <p>
443 <?php echo esc_attr( $error_message ); ?>
444 </p>
445 </div>
446 <?php
447
448 }
449
450 /**
451 * Returns a masked value.
452 *
453 * @since 1.9.6
454 *
455 * @param string $value Value.
456 * @param bool|string $description Description.
457 * @return string Masked Value
458 */
459 public function get_masked_value( $value, $description = false ) {
460
461 $html = sprintf(
462 '<code>%s</code>',
463 str_repeat( '*', strlen( $value ) - 4 ) . substr( $value, - 4 )
464 );
465
466 if ( $description ) {
467 $html .= $this->get_description( $description );
468 }
469
470 return $html;
471
472 }
473
474 /**
475 * Outputs a masked value.
476 *
477 * @since 2.8.5
478 *
479 * @param string $value Value.
480 * @param bool|string $description Description.
481 */
482 public function output_masked_value( $value, $description = false ) {
483
484 $html = sprintf(
485 '<code>%s</code>',
486 str_repeat( '*', strlen( $value ) - 4 ) . substr( $value, - 4 )
487 );
488
489 if ( $description ) {
490 $html .= $this->get_description( $description );
491 }
492
493 echo wp_kses(
494 $html,
495 convertkit_kses_allowed_html()
496 );
497
498 }
499
500 /**
501 * Returns a text field.
502 *
503 * @since 1.9.6
504 *
505 * @param string $name Name.
506 * @param string $value Value.
507 * @param bool|string|array $description Description (false|string|array).
508 * @param bool|array $css_classes CSS Classes (false|array).
509 * @return string HTML Field
510 */
511 public function get_text_field( $name, $value = '', $description = false, $css_classes = false ) {
512
513 $html = sprintf(
514 '<input type="text" class="%s" id="%s" name="%s[%s]" value="%s" />',
515 ( is_array( $css_classes ) ? implode( ' ', $css_classes ) : 'regular-text' ),
516 $name,
517 $this->settings_key,
518 $name,
519 $value
520 );
521
522 return $html . $this->get_description( $description );
523
524 }
525
526 /**
527 * Outputs a text field.
528 *
529 * @since 2.8.5
530 *
531 * @param string $name Name.
532 * @param string $value Value.
533 * @param bool|string|array $description Description (false|string|array).
534 * @param bool|array $css_classes CSS Classes (false|array).
535 */
536 public function output_text_field( $name, $value = '', $description = false, $css_classes = false ) {
537
538 echo wp_kses(
539 $this->get_text_field( $name, $value, $description, $css_classes ),
540 convertkit_kses_allowed_html()
541 );
542
543 }
544
545 /**
546 * Returns a number field.
547 *
548 * @since 2.6.1
549 *
550 * @param string $name Name.
551 * @param string $value Value.
552 * @param int|float $min `min` attribute value.
553 * @param int|float $max `max` attribute value.
554 * @param int|float $step `step` attribute value.
555 * @param bool|string|array $description Description (false|string|array).
556 * @param bool|array $css_classes CSS Classes (false|array).
557 * @return string HTML Field
558 */
559 public function get_number_field( $name, $value = '', $min = 0, $max = 9999, $step = 1, $description = false, $css_classes = false ) {
560
561 $html = sprintf(
562 '<input type="number" class="%s" id="%s" name="%s[%s]" value="%s" min="%s" max="%s" step="%s" />',
563 ( is_array( $css_classes ) ? implode( ' ', $css_classes ) : 'small-text' ),
564 $name,
565 $this->settings_key,
566 $name,
567 $value,
568 $min,
569 $max,
570 $step
571 );
572
573 return $html . $this->get_description( $description );
574
575 }
576
577 /**
578 * Outputs a number field.
579 *
580 * @since 2.8.5
581 *
582 * @param string $name Name.
583 * @param string $value Value.
584 * @param int|float $min `min` attribute value.
585 * @param int|float $max `max` attribute value.
586 * @param int|float $step `step` attribute value.
587 * @param bool|string|array $description Description (false|string|array).
588 * @param bool|array $css_classes CSS Classes (false|array).
589 */
590 public function output_number_field( $name, $value = '', $min = 0, $max = 9999, $step = 1, $description = false, $css_classes = false ) {
591
592 echo wp_kses(
593 $this->get_number_field( $name, $value, $min, $max, $step, $description, $css_classes ),
594 convertkit_kses_allowed_html()
595 );
596
597 }
598
599 /**
600 * Returns a textarea field.
601 *
602 * @since 2.3.5
603 *
604 * @param string $name Name.
605 * @param string $value Value.
606 * @param bool|string|array $description Description (false|string|array).
607 * @param bool|array $css_classes CSS Classes (false|array).
608 * @return string HTML Field
609 */
610 public function get_textarea_field( $name, $value = '', $description = false, $css_classes = false ) {
611
612 $html = sprintf(
613 '<textarea class="%s" id="%s" name="%s[%s]">%s</textarea>',
614 ( is_array( $css_classes ) ? implode( ' ', $css_classes ) : 'regular-text' ),
615 $name,
616 $this->settings_key,
617 $name,
618 $value
619 );
620
621 return $html . $this->get_description( $description );
622
623 }
624
625 /**
626 * Outputs a textarea field.
627 *
628 * @since 2.8.5
629 *
630 * @param string $name Name.
631 * @param string $value Value.
632 * @param bool|string|array $description Description (false|string|array).
633 * @param bool|array $css_classes CSS Classes (false|array).
634 */
635 public function output_textarea_field( $name, $value = '', $description = false, $css_classes = false ) {
636
637 echo wp_kses(
638 $this->get_textarea_field( $name, $value, $description, $css_classes ),
639 convertkit_kses_allowed_html()
640 );
641
642 }
643
644 /**
645 * Returns a date field.
646 *
647 * @since 2.2.8
648 *
649 * @param string $name Name.
650 * @param string $value Value.
651 * @param bool|string|array $description Description (false|string|array).
652 * @param bool|array $css_classes CSS Classes (false|array).
653 * @return string HTML Field
654 */
655 public function get_date_field( $name, $value = '', $description = false, $css_classes = false ) {
656
657 $html = sprintf(
658 '<input type="date" class="%s" id="%s" name="%s[%s]" value="%s" />',
659 ( is_array( $css_classes ) ? implode( ' ', $css_classes ) : 'regular-text' ),
660 $name,
661 $this->settings_key,
662 $name,
663 $value
664 );
665
666 return $html . $this->get_description( $description );
667
668 }
669
670 /**
671 * Outputs a date field.
672 *
673 * @since 2.8.5
674 *
675 * @param string $name Name.
676 * @param string $value Value.
677 * @param bool|string|array $description Description (false|string|array).
678 * @param bool|array $css_classes CSS Classes (false|array).
679 */
680 public function output_date_field( $name, $value = '', $description = false, $css_classes = false ) {
681
682 echo wp_kses(
683 $this->get_date_field( $name, $value, $description, $css_classes ),
684 convertkit_kses_allowed_html()
685 );
686
687 }
688
689 /**
690 * Returns a select dropdown field.
691 *
692 * @since 1.9.6
693 *
694 * @param string $name Name.
695 * @param string $value Value.
696 * @param array $options Options / Choices.
697 * @param bool|string $description Description.
698 * @param bool|array $css_classes <select> CSS class(es).
699 * @param bool|array $attributes <select> attributes.
700 * @return string HTML Select Field
701 */
702 public function get_select_field( $name, $value = '', $options = array(), $description = false, $css_classes = false, $attributes = false ) {
703
704 // Build opening <select> tag.
705 $html = sprintf(
706 '<select id="%s" name="%s[%s]" class="%s" size="1" %s>',
707 $this->settings_key . '_' . $name,
708 $this->settings_key,
709 $name,
710 ( is_array( $css_classes ) ? implode( ' ', $css_classes ) : '' ),
711 ( is_array( $attributes ) ? $this->array_to_attributes( $attributes ) : '' )
712 );
713
714 // Build <option> tags.
715 foreach ( $options as $option => $label ) {
716 $html .= sprintf(
717 '<option value="%s"%s>%s</option>',
718 $option,
719 selected( $value, $option, false ),
720 $label
721 );
722 }
723
724 // Close <select>.
725 $html .= '</select>';
726
727 // If no description exists, just return the select field.
728 if ( empty( $description ) ) {
729 return $html;
730 }
731
732 // Return select field with description appended to it.
733 return $html . $this->get_description( $description );
734
735 }
736
737 /**
738 * Outputs a select dropdown field.
739 *
740 * @since 2.8.5
741 *
742 * @param string $name Name.
743 * @param string $value Value.
744 * @param array $options Options / Choices.
745 * @param bool|string $description Description.
746 * @param bool|array $css_classes <select> CSS class(es).
747 * @param bool|array $attributes <select> attributes.
748 */
749 public function output_select_field( $name, $value = '', $options = array(), $description = false, $css_classes = false, $attributes = false ) {
750
751 echo wp_kses(
752 $this->get_select_field( $name, $value, $options, $description, $css_classes, $attributes ),
753 convertkit_kses_allowed_html()
754 );
755
756 }
757
758 /**
759 * Returns a checkbox field.
760 *
761 * @since 1.9.6
762 *
763 * @param string $name Name.
764 * @param string $value Value.
765 * @param bool $checked Should checkbox be checked/ticked.
766 * @param bool|string $label Label.
767 * @param bool|string|array $description Description.
768 * @param bool|array $css_classes CSS class(es).
769 * @return string HTML Checkbox
770 */
771 public function get_checkbox_field( $name, $value, $checked = false, $label = '', $description = false, $css_classes = false ) {
772
773 $html = '';
774
775 if ( $label ) {
776 $html .= sprintf(
777 '<label for="%s">',
778 $name
779 );
780 }
781
782 $html .= sprintf(
783 '<input type="checkbox" id="%s" name="%s[%s]" class="%s" value="%s" %s />',
784 $name,
785 $this->settings_key,
786 $name,
787 ( is_array( $css_classes ) ? implode( ' ', $css_classes ) : '' ),
788 $value,
789 ( $checked ? ' checked' : '' )
790 );
791
792 if ( $label ) {
793 $html .= sprintf(
794 '%s</label>',
795 $label
796 );
797 }
798
799 // If no description exists, just return the field.
800 if ( empty( $description ) ) {
801 return $html;
802 }
803
804 // Return field with description appended to it.
805 return $html . $this->get_description( $description );
806
807 }
808
809 /**
810 * Outputs a checkbox field.
811 *
812 * @since 2.8.5
813 *
814 * @param string $name Name.
815 * @param string $value Value.
816 * @param bool $checked Should checkbox be checked/ticked.
817 * @param bool|string $label Label.
818 * @param bool|string|array $description Description.
819 * @param bool|array $css_classes CSS class(es).
820 */
821 public function output_checkbox_field( $name, $value, $checked = false, $label = '', $description = false, $css_classes = false ) {
822
823 echo wp_kses(
824 $this->get_checkbox_field( $name, $value, $checked, $label, $description, $css_classes ),
825 convertkit_kses_allowed_html()
826 );
827
828 }
829
830 /**
831 * Returns a link button.
832 *
833 * @since 2.8.5
834 *
835 * @param string $url URL.
836 * @param string $label Button Label.
837 * @param bool|array $css_classes CSS class(es).
838 * @return string HTML Link Button
839 */
840 public function get_link_button( $url, $label, $css_classes = false ) {
841
842 return sprintf(
843 '<a href="%s" class="button %s">%s</a>',
844 esc_url( $url ),
845 ( is_array( $css_classes ) ? implode( ' ', $css_classes ) : '' ),
846 esc_html( $label )
847 );
848
849 }
850
851 /**
852 * Outputs a link button.
853 *
854 * @since 2.8.5
855 *
856 * @param string $url URL.
857 * @param string $label Button Label.
858 * @param bool|array $css_classes CSS class(es).
859 */
860 public function output_link_button( $url, $label, $css_classes = false ) {
861
862 echo wp_kses(
863 $this->get_link_button( $url, $label, $css_classes ),
864 convertkit_kses_allowed_html()
865 );
866
867 }
868
869 /**
870 * Returns the given text wrapped in a paragraph with the description class.
871 *
872 * @since 1.9.6
873 *
874 * @param bool|string|array $description Description.
875 * @return string HTML Description
876 */
877 public function get_description( $description ) {
878
879 // Return blank string if no description specified.
880 if ( ! $description ) {
881 return '';
882 }
883
884 // Return description in paragraph if a string.
885 if ( ! is_array( $description ) ) {
886 return '<p class="description">' . $description . '</p>';
887 }
888
889 // Return description lines in a paragraph, using breaklines for each description entry in the array.
890 return '<p class="description">' . implode( '<br />', $description ) . '</p>';
891
892 }
893
894 /**
895 * Converts the given key/value array pairs into a HTML attribute="value" string.
896 *
897 * @since 1.9.8.5
898 *
899 * @param array $attributes_array Attributes.
900 * @return string HTML attributes string
901 */
902 private function array_to_attributes( $attributes_array ) {
903
904 $attributes = '';
905 foreach ( $attributes_array as $key => $value ) {
906 $attributes .= esc_attr( $key ) . '="' . esc_attr( $value ) . '" ';
907 }
908
909 return trim( $attributes );
910
911 }
912
913 /**
914 * Sanitizes the settings prior to being saved.
915 *
916 * @since 1.9.6
917 *
918 * @param array $settings Submitted Settings Fields.
919 * @return array Sanitized Settings with Defaults
920 */
921 public function sanitize_settings( $settings ) {
922
923 // Merge settings with defaults.
924 $updated_settings = wp_parse_args( $settings, $this->settings->get_defaults() );
925
926 /**
927 * Performs actions prior to settings being saved.
928 *
929 * @since 2.2.8
930 */
931 do_action( 'convertkit_settings_base_sanitize_settings', $this->name, $updated_settings );
932
933 // Return settings to be saved.
934 return $updated_settings;
935
936 }
937
938 /**
939 * Outputs the Intercom help widget in the footer of the Plugin's settings screens.
940 *
941 * @since 2.7.2
942 */
943 public function output_intercom() {
944
945 convertkit_output_intercom_messenger();
946
947 }
948
949 }
950