PluginProbe
Kit (formerly ConvertKit) – Email Newsletter, Email Marketing, Membership, Subscribers and Landing Pages / 2.7.5
Kit (formerly ConvertKit) – Email Newsletter, Email Marketing, Membership, Subscribers and Landing Pages v2.7.5
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 2.7.5, at admin/section/class-convertkit-admin-section-base.php

742 lines 18.0 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 // Register the settings section.
93 $this->register_section();
94
95 }
96
97 /**
98 * Helper method to determine if we're viewing the current settings screen.
99 *
100 * @since 2.5.0
101 *
102 * @param string $tab Current settings tab (general|tools|restrict-content|broadcasts).
103 * @return bool
104 */
105 public function on_settings_screen( $tab ) {
106
107 // phpcs:disable WordPress.Security.NonceVerification
108
109 // Bail if we're not on the settings screen.
110 if ( ! array_key_exists( 'page', $_REQUEST ) ) {
111 return false;
112 }
113 if ( sanitize_text_field( wp_unslash( $_REQUEST['page'] ) ) !== '_wp_convertkit_settings' ) {
114 return false;
115 }
116
117 // Define current settings tab.
118 // General screen won't always be loaded with a `tab` parameter.
119 $current_tab = ( array_key_exists( 'tab', $_REQUEST ) ? sanitize_text_field( wp_unslash( $_REQUEST['tab'] ) ) : 'general' );
120
121 // Return whether the request is for the current settings tab.
122 return ( $current_tab === $tab );
123
124 // phpcs:enable
125
126 }
127
128 /**
129 * Register settings section.
130 */
131 public function register_section() {
132
133 // Register settings sections.
134 foreach ( $this->settings_sections as $name => $settings_section ) {
135 // Determine if this settings section needs to be wrapped in its own container.
136 $wrap = array();
137 if ( $settings_section['wrap'] ) {
138 $wrap = array(
139 'before_section' => $this->get_render_container_start(),
140 'after_section' => $this->get_render_container_end(),
141 );
142 }
143
144 add_settings_section(
145 ( $name === 'general' ? $this->name : $this->name . '-' . $name ),
146 $settings_section['title'],
147 $settings_section['callback'],
148 $this->settings_key,
149 $wrap
150 );
151 }
152
153 // Register settings fields.
154 $this->register_fields();
155
156 // Register setting to store data in options table.
157 register_setting(
158 $this->settings_key,
159 $this->settings_key,
160 array( $this, 'sanitize_settings' )
161 );
162
163 }
164
165 /**
166 * Register fields for this section
167 */
168 public function register_fields() {
169 }
170
171 /**
172 * Prints help info for this section
173 */
174 abstract public function print_section_info();
175
176 /**
177 * Returns the URL for the ConvertKit documentation for this setting section.
178 */
179 abstract public function documentation_url();
180
181 /**
182 * Outputs success and/or error notices if required.
183 *
184 * @since 2.0.0
185 */
186 public function maybe_output_notices() {
187
188 // Define notices that might be displayed as a notification.
189 $notices = array();
190
191 /**
192 * Register success and error notices for settings screens.
193 *
194 * @since 2.5.1
195 *
196 * @param array $notices Regsitered success and error notices.
197 * @return array
198 */
199 $notices = apply_filters( 'convertkit_settings_base_register_notices', $notices );
200
201 // Output the verbose error description if supplied (e.g. OAuth).
202 if ( isset( $_REQUEST['error_description'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
203 $this->output_error( sanitize_text_field( wp_unslash( $_REQUEST['error_description'] ) ) ); // phpcs:ignore WordPress.Security.NonceVerification
204 }
205
206 // Output error notification if defined.
207 if ( isset( $_REQUEST['error'] ) && array_key_exists( sanitize_text_field( wp_unslash( $_REQUEST['error'] ) ), $notices ) ) { // phpcs:ignore WordPress.Security.NonceVerification
208 $this->output_error( $notices[ sanitize_text_field( wp_unslash( $_REQUEST['error'] ) ) ] ); // phpcs:ignore WordPress.Security.NonceVerification
209 }
210
211 // Output success notification if defined.
212 if ( isset( $_REQUEST['success'] ) && array_key_exists( sanitize_text_field( wp_unslash( $_REQUEST['success'] ) ), $notices ) ) { // phpcs:ignore WordPress.Security.NonceVerification
213 $this->output_success( $notices[ sanitize_text_field( wp_unslash( $_REQUEST['success'] ) ) ] ); // phpcs:ignore WordPress.Security.NonceVerification
214 }
215
216 }
217
218 /**
219 * Renders the section
220 */
221 public function render() {
222
223 /**
224 * Performs actions prior to rendering the settings form.
225 *
226 * @since 1.9.6
227 */
228 do_action( 'convertkit_settings_base_render_before' );
229
230 do_settings_sections( $this->settings_key );
231
232 settings_fields( $this->settings_key );
233
234 if ( ! $this->save_disabled ) {
235 submit_button();
236 }
237
238 /**
239 * Performs actions after rendering of the settings form.
240 *
241 * @since 1.9.6
242 */
243 do_action( 'convertkit_settings_base_render_after' );
244
245 }
246
247 /**
248 * Outputs opening .metabox-holder and .postbox container div elements,
249 * used before beginning a setting screen's output.
250 *
251 * @since 2.0.0
252 */
253 public function render_container_start() {
254
255 echo $this->get_render_container_start(); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
256
257 }
258
259 /**
260 * Outputs closing .metabox-holder and .postbox container div elements,
261 * used after finishing a setting screen's output.
262 *
263 * @since 2.0.0
264 */
265 public function render_container_end() {
266
267 echo $this->get_render_container_end(); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
268
269 }
270
271 /**
272 * Returns opening .metabox-holder and .postbox container div elements,
273 * used before beginning a section of a settings screen output.
274 *
275 * @since 2.7.1
276 */
277 public function get_render_container_start() {
278
279 return '<div class="metabox-holder"><div class="postbox ' . sanitize_html_class( $this->is_beta ? 'convertkit-beta' : '' ) . '">';
280
281 }
282
283 /**
284 * Returns closing .metabox-holder and .postbox container div elements,
285 * used after finishing a section of a settings screen output.
286 *
287 * @since 2.7.1
288 */
289 public function get_render_container_end() {
290
291 return '</div></div>';
292
293 }
294
295 /**
296 * Redirects to the settings screen.
297 *
298 * @since 2.2.9
299 */
300 public function redirect() {
301
302 wp_safe_redirect(
303 add_query_arg(
304 array(
305 'page' => '_wp_convertkit_settings',
306 'tab' => $this->name,
307 ),
308 'options-general.php'
309 )
310 );
311 exit();
312
313 }
314
315 /**
316 * Redirects to the settings screen with an error notice key.
317 *
318 * The function maybe_output_notices() will then output the translated error notice
319 * based on the supplied key.
320 *
321 * @since 2.5.1
322 *
323 * @param string $error The error notice key, registered using `convertkit_settings_base_register_notices`.
324 */
325 public function redirect_with_error_notice( $error ) {
326
327 wp_safe_redirect(
328 add_query_arg(
329 array(
330 'page' => '_wp_convertkit_settings',
331 'tab' => $this->name,
332 'error' => $error,
333 ),
334 'options-general.php'
335 )
336 );
337 exit();
338
339 }
340
341 /**
342 * Redirects to the settings screen with the verbose error description.
343 *
344 * @since 2.5.1
345 *
346 * @param string $error_description The error description.
347 */
348 public function redirect_with_error_description( $error_description ) {
349
350 wp_safe_redirect(
351 add_query_arg(
352 array(
353 'page' => '_wp_convertkit_settings',
354 'tab' => $this->name,
355 'error_description' => $error_description,
356 ),
357 'options-general.php'
358 )
359 );
360 exit();
361
362 }
363
364 /**
365 * Redirects to the settings screen with a success notice key.
366 *
367 * The function maybe_output_notices() will then output the translated success notice
368 * based on the supplied key.
369 *
370 * @since 2.5.1
371 *
372 * @param string $success The success notice key, registered using `convertkit_settings_base_register_notices`.
373 */
374 public function redirect_with_success_notice( $success ) {
375
376 wp_safe_redirect(
377 add_query_arg(
378 array(
379 'page' => '_wp_convertkit_settings',
380 'tab' => $this->name,
381 'success' => $success,
382 ),
383 'options-general.php'
384 )
385 );
386 exit();
387
388 }
389
390 /**
391 * Outputs the given success message in an inline notice.
392 *
393 * @since 2.0.0
394 *
395 * @param string $success_message Success Message.
396 */
397 public function output_success( $success_message ) {
398
399 ?>
400 <div class="notice notice-success is-dismissible">
401 <p>
402 <?php echo esc_attr( $success_message ); ?>
403 </p>
404 </div>
405 <?php
406
407 }
408
409 /**
410 * Outputs the given error message in an inline notice.
411 *
412 * @since 1.9.6
413 *
414 * @param string $error_message Error Message.
415 */
416 public function output_error( $error_message ) {
417
418 ?>
419 <div class="notice notice-error is-dismissible">
420 <p>
421 <?php echo esc_attr( $error_message ); ?>
422 </p>
423 </div>
424 <?php
425
426 }
427
428 /**
429 * Returns a masked value.
430 *
431 * @since 1.9.6
432 *
433 * @param string $value Value.
434 * @param bool|string $description Description.
435 * @return string Masked Value
436 */
437 public function get_masked_value( $value, $description = false ) {
438
439 $html = sprintf(
440 '<code>%s</code>',
441 str_repeat( '*', strlen( $value ) - 4 ) . substr( $value, - 4 )
442 );
443
444 if ( $description ) {
445 $html .= $this->get_description( $description );
446 }
447
448 return $html;
449
450 }
451
452 /**
453 * Returns a text field.
454 *
455 * @since 1.9.6
456 *
457 * @param string $name Name.
458 * @param string $value Value.
459 * @param bool|string|array $description Description (false|string|array).
460 * @param bool|array $css_classes CSS Classes (false|array).
461 * @return string HTML Field
462 */
463 public function get_text_field( $name, $value = '', $description = false, $css_classes = false ) {
464
465 $html = sprintf(
466 '<input type="text" class="%s" id="%s" name="%s[%s]" value="%s" />',
467 ( is_array( $css_classes ) ? implode( ' ', $css_classes ) : 'regular-text' ),
468 $name,
469 $this->settings_key,
470 $name,
471 $value
472 );
473
474 return $html . $this->get_description( $description );
475
476 }
477
478 /**
479 * Returns a number field.
480 *
481 * @since 2.6.1
482 *
483 * @param string $name Name.
484 * @param string $value Value.
485 * @param int|float $min `min` attribute value.
486 * @param int|float $max `max` attribute value.
487 * @param int|float $step `step` attribute value.
488 * @param bool|string|array $description Description (false|string|array).
489 * @param bool|array $css_classes CSS Classes (false|array).
490 * @return string HTML Field
491 */
492 public function get_number_field( $name, $value = '', $min = 0, $max = 9999, $step = 1, $description = false, $css_classes = false ) {
493
494 $html = sprintf(
495 '<input type="number" class="%s" id="%s" name="%s[%s]" value="%s" min="%s" max="%s" step="%s" />',
496 ( is_array( $css_classes ) ? implode( ' ', $css_classes ) : 'small-text' ),
497 $name,
498 $this->settings_key,
499 $name,
500 $value,
501 $min,
502 $max,
503 $step
504 );
505
506 return $html . $this->get_description( $description );
507
508 }
509
510 /**
511 * Returns a textarea field.
512 *
513 * @since 2.3.5
514 *
515 * @param string $name Name.
516 * @param string $value Value.
517 * @param bool|string|array $description Description (false|string|array).
518 * @param bool|array $css_classes CSS Classes (false|array).
519 * @return string HTML Field
520 */
521 public function get_textarea_field( $name, $value = '', $description = false, $css_classes = false ) {
522
523 $html = sprintf(
524 '<textarea class="%s" id="%s" name="%s[%s]">%s</textarea>',
525 ( is_array( $css_classes ) ? implode( ' ', $css_classes ) : 'regular-text' ),
526 $name,
527 $this->settings_key,
528 $name,
529 $value
530 );
531
532 return $html . $this->get_description( $description );
533
534 }
535
536 /**
537 * Returns a date field.
538 *
539 * @since 2.2.8
540 *
541 * @param string $name Name.
542 * @param string $value Value.
543 * @param bool|string|array $description Description (false|string|array).
544 * @param bool|array $css_classes CSS Classes (false|array).
545 * @return string HTML Field
546 */
547 public function get_date_field( $name, $value = '', $description = false, $css_classes = false ) {
548
549 $html = sprintf(
550 '<input type="date" class="%s" id="%s" name="%s[%s]" value="%s" />',
551 ( is_array( $css_classes ) ? implode( ' ', $css_classes ) : 'regular-text' ),
552 $name,
553 $this->settings_key,
554 $name,
555 $value
556 );
557
558 return $html . $this->get_description( $description );
559
560 }
561
562 /**
563 * Returns a select dropdown field.
564 *
565 * @since 1.9.6
566 *
567 * @param string $name Name.
568 * @param string $value Value.
569 * @param array $options Options / Choices.
570 * @param bool|string $description Description.
571 * @param bool|array $css_classes <select> CSS class(es).
572 * @param bool|array $attributes <select> attributes.
573 * @return string HTML Select Field
574 */
575 public function get_select_field( $name, $value = '', $options = array(), $description = false, $css_classes = false, $attributes = false ) {
576
577 // Build opening <select> tag.
578 $html = sprintf(
579 '<select id="%s" name="%s[%s]" class="%s" size="1" %s>',
580 $this->settings_key . '_' . $name,
581 $this->settings_key,
582 $name,
583 ( is_array( $css_classes ) ? implode( ' ', $css_classes ) : '' ),
584 ( is_array( $attributes ) ? $this->array_to_attributes( $attributes ) : '' )
585 );
586
587 // Build <option> tags.
588 foreach ( $options as $option => $label ) {
589 $html .= sprintf(
590 '<option value="%s"%s>%s</option>',
591 $option,
592 selected( $value, $option, false ),
593 $label
594 );
595 }
596
597 // Close <select>.
598 $html .= '</select>';
599
600 // If no description exists, just return the select field.
601 if ( empty( $description ) ) {
602 return $html;
603 }
604
605 // Return select field with description appended to it.
606 return $html . $this->get_description( $description );
607
608 }
609
610 /**
611 * Returns a checkbox field.
612 *
613 * @since 1.9.6
614 *
615 * @param string $name Name.
616 * @param string $value Value.
617 * @param bool $checked Should checkbox be checked/ticked.
618 * @param bool|string $label Label.
619 * @param bool|string|array $description Description.
620 * @param bool|array $css_classes CSS class(es).
621 * @return string HTML Checkbox
622 */
623 public function get_checkbox_field( $name, $value, $checked = false, $label = '', $description = false, $css_classes = false ) {
624
625 $html = '';
626
627 if ( $label ) {
628 $html .= sprintf(
629 '<label for="%s">',
630 $name
631 );
632 }
633
634 $html .= sprintf(
635 '<input type="checkbox" id="%s" name="%s[%s]" class="%s" value="%s" %s />',
636 $name,
637 $this->settings_key,
638 $name,
639 ( is_array( $css_classes ) ? implode( ' ', $css_classes ) : '' ),
640 $value,
641 ( $checked ? ' checked' : '' )
642 );
643
644 if ( $label ) {
645 $html .= sprintf(
646 '%s</label>',
647 $label
648 );
649 }
650
651 // If no description exists, just return the field.
652 if ( empty( $description ) ) {
653 return $html;
654 }
655
656 // Return field with description appended to it.
657 return $html . $this->get_description( $description );
658
659 }
660
661 /**
662 * Returns the given text wrapped in a paragraph with the description class.
663 *
664 * @since 1.9.6
665 *
666 * @param bool|string|array $description Description.
667 * @return string HTML Description
668 */
669 public function get_description( $description ) {
670
671 // Return blank string if no description specified.
672 if ( ! $description ) {
673 return '';
674 }
675
676 // Return description in paragraph if a string.
677 if ( ! is_array( $description ) ) {
678 return '<p class="description">' . $description . '</p>';
679 }
680
681 // Return description lines in a paragraph, using breaklines for each description entry in the array.
682 return '<p class="description">' . implode( '<br />', $description ) . '</p>';
683
684 }
685
686 /**
687 * Converts the given key/value array pairs into a HTML attribute="value" string.
688 *
689 * @since 1.9.8.5
690 *
691 * @param array $attributes_array Attributes.
692 * @return string HTML attributes string
693 */
694 private function array_to_attributes( $attributes_array ) {
695
696 $attributes = '';
697 foreach ( $attributes_array as $key => $value ) {
698 $attributes .= esc_attr( $key ) . '="' . esc_attr( $value ) . '" ';
699 }
700
701 return trim( $attributes );
702
703 }
704
705 /**
706 * Sanitizes the settings prior to being saved.
707 *
708 * @since 1.9.6
709 *
710 * @param array $settings Submitted Settings Fields.
711 * @return array Sanitized Settings with Defaults
712 */
713 public function sanitize_settings( $settings ) {
714
715 // Merge settings with defaults.
716 $updated_settings = wp_parse_args( $settings, $this->settings->get_defaults() );
717
718 /**
719 * Performs actions prior to settings being saved.
720 *
721 * @since 2.2.8
722 */
723 do_action( 'convertkit_settings_base_sanitize_settings', $this->name, $updated_settings );
724
725 // Return settings to be saved.
726 return $updated_settings;
727
728 }
729
730 /**
731 * Outputs the Intercom help widget in the footer of the Plugin's settings screens.
732 *
733 * @since 2.7.2
734 */
735 public function output_intercom() {
736
737 convertkit_output_intercom_messenger();
738
739 }
740
741 }
742