Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 237
0.00% covered (danger)
0.00%
0 / 28
CRAP
0.00% covered (danger)
0.00%
0 / 1
Jetpack_Stats_Upgrade_Nudges
0.00% covered (danger)
0.00%
0 / 237
0.00% covered (danger)
0.00%
0 / 28
5112
0.00% covered (danger)
0.00%
0 / 1
 init
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
 unset_nudges_setting
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
 is_backup_active
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
12
 is_plugin_installed
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 is_plugin_active
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
12
 is_scan_active
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
12
 is_search_active
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 has_security_plan
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 1
42
 has_complete_plan
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
12
 has_product
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
12
 is_akismet_active
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 print_header
0.00% covered (danger)
0.00%
0 / 18
0.00% covered (danger)
0.00%
0 / 1
20
 print_footer
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
2
 print_styles
0.00% covered (danger)
0.00%
0 / 43
0.00% covered (danger)
0.00%
0 / 1
2
 print_script
0.00% covered (danger)
0.00%
0 / 18
0.00% covered (danger)
0.00%
0 / 1
2
 get_upgrade_link
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
 get_product_description_link
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 track_event
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
2
 print_item
0.00% covered (danger)
0.00%
0 / 27
0.00% covered (danger)
0.00%
0 / 1
20
 print_security
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
 print_backup
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
 print_scan
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
 print_akismet
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
 print_search
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
 print_videopress
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
 get_boost_output
0.00% covered (danger)
0.00%
0 / 14
0.00% covered (danger)
0.00%
0 / 1
20
 get_crm_output
0.00% covered (danger)
0.00%
0 / 14
0.00% covered (danger)
0.00%
0 / 1
20
 render
