PluginProbe
Jetpack – WP Security, Backup, Speed, & Growth / 16.3
Jetpack – WP Security, Backup, Speed, & Growth v16.3
16.3 16.3-beta 16.3-a.5 16.3-a.7 16.3-a.3 16.3-a.1 16.2 16.2-beta 12.0.3 12.1.3 12.2.3 12.3.2 12.4.2 12.5.2 12.6.4 12.7.3 12.8.3 12.9.5 13.0.2 13.1.5 13.2.4 13.3.3 13.4.5 13.5.2 13.6.2 All 508 releases
← All changes | jetpack_vendor/automattic/jetpack-connection/src/sso/class-user-admin.php +169 -155 13.5.2 → 16.3 View file →
@@ -10,8 +10,9 @@
10 10 use Automattic\Jetpack\Assets;
11 11 use Automattic\Jetpack\Connection\Client;
12 12 use Automattic\Jetpack\Connection\Manager;
13 13 use Automattic\Jetpack\Connection\Package_Version;
14 +use Automattic\Jetpack\Connection\Users_Connection_Admin as Base_Admin;
14 15 use Automattic\Jetpack\Roles;
15 16 use Automattic\Jetpack\Status\Host;
16 17 use Automattic\Jetpack\Tracking;
17 18 use WP_Error;
@@ -17,12 +18,18 @@
17 18 use WP_Error;
18 19 use WP_User;
19 20 use WP_User_Query;
20 21
22 +if ( ! defined( 'ABSPATH' ) ) {
23 + exit( 0 );
24 +}
25 +
21 26 /**
22 27 * Jetpack sso user admin class.
28 + *
29 + * @phan-constructor-used-for-side-effects
23 30 */
24 -class User_Admin {
31 +class User_Admin extends Base_Admin {
25 32 /**
26 33 * Instance of WP_User_Query.
27 34 *
28 35 * @var $user_search
@@ -55,18 +62,21 @@
55 62 add_action( 'user_new_form', array( $this, 'render_wpcom_external_user_checkbox' ), 1 );
56 63 add_action( 'user_new_form', array( $this, 'render_custom_email_message_form_field' ), 1 );
57 64 add_action( 'delete_user_form', array( $this, 'render_invitations_notices_for_deleted_users' ) );
58 65 add_action( 'delete_user', array( $this, 'revoke_user_invite' ) );
59 - add_filter( 'manage_users_columns', array( $this, 'jetpack_user_connected_th' ) );
60 66 add_filter( 'manage_users_custom_column', array( $this, 'jetpack_show_connection_status' ), 10, 3 );
61 67 add_action( 'user_row_actions', array( $this, 'jetpack_user_table_row_actions' ), 10, 2 );
62 - add_action( 'admin_notices', array( $this, 'handle_invitation_results' ) );
68 +
69 + if ( isset( $_GET['jetpack-sso-invite-user'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
70 + add_action( 'admin_notices', array( $this, 'handle_invitation_results' ) );
71 + }
72 +
63 73 add_action( 'admin_post_jetpack_invite_user_to_wpcom', array( $this, 'invite_user_to_wpcom' ) );
64 74 add_action( 'admin_post_jetpack_revoke_invite_user_to_wpcom', array( $this, 'handle_request_revoke_invite' ) );
65 75 add_action( 'admin_post_jetpack_resend_invite_user_to_wpcom', array( $this, 'handle_request_resend_invite' ) );
66 - add_action( 'admin_print_styles-users.php', array( $this, 'jetpack_user_table_styles' ) );
67 76 add_filter( 'users_list_table_query_args', array( $this, 'set_user_query' ), 100, 1 );
68 77 add_action( 'admin_print_styles-user-new.php', array( $this, 'jetpack_new_users_styles' ) );
78 + add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_scripts' ) );
69 79
70 80 self::$tracking = new Tracking();
71 81 }
72 82
@@ -101,8 +111,9 @@
101 111 /**
102 112 * Revokes WordPress.com invitation.
103 113 *
104 114 * @param int $user_id The user ID.
115 + * @return mixed Response from the API call or false on failure.
105 116 */
106 117 public function revoke_user_invite( $user_id ) {
107 118 try {
108 119 $has_pending_invite = self::has_pending_wpcom_invite( $user_id );
@@ -782,9 +793,9 @@
782 793 name="user_external_contractor"
783 794 type="checkbox"
784 795 id="user_external_contractor"
785 796 >
786 - <?php esc_html_e( 'This user is a contractor, freelancer, consultant, or agency.', 'jetpack-connection' ); ?>
797 + <?php esc_html_e( 'Mark as external collaborator', 'jetpack-connection' ); ?>
787 798 </label>
788 799 </fieldset>
789 800 </td>
790 801 </tr>
@@ -969,45 +980,8 @@
969 980 return $errors;
970 981 }
971 982
972 983 /**
973 - * Adds a column in the user admin table to display user connection status and actions.
974 - *
975 - * @param array $columns User list table columns.
976 - *
977 - * @return array
978 - */
979 - public function jetpack_user_connected_th( $columns ) {
980 - Assets::register_script(
981 - 'jetpack-sso-users',
982 - '../../dist/jetpack-sso-users.js',
983 - __FILE__,
984 - array(
985 - 'strategy' => 'defer',
986 - 'in_footer' => true,
987 - 'enqueue' => true,
988 - 'version' => Package_Version::PACKAGE_VERSION,
989 - )
990 - );
991 -
992 - $tooltip_string = esc_attr__( 'Jetpack SSO allows a seamless and secure experience on WordPress.com. Join millions of WordPress users who trust us to keep their accounts safe.', 'jetpack-connection' );
993 -
994 - wp_add_inline_script(
995 - 'jetpack-sso-users',
996 - "var Jetpack_SSOTooltip = { 'tooltipString': '{$tooltip_string}' }",
997 - 'before'
998 - );
999 -
1000 - $columns['user_jetpack'] = sprintf(
1001 - '<span class="jetpack-sso-invitation-tooltip-icon jetpack-sso-status-column" role="tooltip" aria-label="%3$s: %1$s" tabindex="0">%2$s</span>',
1002 - $tooltip_string,
1003 - esc_html__( 'SSO Status', 'jetpack-connection' ),
1004 - esc_attr__( 'Tooltip', 'jetpack-connection' )
1005 - );
1006 - return $columns;
1007 - }
1008 -
1009 - /**
1010 984 * Executed when our WP_User_Query instance is set, and we don't have cached invites.
1011 985 * This function uses the user emails and the 'are-users-invited' endpoint to build the cache.
1012 986 *
1013 987 * @return void
@@ -1097,10 +1071,14 @@
1097 1071 *
1098 1072 * @return false|string returns the user invite code if the user is invited, false otherwise.
1099 1073 */
1100 1074 private static function has_pending_wpcom_invite( $user_id ) {
1075 + $user = get_user_by( 'id', $user_id );
1076 + if ( ! $user instanceof \WP_User ) {
1077 + return false;
1078 + }
1079 +
1101 1080 $blog_id = Manager::get_site_id( true );
1102 - $user = get_user_by( 'id', $user_id );
1103 1081 $cached_invite = self::get_pending_cached_wpcom_invite( $user->user_email );
1104 1082
1105 1083 if ( $cached_invite ) {
1106 1084 return $cached_invite['invite_code'];
@@ -1174,55 +1152,53 @@
1174 1152 *
1175 1153 * @param string $val HTML for the column.
1176 1154 * @param string $col User list table column.
1177 1155 * @param int $user_id User ID.
1178 - *
1179 - * @return string
1156 + * @return string Modified column content.
1180 1157 */
1181 1158 public function jetpack_show_connection_status( $val, $col, $user_id ) {
1182 - if ( 'user_jetpack' === $col ) {
1183 - if ( ( new Manager() )->is_user_connected( $user_id ) ) {
1184 - $connection_html = sprintf(
1185 - '<span title="%1$s" class="jetpack-sso-invitation">%2$s</span>',
1186 - esc_attr__( 'This user is connected and can log-in to this site.', 'jetpack-connection' ),
1187 - esc_html__( 'Connected', 'jetpack-connection' )
1159 + if ( 'user_jetpack' !== $col ) {
1160 + return $val;
1161 + }
1162 +
1163 + // Get base connection status from parent
1164 + $connection_status = parent::render_connection_column( '', $col, $user_id );
1165 +
1166 + // If user is not connected, check for pending invite
1167 + if ( ! $connection_status ) {
1168 + $has_pending_invite = self::has_pending_wpcom_invite( $user_id );
1169 + if ( $has_pending_invite ) {
1170 + return sprintf(
1171 + '<span title="%1$s" class="jetpack-sso-invitation sso-pending-invite">%2$s</span>',
1172 + esc_attr__( 'This user didn&#8217;t accept the invitation to join this site yet.', 'jetpack-connection' ),
1173 + esc_html__( 'Pending invite', 'jetpack-connection' )
1188 1174 );
1189 - return $connection_html;
1190 - } else {
1191 - $has_pending_invite = self::has_pending_wpcom_invite( $user_id );
1192 - if ( $has_pending_invite ) {
1193 - $connection_html = sprintf(
1194 - '<span title="%1$s" class="jetpack-sso-invitation sso-pending-invite">%2$s</span>',
1195 - esc_attr__( 'This user didn&#8217;t accept the invitation to join this site yet.', 'jetpack-connection' ),
1196 - esc_html__( 'Pending invite', 'jetpack-connection' )
1197 - );
1198 - return $connection_html;
1199 - }
1200 - $nonce = wp_create_nonce( 'jetpack-sso-invite-user' );
1201 - $connection_html = sprintf(
1202 - // Using formmethod and formaction because we can't nest forms and have to submit using the main form.
1203 - '<span tabindex="0" role="tooltip" aria-label="%4$s: %3$s" class="jetpack-sso-invitation-tooltip-icon sso-disconnected-user">
1204 - <a href="%1$s" class="jetpack-sso-invitation sso-disconnected-user">%2$s</a>
1205 - <span class="sso-disconnected-user-icon dashicons dashicons-warning">
1206 - <span class="jetpack-sso-invitation-tooltip jetpack-sso-td-tooltip">%3$s</span>
1207 - </span>
1208 - </span>',
1209 - add_query_arg(
1210 - array(
1211 - 'user_id' => $user_id,
1212 - 'invite_nonce' => $nonce,
1213 - 'action' => 'jetpack_invite_user_to_wpcom',
1214 - ),
1215 - admin_url( 'admin-post.php' )
1175 + }
1176 +
1177 + // Show invite button for non-connected users
1178 + $nonce = wp_create_nonce( 'jetpack-sso-invite-user' );
1179 + return sprintf(
1180 + '<span tabindex="0" role="tooltip" aria-label="%4$s: %3$s" class="jetpack-sso-invitation-tooltip-icon sso-disconnected-user">
1181 + <span class="sso-disconnected-user-icon dashicons dashicons-warning">
1182 + <span class="jetpack-sso-invitation-tooltip jetpack-sso-td-tooltip">%3$s</span>
1183 + </span>
1184 + <a href="%1$s" class="jetpack-sso-invitation sso-disconnected-user">%2$s</a>
1185 + </span>',
1186 + add_query_arg(
1187 + array(
1188 + 'user_id' => $user_id,
1189 + 'invite_nonce' => $nonce,
1190 + 'action' => 'jetpack_invite_user_to_wpcom',
1216 1191 ),
1217 - esc_html__( 'Send invite', 'jetpack-connection' ),
1218 - esc_attr__( 'This user doesn&#8217;t have an SSO connection to WordPress.com. Invite them to the site to increase security and improve their experience.', 'jetpack-connection' ),
1219 - esc_attr__( 'Tooltip', 'jetpack-connection' )
1220 - );
1221 - return $connection_html;
1222 - }
1192 + admin_url( 'admin-post.php' )
1193 + ),
1194 + esc_html__( 'Send invite', 'jetpack-connection' ),
1195 + esc_attr__( 'This user doesn&#8217;t have a Jetpack SSO connection to WordPress.com. Invite them to the site to increase security and improve their experience.', 'jetpack-connection' ),
1196 + esc_attr__( 'Tooltip', 'jetpack-connection' )
1197 + );
1223 1198 }
1224 - return $val;
1199 +
1200 + return $connection_status;
1225 1201 }
1226 1202
1227 1203 /**
1228 1204 * Creates error notices and redirects the user to the previous page.
@@ -1227,8 +1203,9 @@
1227 1203 /**
1228 1204 * Creates error notices and redirects the user to the previous page.
1229 1205 *
1230 1206 * @param array $query_params - query parameters added to redirection URL.
1207 + * @phan-suppress PhanPluginNeverReturnMethod
1231 1208 */
1232 1209 public function create_error_notice_and_redirect( $query_params ) {
1233 1210 $ref = wp_get_referer();
1234 1211 if ( empty( $ref ) ) {
@@ -1238,85 +1215,122 @@
1238 1215 $url = add_query_arg(
1239 1216 $query_params,
1240 1217 $ref
1241 1218 );
1242 - return wp_safe_redirect( $url );
1219 + wp_safe_redirect( $url );
1220 + exit;
1243 1221 }
1244 1222
1245 1223 /**
1246 - * Style the Jetpack user rows and columns.
1224 + * Enqueue the styles for the Jetpack user rows and columns.
1247 1225 */
1248 1226 public function jetpack_user_table_styles() {
1249 - ?>
1250 - <style>
1251 - #the-list tr:has(.sso-disconnected-user) {
1252 - background: #F5F1E1;
1227 + $handle = 'jetpack-sso-users-styles';
1228 +
1229 + // No src: the handle only carries the inline CSS below.
1230 + wp_register_style( $handle, false, array(), Package_Version::PACKAGE_VERSION );
1231 + wp_enqueue_style( $handle );
1232 +
1233 + $css = <<<'CSS'
1234 +#the-list tr:has(.sso-disconnected-user) {
1235 + background: #F5F1E1;
1236 +}
1237 +
1238 +#the-list tr:has(.sso-pending-invite) {
1239 + background: #E9F0F5;
1240 +}
1241 +
1242 +.jetpack-sso-invitation {
1243 + background: none;
1244 + border: none;
1245 + color: #50575e;
1246 + padding: 0;
1247 + text-align: unset;
1248 +}
1249 +
1250 +.jetpack-sso-invitation.sso-disconnected-user {
1251 + color: #0073aa;
1252 + cursor: pointer;
1253 + text-decoration: underline;
1254 +}
1255 +
1256 +.jetpack-sso-invitation.sso-disconnected-user:hover,
1257 +.jetpack-sso-invitation.sso-disconnected-user:focus,
1258 +.jetpack-sso-invitation.sso-disconnected-user:active {
1259 + color: #0096dd;
1260 +}
1261 +
1262 +.sso-disconnected-user-icon {
1263 + cursor: pointer;
1264 + background: gray;
1265 + border-radius: 10px;
1266 +}
1267 +
1268 +.sso-disconnected-user-icon.dashicons {
1269 + font-size: 1rem;
1270 + height: 1rem;
1271 + width: 1rem;
1272 + background-color: #9D6E00;
1273 + color: #F5F1E1;
1274 +}
1275 +
1276 +.jetpack-sso-invitation-tooltip-icon {
1277 + position: relative;
1278 + cursor: pointer;
1279 + display: inline-flex;
1280 + align-items: center;
1281 + column-gap: 6px;
1282 +}
1283 +
1284 +.jetpack-sso-td-tooltip {
1285 + left: -256px;
1286 +}
1287 +
1288 +.jetpack-sso-invitation-tooltip {
1289 + position: absolute;
1290 + background: #f6f7f7;
1291 + top: -85px;
1292 + width: 250px;
1293 + padding: 7px;
1294 + color: #3c434a;
1295 + font-size: .75rem;
1296 + line-height: 17px;
1297 + text-align: left;
1298 + margin: 0;
1299 + display: none;
1300 + border-radius: 4px;
1301 + font-family: sans-serif;
1302 + box-shadow: 5px 10px 10px rgba(0, 0, 0, 0.1);
1303 +}
1304 +CSS;
1305 +
1306 + wp_add_inline_style( $handle, $css );
1307 + }
1308 +
1309 + /**
1310 + * Enqueue SSO-specific scripts.
1311 + *
1312 + * @param string $hook The current admin page.
1313 + */
1314 + public function enqueue_scripts( $hook ) {
1315 + if ( 'users.php' !== $hook ) {
1316 + return;
1253 1317 }
1254 - #the-list tr:has(.sso-pending-invite) {
1255 - background: #E9F0F5;
1256 - }
1257 - .fixed .column-user_jetpack {
1258 - width: 100px;
1259 - }
1260 - .jetpack-sso-invitation {
1261 - background: none;
1262 - border: none;
1263 - color: #50575e;
1264 - padding: 0;
1265 - text-align: unset;
1266 - }
1267 - .jetpack-sso-invitation.sso-disconnected-user {
1268 - color: #0073aa;
1269 - cursor: pointer;
1270 - text-decoration: underline;
1271 - }
1272 - .jetpack-sso-invitation.sso-disconnected-user:hover,
1273 - .jetpack-sso-invitation.sso-disconnected-user:focus,
1274 - .jetpack-sso-invitation.sso-disconnected-user:active {
1275 - color: #0096dd;
1276 - }
1277 1318
1278 - .sso-disconnected-user-icon {
1279 - margin-left: 4px;
1280 - cursor: pointer;
1281 - background: gray;
1282 - border-radius: 10px;
1283 - }
1319 + parent::enqueue_scripts( $hook );
1284 1320
1285 - .sso-disconnected-user-icon.dashicons {
1286 - font-size: 1rem;
1287 - height: 1rem;
1288 - width: 1rem;
1289 - background-color: #9D6E00;
1290 - color: #F5F1E1;
1291 - }
1292 - .jetpack-sso-invitation-tooltip-icon{
1293 - position: relative;
1294 - cursor: pointer;
1295 - }
1296 - .jetpack-sso-th-tooltip {
1297 - left: -170px;
1298 - }
1299 - .jetpack-sso-td-tooltip {
1300 - left: -256px;
1301 - }
1302 - .jetpack-sso-invitation-tooltip {
1303 - position: absolute;
1304 - background: #f6f7f7;
1305 - top: -85px;
1306 - width: 250px;
1307 - padding: 7px;
1308 - color: #3c434a;
1309 - font-size: .75rem;
1310 - line-height: 17px;
1311 - text-align: left;
1312 - margin: 0;
1313 - display: none;
1314 - border-radius: 4px;
1315 - font-family: sans-serif;
1316 - box-shadow: 5px 10px 10px rgba(0, 0, 0, 0.1);
1317 - }
1321 + $this->jetpack_user_table_styles();
1318 1322
1319 - </style>
1320 - <?php
1323 + // Enqueue the SSO users script.
1324 + Assets::register_script(
1325 + 'jetpack-sso-users',
1326 + '../../dist/jetpack-sso-users.js',
1327 + __FILE__,
1328 + array(
1329 + 'strategy' => 'defer',
1330 + 'in_footer' => true,
1331 + 'enqueue' => true,
1332 + 'version' => Package_Version::PACKAGE_VERSION,
1333 + )
1334 + );
1321 1335 }
1322 1336 }