PluginProbe
Jetpack – WP Security, Backup, Speed, & Growth / 16.2
Jetpack – WP Security, Backup, Speed, & Growth v16.2
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 13.7.2 13.8.3 All 506 releases
jetpack / jetpack_vendor / automattic / jetpack-connection / src / class-connection-notice.php

class-connection-notice.php in Jetpack – WP Security, Backup, Speed, & Growth 16.2, at jetpack_vendor/automattic/jetpack-connection/src/class-connection-notice.php

270 lines 8.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Admin connection notices.
4 *
5 * @package automattic/jetpack-admin-ui
6 */
7
8 namespace Automattic\Jetpack\Connection;
9
10 use Automattic\Jetpack\Redirect;
11 use Automattic\Jetpack\Tracking;
12
13 /**
14 * Admin connection notices.
15 *
16 * @phan-constructor-used-for-side-effects
17 */
18 class Connection_Notice {
19
20 /**
21 * Whether the class has been initialized.
22 *
23 * @var bool
24 */
25 private static $is_initialized = false;
26
27 /**
28 * The constructor.
29 */
30 public function __construct() {
31 if ( ! static::$is_initialized ) {
32 add_action( 'current_screen', array( $this, 'initialize_notices' ) );
33 static::$is_initialized = true;
34 }
35 }
36
37 /**
38 * Initialize the notices if needed.
39 *
40 * @param \WP_Screen $screen WP Core's screen object.
41 *
42 * @return void
43 */
44 public function initialize_notices( $screen ) {
45 if ( in_array(
46 $screen->id,
47 array(
48 'jetpack_page_akismet-key-config',
49 'admin_page_jetpack_modules',
50 ),
51 true
52 ) ) {
53 return;
54 }
55
56 /*
57 * phpcs:disable WordPress.Security.NonceVerification.Recommended
58 *
59 * This function is firing within wp-admin and checks (below) if it is in the midst of a deletion on the users
60 * page. Nonce will be already checked by WordPress, so we do not need to check ourselves.
61 */
62
63 if ( isset( $screen->base ) && 'users' === $screen->base
64 && isset( $_REQUEST['action'] ) && 'delete' === $_REQUEST['action']
65 ) {
66 add_action( 'admin_notices', array( $this, 'delete_user_update_connection_owner_notice' ) );
67 }
68 }
69
70 /**
71 * This is an entire admin notice dedicated to messaging and handling of the case where a user is trying to delete
72 * the connection owner.
73 */
74 public function delete_user_update_connection_owner_notice() {
75 // Get connection owner or bail.
76 $connection_manager = new Manager();
77 $connection_owner_id = $connection_manager->get_connection_owner_id();
78 if ( ! $connection_owner_id ) {
79 return;
80 }
81 $connection_owner_userdata = get_userdata( $connection_owner_id );
82
83 // Bail if we're not trying to delete connection owner.
84 $user_ids_to_delete = array();
85 if ( isset( $_REQUEST['users'] ) ) {
86 $user_ids_to_delete = array_map( 'sanitize_text_field', wp_unslash( $_REQUEST['users'] ) );
87 } elseif ( isset( $_REQUEST['user'] ) ) {
88 $user_ids_to_delete[] = sanitize_text_field( wp_unslash( $_REQUEST['user'] ) );
89 }
90
91 // phpcs:enable
92 $user_ids_to_delete = array_map( 'absint', $user_ids_to_delete );
93 $deleting_connection_owner = in_array( $connection_owner_id, (array) $user_ids_to_delete, true );
94 if ( ! $deleting_connection_owner ) {
95 return;
96 }
97
98 // Bail if they're trying to delete themselves to avoid confusion.
99 if ( get_current_user_id() === $connection_owner_id ) {
100 return;
101 }
102
103 $tracking = new Tracking();
104
105 // Track it!
106 if ( method_exists( $tracking, 'record_user_event' ) ) {
107 $tracking->record_user_event( 'delete_connection_owner_notice_view' );
108 }
109
110 $connected_admins = $connection_manager->get_connected_users( 'jetpack_disconnect' );
111 $user = is_a( $connection_owner_userdata, 'WP_User' ) ? esc_html( $connection_owner_userdata->data->user_login ) : '';
112
113 echo "<div class='notice notice-warning' id='jetpack-notice-switch-connection-owner'>";
114 echo '<h2>' . esc_html__( 'Important notice about your Jetpack connection:', 'jetpack-connection' ) . '</h2>';
115 echo '<p>' . sprintf(
116 /* translators: WordPress User, if available. */
117 esc_html__( 'Warning! You are about to delete the Jetpack connection owner (%s) for this site, which may cause some of your Jetpack features to stop working.', 'jetpack-connection' ),
118 esc_html( $user )
119 ) . '</p>';
120
121 if ( ! empty( $connected_admins ) && count( $connected_admins ) > 1 ) {
122 echo '<form id="jp-switch-connection-owner" action="" method="post">';
123 echo "<label for='owner'>" . esc_html__( 'You can choose to transfer connection ownership to one of these already-connected admins:', 'jetpack-connection' ) . ' </label>';
124
125 $connected_admin_ids = array_map(
126 function ( $connected_admin ) {
127 return $connected_admin->ID;
128 },
129 $connected_admins
130 );
131
132 wp_dropdown_users(
133 array(
134 'name' => 'owner',
135 'include' => array_diff( $connected_admin_ids, array( $connection_owner_id ) ),
136 'show' => 'display_name_with_login',
137 )
138 );
139
140 echo '<p>';
141 submit_button( esc_html__( 'Set new connection owner', 'jetpack-connection' ), 'primary', 'jp-switch-connection-owner-submit', false );
142 echo '</p>';
143
144 echo "<div id='jp-switch-user-results'></div>";
145 echo '</form>';
146
147 $this->enqueue_connection_owner_script();
148 } else {
149 echo '<p>' . esc_html__( 'Every Jetpack site needs at least one connected admin for the features to work properly. Please connect to your WordPress.com account via the button below. Once you connect, you may refresh this page to see an option to change the connection owner.', 'jetpack-connection' ) . '</p>';
150 $connect_url = $connection_manager->get_authorization_url();
151 $connect_url = add_query_arg( 'from', 'delete_connection_owner_notice', $connect_url );
152 echo "<a href='" . esc_url( $connect_url ) . "' target='_blank' rel='noopener noreferrer' class='button-primary'>" . esc_html__( 'Connect to WordPress.com', 'jetpack-connection' ) . '</a>';
153 }
154
155 echo '<p>';
156 printf(
157 wp_kses(
158 /* translators: URL to Jetpack support doc regarding the primary user. */
159 __( "<a href='%s' target='_blank' rel='noopener noreferrer'>Learn more</a> about the connection owner and what will break if you do not have one.", 'jetpack-connection' ),
160 array(
161 'a' => array(
162 'href' => true,
163 'target' => true,
164 'rel' => true,
165 ),
166 )
167 ),
168 esc_url( Redirect::get_url( 'jetpack-support-primary-user' ) )
169 );
170 echo '</p>';
171 echo '<p>';
172 printf(
173 wp_kses(
174 /* translators: URL to contact Jetpack support. */
175 __( 'As always, feel free to <a href="%s" target="_blank" rel="noopener noreferrer">contact our support team</a> if you have any questions.', 'jetpack-connection' ),
176 array(
177 'a' => array(
178 'href' => true,
179 'target' => true,
180 'rel' => true,
181 ),
182 )
183 ),
184 esc_url( Redirect::get_url( 'jetpack-contact-support' ) )
185 );
186 echo '</p>';
187 echo '</div>';
188 }
189
190 /**
191 * Enqueue the script that hands the chosen owner to the connection owner REST endpoint.
192 *
193 * The notice prints on `admin_notices`, after `admin_enqueue_scripts` has run, so the handle
194 * has no source of its own and goes in the footer, where the form it binds to already exists.
195 *
196 * @return void
197 */
198 private function enqueue_connection_owner_script() {
199 $handle = 'jetpack-connection-owner-notice';
200
201 wp_register_script( $handle, false, array(), Package_Version::PACKAGE_VERSION, true );
202 wp_enqueue_script( $handle );
203 wp_add_inline_script( $handle, $this->get_connection_owner_script() );
204 }
205
206 /**
207 * Build the script that hands the chosen owner to the connection owner REST endpoint.
208 *
209 * @return string
210 */
211 private function get_connection_owner_script() {
212 $json_flags = JSON_UNESCAPED_SLASHES | JSON_HEX_TAG | JSON_HEX_AMP;
213
214 ob_start();
215 ?>
216 ( function() {
217 const switchOwnerButton = document.getElementById('jp-switch-connection-owner');
218 if ( ! switchOwnerButton ) {
219 return;
220 }
221
222 switchOwnerButton.addEventListener( 'submit', function ( e ) {
223 e.preventDefault();
224
225 const submitBtn = document.getElementById('jp-switch-connection-owner-submit');
226 submitBtn.disabled = true;
227
228 const results = document.getElementById('jp-switch-user-results');
229 results.innerHTML = '';
230 results.classList.remove( 'error-message' );
231
232 const handleAPIError = ( message ) => {
233 submitBtn.disabled = false;
234
235 results.classList.add( 'error-message' );
236 results.innerHTML = message || <?php echo wp_json_encode( esc_html__( 'Something went wrong. Please try again.', 'jetpack-connection' ), $json_flags ); ?>;
237 }
238
239 fetch(
240 <?php echo wp_json_encode( esc_url_raw( get_rest_url() . 'jetpack/v4/connection/owner' ), $json_flags ); ?>,
241 {
242 method: 'POST',
243 headers: {
244 'X-WP-Nonce': <?php echo wp_json_encode( wp_create_nonce( 'wp_rest' ), $json_flags ); ?>,
245 },
246 body: new URLSearchParams( new FormData( this ) ),
247 }
248 )
249 .then( response => response.json() )
250 .then( data => {
251 if ( data.hasOwnProperty( 'code' ) && data.code === 'success' ) {
252 // Owner successfully changed.
253 results.innerHTML = <?php echo wp_json_encode( esc_html__( 'Success!', 'jetpack-connection' ), $json_flags ); ?>;
254 setTimeout(function () {
255 document.getElementById( 'jetpack-notice-switch-connection-owner' ).style.display = 'none';
256 }, 1000);
257
258 return;
259 }
260
261 handleAPIError( data?.message );
262 } )
263 .catch( () => handleAPIError() );
264 });
265 } )();
266 <?php
267 return ob_get_clean();
268 }
269 }
270