0.00% covered (danger)
0.00%
0 / 24
0.00% covered (danger)
0.00%
0 / 1
210
1<?php
2/**
3 * Adds a section with Upgrade nudges to the Status Report page
4 *
5 * @package jetpack
6 */
7
8use Automattic\Jetpack\Connection\Manager;
9use Automattic\Jetpack\Current_Plan as Jetpack_Plan;
10use Automattic\Jetpack\Jetpack_CRM_Data;
11use Automattic\Jetpack\Plugins_Installer;
12use Automattic\Jetpack\Redirect;
13use Automattic\Jetpack\Tracking;
14
15/**
16 * Class that adds a new section to the Stats Report page
17 */
18class Jetpack_Stats_Upgrade_Nudges {
19
20    /**
21     * Indicates whether the class initialized or not
22     *
23     * @var bool
24     */
25    private static $initialized = false;
26
27    /**
28     * Initialize the class by registering the action
29     *
30     * @return void
31     */
32    public static function init() {
33        if ( ! self::$initialized ) {
34            self::$initialized = true;
35            add_action( 'jetpack_admin_pages_wrap_ui_after_callback', array( __CLASS__, 'render' ) );
36        }
37    }
38
39    /**
40     * Unsets the collapse nudges setting.
41     */
42    public static function unset_nudges_setting() {
43        $stats_options = get_option( 'stats_options' );
44
45        if ( $stats_options ) {
46            unset( $stats_options['collapse_nudges'] );
47            update_option( 'stats_options', $stats_options );
48        }
49    }
50
51    /**
52     * Determines whether Backup is active
53     *
54     * @return boolean
55     */
56    private static function is_backup_active() {
57        $rewind_data = Jetpack_Core_Json_Api_Endpoints::rewind_data();
58        return is_object( $rewind_data ) && isset( $rewind_data->state ) && 'unavailable' !== $rewind_data->state;
59    }
60
61    /**
62     * Checks if a plugin is installed.
63     *
64     * @param string $plugin_file The plugin filename.
65     * @return boolean
66     */
67    private static function is_plugin_installed( $plugin_file ) {
68        $plugins = Plugins_Installer::get_plugins();
69        return isset( $plugins[ $plugin_file ] );
70    }
71
72    /**
73     * Checks if a plugin is active.
74     *
75     * @param string $plugin_file The plugin filename.
76     * @return boolean
77     */
78    private static function is_plugin_active( $plugin_file ) {
79        $plugins = Plugins_Installer::get_plugins();
80        return isset( $plugins[ $plugin_file ] ) && isset( $plugins[ $plugin_file ]['active'] ) && $plugins[ $plugin_file ]['active'];
81    }
82
83    /**
84     * Determines whether Scan is active
85     *
86     * @return boolean
87     */
88    private static function is_scan_active() {
89        $scan_data = Jetpack_Core_Json_Api_Endpoints::scan_state();
90        return is_object( $scan_data ) && isset( $scan_data->state ) && 'unavailable' !== $scan_data->state;
91    }
92
93    /**
94     * Determines whether Search module is active
95     *
96     * @return boolean
97     */
98    private static function is_search_active() {
99        return Jetpack::is_module_active( 'search' );
100    }
101
102    /**
103     * Determines whether the Site is on a Security Plan. It will also return true if site has backup, scan and akismet.
104     *
105     * @return boolean
106     */
107    private static function has_security_plan() {
108        $plan_data = Jetpack_Plan::get();
109        if ( is_array( $plan_data ) && isset( $plan_data['product_slug'] ) ) {
110            $has_plan = wp_startswith( $plan_data['product_slug'], 'jetpack_security' );
111            return (
112                $has_plan || (
113                    self::is_backup_active() &&
114                    self::is_scan_active() &&
115                    self::is_akismet_active()
116                )
117            );
118        }
119        return false;
120    }
121
122    /**
123     * Determines whether the Site is on the Complete Plan.
124     *
125     * @return boolean
126     */
127    private static function has_complete_plan() {
128        $plan_data = Jetpack_Plan::get();
129        if ( is_array( $plan_data ) && isset( $plan_data['product_slug'] ) ) {
130            return wp_startswith( $plan_data['product_slug'], 'jetpack_complete' );
131        }
132        return false;
133    }
134
135    /**
136     * Determines whether the Site has a specific product.
137     *
138     * @param string $target_product_slug The product slug we are looking for.
139     *
140     * @return boolean
141     */
142    private static function has_product( $target_product_slug ) {
143        $site_products_slugs = array_column( Jetpack_Plan::get_products(), 'product_slug' );
144
145        foreach ( $site_products_slugs as $product_slug ) {
146            if ( wp_startswith( $product_slug, $target_product_slug ) ) {
147                return true;
148            }
149        }
150
151        return false;
152    }
153
154    /**
155     * Determines whether Akismet is active
156     *
157     * @return boolean
158     */
159    private static function is_akismet_active() {
160        return Jetpack::is_akismet_active();
161    }
162
163    /**
164     * Outputs the header of the Upgrade Secion
165     *
166     * @return void
167     */
168    private static function print_header() {
169        if ( self::has_security_plan() ) {
170            // translators: %s is the Site Name.
171            $title = __( 'Performance and growth tools for %s', 'jetpack' );
172        } else {
173            // translators: %s is the Site Name.
174            $title = __( 'Security, performance, and growth tools for %s', 'jetpack' );
175        }
176        $title = sprintf( $title, get_bloginfo( 'site_name' ) );
177
178        $aria_expanded  = 'true';
179        $postbox_closed = '';
180
181        $stats_options = get_option( 'stats_options' );
182
183        if ( isset( $stats_options['collapse_nudges'] ) && $stats_options['collapse_nudges'] ) {
184            $aria_expanded  = 'false';
185            $postbox_closed = ' closed';
186        }
187
188        ?>
189        <div id="jp-stats-report-upgrade-wrap">
190            <div class="meta-box-sortables">
191                <div class="postbox<?php echo esc_attr( $postbox_closed ); ?>">
192                    <div class="dops-card dops-section-header is-compact jp-stats-report-upgrade-header">
193                        <div class="dops-section-header__label">
194                            <span class="dops-section-header__label-text">
195                                <?php echo esc_html( $title ); ?>
196                            </span>
197                        </div>
198                        <div class="dops-section-header__actions handle-actions hide-if-no-js">
199                            <button type="button" id="stats_nudges_toggle" class="handlediv" aria-expanded="<?php echo esc_attr( $aria_expanded ); ?>">
200                                <span class="screen-reader-text">Toggle Upgrade Nudges</span>
201                                <span class="toggle-indicator" aria-hidden="true"></span>
202                            </button>
203                        </div>
204                    </div>
205                    <div class="inside">
206        <?php
207    }
208
209    /**
210     * Outputs the footer of the Upgrade Section
211     *
212     * @return void
213     */
214    private static function print_footer() {
215        ?>
216                    </div>
217                </div>
218            </div>
219        </div>
220        <?php
221    }
222
223    /**
224     * Outputs the custom css rules of the Upgrade Section
225     *
226     * @return void
227     */
228    private static function print_styles() {
229        ?>
230        <style>
231            .dops-section-header.dops-card.jp-stats-report-upgrade-header {
232                font-weight: bold;
233                box-shadow: none;
234                flex-wrap: nowrap;
235            }
236            #jp-stats-report-upgrade-wrap .dops-section-header__label-text {
237                white-space: normal;
238            }
239            #stats_nudges_toggle {
240                height: 100%;
241            }
242            .dops-banner.dops-card.is-product.jp-stats-report-upgrade-item {
243                margin-bottom: 0;
244                border-left: 0;
245                box-shadow: none;
246                border-top: 1px solid #c3c4c7;
247                padding: 12px 24px;
248            }
249            .dops-banner.dops-card.jp-stats-report-upgrade-item.jp-stats-report-upgrade-subitem {
250                margin-left: 72px;
251                padding-left: 0;
252            }
253            .jp-stats-report-upgrade-item .dops-banner__action {
254                margin-right: 0;
255            }
256            #jp-stats-report-upgrade-wrap .dops-card::after {
257                content: "";
258            }
259            .jp-stats-report-upgrade-item .dops-banner__title p {
260                margin: 5px 0 0 0;
261                font-weight: normal;
262            }
263            #jp-stats-report-upgrade-wrap .postbox {
264                background-color: white;
265                border: 1px solid #c3c4c7;
266                margin-bottom: 0;
267            }
268            #jp-stats-report-upgrade-wrap .postbox .inside {
269                padding: 0;
270            }
271        </style>
272        <?php
273    }
274    /**
275     * Add a script which handles collapse/expansion of the nudge UI.
276     */
277    private static function print_script() {
278        ?>
279        <script>
280            (function(window, document, undefined){
281                window.onload = set_up_click_handler;
282
283                const stats_wrap = document.getElementById( 'jp-stats-wrap' );
284                stats_wrap.addEventListener( 'stats-loaded', function () {
285                    const stat_chart = document.getElementById( 'statchart' );
286                    if ( stat_chart === null ) {
287                        document.getElementById( 'stats_nudges_toggle' ).style.display = 'none';
288                    }
289                });
290
291                function set_up_click_handler(){
292                    document.getElementById( 'stats_nudges_toggle' ).onclick = function () {
293                        const collapseValue = 'true' === this.getAttribute( 'aria-expanded' );
294
295                        fetch( '/wp-json/jetpack/v4/settings', {
296                            method: 'post',
297                            body: JSON.stringify( { collapse_nudges: collapseValue } ),
298                            headers: {
299                                'X-WP-Nonce': <?php echo wp_json_encode( wp_create_nonce( 'wp_rest' ), JSON_UNESCAPED_SLASHES | JSON_HEX_TAG | JSON_HEX_AMP ); ?>,
300                                'Content-type': 'application/json' }
301                        } );
302                    };
303                }
304            })(window, document, undefined);
305        </script>
306        <?php
307    }
308
309    /**
310     * Gets the upgrade Redirect link
311     *
312     * @param string $source The source of the redirect link.
313     * @return string
314     */
315    private static function get_upgrade_link( $source ) {
316        $args = array();
317        if ( ! ( new Manager( 'jetpack' ) )->has_connected_owner() ) {
318            $args['query'] = 'unlinked=1';
319        }
320        return Redirect::get_url( $source, $args );
321    }
322
323    /**
324     * Gets the product description link.
325     *
326     * @param string $product_key The product key of the product we wish to display.
327     * @return string
328     */
329    private static function get_product_description_link( $product_key ) {
330        return Jetpack::admin_url( array( 'page' => sprintf( 'jetpack#/product/%s', $product_key ) ) );
331    }
332
333    /**
334     * Tracks an event in Tracks
335     *
336     * @param string $event_name The event name.
337     * @return void
338     */
339    private static function track_event( $event_name ) {
340        $connection_manager = new Manager( 'jetpack' );
341        $tracking           = new Tracking( 'jetpack', $connection_manager );
342        $tracking->record_user_event(
343            $event_name,
344            array(
345                'has_connected_owner' => $connection_manager->has_connected_owner(),
346            )
347        );
348    }
349
350    /**
351     * Outputs one Upgrade item
352     *
353     * @param string  $title The title of the item.
354     * @param string  $text The description of the item.
355     * @param string  $icon The path of the icon, relative to Jetpack images folder.
356     * @param string  $link The link of the button.
357     * @param string  $tracks_id The id used to identify the tracks events. Automatically prefixed with "jetpack_stats_nudges_{view|click|learn_more}_".
358     * @param string  $learn_more_link The target of the "Learn more" link.
359     * @param boolean $subitem Whether it is a subitem or not.
360     * @param string  $button_label The button label.
361     * @return void
362     */
363    private static function print_item( $title, $text, $icon, $link, $tracks_id, $learn_more_link, $subitem = false, $button_label = null ) {
364        $additional_classes = $subitem ? 'jp-stats-report-upgrade-subitem' : '';
365        $button_class       = $subitem ? 'is-secondary' : 'is-primary';
366        $icon_url           = plugins_url( '', JETPACK__PLUGIN_FILE ) . '/images/products/' . $icon;
367        $button_label       = $button_label === null ? _x( 'Upgrade', 'Call to action to buy a new plan', 'jetpack' ) : $button_label;
368        $view_event         = "stats_nudges_view_$tracks_id";
369        $click_event        = "stats_nudges_click_$tracks_id";
370        $learn_more_event   = "stats_nudges_learn_more_$tracks_id";
371        self::track_event( $view_event );
372
373        ?>
374            <div class="dops-card dops-banner has-call-to-action is-product jp-stats-report-upgrade-item <?php echo esc_attr( $additional_classes ); ?>">
375                <div class="dops-banner__icon-plan">
376                    <img src="<?php echo esc_attr( $icon_url ); ?>" alt="" width="32" height="32">
377                </div>
378                <div class="dops-banner__content">
379                    <div class="dops-banner__info">
380                        <div class="dops-banner__title">
381                            <?php echo esc_html( $title ); ?>
382                            <p>
383                                <?php echo esc_html( $text ); ?>
384                                <a href="<?php echo esc_attr( $learn_more_link ); ?>" class="jptracks" target="_blank" rel="noopener noreferrer" data-jptracks-name="<?php echo esc_attr( $learn_more_event ); ?>">
385                                    <?php esc_html_e( 'Learn more', 'jetpack' ); ?>
386                                </a>
387                            </p>
388                        </div>
389                    </div>
390                    <div class="dops-banner__action">
391                        <a href="<?php echo esc_attr( $link ); ?>" type="button" class="jptracks dops-button is-compact <?php echo esc_attr( $button_class ); ?>" data-jptracks-name="<?php echo esc_attr( $click_event ); ?>">
392                        <?php echo esc_html( $button_label ); ?>
393                        </a>
394                    </div>
395                </div>
396            </div>
397        <?php
398    }
399
400    /**
401     * Prints the Security item
402     *
403     * @return void
404     */
405    private static function print_security() {
406        $link       = self::get_product_description_link( 'security' );
407        $learn_link = self::get_upgrade_link( 'stats-nudges-security-learn' );
408        $text       = __( 'Comprehensive protection for your site, including Backup, Scan, and Anti-spam.', 'jetpack' );
409        self::print_item( _x( 'Security', 'Jetpack product name', 'jetpack' ), $text, 'product-jetpack.svg', $link, 'security', $learn_link );
410    }
411
412    /**
413     * Prints the Backup item
414     *
415     * @return void
416     */
417    private static function print_backup() {
418        $link       = self::get_product_description_link( 'backup' );
419        $learn_link = self::get_upgrade_link( 'stats-nudges-backup-learn' );
420        $text       = __( 'Save every change and get back online quickly with one-click restores.', 'jetpack' );
421        self::print_item( __( 'VaultPress Backup', 'jetpack' ), $text, 'product-jetpack-backup.svg', $link, 'backup', $learn_link, true );
422    }
423
424    /**
425     * Prints the Scan item
426     *
427     * @since 10.1
428     * @since 10.3 The scan nudge has been removed, but leaving this here in case we reverse course.
429     *
430     * @todo Remove this function is not used ~6 months.
431     *
432     * @return void
433     */
434    private static function print_scan() {
435        $link       = self::get_product_description_link( 'scan' );
436        $learn_link = self::get_upgrade_link( 'stats-nudges-scan-learn' );
437        $text       = __( 'Stay ahead of security threats with automated scanning and one-click fixes.', 'jetpack' );
438        self::print_item( __( 'Scan', 'jetpack' ), $text, 'product-jetpack-scan.svg', $link, 'scan', $learn_link, true );
439    }
440
441    /**
442     * Prints the Akismet item
443     *
444     * @since 10.1
445     * @since 10.3 The anti-spam nudge has been removed, but leaving this here in case we reverse course.
446     *
447     * @todo Remove this function is not used ~6 months.
448     *
449     * @return void
450     */
451    private static function print_akismet() {
452        $link       = self::get_product_description_link( 'akismet' );
453        $learn_link = self::get_upgrade_link( 'stats-nudges-akismet-learn' );
454        $text       = __( 'Automatically clear spam from comments and forms.', 'jetpack' );
455        self::print_item( __( 'Akismet Anti-spam', 'jetpack' ), $text, 'product-jetpack-anti-spam.svg', $link, 'akismet', $learn_link, true );
456    }
457
458    /**
459     * Prints the Search item
460     *
461     * @return void
462     */
463    private static function print_search() {
464        $link       = self::get_product_description_link( 'search' );
465        $learn_link = self::get_upgrade_link( 'stats-nudges-search-learn' );
466        $text       = __( 'Help your site visitors instantly find what they\'re looking for so they read and buy more.', 'jetpack' );
467        self::print_item( __( 'Search', 'jetpack' ), $text, 'product-jetpack-search.svg', $link, 'search', $learn_link );
468    }
469
470    /**
471     * Prints the VideoPress item
472     *
473     * @return void
474     */
475    private static function print_videopress() {
476        $link       = self::get_product_description_link( 'videopress' );
477        $learn_link = self::get_upgrade_link( 'stats-nudges-videopress-learn' );
478        $text       = __( 'Engage your visitors with high-quality, ad-free videos built specifically for WordPress.', 'jetpack' );
479        self::print_item( __( 'VideoPress', 'jetpack' ), $text, 'product-jetpack-videopress.svg', $link, 'videopress', $learn_link );
480    }
481
482    /**
483     * Prints the Boost item
484     *
485     * @param bool $print Whether to print the item output or just check whether it would be printed or not.
486     *
487     * @return bool
488     */
489    private static function get_boost_output( $print = true ) {
490        $plugin_file = 'jetpack-boost/jetpack-boost.php';
491        $plugin_slug = 'jetpack-boost';
492        if ( self::is_plugin_active( $plugin_file ) ) {
493            return false;
494        } elseif ( self::is_plugin_installed( $plugin_file ) ) {
495            $label = __( 'Activate Boost', 'jetpack' );
496            $link  = wp_nonce_url( 'plugins.php?action=activate&amp;plugin=' . rawurlencode( $plugin_file ) . '&amp;plugin_status=all&amp;paged=1', 'activate-plugin_' . $plugin_file );
497        } else {
498            $label = __( 'Install Boost', 'jetpack' );
499            $link  = wp_nonce_url( self_admin_url( 'update.php?action=install-plugin&plugin=' . $plugin_slug ), 'install-plugin_' . $plugin_slug );
500        }
501        if ( $print ) {
502            $learn_link = self::get_upgrade_link( 'stats-nudges-boost-learn' );
503            $text       = __( 'Improve your site\'s performance and SEO in a few clicks with the free Jetpack Boost plugin.', 'jetpack' );
504            self::print_item( __( 'Boost', 'jetpack' ), $text, 'product-jetpack-boost.svg', $link, 'boost', $learn_link, false, $label );
505        }
506        return true;
507    }
508
509    /**
510     * Prints the CRM item
511     *
512     * @param bool $print Whether to print the item output or just check whether it would be printed or not.
513     *
514     * @since 10.1
515     *
516     * @return bool
517     */
518    private static function get_crm_output( $print = true ) {
519        $plugin_file = Jetpack_CRM_Data::JETPACK_CRM_PLUGIN_SLUG;
520        $plugin_slug = substr( $plugin_file, 0, strpos( $plugin_file, '/' ) );
521        if ( self::is_plugin_active( $plugin_file ) ) {
522            return false;
523        } elseif ( self::is_plugin_installed( $plugin_file ) ) {
524            $link  = wp_nonce_url( 'plugins.php?action=activate&amp;plugin=' . rawurlencode( $plugin_file ) . '&amp;plugin_status=all&amp;paged=1', 'activate-plugin_' . $plugin_file );
525            $label = __( 'Activate CRM', 'jetpack' );
526        } else {
527            $link  = wp_nonce_url( self_admin_url( 'update.php?action=install-plugin&plugin=' . $plugin_slug ), 'install-plugin_' . $plugin_slug );
528            $label = __( 'Install CRM', 'jetpack' );
529        }
530        if ( $print ) {
531            $learn_link = self::get_upgrade_link( 'stats-nudges-crm-learn' );
532            $text       = __( 'Sell more and get more leads with the free Jetpack CRM plugin built specifically for WordPress.', 'jetpack' );
533            self::print_item( __( 'CRM', 'jetpack' ), $text, 'product-jetpack-crm.svg', $link, 'crm', $learn_link, false, $label );
534        }
535        return true;
536    }
537
538    /**
539     * Outputs the section to the Stats Report page
540     *
541     * @param string $callback The callback passed to the jetpack admin page.
542     * @return void
543     */
544    public static function render( $callback ) {
545        /** This filter is documented in _inc/lib/admin-pages/class.jetpack-react-page.php */
546        if ( 'stats_reports_page' !== $callback || ! apply_filters( 'jetpack_show_promotions', true ) || ! current_user_can( 'manage_options' ) ) {
547            return;
548        }
549
550        if ( self::has_complete_plan() ) {
551            return;
552        }
553
554        if (
555            self::has_security_plan() &&
556            self::is_backup_active() &&
557            self::is_search_active() &&
558            ! self::get_boost_output( false ) &&
559            ! self::get_crm_output( false )
560        ) {
561            return;
562        }
563
564        self::print_styles();
565        self::print_script();
566        self::print_header();
567        if ( ! self::has_security_plan() ) {
568            self::print_security();
569            if ( ! self::is_backup_active() ) {
570                self::print_backup();
571            }
572        }
573        if ( ! self::is_search_active() ) {
574            self::print_search();
575        }
576        if ( ! self::has_product( 'jetpack_videopress' ) ) {
577            self::print_videopress();
578        }
579        self::get_boost_output();
580        self::get_crm_output();
581        self::print_footer();
582    }
583}