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/class-connection-notice.php +269 -0 16.2-beta → 16.3 View file →
@@ -1,0 +1,269 @@
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 +}