PluginProbe
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More / 6.26
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More v6.26
6.35 6.34 6.33.1 6.33 6.32.1 6.32 6.31 6.25 6.25.1 6.26 6.26.1 6.27 6.28 6.29 6.3 6.3.1 6.3.2 6.30 6.4 6.4.1 6.4.2 6.5 6.5.1 6.5.2 6.5.3 All 141 releases
formidable / classes / models / FrmSolution.php

FrmSolution.php in Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More 6.26, at classes/models/FrmSolution.php

953 lines 21.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Handles the installation of a solution and any dependencies.
4 * This page is shown when a Formidable plugin is activated.
5 *
6 * @since 4.06.02
7 *
8 * @package Formidable
9 */
10
11 if ( ! defined( 'ABSPATH' ) ) {
12 die( 'You are not allowed to call this page directly.' );
13 }
14
15 class FrmSolution {
16
17 /**
18 * @var string
19 */
20 protected $plugin_slug = '';
21
22 /**
23 * @var string
24 */
25 protected $plugin_file = '';
26
27 /**
28 * Hidden welcome page slug.
29 *
30 * @since 4.06.02
31 *
32 * @var string
33 */
34 protected $page = '';
35
36 /**
37 * @var string
38 */
39 protected $icon = 'frm_icon_font frm_settings_icon';
40
41 /**
42 * @param array $atts
43 */
44 public function __construct( $atts = array() ) {
45 if ( empty( $this->plugin_slug ) ) {
46 return;
47 }
48
49 add_action( 'plugins_loaded', array( $this, 'load_hooks' ), 50 );
50 add_action( 'admin_init', array( $this, 'redirect' ), 9999 );
51
52 if ( empty( $this->plugin_file ) ) {
53 $this->plugin_file = $this->plugin_slug . '.php';
54 }
55 }
56
57 /**
58 * Register all WP hooks.
59 *
60 * @since 4.06.02
61 *
62 * @return void
63 */
64 public function load_hooks() {
65 // If user is in admin ajax or doing cron, return.
66 if ( wp_doing_cron() ) {
67 return;
68 }
69
70 add_filter( 'frm_add_settings_section', array( $this, 'add_settings' ) );
71
72 if ( wp_doing_ajax() ) {
73 return;
74 }
75
76 // If user cannot manage_options, return.
77 if ( ! current_user_can( 'frm_change_settings' ) && ! FrmAppHelper::is_formidable_admin() ) {
78 return;
79 }
80
81 add_filter( 'plugin_action_links_' . $this->plugin_slug . '/' . $this->plugin_file, array( $this, 'plugin_links' ) );
82 add_action( 'admin_menu', array( $this, 'register' ) );
83 add_action( 'admin_head', array( $this, 'hide_menu' ) );
84 }
85
86 /**
87 * @param array $links
88 *
89 * @return array
90 */
91 public function plugin_links( $links ) {
92 if ( ! $this->is_complete() ) {
93 $settings = '<a href="' . esc_url( $this->settings_link() ) . '">' . __( 'Setup', 'formidable' ) . '</a>';
94 array_unshift( $links, $settings );
95 }
96
97 return $links;
98 }
99
100 /**
101 * Register the pages to be used for the Welcome screen (and tabs).
102 *
103 * These pages will be removed from the Dashboard menu, so they will
104 * not actually show. Sneaky, sneaky.
105 *
106 * @since 4.06.02
107 *
108 * @return void
109 */
110 public function register() {
111
112 // Getting started - shows after installation.
113 add_dashboard_page(
114 esc_html( $this->page_title() ),
115 esc_html( $this->page_title() ),
116 'frm_change_settings',
117 $this->page,
118 array( $this, 'output' )
119 );
120 }
121
122 /**
123 * Removed the dashboard pages from the admin menu.
124 *
125 * This means the pages are still available to us, but hidden.
126 *
127 * @since 4.06.02
128 *
129 * @return void
130 */
131 public function hide_menu() {
132 remove_submenu_page( 'index.php', $this->page );
133 }
134
135 /**
136 * @return string
137 *
138 * @psalm-return ''
139 */
140 protected function plugin_name() {
141 return '';
142 }
143
144 /**
145 * @return string
146 */
147 protected function page_title() {
148 return __( 'Welcome to Formidable Forms', 'formidable' );
149 }
150
151 /**
152 * @return string
153 */
154 protected function page_description() {
155 return __( 'Follow the steps below to get started.', 'formidable' );
156 }
157
158 /**
159 * Welcome screen redirect.
160 *
161 * This function checks if a new install or update has just occurred. If so,
162 * then we redirect the user to the appropriate page.
163 *
164 * @since 4.06.02
165 *
166 * @return void
167 */
168 public function redirect() {
169
170 $current_page = FrmAppHelper::simple_get( 'page', 'sanitize_title' );
171
172 if ( $current_page === $this->page ) {
173 // Prevent endless loop.
174 return;
175 }
176
177 // Only do this for single site installs.
178 if ( isset( $_GET['activate-multi'] ) || is_network_admin() ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
179 return;
180 }
181
182 // Check if we should consider redirection.
183 if ( ! $this->is_current_plugin() ) {
184 return;
185 }
186
187 delete_transient( FrmOnboardingWizardController::TRANSIENT_NAME );
188
189 // Initial install.
190 wp_safe_redirect( $this->settings_link() );
191 exit;
192 }
193
194 /**
195 * @return string
196 */
197 protected function settings_link() {
198 return admin_url( 'index.php?page=' . $this->page );
199 }
200
201 /**
202 * Add page to global settings.
203 *
204 * @param array $sections Sections.
205 *
206 * @return array
207 */
208 public function add_settings( $sections ) {
209 wp_enqueue_style( 'formidable-pro-fields' );
210 $sections[ $this->plugin_slug ] = array(
211 'class' => $this,
212 'function' => 'settings_page',
213 'name' => $this->plugin_name(),
214 'icon' => $this->icon,
215 'ajax' => true,
216 );
217 return $sections;
218 }
219
220 /*
221 * Output for global settings.
222 */
223 /**
224 * @return void
225 */
226 public function settings_page() {
227 $steps = $this->get_steps_data();
228
229 if ( ! $steps['license']['complete'] || ( isset( $steps['plugin'] ) && ! $steps['plugin']['complete'] ) ) {
230 // Redirect to the welcome page if install hasn't been done.
231 $url = $this->settings_link();
232 echo '<script>window.location.replace("' . esc_url_raw( $url ) . '");</script>';
233 return;
234 }
235
236 $all_imported = $this->is_complete( 'all' );
237
238 $step = $steps['import'];
239 $step['label'] = '';
240 $step['nested'] = true;
241
242 if ( $steps['complete']['current'] ) {
243 // Always show this step in settings.
244 $step['current'] = true;
245
246 $new_class = $all_imported ? ' button frm_hidden' : '';
247 $step['button_class'] = str_replace( 'frm_grey disabled', $new_class, $step['button_class'] );
248 }
249
250 if ( $all_imported ) {
251 $step['description'] = __( 'The following form(s) have been created.', 'formidable' );
252 }
253 $this->show_app_install( $step );
254
255 if ( ! $all_imported ) {
256 $step = $steps['complete'];
257 $step['current'] = false;
258 $step['button_class'] .= ' frm_grey disabled';
259 $this->show_page_links( $step );
260 }
261 }
262
263 /**
264 * Getting Started screen. Shows after first install.
265 *
266 * @return void
267 */
268 public function output() {
269 FrmAppHelper::include_svg();
270 $this->css();
271 $class = FrmAppHelper::pro_is_installed() ? 'pro' : 'lite';
272
273 echo '<div id="frm-welcome" class="wrap frm-wrap frm-admin-plugin-landing upgrade_to_pro ' . sanitize_html_class( $class ) . '">';
274
275 $this->header();
276 $this->main_content();
277
278 echo '</div>';
279 }
280
281 /**
282 * Heading section.
283 *
284 * @return void
285 */
286 protected function header() {
287 $size = array(
288 'height' => 90,
289 'width' => 90,
290 );
291
292 ?>
293 <section class="top">
294 <div class="frm-smtp-logos">
295 <?php FrmAppHelper::show_logo( $size ); ?>
296 <?php
297 FrmAppHelper::icon_by_class(
298 'frmfont frm_arrow_right_icon',
299 array(
300 'aria-label' => 'Install',
301 'style' => 'width:30px;height:30px;margin:0 35px;',
302 )
303 );
304 FrmAppHelper::icon_by_class(
305 'frmfont frm_wordpress_icon',
306 array(
307 'aria-label' => 'WordPress',
308 'style' => 'width:90px;height:90px;',
309 )
310 );
311 ?>
312 </div>
313 <h1><?php echo esc_html( $this->page_title() ); ?></h1>
314 <p><?php echo esc_html( $this->page_description() ); ?></p>
315 </section>
316 <?php
317 }
318
319 /**
320 * This is the welcome page content.
321 * Override me to insert different content.
322 *
323 * @return void
324 */
325 protected function main_content() {
326 $steps = $this->get_steps_data();
327 $this->license_box( $steps['license'] );
328
329 if ( isset( $steps['plugin'] ) ) {
330 $this->show_plugin_install( $steps['plugin'] );
331 }
332 $this->show_app_install( $steps['import'] );
333 $this->show_page_links( $steps['complete'] );
334 }
335
336 /**
337 * @return array
338 */
339 protected function get_steps_data() {
340 $pro_installed = FrmAppHelper::pro_is_connected();
341
342 $steps = array(
343 'license' => array(
344 'label' => __( 'Connect to FormidableForms.com', 'formidable' ),
345 'description' => __( 'Create a connection to get plugin downloads.', 'formidable' ),
346 'button_label' => __( 'Connect an Account', 'formidable' ),
347 'current' => empty( $pro_installed ),
348 'complete' => $pro_installed,
349 'num' => 1,
350 ),
351 'plugin' => array(
352 'label' => __( 'Install and Activate Add-Ons', 'formidable' ),
353 'description' => __( 'Install any required add-ons from FormidableForms.com.', 'formidable' ),
354 'button_label' => __( 'Install & Activate', 'formidable' ),
355 'current' => false,
356 'complete' => false,
357 'num' => 2,
358 ),
359 'import' => array(
360 'label' => __( 'Setup Forms, Views, and Pages', 'formidable' ),
361 'description' => __( 'Build the forms, views, and pages automatically.', 'formidable' ),
362 'button_label' => __( 'Create Now', 'formidable' ),
363 'complete' => $this->is_complete(),
364 'num' => 3,
365 ),
366 'complete' => array(
367 'label' => __( 'Customize Your New Pages', 'formidable' ),
368 'description' => __( 'Make any required changes and publish the page.', 'formidable' ),
369 'button_label' => __( 'View Page', 'formidable' ),
370 'complete' => false,
371 'num' => 4,
372 ),
373 );
374
375 $this->adjust_plugin_install_step( $steps );
376
377 $has_current = false;
378
379 foreach ( $steps as $k => $step ) {
380 // Set the current step.
381 if ( ! isset( $step['current'] ) ) {
382 if ( $step['complete'] ) {
383 $steps[ $k ]['current'] = false;
384 } else {
385 $steps[ $k ]['current'] = ! $has_current;
386 $has_current = true;
387 }
388 } elseif ( $step['current'] ) {
389 $has_current = true;
390 }
391
392 // Set disabled buttons.
393 $class = $step['button_class'] ?? '';
394 $class .= ' button-primary frm-button-primary';
395
396 if ( ! $steps[ $k ]['current'] ) {
397 $class .= ' frm_grey disabled';
398 }
399 $steps[ $k ]['button_class'] = $class;
400 }//end foreach
401
402 return $steps;
403 }
404
405 /**
406 * @param array $steps
407 *
408 * @return void
409 */
410 protected function adjust_plugin_install_step( &$steps ) {
411 $plugins = $this->required_plugins();
412
413 if ( empty( $plugins ) ) {
414 unset( $steps['plugin'] );
415 $steps['import']['num'] = 2;
416 $steps['complete']['num'] = 3;
417 return;
418 }
419
420 $missing = array();
421 $rel = array();
422
423 foreach ( $plugins as $plugin_key ) {
424 $plugin = FrmAddonsController::install_link( $plugin_key );
425
426 if ( $plugin['status'] === 'active' ) {
427 continue;
428 }
429
430 if ( isset( $plugin['url'] ) ) {
431 $rel[] = $plugin['url'];
432 } else {
433 // Add-on is required but not allowed.
434 $missing[] = $plugin_key;
435 }
436 }
437
438 if ( empty( $rel ) && empty( $missing ) ) {
439 $steps['plugin']['complete'] = true;
440 } elseif ( ! empty( $missing ) ) {
441 $steps['plugin']['error'] = sprintf(
442 /* translators: %1$s: Plugin name */
443 esc_html__( 'You need permission to download the Formidable %1$s plugin', 'formidable' ),
444 implode( ', ', $missing )
445 );
446 } else {
447 $steps['plugin']['links'] = $rel;
448 $steps['plugin']['button_class'] = 'frm-solution-multiple ';
449 }
450
451 if ( $steps['license']['complete'] && ! $steps['plugin']['complete'] ) {
452 $steps['plugin']['current'] = true;
453 }
454 }
455
456 /**
457 * @param array $step Step.
458 *
459 * @return void
460 */
461 protected function step_top( $step ) {
462 $section_class = empty( $step['current'] ) ? 'frm_grey' : '';
463
464 ?>
465 <section class="step step-install <?php echo esc_attr( $section_class ); ?>">
466 <aside class="num">
467 <?php
468 if ( isset( $step['complete'] ) && $step['complete'] ) {
469 FrmAppHelper::icon_by_class(
470 'frmfont frm_step_complete_icon',
471 array(
472 /* translators: %1$s: Step number */
473 'aria-label' => sprintf( __( 'Step %1$d', 'formidable' ), $step['num'] ),
474 'style' => 'width:50px;height:50px;',
475 )
476 );
477 } else {
478 ?>
479 <svg xmlns="http://www.w3.org/2000/svg" width="50" height="50" viewBox="0 0 100 100"><circle cx="50" cy="50" r="50" fill="#ccc"/><text x="50%" y="50%" text-anchor="middle" fill="#fff" stroke="#fff" stroke-width="2px" dy=".3em" font-size="3.7em"><?php echo esc_html( $step['num'] ); ?></text></svg>
480 <?php
481 }
482 ?>
483 <i class="loader hidden"></i>
484 </aside>
485 <div>
486 <?php if ( $step['label'] ) { ?>
487 <h3 class="frm-step-heading"><?php echo esc_html( $step['label'] ); ?></h3>
488 <?php } ?>
489 <p><?php echo esc_html( $step['description'] ); ?></p>
490 <?php if ( isset( $step['error'] ) ) { ?>
491 <p class="frm_error"><?php echo esc_html( $step['error'] ); ?></p>
492 <?php } ?>
493 <?php
494 }
495
496 /**
497 * @param array $step Step.
498 *
499 * @return void
500 */
501 protected function step_bottom( $step ) {
502 ?>
503 </div>
504 </section>
505 <?php
506 }
507
508 /**
509 * Generate and output Connect step section HTML.
510 *
511 * @param array $step Step.
512 *
513 * @return void
514 */
515 protected function license_box( $step ) {
516 $this->step_top( $step );
517
518 if ( $step['complete'] ) {
519 ?>
520 <a href="#" class="<?php echo esc_attr( $step['button_class'] ); ?>">
521 <?php echo esc_html( $step['button_label'] ); ?>
522 </a>
523 <?php
524 } else {
525 FrmSettingsController::license_box();
526 }
527
528 $this->step_bottom( $step );
529 }
530
531 /**
532 * @param array $step Step.
533 *
534 * @return void
535 */
536 protected function show_plugin_install( $step ) {
537 $this->step_top( $step );
538
539 if ( ! isset( $step['error'] ) ) {
540 $rel = $step['links'] ?? array();
541
542 ?>
543 <a rel="<?php echo esc_attr( implode( ',', $rel ) ); ?>" class="<?php echo esc_attr( $step['button_class'] ); ?>">
544 <?php echo esc_html( $step['button_label'] ); ?>
545 </a>
546 <?php
547 }
548
549 $this->step_bottom( $step );
550 }
551
552 /**
553 * @param array $step Step.
554 *
555 * @return void
556 */
557 protected function show_app_install( $step ) {
558 $is_complete = $step['complete'];
559
560 if ( ! empty( $this->form_options() ) && ! $is_complete ) {
561 $step['description'] = __( 'Select the form or view you would like to create.', 'formidable' );
562 }
563
564 $this->step_top( $step );
565
566 $api = new FrmFormApi();
567 $addons = $api->get_api_info();
568
569 $id = $this->download_id();
570 $has_file = isset( $addons[ $id ] ) && isset( $addons[ $id ]['beta'] );
571
572 if ( ! $step['current'] ) {
573 ?>
574 <a href="#" class="<?php echo esc_attr( $step['button_class'] ); ?>">
575 <?php echo esc_html( $step['button_label'] ); ?>
576 </a>
577 <?php
578
579 $this->step_bottom( $step );
580 return;
581 }
582
583 if ( ! $has_file ) {
584 echo '<p class="frm_error_style">' . esc_html__( 'We didn\'t find anything to import. Please contact our team.', 'formidable' ) . '</p>';
585 } elseif ( ! isset( $addons[ $id ]['beta']['package'] ) ) {
586 echo '<p class="frm_error_style">' . esc_html__( 'Looks like you may not have a current subscription for this solution. Please check your account.', 'formidable' ) . '</p>';
587 } else {
588 $xml = $addons[ $id ]['beta']['package'];
589
590 if ( is_array( $xml ) ) {
591 $xml = reset( $xml );
592 }
593
594 if ( isset( $step['nested'] ) ) {
595 echo '<fieldset id="frm-new-template" class="field-group">';
596 } else {
597 echo '<form name="frm-new-template" id="frm-new-template" method="post" class="field-group">';
598 }
599
600 ?>
601 <input type="hidden" name="link" id="frm_link" value="<?php echo esc_attr( $xml ); ?>" />
602 <input type="hidden" name="type" id="frm_action_type" value="frm_install_template" />
603 <input type="hidden" name="template_name" id="frm_template_name" value="" />
604 <input type="hidden" name="template_desc" id="frm_template_desc" value="" />
605 <input type="hidden" name="redirect" value="0" />
606 <input type="hidden" name="show_response" value="frm_install_error" />
607 <?php
608 $this->show_form_options( $xml );
609 $this->show_view_options();
610
611 if ( ! $this->is_complete( 'all' ) ) {
612 // Don't show on the settings page when complete.
613 $this->show_page_options();
614 }
615 ?>
616 <p>
617 <button <?php echo esc_html( isset( $step['nested'] ) ? '' : 'type="submit" ' ); ?>class="<?php echo esc_attr( $step['button_class'] ); ?>">
618 <?php echo esc_html( $step['button_label'] ); ?>
619 </button>
620 </p>
621 <p id="frm_install_error" class="frm_error_style frm_hidden"></p>
622 <?php
623 if ( isset( $step['nested'] ) ) {
624 echo '</fieldset>';
625 } else {
626 echo '</form>';
627 }
628 }//end if
629
630 $this->step_bottom( $step );
631 }
632
633 /**
634 * @param string $xml
635 *
636 * @return void
637 */
638 protected function show_form_options( $xml ) {
639 $this->show_import_options( $this->form_options(), 'form', $xml );
640 }
641
642 /**
643 * @return void
644 */
645 protected function show_view_options() {
646 $this->show_import_options( $this->view_options(), 'view' );
647 }
648
649 /**
650 * @param array $options
651 * @param string $importing
652 * @param string $xml
653 *
654 * @psalm-param 'form'|'view' $importing
655 *
656 * @return void
657 */
658 protected function show_import_options( $options, $importing, $xml = '' ) {
659 if ( empty( $options ) ) {
660 return;
661 }
662
663 $imported = $this->previously_imported_forms();
664 $count = count( $options );
665
666 foreach ( $options as $info ) {
667 // Count the number of options displayed for css.
668 if ( $count > 1 && ! isset( $info['img'] ) ) {
669 --$count;
670 }
671 }
672
673 $width = floor( ( 533 - ( ( $count - 1 ) * 20 ) ) / $count );
674 unset( $count );
675
676 $selected = false;
677
678 include FrmAppHelper::plugin_path() . '/classes/views/solutions/_import.php';
679 }
680
681 /**
682 * @return void
683 */
684 protected function show_page_options() {
685 $pages = $this->needed_pages();
686
687 if ( empty( $pages ) ) {
688 return;
689 }
690
691 echo '<h3>Choose New Page Title</h3>';
692
693 foreach ( $pages as $page ) {
694 ?>
695 <p>
696 <label for="pages_<?php echo esc_html( $page['type'] ); ?>">
697 <?php echo esc_html( $page['label'] ); ?>
698 </label>
699 <input type="text" name="pages[<?php echo esc_html( $page['type'] ); ?>]" value="<?php echo esc_attr( $page['name'] ); ?>" id="pages_<?php echo esc_html( $page['type'] ); ?>" required />
700 </p>
701 <?php
702 }
703 }
704
705 /**
706 * @param array $step
707 *
708 * @return void
709 */
710 protected function show_page_links( $step ) {
711 if ( $step['current'] ) {
712 return;
713 }
714
715 $this->step_top( $step );
716
717 ?>
718 <a href="#" target="_blank" rel="noopener" id="frm-redirect-link" class="<?php echo esc_attr( $step['button_class'] ); ?>">
719 <?php echo esc_html( $step['button_label'] ); ?>
720 </a>
721 <?php
722
723 $this->step_bottom( $step );
724 }
725
726 /**
727 * Only show the content for the correct plugin.
728 *
729 * @return bool
730 */
731 protected function is_current_plugin() {
732 $to_redirect = get_transient( FrmOnboardingWizardController::TRANSIENT_NAME );
733 return $to_redirect === $this->plugin_slug && empty( $this->is_complete() );
734 }
735
736 /**
737 * Override this function to indicate when install is complete.
738 *
739 * @param int|string $count
740 *
741 * @psalm-param 'all'|1 $count
742 *
743 * @return bool
744 */
745 protected function is_complete( $count = 1 ) {
746 $imported = $this->previously_imported_forms();
747
748 if ( $count === 'all' ) {
749 return count( $imported ) >= count( $this->form_options() );
750 }
751 return ! empty( $imported );
752 }
753
754 /**
755 * Get an array of all of the forms that have been imported.
756 *
757 * @return array
758 */
759 protected function previously_imported_forms() {
760 $imported = array();
761 $forms = $this->form_options();
762
763 foreach ( $forms as $form ) {
764 $was_imported = isset( $form['form'] ) ? FrmForm::get_id_by_key( $form['form'] ) : false;
765
766 if ( $was_imported ) {
767 $imported[ $form['form'] ] = $was_imported;
768 }
769 }
770
771 return $imported;
772 }
773
774 /**
775 * In the new plugin has any dependencies, include them here.
776 *
777 * @return array
778 */
779 protected function required_plugins() {
780 return array();
781 }
782
783 /**
784 * This needs to be overridden.
785 *
786 * @return int
787 */
788 protected function download_id() {
789 return 0;
790 }
791
792 /**
793 * Give options for which forms to import.
794 *
795 * @return array
796 */
797 protected function form_options() {
798 /**
799 * Example:
800 * array(
801 * 'unique-key' => array(
802 * 'keys' => 'forms keys here',
803 * 'name' => 'displayed label here',
804 * 'img' => 'svg code',
805 * ),
806 * )
807 */
808 return array();
809 }
810
811 /**
812 * Give options for which view to use.
813 *
814 * @return array
815 */
816 protected function view_options() {
817 return array();
818 }
819
820 /**
821 * If the pages aren't imported automatically, set the page names.
822 *
823 * @return array
824 */
825 protected function needed_pages() {
826 /**
827 * Example:
828 * array(
829 * array(
830 * 'label' => 'Page Name',
831 * 'name' => 'Default name',
832 * 'type' => 'form' or 'view',
833 * ),
834 * )
835 */
836
837 return array();
838 }
839
840 /**
841 * @return void
842 */
843 private function css() {
844 wp_enqueue_style( 'formidable-pro-fields' );
845 ?>
846 <style>
847 #frm-welcome *, #frm-welcome *::before, #frm-welcome *::after {
848 box-sizing: border-box;
849 }
850 #frm-welcome{
851 width: 700px;
852 margin: 0 auto;
853 }
854 #frm-welcome p {
855 font-size: 15px;
856 }
857 #frm-welcome section{
858 margin: 50px 0;
859 text-align: left;
860 clear: both;
861 }
862 #frm-welcome .top{
863 text-align: center;
864 }
865 .frm-smtp-logos {
866 margin-bottom: 38px;
867 }
868 .frm-smtp-logos svg {
869 vertical-align: middle;
870 }
871 #frm-welcome .top h1 {
872 font-size: 26px;
873 font-weight: 600;
874 margin-bottom: 0;
875 padding: 0;
876 }
877 #frm-welcome .top p {
878 font-size: 17px;
879 color: #777;
880 margin-top: .5em;
881 }
882 #frm-welcome .screenshot ul {
883 display: inline-block;
884 margin: 0 0 0 30px;
885 list-style-type: none;
886 max-width: calc(100% - 350px);
887 }
888 #frm-welcome .screenshot li {
889 margin: 16px 0;
890 padding: 0;
891 font-size: 15px;
892 color: #777;
893 }
894 #frm-welcome .screenshot .cont img {
895 max-width: 100%;
896 display: block;
897 }
898 #frm-welcome .screenshot .cont {
899 display: inline-block;
900 position: relative;
901 width: 315px;
902 padding: 5px;
903 background-color: #fff;
904 border-radius: 3px;
905 }
906 #frm-welcome .step,
907 #frm-welcome .screenshot .cont {
908 box-shadow: 0px 2px 5px 0px rgba(0, 0, 0, 0.05);
909 }
910 #frm-welcome .step {
911 background-color: #F9F9F9;
912 border: 1px solid #E5E5E5;
913 margin: 0 0 25px;
914 }
915 #frm-welcome .screenshot > *,
916 #frm-welcome .step > * {
917 vertical-align: middle;
918 }
919 #frm-welcome .step p {
920 font-size: 16px;
921 color: #777777;
922 }
923 #frm-welcome .step .num {
924 display: inline-block;
925 position: relative;
926 width: 100px;
927 height: 50px;
928 text-align: center;
929 }
930 #frm-welcome .step > div {
931 display: inline-block;
932 width: calc(100% - 104px);
933 background-color: #fff;
934 padding: 30px;
935 border-left: 1px solid #eee;
936 }
937 #frm-welcome .step h3.frm-step-heading {
938 font-size: 24px;
939 line-height: 22px;
940 margin-top: 0;
941 margin-bottom: 15px;
942 }
943 #frm-welcome .button.disabled {
944 cursor: default;
945 }
946 #frm-welcome #frm-using-lite {
947 display: none;
948 }
949 </style>
950 <?php
951 }
952 }
953