Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 106
0.00% covered (danger)
0.00%
0 / 3
CRAP
n/a
0 / 0
load_wpcom_dashboard_widgets
0.00% covered (danger)
0.00%
0 / 67
0.00% covered (danger)
0.00%
0 / 1
462
enqueue_wpcom_dashboard_widgets
0.00% covered (danger)
0.00%
0 / 23
0.00% covered (danger)
0.00%
0 / 1
2
render_wpcom_dashboard_widget
0.00% covered (danger)
0.00%
0 / 15
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2/**
3 * Load the widgets of Dashboard for WordPress.com sites.
4 *
5 * @package automattic/jetpack-mu-plugins
6 */
7
8use Automattic\Jetpack\Connection\Client;
9
10/**
11 * Load all wpcom dashboard widgets.
12 */
13function load_wpcom_dashboard_widgets() {
14    if ( ! current_user_can( 'manage_options' ) ) {
15        return;
16    }
17
18    // wpcom_json_api_request_as_user does not support internal requests.
19    $request = defined( 'IS_WPCOM' ) && IS_WPCOM ? 'wpcom_json_api_request_as_blog' : 'wpcom_json_api_request_as_user';
20
21    $layout_response = Client::$request(
22        '/sites/' . get_wpcom_blog_id() . '/home/layout',
23        'v2',
24        array(),
25        null,
26        'wpcom'
27    );
28
29    $tasks = array();
30
31    if ( ! is_wp_error( $layout_response ) ) {
32        $layout = json_decode( $layout_response['body'], true );
33        if ( isset( $layout['secondary'] ) && is_array( $layout['secondary'] ) ) {
34            // If there's an array within the secondary section, it's the task
35            // list.
36            foreach ( $layout['secondary'] as $item ) {
37                if ( is_array( $item ) ) {
38                    // Delete any tasks that don't have a corresponding PHP file.
39                    foreach ( $item as $task ) {
40                        if ( file_exists( __DIR__ . '/wpcom-general-tasks-widget/tasks/' . $task ) ) {
41                            $tasks[] = $task;
42                        }
43                    }
44                    break;
45                }
46            }
47        }
48    }
49
50    enqueue_wpcom_dashboard_widgets( array( 'tasks' => $tasks ) );
51
52    $wpcom_dashboard_widgets = array(
53        array(
54            'id'       => 'wpcom_site_preview_widget',
55            'name'     => __( 'Site', 'jetpack-mu-wpcom' ),
56            'context'  => 'side',
57            'priority' => 'high',
58        ),
59    );
60
61    $launchpad_context = 'wpadmin-dashboard-widget';
62    $checklist_slug    = get_option( 'site_intent' );
63
64    // The AI Launchpad's Site Setup screen supersedes this widget: showing both surfaces two
65    // different checklists under the same name. Dismissing the AI Launchpad now means
66    // no-guidance (see below), not a fallback to this widget.
67    $has_ai_launchpad = function_exists( 'wpcom_ai_launchpad_is_eligible' )
68        && wpcom_ai_launchpad_is_eligible();
69
70    // No-guidance sites get no launchpad surface; unlike the AI Launchpad there is no dismissal fallback.
71    require_once __DIR__ . '/../../common/launchpad-no-guidance.php';
72    $is_no_guidance = wpcom_launchpad_is_no_guidance();
73
74    if (
75        defined( 'IS_WPCOM' ) && IS_WPCOM &&
76        ! $has_ai_launchpad &&
77        ! $is_no_guidance &&
78        get_option( 'launch-status', 'launched' ) !== 'launched' &&
79        ! empty( wpcom_get_launchpad_checklist_by_checklist_slug( $checklist_slug, $launchpad_context ) ) &&
80        ! wpcom_launchpad_is_task_list_dismissed( $checklist_slug )
81    ) {
82        $wpcom_dashboard_widgets[] = array(
83            'id'       => 'wpcom_launchpad_widget',
84            'name'     => __( 'Site Setup', 'jetpack-mu-wpcom' ),
85            'context'  => 'normal',
86            'priority' => 'high',
87        );
88    }
89
90    if ( ! empty( $tasks ) ) {
91        $wpcom_dashboard_widgets[] = array(
92            'id'       => 'wpcom_general_tasks_widget',
93            'name'     => __( 'Suggestions', 'jetpack-mu-wpcom' ),
94            'context'  => 'normal',
95            'priority' => 'high',
96        );
97    }
98
99    foreach ( $wpcom_dashboard_widgets as $wpcom_dashboard_widget ) {
100        wp_add_dashboard_widget(
101            $wpcom_dashboard_widget['id'],
102            $wpcom_dashboard_widget['name'],
103            'render_wpcom_dashboard_widget',
104            null, // @phan-suppress-current-line PhanTypeMismatchArgumentProbablyReal -- Core should ideally document null for no-callback arg. See https://core.trac.wordpress.org/ticket/52539.
105            array(
106                'id'   => $wpcom_dashboard_widget['id'],
107                'name' => $wpcom_dashboard_widget['name'],
108            ),
109            $wpcom_dashboard_widget['context'],
110            $wpcom_dashboard_widget['priority']
111        );
112    }
113}
114add_action( 'wp_dashboard_setup', 'load_wpcom_dashboard_widgets' );
115
116/**
117 * Enqueue the assets of the wpcom dashboard widgets.
118 *
119 * @param array $args Settings to pass.
120 */
121function enqueue_wpcom_dashboard_widgets( $args = array() ) {
122    $handle = jetpack_mu_wpcom_enqueue_assets( 'wpcom-dashboard-widgets', array( 'js', 'css' ) );
123
124    $bundles      = wp_list_filter( wpcom_get_site_purchases(), array( 'product_type' => 'bundle' ) );
125    $current_plan = array_pop( $bundles );
126
127    $data = wp_json_encode(
128        array(
129            'siteName'        => wp_specialchars_decode( get_bloginfo( 'name' ), ENT_QUOTES ),
130            'siteUrl'         => home_url(),
131            'siteIconUrl'     => get_site_icon_url( 38 ),
132            'isBlockTheme'    => wp_is_block_theme(),
133            'siteDomain'      => wp_parse_url( home_url(), PHP_URL_HOST ),
134            'siteIntent'      => get_option( 'site_intent' ),
135            'sitePlan'        => $current_plan,
136            'hasCustomDomain' => wpcom_site_has_feature( 'custom-domain' ),
137            'tasks'           => $args['tasks'],
138            'blogId'          => get_current_blog_id(),
139        ),
140        JSON_UNESCAPED_SLASHES | JSON_HEX_TAG | JSON_HEX_AMP
141    );
142
143    wp_add_inline_script(
144        $handle,
145        "var JETPACK_MU_WPCOM_DASHBOARD_WIDGETS = $data;var configData = {};",
146        'before'
147    );
148}
149
150/**
151 * Render the container of the wpcom dashboard widget.
152 *
153 * @param WP_Post $post The post object.
154 * @param array   $callback_args The callback args of the render function.
155 */
156function render_wpcom_dashboard_widget( $post, $callback_args ) {
157    $args         = $callback_args['args'];
158    $widget_id    = $args['id'] . '_main';
159    $widget_class = $args['class'] ?? $args['id'];
160    $widget_name  = $args['name'];
161
162    $warning = sprintf(
163        /* translators: The name of the widget. */
164        __( 'Your %s widget requires JavaScript to function properly.', 'jetpack-mu-wpcom' ),
165        $widget_name
166    );
167
168    ?>
169    <div>
170        <div class="hide-if-js">
171            <?php echo esc_html( $warning ); ?>
172        </div>
173        <div
174            id="<?php echo esc_attr( $widget_id ); ?>"
175            class="<?php echo esc_attr( $widget_class ); ?> hide-if-no-js"
176            style="height: 100%">
177        </div>
178    </div>
179    <?php
180}