PluginProbe
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More / 6.21
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More v6.21
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.21, at classes/models/FrmSolution.php

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