Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
62.30% covered (warning)
62.30%
38 / 61
44.44% covered (danger)
44.44%
4 / 9
CRAP
0.00% covered (danger)
0.00%
0 / 1
Users_Connection_Admin
62.30% covered (warning)
62.30%
38 / 61
44.44% covered (danger)
44.44%
4 / 9
44.64
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 init
80.00% covered (warning)
80.00%
4 / 5
0.00% covered (danger)
0.00%
0 / 1
4.13
 add_connection_column
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
2
 render_connection_column
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 1
12
 enqueue_scripts
100.00% covered (success)
100.00%
22 / 22
100.00% covered (success)
100.00%
1 / 1
2
 enqueue_connection_column_styles
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
 add_connection_column_styles
n/a
0 / 0
n/a
0 / 0
1
 get_connection_column_styles
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 get_column_tooltip_text
62.50% covered (warning)
62.50%
5 / 8
0.00% covered (danger)
0.00%
0 / 1
6.32
 get_column_id
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2/**
3 * Handles the WordPress.com account column in the users list table.
4 *
5 * @package automattic/jetpack-connection
6 */
7
8namespace Automattic\Jetpack\Connection;
9
10use Automattic\Jetpack\Assets;
11use Automattic\Jetpack\Status\Host;
12
13/**
14 * Class Users_Connection_Admin
15 */
16class Users_Connection_Admin {
17    /**
18     * The column ID used for the WordPress.com account column.
19     *
20     * @var string
21     */
22    const COLUMN_ID = 'user_jetpack';
23
24    /**
25     * The handle used for the users list table column styles.
26     *
27     * @var string
28     */
29    const STYLE_HANDLE = 'jetpack-connection-users-column';
30
31    /**
32     * Constructor.
33     */
34    public function __construct() {
35        // Only set up hooks if we're in the admin area and user has proper permissions
36        add_action( 'init', array( $this, 'init' ) );
37    }
38
39    /**
40     * Initialize the admin functionality if conditions are met.
41     */
42    public function init() {
43        if ( ! is_admin() || ! current_user_can( 'manage_options' ) || ( new Host() )->is_wpcom_simple() ) {
44            return;
45        }
46
47        add_filter( 'manage_users_columns', array( $this, 'add_connection_column' ) );
48        add_filter( 'manage_users_custom_column', array( $this, 'render_connection_column' ), 9, 3 ); // Priority 9 to run before SSO
49        add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_scripts' ) );
50    }
51
52    /**
53     * Add the connection column to the users list table.
54     *
55     * @param array $columns The current columns.
56     * @return array Modified columns.
57     */
58    public function add_connection_column( $columns ) {
59        $columns[ self::COLUMN_ID ] = sprintf(
60            '<span class="jetpack-connection-tooltip-icon" role="tooltip" tabindex="0" aria-label="%2$s: %1$s">
61                %1$s
62                <span class="jetpack-connection-tooltip"></span>
63            </span>',
64            esc_html__( 'WordPress.com account', 'jetpack-connection' ),
65            esc_attr__( 'Tooltip', 'jetpack-connection' )
66        );
67        return $columns;
68    }
69
70    /**
71     * Render the connection column content.
72     *
73     * @param string $output      Custom column output.
74     * @param string $column_name Column name.
75     * @param int    $user_id     ID of the currently-listed user.
76     * @return string
77     */
78    public function render_connection_column( $output, $column_name, $user_id ) {
79        if ( self::COLUMN_ID !== $column_name ) {
80            return $output;
81        }
82
83        if ( ( new Manager() )->is_user_connected( $user_id ) ) {
84            $logo_url = Jetpack_Connector::get_inline_connector_logo_url();
85
86            return sprintf(
87                '<span title="%1$s" class="jetpack-connection-status"><img src="%2$s" alt="" class="jetpack-connection-status__logo" height="18" decoding="async" loading="lazy" />%3$s</span>',
88                esc_attr__( 'This user has connected their WordPress.com account.', 'jetpack-connection' ),
89                esc_url( $logo_url ),
90                esc_html__( 'Connected', 'jetpack-connection' )
91            );
92        }
93
94        return $output;
95    }
96
97    /**
98     * Enqueue scripts and styles.
99     *
100     * @param string $hook The current admin page.
101     */
102    public function enqueue_scripts( $hook ) {
103        if ( 'users.php' !== $hook ) {
104            return;
105        }
106
107        self::enqueue_connection_column_styles();
108
109        Assets::register_script(
110            'jetpack-users-connection',
111            '../dist/jetpack-users-connection.js',
112            __FILE__,
113            array(
114                'strategy'  => 'defer',
115                'in_footer' => true,
116                'enqueue'   => true,
117                'version'   => Package_Version::PACKAGE_VERSION,
118                'deps'      => array( 'wp-i18n' ),
119
120            )
121        );
122
123        wp_localize_script(
124            'jetpack-users-connection',
125            'jetpackConnectionTooltips',
126            array(
127                'columnTooltip' => esc_html( self::get_column_tooltip_text() ),
128            )
129        );
130    }
131
132    /**
133     * Enqueue the styles for the connection column as inline CSS on a source-less handle.
134     */
135    private static function enqueue_connection_column_styles() {
136        // A request can run several instances of this class, and wp_add_inline_style() appends, so the CSS is added once per handle.
137        if ( ! wp_style_is( self::STYLE_HANDLE, 'registered' ) ) {
138            wp_register_style( self::STYLE_HANDLE, false, array(), Package_Version::PACKAGE_VERSION );
139            wp_add_inline_style( self::STYLE_HANDLE, self::get_connection_column_styles() );
140        }
141        wp_enqueue_style( self::STYLE_HANDLE );
142    }
143
144    /**
145     * Add the styles for the connection column.
146     *
147     * @deprecated 8.12.0 The CSS is enqueued on the `jetpack-connection-users-column` style handle by enqueue_scripts().
148     */
149    public function add_connection_column_styles() {
150        _deprecated_function( __METHOD__, 'connection-8.12.0', __CLASS__ . '::enqueue_scripts' );
151        self::enqueue_connection_column_styles();
152    }
153
154    /**
155     * Get the styles for the connection column.
156     *
157     * @return string CSS rules.
158     */
159    private static function get_connection_column_styles() {
160        return '
161        .jetpack-connection-tooltip-icon {
162            position: relative;
163            cursor: pointer;
164        }
165        /* Add [?] icon using pseudo-element, only in column header */
166        th.manage-column .jetpack-connection-tooltip-icon::after {
167            content: \'[?]\';
168            color: #3c434a;
169            font-size: 1em;
170            margin-left: 4px;
171        }
172        .jetpack-connection-tooltip {
173            position: absolute;
174            background: #f6f7f7;
175            top: -85px;
176            width: 250px;
177            padding: 7px;
178            color: #3c434a;
179            font-size: .75rem;
180            line-height: 17px;
181            text-align: left;
182            margin: 0;
183            display: none;
184            border-radius: 4px;
185            font-family: sans-serif;
186            box-shadow: 5px 10px 10px rgba(0, 0, 0, 0.1);
187            left: -170px;
188        }
189        .column-user_jetpack {
190            width: 190px;
191        }
192        @media screen and (max-width: 1100px) {
193            .column-user_jetpack {
194                width: auto;
195            }
196        }
197        .jetpack-connection-status {
198            display: inline-flex;
199            align-items: center;
200            column-gap: 6px;
201        }
202        .jetpack-connection-status__logo {
203            display: block;
204            flex-shrink: 0;
205        }
206        /* Show tooltip on hover and focus */
207        .jetpack-connection-tooltip-icon:hover .jetpack-connection-tooltip,
208        .jetpack-connection-tooltip-icon:focus-within .jetpack-connection-tooltip {
209            display: block;
210        }
211        ';
212    }
213
214    /**
215     * Build the column header tooltip text based on which plugin families use the connection.
216     *
217     * @return string Tooltip text.
218     */
219    private static function get_column_tooltip_text() {
220        $families = Jetpack_Connector::get_connected_plugin_families();
221
222        if ( $families['has_woo'] && $families['has_a4a'] ) {
223            return __( 'Connecting a WordPress.com account unlocks features for Jetpack, WooCommerce, and Automattic for Agencies including secure logins.', 'jetpack-connection' );
224        }
225
226        if ( $families['has_woo'] ) {
227            return __( 'Connecting a WordPress.com account unlocks features for Jetpack and WooCommerce including secure logins.', 'jetpack-connection' );
228        }
229
230        if ( $families['has_a4a'] ) {
231            return __( 'Connecting a WordPress.com account unlocks features for Jetpack and Automattic for Agencies including secure logins.', 'jetpack-connection' );
232        }
233
234        return __( 'Connecting a WordPress.com account unlocks Jetpack features including secure logins.', 'jetpack-connection' );
235    }
236
237    /**
238     * Get the column ID. Allows other classes to reference the same column.
239     *
240     * @return string
241     */
242    public static function get_column_id() {
243        return self::COLUMN_ID;
244    }
245}