Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
98.46% covered (success)
98.46%
64 / 65
75.00% covered (warning)
75.00%
3 / 4
CRAP
0.00% covered (danger)
0.00%
0 / 1
Notices
98.46% covered (success)
98.46%
64 / 65
75.00% covered (warning)
75.00%
3 / 4
15
0.00% covered (danger)
0.00%
0 / 1
 update_notice
100.00% covered (success)
100.00%
24 / 24
100.00% covered (success)
100.00%
1 / 1
1
 get_notices_to_show
100.00% covered (success)
100.00%
22 / 22
100.00% covered (success)
100.00%
1 / 1
10
 get_notices_from_wpcom
94.12% covered (success)
94.12%
16 / 17
0.00% covered (danger)
0.00%
0 / 1
2.00
 is_notice_hidden
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
2
1<?php
2/**
3 * A class that handles the notices for the Stats Admin dashboard.
4 *
5 * @package automattic/jetpack-stats-admin
6 */
7
8namespace Automattic\Jetpack\Stats_Admin;
9
10use Automattic\Jetpack\Stats\Options as Stats_Options;
11use Jetpack_Options;
12
13/**
14 * The Notices class handles the notices for the Stats Admin dashboard.
15 *
16 * @package Automattic\Jetpack\Stats_Admin
17 */
18class Notices {
19    const STATS_DASHBOARD_NOTICES_CACHE_KEY = 'jetpack_stats_dashboard_notices_cache_key';
20    const OPT_OUT_NEW_STATS_NOTICE_ID       = 'opt_out_new_stats';
21    const NEW_STATS_FEEDBACK_NOTICE_ID      = 'new_stats_feedback';
22    const OPT_IN_NEW_STATS_NOTICE_ID        = 'opt_in_new_stats';
23    const GDPR_COOKIE_CONSENT_NOTICE_ID     = 'gdpr_cookie_consent';
24
25    const VIEWS_TO_SHOW_FEEDBACK      = 3;
26    const POSTPONE_OPT_IN_NOTICE_DAYS = 30;
27
28    /**
29     * Update notice status.
30     *
31     * @param mixed $id ID of the notice.
32     * @param mixed $status Status of the notice.
33     * @param int   $postponed_for Postponed for how many seconds.
34     * @return bool
35     */
36    public function update_notice( $id, $status, $postponed_for = 0 ) {
37        delete_transient( self::STATS_DASHBOARD_NOTICES_CACHE_KEY );
38        return WPCOM_Client::request_as_blog(
39            sprintf(
40                '/sites/%d/jetpack-stats-dashboard/notices',
41                Jetpack_Options::get_option( 'id' )
42            ),
43            'v2',
44            array(
45                'timeout' => 5,
46                'method'  => 'POST',
47                'headers' => array(
48                    'Content-Type' => 'application/json',
49                ),
50            ),
51            wp_json_encode(
52                array(
53                    'id'            => $id,
54                    'status'        => $status,
55                    'postponed_for' => $postponed_for,
56                ),
57                JSON_UNESCAPED_SLASHES
58            ),
59            'wpcom'
60        );
61    }
62
63    /**
64     * Return an array of notices IDs as keys and their value to flag whther to show them.
65     *
66     * @return array
67     */
68    public function get_notices_to_show() {
69        $notices_wpcom = $this->get_notices_from_wpcom();
70
71        $new_stats_enabled        = Stats_Options::get_option( 'enable_odyssey_stats' );
72        $stats_views              = intval( Stats_Options::get_option( 'views' ) );
73        $odyssey_stats_changed_at = intval( Stats_Options::get_option( 'odyssey_stats_changed_at' ) );
74
75        // Check if Jetpack is integrated with the Complianz plugin, which blocks the Stats.
76        $complianz_options_integrations  = get_option( 'complianz_options_integrations' );
77        $is_jetpack_blocked_by_complianz = ! isset( $complianz_options_integrations['jetpack'] ) || $complianz_options_integrations['jetpack'];
78
79        return array_merge(
80            $notices_wpcom,
81            array(
82                // Show Opt-in notice 30 days after the new stats being disabled.
83                self::OPT_IN_NEW_STATS_NOTICE_ID    => ! $new_stats_enabled
84                    && $odyssey_stats_changed_at < time() - self::POSTPONE_OPT_IN_NOTICE_DAYS * DAY_IN_SECONDS
85                    && ! $this->is_notice_hidden( self::OPT_IN_NEW_STATS_NOTICE_ID ),
86
87                // Show feedback notice after 3 views of the new stats.
88                self::NEW_STATS_FEEDBACK_NOTICE_ID  => $new_stats_enabled
89                    && $stats_views >= self::VIEWS_TO_SHOW_FEEDBACK
90                    && ! $this->is_notice_hidden( self::NEW_STATS_FEEDBACK_NOTICE_ID ),
91
92                // Show opt-out notice before 3 views of the new stats, where 3 is included.
93                self::OPT_OUT_NEW_STATS_NOTICE_ID   => $new_stats_enabled
94                    && $stats_views < self::VIEWS_TO_SHOW_FEEDBACK
95                    && ! $this->is_notice_hidden( self::OPT_OUT_NEW_STATS_NOTICE_ID ),
96
97                // GDPR cookie consent notice for Complianz users.
98                self::GDPR_COOKIE_CONSENT_NOTICE_ID => class_exists( 'COMPLIANZ' ) && $is_jetpack_blocked_by_complianz
99                    && ! $this->is_notice_hidden( self::GDPR_COOKIE_CONSENT_NOTICE_ID ),
100            )
101        );
102    }
103
104    /**
105     * Get the array of hidden notices from WPCOM.
106     */
107    public function get_notices_from_wpcom() {
108        $notices_wpcom = WPCOM_Client::request_as_blog_cached(
109            sprintf(
110                '/sites/%d/jetpack-stats-dashboard/notices',
111                Jetpack_Options::get_option( 'id' )
112            ),
113            'v2',
114            array(
115                'timeout' => 5,
116            ),
117            null,
118            'wpcom',
119            true,
120            static::STATS_DASHBOARD_NOTICES_CACHE_KEY
121        );
122
123        if ( is_wp_error( $notices_wpcom ) ) {
124            return array();
125        }
126        return $notices_wpcom;
127    }
128
129    /**
130     * Checks if a notice is hidden.
131     *
132     * @param mixed $id ID of the notice.
133     * @return bool
134     */
135    public function is_notice_hidden( $id ) {
136        $notices_wpcom = $this->get_notices_from_wpcom();
137        return array_key_exists( $id, $notices_wpcom ) && $notices_wpcom[ $id ] === false;
138    }
139}