Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
89.19% covered (warning)
89.19%
33 / 37
75.00% covered (warning)
75.00%
3 / 4
CRAP
n/a
0 / 0
wpcom_editor_welcome_guides_is_enabled
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
wpcom_editor_welcome_guides_meta_key
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
wpcom_editor_welcome_guides_filter_preferences
100.00% covered (success)
100.00%
20 / 20
100.00% covered (success)
100.00%
1 / 1
12
wpcom_editor_welcome_guides_record_preferences
100.00% covered (success)
100.00%
12 / 12
100.00% covered (success)
100.00%
1 / 1
13
1<?php
2/**
3 * Once-per-user editor welcome guides: merges the guides WordPress.com records as dismissed
4 * for the user into each site's editor preferences, and reports newly dismissed ones back.
5 *
6 * @package automattic/jetpack-mu-wpcom
7 */
8
9declare( strict_types = 1 );
10
11/**
12 * Whether the feature is enabled for the current site.
13 *
14 * @return bool
15 */
16function wpcom_editor_welcome_guides_is_enabled(): bool {
17    return wpcom_has_blog_sticker( 'editor-welcome-guides-per-user', get_wpcom_blog_id() );
18}
19
20/**
21 * The current site's editor preferences meta key.
22 *
23 * @return string
24 */
25function wpcom_editor_welcome_guides_meta_key(): string {
26    global $wpdb;
27
28    return $wpdb->get_blog_prefix() . 'persisted_preferences';
29}
30
31/**
32 * When the editor preferences are read, marks the guides the user already dismissed
33 * on another site as dismissed on this one too.
34 *
35 * @param mixed  $value    Value another filter already supplied, or null.
36 * @param int    $user_id  User ID.
37 * @param string $meta_key Meta key being read.
38 * @return mixed The adjusted preferences wrapped in an array, or `$value` unchanged.
39 */
40function wpcom_editor_welcome_guides_filter_preferences( $value, $user_id, $meta_key ) {
41    static $is_reading = false;
42
43    if ( null !== $value || $is_reading || wpcom_editor_welcome_guides_meta_key() !== $meta_key || ! wpcom_editor_welcome_guides_is_enabled() ) {
44        return $value;
45    }
46
47    /**
48     * Filters the guides the user has dismissed on any site.
49     *
50     * @param array $dismissed Map of preferences scope to guide keys.
51     * @param int   $user_id   User ID.
52     */
53    $dismissed = apply_filters( 'wpcom_editor_welcome_guides_dismissed', array(), $user_id );
54    if ( empty( $dismissed ) || ! is_array( $dismissed ) ) {
55        return $value;
56    }
57
58    $is_reading  = true;
59    $preferences = get_user_meta( $user_id, $meta_key, true );
60    $is_reading  = false;
61
62    if ( ! is_array( $preferences ) ) {
63        $preferences = array();
64    }
65
66    $changed = false;
67    foreach ( $dismissed as $scope => $guides ) {
68        foreach ( (array) $guides as $guide ) {
69            if ( false !== ( $preferences[ $scope ][ $guide ] ?? null ) ) {
70                $preferences[ $scope ][ $guide ] = false;
71                $changed                         = true;
72            }
73        }
74    }
75
76    if ( $changed ) {
77        // Newer than the browser's localStorage copy, so the editor uses this one.
78        $preferences['_modified'] = gmdate( 'Y-m-d\TH:i:s.v\Z' );
79    }
80
81    // get_user_meta( $user_id, $meta_key, true ) returns the first element of a filtered array,
82    // so without this wrap the editor would get $preferences[0], which does not exist.
83    return array( $preferences );
84}
85add_filter( 'get_user_metadata', 'wpcom_editor_welcome_guides_filter_preferences', 1, 3 );
86
87/**
88 * Reports the guides turned off in the editor preferences just saved.
89 *
90 * @param int    $meta_id  Meta ID.
91 * @param int    $user_id  User ID.
92 * @param string $meta_key Meta key.
93 * @param mixed  $value    Meta value.
94 * @return void
95 */
96function wpcom_editor_welcome_guides_record_preferences( $meta_id, $user_id, $meta_key, $value ) {
97    if ( wpcom_editor_welcome_guides_meta_key() !== $meta_key || ! is_array( $value ) || ! wpcom_editor_welcome_guides_is_enabled() ) {
98        return;
99    }
100
101    $dismissed = array();
102    foreach ( $value as $scope => $preferences ) {
103        if ( ! is_string( $scope ) || ! str_starts_with( $scope, 'core/' ) || ! is_array( $preferences ) ) {
104            continue;
105        }
106
107        foreach ( $preferences as $key => $preference ) {
108            if ( is_string( $key ) && str_starts_with( $key, 'welcomeGuide' ) && false === $preference ) {
109                $dismissed[ $scope ][] = $key;
110            }
111        }
112    }
113
114    if ( empty( $dismissed ) ) {
115        return;
116    }
117
118    /**
119     * Fires when the user has turned welcome guides off.
120     *
121     * @param int   $user_id   User ID.
122     * @param array $dismissed Map of preferences scope to guide keys.
123     */
124    do_action( 'wpcom_editor_welcome_guides_dismiss', $user_id, $dismissed );
125}
126add_action( 'added_user_meta', 'wpcom_editor_welcome_guides_record_preferences', 10, 4 );
127add_action( 'updated_user_meta', 'wpcom_editor_welcome_guides_record_preferences', 10, 4 );