Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
12.32% covered (danger)
12.32%
75 / 609
16.00% covered (danger)
16.00%
8 / 50
CRAP
n/a
0 / 0
wpcom_launchpad_get_task_list_definitions
0.00% covered (danger)
0.00%
0 / 317
0.00% covered (danger)
0.00%
0 / 1
2
wpcom_launchpad_get_task_list
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
12
wpcom_launchpad_get_task_lists
18.18% covered (danger)
18.18%
2 / 11
0.00% covered (danger)
0.00%
0 / 1
18.69
wpcom_register_default_launchpad_checklists
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
wpcom_launchpad_get_retired_site_intents
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
wpcom_launchpad_clear_retired_site_intents
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
wpcom_launchpad_clear_retired_site_intents_on_correct_action
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
wpcom_add_active_task_listener_hooks_to_correct_action
75.00% covered (warning)
75.00%
3 / 4
0.00% covered (danger)
0.00%
0 / 1
2.06
wpcom_launchpad_add_active_task_listeners
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
wpcom_can_update_design_selected_task
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
20
wpcom_is_checklist_task_complete
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
wpcom_get_launchpad_checklist_by_checklist_slug
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
wpcom_register_launchpad_task_list
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
wpcom_launchpad_get_required_tasks
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
2
wpcom_launchpad_get_launch_tasks
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
6
wpcom_launchpad_are_all_tasks_completed
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
6
wpcom_default_launchpad_task_list_completed
0.00% covered (danger)
0.00%
0 / 16
0.00% covered (danger)
0.00%
0 / 1
42
wpcom_launchpad_is_task_list_completed
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
wpcom_register_launchpad_tasks
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
wpcom_register_launchpad_task
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
wpcom_launchpad_checklists
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
wpcom_hacky_track_video_uploaded_task
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
20
wpcom_maybe_disable_for_difm
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
12
wpcom_maybe_disable_launchpad_screen_for_site_setup
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
4
wpcom_maybe_preview_with_no_interactions
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
12
wpcom_log_launchpad_being_enabled_for_test_sites
0.00% covered (danger)
0.00%
0 / 16
0.00% covered (danger)
0.00%
0 / 1
12
wpcom_launchpad_get_fullscreen_enabled
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
wpcom_get_launchpad_task_list_is_enabled
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
wpcom_launchpad_is_task_list_dismissed
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
wpcom_launchpad_is_task_list_dismissible
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
wpcom_launchpad_task_list_dismissed_until
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
wpcom_launchpad_set_task_list_dismissed
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
wpcom_launchpad_is_fse_next_steps_modal_hidden
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
20
wpcom_launchpad_set_fse_next_steps_modal_hidden
0.00% covered (danger)
0.00%
0 / 15
0.00% covered (danger)
0.00%
0 / 1
110
wpcom_launchpad_navigator_get_checklists
0.00% covered (danger)
0.00%
0 / 14
0.00% covered (danger)
0.00%
0 / 1
20
wpcom_launchpad_navigator_update_checklists
80.00% covered (warning)
80.00%
4 / 5
0.00% covered (danger)
0.00%
0 / 1
2.03
wpcom_launchpad_navigator_remove_checklist
71.43% covered (warning)
71.43%
20 / 28
0.00% covered (danger)
0.00%
0 / 1
8.14
wpcom_launchpad_navigator_add_checklist
85.71% covered (warning)
85.71%
6 / 7
0.00% covered (danger)
0.00%
0 / 1
3.03
wpcom_launchpad_get_active_checklist
81.82% covered (warning)
81.82%
9 / 11
0.00% covered (danger)
0.00%
0 / 1
6.22
wpcom_launchpad_set_current_active_checklist
66.67% covered (warning)
66.67%
12 / 18
0.00% covered (danger)
0.00%
0 / 1
13.70
wpcom_launchpad_is_keep_building_enabled
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
12
wpcom_launchpad_is_hosting_flow_enabled
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
wpcom_launchpad_is_intent_write_enabled
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
wpcom_launchpad_is_free_newsletter_enabled
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
12
wpcom_launchpad_is_paid_newsletter_enabled
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
12
wpcom_launchpad_is_newsletter_goal_enabled
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
add_launchpad_options_to_jetpack_sync
0.00% covered (danger)
0.00%
0 / 13
0.00% covered (danger)
0.00%
0 / 1
20
wpcom_get_launchpad_checklist_title_by_checklist_slug
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
wpcom_get_launchpad_config_option
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
12
wpcom_set_launchpad_config_option
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2/**
3 * Launchpad Helpers
4 *
5 * @package automattic/jetpack-mu-wpcom
6 * @since 1.4.0
7 */
8
9/**
10 * This file provides helpers that return the appropriate Launchpad
11 * checklist and tasks for a given checklist id.
12 *
13 * @package automattic/jetpack-mu-wpcom
14 * @since 1.4.0
15 */
16
17// Type aliases used in a bunch of places in this file. Unfortunately Phan doesn't have a way to set these more globally than copy-pasting them into each file needing them.
18<<<'PHAN'
19@phan-type Task_List = array{id:string, task_ids:string[], required_task_ids?:string[], visible_tasks_callback?:callable, require_last_task_completion?:bool, get_title?:callable, is_dismissible?:bool, is_enabled_callback?:callable}
20@phan-type Task = array{id:string, title?:string, get_title?:callable, id_map?:string, add_listener_callback?:callable, badge_text_callback?:callable, extra_data_callback?:callable, get_calypso_path?:callable, is_complete_callback?:callable, is_disabled_callback?:callable, isLaunchTask?:bool, is_visible_callback?:callable, target_repetitions?:int, repetition_count_callback?:callable, subtitle?:callable, completed?:bool}
21PHAN;
22
23require_once __DIR__ . '/../../utils.php';
24require_once __DIR__ . '/../../common/launchpad-no-guidance.php';
25require_once __DIR__ . '/class-launchpad-task-lists.php';
26require_once __DIR__ . '/launchpad-task-definitions.php';
27
28/**
29 * Registers all default launchpad checklists
30 *
31 * @return Task[]
32 */
33function wpcom_launchpad_get_task_list_definitions() {
34    $core_task_list_definitions = array(
35        'build'                   => array(
36            'get_title'           => function () {
37                return __( 'Next steps for your site', 'jetpack-mu-wpcom' );
38            },
39            'task_ids'            => array(
40                'plan_selected',
41                'site_theme_selected',
42                'domain_upsell',
43                'mobile_app_installed',
44                'site_launched',
45            ),
46            'is_enabled_callback' => 'wpcom_launchpad_get_fullscreen_enabled',
47        ),
48        'free'                    => array(
49            'get_title'           => function () {
50                return __( 'Next steps for your site', 'jetpack-mu-wpcom' );
51            },
52            'task_ids'            => array(
53                'plan_selected',
54                'setup_free',
55                'design_completed',
56                'site_theme_selected',
57                'domain_upsell',
58                'first_post_published',
59                'site_launched',
60            ),
61            'is_enabled_callback' => 'wpcom_launchpad_get_fullscreen_enabled',
62        ),
63        'link-in-bio'             => array(
64            'get_title'           => function () {
65                return __( 'Next steps for your site', 'jetpack-mu-wpcom' );
66            },
67            'task_ids'            => array(
68                'design_selected',
69                'plan_selected',
70                'links_added',
71                'link_in_bio_launched',
72            ),
73            'is_enabled_callback' => 'wpcom_launchpad_get_fullscreen_enabled',
74        ),
75        'link-in-bio-tld'         => array(
76            'get_title'           => function () {
77                return __( 'Next steps for your site', 'jetpack-mu-wpcom' );
78            },
79            'task_ids'            => array(
80                'design_selected',
81                'plan_selected',
82                'links_added',
83                'link_in_bio_launched',
84            ),
85            'is_enabled_callback' => 'wpcom_launchpad_get_fullscreen_enabled',
86        ),
87        'newsletter'              => array(
88            'get_title'           => function () {
89                return __( 'Next steps for your site', 'jetpack-mu-wpcom' );
90            },
91            'task_ids'            => array(
92                'setup_newsletter',
93                'plan_selected',
94                'verify_email',
95                'migrate_content',
96                'subscribers_added',
97                'set_up_payments',
98                'newsletter_plan_created',
99                'first_post_published_newsletter',
100            ),
101            'is_enabled_callback' => 'wpcom_launchpad_get_fullscreen_enabled',
102        ),
103        'intent-newsletter-goal'  => array(
104            'get_title'           => function () {
105                return __( 'Next steps for your site', 'jetpack-mu-wpcom' );
106            },
107            'task_ids'            => array(
108                'verify_email',
109                'site_title',
110                'start_building_your_audience',
111                'customize_welcome_message',
112                'first_post_published',
113                'site_launched',
114            ),
115            'is_enabled_callback' => 'wpcom_launchpad_get_fullscreen_enabled',
116        ),
117        'create-course-goal'      => array(
118            'get_title'           => function () {
119                return __( 'Next steps for your site', 'jetpack-mu-wpcom' );
120            },
121            'task_ids'            => array(
122                'site_title',
123                'verify_email',
124                'domain_customize',
125                'site_launched',
126            ),
127            'is_enabled_callback' => 'wpcom_launchpad_get_fullscreen_enabled',
128        ),
129        'videopress'              => array(
130            'get_title'           => function () {
131                return __( 'Next steps for your site', 'jetpack-mu-wpcom' );
132            },
133            'task_ids'            => array(
134                'videopress_setup',
135                'plan_selected',
136                'videopress_upload',
137                'videopress_launched',
138            ),
139            'is_enabled_callback' => 'wpcom_launchpad_get_fullscreen_enabled',
140        ),
141        'write'                   => array(
142            'get_title'           => function () {
143                return __( 'Next steps for your site', 'jetpack-mu-wpcom' );
144            },
145            'task_ids'            => array(
146                'verify_email',
147                'site_title',
148                'start_building_your_audience',
149                'complete_profile',
150                'first_post_published',
151                'site_launched',
152            ),
153            'is_enabled_callback' => 'wpcom_launchpad_get_fullscreen_enabled',
154        ),
155        'design-first'            => array(
156            'get_title'           => function () {
157                return __( 'Next steps for your site', 'jetpack-mu-wpcom' );
158            },
159            'task_ids'            => array(
160                'design_completed',
161                'setup_blog',
162                'domain_upsell',
163                'plan_completed',
164                'first_post_published',
165                'blog_launched',
166            ),
167            'is_enabled_callback' => 'wpcom_launchpad_get_fullscreen_enabled',
168        ),
169        'intent-build'            => array(
170            'get_title'           => function () {
171                return __( 'Next steps for your site', 'jetpack-mu-wpcom' );
172            },
173            'task_ids'            => array(
174                'site_title',
175                'domain_claim',
176                'verify_email',
177                'domain_customize',
178                'add_new_page',
179                'drive_traffic',
180                'edit_page',
181                'share_site',
182                'update_about_page',
183            ),
184            'is_enabled_callback' => 'wpcom_launchpad_is_keep_building_enabled',
185        ),
186        'intent-write'            => array(
187            'get_title'           => function () {
188                return __( 'Next steps for your site', 'jetpack-mu-wpcom' );
189            },
190            'task_ids'            => array(
191                'site_title',
192                'domain_claim',
193                'verify_email',
194                'domain_customize',
195                'drive_traffic',
196                'write_3_posts',
197            ),
198            'is_enabled_callback' => 'wpcom_launchpad_is_intent_write_enabled',
199        ),
200        'intent-free-newsletter'  => array(
201            'get_title'           => function () {
202                return __( 'Next steps for your site', 'jetpack-mu-wpcom' );
203            },
204            'task_ids'            => array(
205                'enable_subscribers_modal',
206                'verify_email',
207                'migrate_content',
208                'subscribers_added',
209                'share_site',
210                'manage_subscribers',
211                'update_about_page',
212                'add_about_page',
213            ),
214            'is_enabled_callback' => 'wpcom_launchpad_is_free_newsletter_enabled',
215        ),
216        'intent-paid-newsletter'  => array(
217            'get_title'           => function () {
218                return __( 'Next steps for your site', 'jetpack-mu-wpcom' );
219            },
220            'task_ids'            => array(
221                'enable_subscribers_modal',
222                'verify_email',
223                'migrate_content',
224                'subscribers_added',
225                'share_site',
226                'set_up_payments',
227                'manage_subscribers',
228                'manage_paid_newsletter_plan',
229                'update_about_page',
230                'add_about_page',
231            ),
232            'is_enabled_callback' => 'wpcom_launchpad_is_paid_newsletter_enabled',
233        ),
234        'earn'                    => array(
235            'task_ids'            => array(
236                'stripe_connected',
237                'paid_offer_created',
238            ),
239            'is_enabled_callback' => '__return_true',
240        ),
241        'host-site'               => array(
242            'task_ids'            => array(
243                'site_theme_selected',
244                'install_custom_plugin',
245                'setup_ssh',
246                'verify_email',
247                'site_monitoring_page',
248                'site_launched',
249            ),
250            'is_enabled_callback' => 'wpcom_launchpad_is_hosting_flow_enabled',
251        ),
252        'subscribers'             => array(
253            'task_ids' => array(
254                'import_subscribers',
255                'add_subscribe_block',
256                'share_site',
257            ),
258        ),
259        'assembler-first'         => array(
260            'get_title'           => function () {
261                return __( 'Next steps for your site', 'jetpack-mu-wpcom' );
262            },
263            'task_ids'            => array(
264                'verify_domain_email',
265                'plan_completed',
266                'setup_free',
267                'design_selected',
268                'site_theme_selected',
269                'domain_upsell',
270                'first_post_published',
271                'site_launched',
272            ),
273            'is_enabled_callback' => 'wpcom_launchpad_get_fullscreen_enabled',
274        ),
275        'ai-assembler'            => array(
276            'get_title'           => function () {
277                return __( 'Next steps for your site', 'jetpack-mu-wpcom' );
278            },
279            'task_ids'            => array(
280                'verify_domain_email',
281                'plan_completed',
282                'setup_free',
283                'design_selected',
284                'site_theme_selected',
285                'domain_upsell',
286                'site_launched',
287            ),
288            'is_enabled_callback' => 'wpcom_launchpad_get_fullscreen_enabled',
289        ),
290        'legacy-site-setup'       => array(
291            'get_title'      => function () {
292                return __( 'Site setup', 'jetpack-mu-wpcom' );
293            },
294            'is_dismissible' => true,
295            'task_ids'       => array(
296                'woocommerce_setup',
297                'sensei_setup',
298                'site_title',
299                'front_page_updated',
300                'verify_domain_email',
301                'verify_email',
302                'mobile_app_installed',
303                'post_sharing_enabled',
304                'site_launched',
305            ),
306        ),
307        'sell'                    => array(
308            'get_title'      => function () {
309                return __( 'Site setup', 'jetpack-mu-wpcom' );
310            },
311            'is_dismissible' => true,
312            'task_ids'       => array(
313                'woocommerce_setup',
314                'sensei_setup',
315                'site_title',
316                'front_page_updated',
317                'verify_domain_email',
318                'verify_email',
319                'mobile_app_installed',
320                'post_sharing_enabled',
321                'site_launched',
322            ),
323        ),
324        'entrepreneur-site-setup' => array(
325            'task_ids' => array(
326                'woo_customize_store',
327                'woo_products',
328                'woo_woocommerce_payments',
329                'woo_tax',
330                'woo_marketing',
331                'woo_add_domain',
332                'woo_launch_site',
333            ),
334        ),
335        'post-migration'          => array(
336            'get_title' => function () {
337                return __( 'Site migration', 'jetpack-mu-wpcom' );
338            },
339            'task_ids'  => array(
340                'migrating_site',
341                'review_site',
342                'review_plugins',
343                'connect_migration_domain',
344                'domain_dns_mapped',
345                'check_ssl_status',
346            ),
347        ),
348    );
349
350    $extended_task_list_definitions = apply_filters( 'wpcom_launchpad_extended_task_list_definitions', array() );
351
352    // As for tasks, we can decide what overrides we allow later.
353    return array_merge( $extended_task_list_definitions, $core_task_list_definitions );
354}
355
356/**
357 * Get a registered task list.
358 *
359 * @param string $checklist_slug The checklist slug to get the task list for.
360 *
361 * @return Task_List
362 */
363function wpcom_launchpad_get_task_list( $checklist_slug = null ) {
364    // If we don't have a checklist slug, fall back to the site intent option.
365    $checklist_slug = $checklist_slug ? $checklist_slug : get_option( 'site_intent' );
366    if ( ! $checklist_slug ) {
367        return array();
368    }
369
370    return wpcom_launchpad_checklists()->get_task_list( $checklist_slug );
371}
372
373/**
374 * Register all tasks and task lists from definitions
375 *
376 * @param bool $rebuild Whether to rebuild the task lists or not.
377 *
378 * @return Task_List[]
379 */
380function wpcom_launchpad_get_task_lists( $rebuild = false ) {
381    // If we already have task lists registered and we don't want to rebuild, return all task lists.
382    if ( ! $rebuild && wpcom_launchpad_checklists()->has_task_lists() ) {
383        return wpcom_launchpad_checklists()->get_all_task_lists();
384    }
385
386    $task_definitions = wpcom_launchpad_get_task_definitions();
387
388    // Register all tasks.
389    foreach ( $task_definitions as $task_id => $task_definition ) {
390        $task_data = array_merge( $task_definition, array( 'id' => $task_id ) );
391        wpcom_register_launchpad_task( $task_data );
392    }
393
394    $task_list_definitions = wpcom_launchpad_get_task_list_definitions();
395
396    // Register all task lists.
397    foreach ( $task_list_definitions as $task_list_id => $task_list_definition ) {
398        $task_list_data = array_merge( $task_list_definition, array( 'id' => $task_list_id ) );
399        wpcom_register_launchpad_task_list( $task_list_data );
400    }
401
402    // Assuming the reference is good, just return all checklists.
403    return wpcom_launchpad_checklists()->get_all_task_lists();
404}
405
406/**
407 * Register all tasks and task lists on init.
408 */
409function wpcom_register_default_launchpad_checklists() {
410    wpcom_launchpad_get_task_lists();
411    wpcom_add_active_task_listener_hooks_to_correct_action();
412}
413add_action( 'init', 'wpcom_register_default_launchpad_checklists', 11 );
414
415/**
416 * The site intents of retired onboarding flows.
417 *
418 * These no longer have a checklist, but sites created under them still carry
419 * the value, and clients still pass it to the launchpad endpoint as a checklist
420 * slug. The endpoint keeps accepting these so such a request degrades to an
421 * empty checklist rather than a 400. Empty this list once no site carries one.
422 *
423 * @return string[] Retired site intents.
424 */
425function wpcom_launchpad_get_retired_site_intents() {
426    return array( 'start-writing', 'readymade-template' );
427}
428
429/**
430 * Clears the site intent for a retired onboarding flow.
431 *
432 * A retired flow no longer accepts new sites, so the sites left on one sit in
433 * an onboarding they can never be guided through. Clearing the intent returns
434 * them to the same state as a site that never picked one: no Launchpad, and no
435 * onboarding email campaign.
436 *
437 * Writes once per site, since the intent stops matching afterwards. Delete this
438 * once no site carries one of these values.
439 */
440function wpcom_launchpad_clear_retired_site_intents() {
441    if ( ! in_array( get_option( 'site_intent' ), wpcom_launchpad_get_retired_site_intents(), true ) ) {
442        return;
443    }
444
445    update_option( 'site_intent', '' );
446    update_option( 'launchpad_screen', 'off' );
447}
448
449/**
450 * Clears the retired site intent once the target site's options are readable.
451 *
452 * On `public-api.wordpress.com`, `init` fires before the request switches to
453 * the blog, so reading `site_intent` there would read the wrong site.
454 *
455 * Runs ahead of the checklist registration, on both paths, so that the active
456 * task listeners are never registered for an intent that is about to be gone.
457 *
458 * @return void
459 */
460function wpcom_launchpad_clear_retired_site_intents_on_correct_action() {
461    if ( wp_parse_url( home_url(), PHP_URL_HOST ) === 'public-api.wordpress.com' ) {
462        add_action( 'rest_api_switched_to_blog', 'wpcom_launchpad_clear_retired_site_intents' );
463        return;
464    }
465
466    wpcom_launchpad_clear_retired_site_intents();
467}
468add_action( 'init', 'wpcom_launchpad_clear_retired_site_intents_on_correct_action', 10 );
469
470/**
471 * Adds hooks to the correct action to add active task listeners.
472 * Handles REST API requests vs non-REST API requests.
473 *
474 * @return null
475 */
476function wpcom_add_active_task_listener_hooks_to_correct_action() {
477    $url = wp_parse_url( home_url(), PHP_URL_HOST );
478    if ( $url === 'public-api.wordpress.com' ) {
479        return add_action( 'rest_api_switched_to_blog', 'wpcom_launchpad_add_active_task_listeners' );
480    }
481
482    // If we're not deferring to REST API blog switch, just run now
483    return wpcom_launchpad_add_active_task_listeners();
484}
485
486/**
487 * Adds task-defined `add_listener_callback` hooks for incomplete tasks.
488 *
489 * @return void
490 */
491function wpcom_launchpad_add_active_task_listeners() {
492    wpcom_launchpad_checklists()->add_hooks_for_active_tasks();
493}
494
495/**
496 * Determines whether or not design selected task is enabled
497 *
498 * @return boolean True if design selected task is enabled
499 */
500function wpcom_can_update_design_selected_task() {
501    $site_intent = get_option( 'site_intent' );
502    return $site_intent === 'free' || $site_intent === 'build' || $site_intent === 'write' || $site_intent === 'design-first';
503}
504
505/**
506 * Returns launchpad checklist task by task id.
507 *
508 * @param string $task_id Task id.
509 *
510 * @return array Associative array with task data
511 *               or false if task id is not found.
512 */
513function wpcom_is_checklist_task_complete( $task_id ) {
514    return wpcom_launchpad_checklists()->is_task_id_complete( $task_id );
515}
516
517/**
518 * Returns launchpad checklist by checklist slug.
519 *
520 * @param string      $checklist_slug Checklist slug.
521 * @param string|null $launchpad_context Optional. Screen where Launchpad is loading.
522 *
523 * @return Task[] Collection of tasks for a given checklist
524 */
525function wpcom_get_launchpad_checklist_by_checklist_slug( $checklist_slug, $launchpad_context = null ) {
526    if ( ! $checklist_slug ) {
527        return array();
528    }
529
530    return wpcom_launchpad_checklists()->build( $checklist_slug, $launchpad_context );
531}
532
533// TODO: Write code p2 post or dotcom post
534/**
535 * Wrapper that registers a launchpad checklist.
536 *
537 * @param Task_List $task_list Task list definition.
538 *
539 * @return bool True if successful, false otherwise.
540 */
541function wpcom_register_launchpad_task_list( $task_list ) {
542    return wpcom_launchpad_checklists()->register_task_list( $task_list );
543}
544
545/**
546 * Retrieves the required tasks from a given set of tasks.
547 *
548 * This function filters the provided tasks array and returns only the tasks that are marked as required,
549 * based on the specified array of required task IDs. It's worth noting that some tasks may not be
550 * visible to the user, so we are going to return all tasks that are marked as required, regardless
551 *
552 * @param array  $required_task_ids An array of task IDs that are considered required.
553 * @param Task[] $tasks An array of tasks to filter.
554 * @return array An array containing only the required tasks from the provided task list.
555 */
556function wpcom_launchpad_get_required_tasks( $required_task_ids, $tasks ) {
557    return array_filter(
558        $tasks,
559        function ( $task ) use ( $required_task_ids ) {
560            return in_array( $task['id'], $required_task_ids, true );
561        }
562    );
563}
564
565/**
566 * Get all tasks that are marked as launch tasks.
567 *
568 * @param Task[] $tasks Array of tasks.
569 * @return Task[] Array of launch tasks.
570 */
571function wpcom_launchpad_get_launch_tasks( $tasks ) {
572    return array_filter(
573        $tasks,
574        function ( $task ) {
575            if ( isset( $task['isLaunchTask'] ) ) {
576                return $task['isLaunchTask'];
577            }
578            return false;
579        }
580    );
581}
582
583/**
584 * Check if all the given tasks are completed.
585 *
586 * @param Task[] $tasks Array of tasks to check if they are completed.
587 * @return bool True if all tasks are completed, false otherwise.
588 */
589function wpcom_launchpad_are_all_tasks_completed( $tasks ) {
590    return array_reduce(
591        $tasks,
592        function ( $carry, $launch_task ) {
593            return $carry && $launch_task['completed'];
594        },
595        true
596    );
597}
598
599/**
600 * Determine the completion status of a task list based on its tasks.
601 *
602 * This function identifies any required tasks within the task list. If there are required tasks, the task list is considered complete
603 * only if all required tasks are completed. In the absence of required tasks, a secondary check is performed on tasks flagged with
604 * "isLaunchTask" to determine completion based on whether all of those tasks are complete. If there are no required tasks and no
605 * launch tasks, the task list's completion is determined by checking whether all tasks are complete. However, if there are incomplete
606 * tasks in this scenario, the completion status is based on whether the last task was completed. It is possible to control this behavior
607 * using a flag, as the default approach might be confusing for task lists where the steps may not be sequential. By default, the task
608 * list is marked as incomplete to align with most use cases that focus on user guidance and next steps rather than a specific end goal.
609 *
610 * @param Task_List $task_list Task list.
611 * @return bool True if the task list is considered complete, false otherwise.
612 */
613function wpcom_default_launchpad_task_list_completed( $task_list ) {
614    $task_list_id      = $task_list['id'];
615    $required_task_ids = wpcom_launchpad_checklists()->get_required_task_ids( $task_list_id );
616    $all_visible_tasks = wpcom_launchpad_checklists()->build( $task_list_id );
617
618    // If there are required tasks, check if they are all completed.
619    if ( ! empty( $required_task_ids ) ) {
620        $required_tasks = wpcom_launchpad_get_required_tasks( $required_task_ids, $all_visible_tasks );
621        return wpcom_launchpad_are_all_tasks_completed( $required_tasks );
622    }
623
624    // If there are no required tasks, check if there are any launch tasks.
625    $launch_tasks = wpcom_launchpad_get_launch_tasks( $all_visible_tasks );
626    if ( ! empty( $launch_tasks ) ) {
627        return wpcom_launchpad_are_all_tasks_completed( $launch_tasks );
628    }
629
630    // If there are no required tasks and no launch tasks, check if all tasks are completed.
631    if ( wpcom_launchpad_are_all_tasks_completed( $all_visible_tasks ) ) {
632        return true;
633    }
634
635    // If there are incomplete tasks, check if the last task was completed.
636    $require_last_task_completion = wpcom_launchpad_checklists()->get_require_last_task_completion( $task_list_id );
637    $last_task                    = end( $all_visible_tasks );
638    if ( $require_last_task_completion && $last_task['completed'] ) {
639        return true;
640    }
641
642    return false;
643}
644
645/**
646 * Callback to determine the completion status of a task list.
647 *
648 * @param string $task_list_id The task list ID.
649 * @return bool True if the task list is considered complete, false otherwise.
650 */
651function wpcom_launchpad_is_task_list_completed( $task_list_id ) {
652    return wpcom_launchpad_checklists()->is_task_list_completed( $task_list_id );
653}
654
655/**
656 * Wrapper that registers a launchpad checklist.
657 *
658 * @param Task $tasks Collection of Task definitions.
659 *
660 * @return bool True if successful, false otherwise.
661 */
662function wpcom_register_launchpad_tasks( $tasks ) {
663    return wpcom_launchpad_checklists()->register_tasks( $tasks );
664}
665
666/**
667 * Wrapper that registers a launchpad checklist.
668 *
669 * @param Task $task Task definition.
670 *
671 * @return bool True if successful, false otherwise.
672 */
673function wpcom_register_launchpad_task( $task ) {
674    return wpcom_launchpad_checklists()->register_task( $task );
675}
676
677/**
678 * Helper function to return a `Launchpad_Task_Lists` instance.
679 *
680 * @return object Launchpad_Task_Lists instance.
681 */
682function wpcom_launchpad_checklists() {
683    return Launchpad_Task_Lists::get_instance();
684}
685
686/**
687 * The `/rest/v1.1/video-uploads` endpoint operates without calling the `rest_api_switched_to_blog` hook.
688 * Which prevents our listeners from being added.
689 * This mimics the legacy mu-plugin logic of always adding the listener.
690 *
691 * @param int $post_id The attachment ID.
692 * @return void
693 */
694function wpcom_hacky_track_video_uploaded_task( $post_id ) {
695    if ( get_option( 'site_intent' ) !== 'videopress' ) {
696        return;
697    }
698    if ( get_option( 'launchpad_screen' ) !== 'full' ) {
699        return;
700    }
701    if ( has_action( 'add_attachment', 'wpcom_launchpad_track_video_uploaded_task' ) ) {
702        return;
703    }
704
705    wpcom_launchpad_track_video_uploaded_task( $post_id );
706}
707add_action( 'add_attachment', 'wpcom_hacky_track_video_uploaded_task' );
708
709//
710// Misc other Launchpad-related functionality below.
711//
712
713/**
714 * A filter for `get_option( 'launchpad_screen' )`
715 *
716 * @param mixed $value The filterable option value, retrieved from the DB.
717 * @return mixed       false if DIFM is active, the unaltered value otherwise.
718 */
719function wpcom_maybe_disable_for_difm( $value ) {
720    // If it's already false I don't care
721    if ( $value === false ) {
722        return $value;
723    }
724
725    // We want to disable for Built By Express aka DIFM, in case they've
726    // 1) Entered the Launchpad during signup, then 2) Purchased DIFM
727    if ( has_blog_sticker( 'difm-lite-in-progress' ) ) {
728        return false;
729    }
730    // Just in case, always return from a filter!
731    return $value;
732}
733// only WPCOM has blog stickers.
734if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) {
735    add_filter( 'option_launchpad_screen', 'wpcom_maybe_disable_for_difm' );
736}
737
738/**
739 * Filter for `get_option( 'launchpad_screen' )`: hide the old Launchpad on Site Setup and no-guidance sites.
740 *
741 * @param mixed $value The filterable option value, retrieved from the DB.
742 * @return mixed 'off' for those sites, the unaltered value otherwise.
743 */
744function wpcom_maybe_disable_launchpad_screen_for_site_setup( $value ) {
745    if ( false === $value ) {
746        return $value;
747    }
748
749    if ( get_option( 'wpcom_ai_launchpad_enabled' ) || wpcom_launchpad_is_no_guidance() ) {
750        return 'off';
751    }
752
753    return $value;
754}
755add_filter( 'option_launchpad_screen', 'wpcom_maybe_disable_launchpad_screen_for_site_setup' );
756
757add_action( 'wp_head', 'wpcom_maybe_preview_with_no_interactions', PHP_INT_MAX );
758/**
759 * Add CSS that disallows interaction with the Launchpad preview.
760 *
761 * @return void|string
762 */
763function wpcom_maybe_preview_with_no_interactions() {
764    // phpcs:ignore
765    if ( empty( $_GET['do_preview_no_interactions'] ) || $_GET['do_preview_no_interactions'] !== 'true' ) {
766        return;
767    }
768
769    ?>
770        <style type="text/css">
771                body {
772                    pointer-events: none !important;
773                }
774        </style>
775    <?php
776}
777
778// Temporarily log information to debug intermittent launchpad errors for e2e tests
779if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) {
780    add_action( 'add_option_launchpad_screen', 'wpcom_log_launchpad_being_enabled_for_test_sites', 10, 2 );
781}
782
783/**
784 * Logs data when e2eflowtesting5.wordpress.com has launchpad enabled
785 *
786 * @param string $option The previous option value.
787 * @param string $value The new option value.
788 * @return void
789 */
790function wpcom_log_launchpad_being_enabled_for_test_sites( $option, $value ) {
791    // e2eflowtesting5.wordpress.com
792    if ( get_current_blog_id() !== 208860881 || $value !== 'full' ) {
793        return;
794    }
795
796    require_once WP_CONTENT_DIR . '/lib/log2logstash/log2logstash.php';
797    require_once WP_CONTENT_DIR . '/admin-plugins/wpcom-billing.php';
798    $current_plan = WPCOM_Store_API::get_current_plan( get_current_blog_id() );
799    $extra        = array(
800        'is_free'     => $current_plan['is_free'],
801        'site_intent' => get_option( 'site_intent' ),
802    );
803
804    log2logstash(
805        array(
806            'feature' => 'launchpad',
807            'message' => 'Launchpad enabled for e2e test site.',
808            'extra'   => wp_json_encode( $extra, JSON_UNESCAPED_SLASHES ),
809        )
810    );
811}
812
813/**
814 * Checks if the overall launchpad is enabled. Used with `is_enabled_callback`
815 * for backwards compatibility with established task lists
816 * that relied on the old `launchpad_screen` option.
817 *
818 * @return bool True if the launchpad is enabled, false otherwise.
819 */
820function wpcom_launchpad_get_fullscreen_enabled() {
821    return wpcom_launchpad_checklists()->is_fullscreen_launchpad_enabled();
822}
823
824/**
825 * Checks if a specific launchpad task list is enabled.
826 *
827 * @param string $checklist_slug The slug of the launchpad task list to check.
828 * @return bool True if the task list is enabled, false otherwise.
829 */
830function wpcom_get_launchpad_task_list_is_enabled( $checklist_slug ) {
831    if ( false !== $checklist_slug ) {
832        return wpcom_launchpad_checklists()->is_task_list_enabled( $checklist_slug );
833    }
834
835    return false;
836}
837
838/**
839 * Checks if a specific task list is dismissed.
840 *
841 * @param string $checklist_slug The slug of the launchpad task list to check.
842 * @return bool True if the task list is dismissed, false otherwise.
843 */
844function wpcom_launchpad_is_task_list_dismissed( $checklist_slug ) {
845    return wpcom_launchpad_checklists()->is_task_list_dismissed( $checklist_slug );
846}
847
848/**
849 * Checks if the Launchpad is dismissible.
850 *
851 * @param string $checklist_slug The slug of the launchpad task list to check.
852 * @return bool True if the Launchpad is dismissible, false otherwise.
853 */
854function wpcom_launchpad_is_task_list_dismissible( $checklist_slug ) {
855    if ( false === $checklist_slug ) {
856        return false;
857    }
858    return wpcom_launchpad_checklists()->is_task_list_dismissible( $checklist_slug );
859}
860
861/**
862 * Returns the the temporary dismissed timestamps for a specific task list.
863 *
864 * @param string $checklist_slug The slug of the launchpad task list to check.
865 * @return int The timestamp until which the task list is dismissed.
866 */
867function wpcom_launchpad_task_list_dismissed_until( $checklist_slug ) {
868    return wpcom_launchpad_checklists()->get_task_list_dismissed_until( $checklist_slug );
869}
870
871/**
872 * Sets a specific task list dismissed state.
873 *
874 * @param string        $checklist_slug The slug of the launchpad task list to check.
875 * @param bool          $is_dismissed True if the task list is dismissed, false otherwise.
876 * @param string | null $dismissed_until The date until which the task list is dismissed.
877 */
878function wpcom_launchpad_set_task_list_dismissed( $checklist_slug, $is_dismissed, $dismissed_until ) {
879
880    if ( isset( $dismissed_until ) ) {
881        wpcom_launchpad_checklists()->set_task_list_dismissed_until( $checklist_slug, $dismissed_until );
882    } else {
883        wpcom_launchpad_checklists()->set_task_list_dismissed( $checklist_slug, $is_dismissed );
884    }
885}
886
887/**
888 * Helper function to indicate whether the Next Steps modal in
889 * the Full Site Editor should be hidden.
890 *
891 * @return bool
892 */
893function wpcom_launchpad_is_fse_next_steps_modal_hidden() {
894    $wpcom_launchpad_config = get_option( 'wpcom_launchpad_config' );
895
896    if ( ! $wpcom_launchpad_config || ! is_array( $wpcom_launchpad_config ) ) {
897        return false;
898    }
899
900    if ( ! isset( $wpcom_launchpad_config['hide_fse_next_steps_modal'] ) ) {
901        return false;
902    }
903
904    return true === $wpcom_launchpad_config['hide_fse_next_steps_modal'];
905}
906
907/**
908 * Helper function to hide and show the Next Steps modal we show in the
909 * Full Site Editor.
910 *
911 * @param bool $should_hide Should the modal be hidden (true) or displayed (false).
912 * @return bool Whether the option update succeeded.
913 */
914function wpcom_launchpad_set_fse_next_steps_modal_hidden( $should_hide ) {
915    $wpcom_launchpad_config = get_option( 'wpcom_launchpad_config' );
916
917    // If we want to show the modal, we don't need to do anything if either the main
918    // wpcom_launchpad_config option OR the hide sub-option aren't set.
919    if ( ! $should_hide ) {
920        if ( ! $wpcom_launchpad_config || ! is_array( $wpcom_launchpad_config ) ) {
921            return true;
922        }
923
924        if ( ! isset( $wpcom_launchpad_config['hide_fse_next_steps_modal'] ) ) {
925            return true;
926        }
927
928        unset( $wpcom_launchpad_config['hide_fse_next_steps_modal'] );
929    } else {
930        // Make sure we have an array for the main option.
931        if ( ! $wpcom_launchpad_config || ! is_array( $wpcom_launchpad_config ) ) {
932            $wpcom_launchpad_config = array();
933        }
934
935        // If we already have the option set, we can return early.
936        if ( isset( $wpcom_launchpad_config['hide_fse_next_steps_modal'] ) && true === $wpcom_launchpad_config['hide_fse_next_steps_modal'] ) {
937            return true;
938        }
939
940        $wpcom_launchpad_config['hide_fse_next_steps_modal'] = true;
941    }
942
943    if ( empty( $wpcom_launchpad_config ) ) {
944        return delete_option( 'wpcom_launchpad_config' );
945    }
946
947    return update_option( 'wpcom_launchpad_config', $wpcom_launchpad_config );
948}
949
950/**
951 * Returns a list of all the checklists that are currently available for the navigator.
952 *
953 * @return array Array of strings representing the checklist slugs.
954 */
955function wpcom_launchpad_navigator_get_checklists() {
956    $wpcom_launchpad_config = get_option( 'wpcom_launchpad_config', array() );
957
958    if ( ! isset( $wpcom_launchpad_config['navigator_checklists'] ) ) {
959        return array();
960    }
961    $all_checklists  = wpcom_launchpad_checklists()->get_all_task_lists();
962    $checklist_slugs = $wpcom_launchpad_config['navigator_checklists'];
963
964    $results = array();
965    foreach ( $checklist_slugs as $slug ) {
966        if ( ! isset( $all_checklists[ $slug ] ) ) {
967            continue;
968        }
969
970        $results[ $slug ] = array(
971            'slug'  => $slug,
972            'title' => $all_checklists[ $slug ]['title'],
973        );
974    }
975
976    return $results;
977}
978
979/**
980 * Updates the list of checklists that are currently available for the navigator.
981 *
982 * @param array $new_checklists Array of strings representing the checklist slugs.
983 * @return bool Whether the option update succeeded.
984 */
985function wpcom_launchpad_navigator_update_checklists( $new_checklists ) {
986    if ( ! is_array( $new_checklists ) ) {
987        return false;
988    }
989
990    $wpcom_launchpad_config = get_option( 'wpcom_launchpad_config', array() );
991
992    $wpcom_launchpad_config['navigator_checklists'] = $new_checklists;
993
994    return update_option( 'wpcom_launchpad_config', $wpcom_launchpad_config );
995}
996
997/**
998 * Removes a checklist from the list of checklists that are currently available for the navigator.
999 *
1000 * @param string $checklist_slug The slug of the checklist to remove.
1001 * @return array Array with two values: whether the option update succeeded, and the new active checklist slug.
1002 */
1003function wpcom_launchpad_navigator_remove_checklist( $checklist_slug ) {
1004    $wpcom_launchpad_config = get_option( 'wpcom_launchpad_config', array() );
1005
1006    if ( ! isset( $wpcom_launchpad_config['navigator_checklists'] ) ) {
1007        return array(
1008            'updated'              => false,
1009            'new_active_checklist' => null,
1010        );
1011    }
1012
1013    $checklists = $wpcom_launchpad_config['navigator_checklists'];
1014    // Find if $checklist_slug is in the checklists array. If it is, remove it.
1015    $key = array_search( $checklist_slug, $checklists, true );
1016    if ( $key === false ) {
1017        return array(
1018            'updated'              => false,
1019            'new_active_checklist' => wpcom_launchpad_get_active_checklist(),
1020        );
1021    }
1022
1023    unset( $checklists[ $key ] );
1024
1025    // Compare against the raw stored slug, not the getter: a retired active checklist
1026    // reads as null there, which would otherwise hide that it was the one removed.
1027    $stored_active_slug = $wpcom_launchpad_config['active_checklist_slug'] ?? null;
1028
1029    $new_active_checklist = wpcom_launchpad_get_active_checklist();
1030    if ( $stored_active_slug === $checklist_slug ) {
1031        // The active checklist was removed. Promote the most recently added one that
1032        // is still registered, skipping any other retired slugs, or clear it.
1033        $registered_checklists = wpcom_launchpad_checklists()->get_all_task_lists();
1034        $new_active_checklist  = null;
1035        foreach ( array_reverse( $checklists ) as $remaining_slug ) {
1036            if ( is_string( $remaining_slug ) && array_key_exists( $remaining_slug, $registered_checklists ) ) {
1037                $new_active_checklist = $remaining_slug;
1038                break;
1039            }
1040        }
1041        wpcom_launchpad_set_current_active_checklist( $new_active_checklist );
1042    }
1043
1044    return array(
1045        'updated'              => wpcom_launchpad_navigator_update_checklists( $checklists ),
1046        'new_active_checklist' => $new_active_checklist,
1047    );
1048}
1049
1050/**
1051 * Adds a new checklist to the list of checklists that are currently available for the navigator.
1052 *
1053 * @param string $new_checklist_slug The slug of the launchpad task list to add.
1054 */
1055function wpcom_launchpad_navigator_add_checklist( $new_checklist_slug ) {
1056    $wpcom_launchpad_config = get_option( 'wpcom_launchpad_config', array() );
1057    $checklists             = array();
1058
1059    if ( isset( $wpcom_launchpad_config['navigator_checklists'] ) ) {
1060        $checklists = $wpcom_launchpad_config['navigator_checklists'];
1061    }
1062
1063    // add the new_checklist_slug to the checklists array if it's not already there.
1064    if ( ! in_array( $new_checklist_slug, $checklists, true ) ) {
1065        $checklists[] = $new_checklist_slug;
1066    }
1067
1068    wpcom_launchpad_navigator_update_checklists( $checklists );
1069}
1070
1071/**
1072 * Helper function to indicate what's the current active checklist
1073 * in the context of the navigator.
1074 * It will try to read the key 'active_checklist_slug' from the 'wpcom_launchpad_config' option.
1075 *
1076 * @return string|null The active checklist slug, null if none is set.
1077 */
1078function wpcom_launchpad_get_active_checklist() {
1079    $wpcom_launchpad_config = get_option( 'wpcom_launchpad_config' );
1080
1081    if ( ! $wpcom_launchpad_config || ! is_array( $wpcom_launchpad_config ) ) {
1082        return null;
1083    }
1084
1085    if ( ! isset( $wpcom_launchpad_config['active_checklist_slug'] ) ) {
1086        return null;
1087    }
1088
1089    $active_checklist_slug = $wpcom_launchpad_config['active_checklist_slug'];
1090
1091    // This repairs persisted state, so it cannot assume a well-formed value: legacy
1092    // or custom code may have stored a non-string, which would fatal below.
1093    if ( ! is_string( $active_checklist_slug ) ) {
1094        return null;
1095    }
1096
1097    // A retired checklist can linger here from before it was unregistered. Treat it
1098    // as unset, matching how the available list drops unregistered slugs and how the
1099    // setter refuses them, so the Navigator never reports a checklist that is gone.
1100    if ( ! array_key_exists( $active_checklist_slug, wpcom_launchpad_checklists()->get_all_task_lists() ) ) {
1101        return null;
1102    }
1103
1104    return $active_checklist_slug;
1105}
1106
1107/**
1108 * Helper function to set the current active checklist in the navigator context.
1109 *
1110 * @param string|null $checklist_slug The slug of the launchpad task list to mark as active, or null to clear it.
1111 * @return bool Whether the option update succeeded.
1112 */
1113function wpcom_launchpad_set_current_active_checklist( $checklist_slug ) {
1114    $wpcom_launchpad_config = get_option( 'wpcom_launchpad_config' );
1115
1116    if ( null !== $checklist_slug ) {
1117        $checklists = wpcom_launchpad_checklists()->get_all_task_lists();
1118        if ( ! array_key_exists( $checklist_slug, $checklists ) ) {
1119            return false;
1120        }
1121    }
1122
1123    if ( ! $wpcom_launchpad_config || ! is_array( $wpcom_launchpad_config ) ) {
1124        $wpcom_launchpad_config = array();
1125    }
1126
1127    if ( null === $checklist_slug ) {
1128        if ( ! isset( $wpcom_launchpad_config['active_checklist_slug'] ) ) {
1129            return true;
1130        }
1131        unset( $wpcom_launchpad_config['active_checklist_slug'] );
1132    } else {
1133        if ( isset( $wpcom_launchpad_config['active_checklist_slug'] ) && $checklist_slug === $wpcom_launchpad_config['active_checklist_slug'] ) {
1134            return true;
1135        }
1136        $wpcom_launchpad_config['active_checklist_slug'] = $checklist_slug;
1137    }
1138
1139    $return_value = update_option( 'wpcom_launchpad_config', $wpcom_launchpad_config );
1140    // add to available checklists if not null
1141    if ( $checklist_slug !== null ) {
1142        wpcom_launchpad_navigator_add_checklist( $checklist_slug );
1143    }
1144
1145    return $return_value;
1146}
1147
1148/**
1149 * Checks if the Keep building task list is enabled.
1150 *
1151 * @return bool True if the task list is enabled, false otherwise.
1152 */
1153function wpcom_launchpad_is_keep_building_enabled() {
1154    $intent  = get_option( 'site_intent', false );
1155    $blog_id = get_current_blog_id();
1156
1157    if ( 'build' === $intent && $blog_id > 220443356 ) {
1158        return true;
1159    }
1160
1161    return false;
1162}
1163
1164/**
1165 * Checks if the hosting flow task list is enabled.
1166 *
1167 * @return bool True if the task list is enabled, false otherwise.
1168 */
1169function wpcom_launchpad_is_hosting_flow_enabled() {
1170    return apply_filters( 'is_launchpad_intent_hosting_enabled', false );
1171}
1172
1173/**
1174 * Checks if the Blog flow task list is enabled.
1175 *
1176 * @return bool True if the task list is enabled, false otherwise.
1177 */
1178function wpcom_launchpad_is_intent_write_enabled() {
1179    return apply_filters( 'is_launchpad_intent_write_enabled', false );
1180}
1181
1182/**
1183 * Checks if the Free Newsletter flow task list is enabled.
1184 *
1185 * @return bool True if the task list is enabled, false otherwise.
1186 */
1187function wpcom_launchpad_is_free_newsletter_enabled() {
1188    $intent = get_option( 'site_intent', false );
1189    if ( 'newsletter' !== $intent ) {
1190        return false;
1191    }
1192
1193    return ! wpcom_launchpad_has_goal_paid_subscribers() && apply_filters( 'wpcom_launchpad_intent_free_newsletter_enabled', false );
1194}
1195
1196/**
1197 * Checks if the Paid Newsletter flow task list is enabled.
1198 *
1199 * @return bool True if the task list is enabled, false otherwise.
1200 */
1201function wpcom_launchpad_is_paid_newsletter_enabled() {
1202    $intent = get_option( 'site_intent', false );
1203    if ( 'newsletter' !== $intent ) {
1204        return false;
1205    }
1206
1207    return wpcom_launchpad_has_goal_paid_subscribers() && apply_filters( 'wpcom_launchpad_intent_paid_newsletter_enabled', false );
1208}
1209
1210/**
1211 * Checks if the Newsletter goal flow task list is enabled.
1212 *
1213 * @return bool True if the task list is enabled, false otherwise.
1214 */
1215function wpcom_launchpad_is_newsletter_goal_enabled() {
1216    $intent = get_option( 'site_intent', false );
1217    if ( 'intent-newsletter-goal' !== $intent ) {
1218        return false;
1219    }
1220
1221    return apply_filters( 'wpcom_launchpad_intent_newsletter_goal_enabled', false );
1222}
1223/**
1224 * Add launchpad options to Jetpack Sync.
1225 *
1226 * @param array $allowed_options The allowed options.
1227 */
1228function add_launchpad_options_to_jetpack_sync( $allowed_options ) {
1229    // We are not either in Simple or Atomic
1230    if ( ! class_exists( 'Automattic\Jetpack\Status\Host' ) ) {
1231        return $allowed_options;
1232    }
1233
1234    if ( ! ( new Automattic\Jetpack\Status\Host() )->is_woa_site() ) {
1235        return $allowed_options;
1236    }
1237
1238    if ( ! is_array( $allowed_options ) ) {
1239        return $allowed_options;
1240    }
1241
1242    $launchpad_options = array(
1243        'site_intent',
1244        'launchpad_checklist_tasks_statuses',
1245        'site_goals',
1246        'sm_enabled',
1247    );
1248
1249    return array_merge( $allowed_options, $launchpad_options );
1250}
1251add_filter( 'jetpack_sync_options_whitelist', 'add_launchpad_options_to_jetpack_sync', 10, 1 );
1252
1253/**
1254 * Get the title of a checklist by its slug.
1255 *
1256 * @param string $checklist_slug The slug of the checklist.
1257 * @return string The title of the checklist.
1258 */
1259function wpcom_get_launchpad_checklist_title_by_checklist_slug( $checklist_slug ) {
1260    if ( ! $checklist_slug ) {
1261        return array();
1262    }
1263
1264    return wpcom_launchpad_checklists()->get_task_list_title( $checklist_slug );
1265}
1266
1267/**
1268 * Gets a launchpad config option.
1269 *
1270 * @param string $option The option to get.
1271 * @param mixed  $default The default value to return if the option is not set.
1272 */
1273function wpcom_get_launchpad_config_option( $option, $default = null ) {
1274    $wpcom_launchpad_config = get_option( 'wpcom_launchpad_config', array() );
1275
1276    if ( ! is_array( $wpcom_launchpad_config ) || ! isset( $wpcom_launchpad_config[ $option ] ) ) {
1277        return $default;
1278    }
1279
1280    return $wpcom_launchpad_config[ $option ];
1281}
1282
1283/**
1284 * Sets a launchpad config option.
1285 *
1286 * @param string $option The option to set.
1287 * @param mixed  $value The value to set.
1288 */
1289function wpcom_set_launchpad_config_option( $option, $value ) {
1290    $wpcom_launchpad_config = get_option( 'wpcom_launchpad_config', array() );
1291
1292    $wpcom_launchpad_config[ $option ] = $value;
1293
1294    return update_option( 'wpcom_launchpad_config', $wpcom_launchpad_config );
1295}