Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
90.74% covered (success)
90.74%
49 / 54
60.00% covered (warning)
60.00%
3 / 5
CRAP
0.00% covered (danger)
0.00%
0 / 1
Pre_Connection_JITM
92.31% covered (success)
92.31%
48 / 52
60.00% covered (warning)
60.00%
3 / 5
18.15
0.00% covered (danger)
0.00%
0 / 1
 filter_messages
100.00% covered (success)
100.00%
22 / 22
100.00% covered (success)
100.00%
1 / 1
3
 validate_messages
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
4
 get_message_icon
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
3
 get_messages
85.71% covered (warning)
85.71%
12 / 14
0.00% covered (danger)
0.00%
0 / 1
7.14
 dismiss
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2/**
3 * Jetpack's Pre-Connection JITM class.
4 *
5 * @package automattic/jetpack-jitm
6 */
7
8namespace Automattic\Jetpack\JITMS;
9
10if ( ! defined( 'ABSPATH' ) ) {
11    exit( 0 );
12}
13
14/**
15 * Jetpack pre-connection just in time messaging through out the admin.
16 */
17class Pre_Connection_JITM extends JITM {
18
19    /**
20     * Filters and formats the messages for the client-side JS renderer
21     *
22     * @param string $message_path Current message path.
23     *
24     * @return array Formatted messages.
25     */
26    private function filter_messages( $message_path ) {
27        /**
28         * Allows filtering of the pre-connection JITMs.
29         *
30         * This filter allows plugins to add pre-connection JITMs that will be
31         * displayed by the JITM package.
32         *
33         * @since 1.14.1
34         *
35         * @param array An array of pre-connection messages.
36         */
37        $messages = apply_filters( 'jetpack_pre_connection_jitms', array() );
38
39        $messages = $this->validate_messages( $messages );
40
41        $formatted_messages = array();
42
43        foreach ( $messages as $message ) {
44            if ( ! preg_match( $message['message_path'], $message_path ) ) {
45                continue;
46            }
47
48            $obj                 = new \stdClass();
49            $obj->CTA            = array( // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
50                'message'   => $message['button_caption'],
51                'newWindow' => false,
52            );
53            $obj->url            = $message['button_link'];
54            $obj->id             = $message['id'];
55            $obj->is_dismissible = true;
56            $obj->content        = array(
57                'message'     => $message['message'],
58                'description' => $message['description'],
59                'list'        => array(),
60                'icon'        => $this->get_message_icon( $message ),
61            );
62
63            $formatted_messages[] = $obj;
64        }
65
66        return $formatted_messages;
67    }
68
69    /**
70     * Validates that each of the messages contains all of the required keys:
71     *   - id
72     *   - message_path
73     *   - message
74     *   - description
75     *   - button_link
76     *   - button_caption
77     *
78     * @param array $messages An array of JITM messages.
79     *
80     * @return array An array of JITM messages that contain all of the required keys.
81     */
82    private function validate_messages( $messages ) {
83        if ( ! is_array( $messages ) ) {
84            return array();
85        }
86
87        $expected_keys = array_flip( array( 'id', 'message_path', 'message', 'description', 'button_link', 'button_caption' ) );
88
89        foreach ( $messages as $index => $message ) {
90            if ( count( array_intersect_key( $expected_keys, $message ) ) !== count( $expected_keys ) ) {
91                // Remove any messages that are missing expected keys.
92                unset( $messages[ $index ] );
93            }
94        }
95
96        return $messages;
97    }
98
99    /**
100     * Get the icon for the message.
101     *
102     * The message may contain an 'icon' key. If the value of the 'icon' key matches a supported icon (or empty string), the value is used.
103     * If the message does not contain an icon key or if the value does not match a supported icon, the Jetpack icon is used by default.
104     *
105     * @param array $message A pre-connection JITM.
106     *
107     * @return string The icon to use in the JITM.
108     */
109    private function get_message_icon( $message ) {
110        // Default to the Jetpack icon.
111        $icon = 'jetpack';
112
113        if ( ! isset( $message['icon'] ) ) {
114            return $icon;
115        }
116
117        $supported_icons = $this->get_supported_icons();
118
119        if ( in_array( $message['icon'], $supported_icons, true ) ) {
120            // Only use the message icon if it's a supported icon or an empty string (for no icon).
121            $icon = $message['icon'];
122        }
123
124        return $icon;
125    }
126
127    /**
128     * Retrieve the current message to display keyed on query string and message path
129     *
130     * @param string $message_path The message path to ask for.
131     * @param array  $query Query parameters as an associative array. Unused in this subclass.
132     * @param bool   $full_jp_logo_exists If there is a full Jetpack logo already on the page.
133     *
134     * @return array The JITMs to show, or an empty array if there is nothing to show
135     */
136    public function get_messages( $message_path, $query, $full_jp_logo_exists ) {
137        // Ensure only admins see pre-connection JITMs since only they can connect to WordPress.com
138        // and enable modules.
139        if ( ! current_user_can( 'install_plugins' ) ) {
140            return array();
141        }
142
143        $messages = $this->filter_messages( $message_path );
144
145        if ( empty( $messages ) ) {
146            return array();
147        }
148
149        $hidden_jitms = \Jetpack_Options::get_option( 'hide_jitm' );
150
151        foreach ( $messages as $idx => &$envelope ) {
152            $dismissed_feature = isset( $hidden_jitms[ 'pre-connection-' . $envelope->id ] ) &&
153                is_array( $hidden_jitms[ 'pre-connection-' . $envelope->id ] ) ? $hidden_jitms[ 'pre-connection-' . $envelope->id ] : null;
154
155            if ( is_array( $dismissed_feature ) ) {
156                unset( $messages[ $idx ] );
157                continue;
158            }
159
160            $envelope->content['icon'] = $this->generate_icon( $envelope->content['icon'], $full_jp_logo_exists );
161        }
162
163        return $messages;
164    }
165
166    /**
167     * Dismisses a JITM ID so that it will no longer be shown.
168     *
169     * @param string $id The id of the JITM that was dismissed.
170     *
171     * @return bool Always true
172     */
173    public function dismiss( $id ) {
174        $this->save_dismiss( 'pre-connection-' . $id );
175        return true;
176    }
177}