These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | /** |
||
4 | * Just a sack of functions. Not actually an IXR_Server |
||
5 | */ |
||
6 | class Jetpack_XMLRPC_Server { |
||
7 | /** |
||
8 | * The current error object |
||
9 | */ |
||
10 | public $error = null; |
||
11 | |||
12 | /** |
||
13 | * The current user |
||
14 | */ |
||
15 | public $user = null; |
||
16 | |||
17 | /** |
||
18 | * Whitelist of the XML-RPC methods available to the Jetpack Server. If the |
||
19 | * user is not authenticated (->login()) then the methods are never added, |
||
20 | * so they will get a "does not exist" error. |
||
21 | */ |
||
22 | function xmlrpc_methods( $core_methods ) { |
||
23 | $jetpack_methods = array( |
||
24 | 'jetpack.jsonAPI' => array( $this, 'json_api' ), |
||
25 | 'jetpack.verifyAction' => array( $this, 'verify_action' ), |
||
26 | ); |
||
27 | |||
28 | $this->user = $this->login(); |
||
29 | |||
30 | if ( $this->user ) { |
||
31 | $jetpack_methods = array_merge( $jetpack_methods, array( |
||
32 | 'jetpack.testConnection' => array( $this, 'test_connection' ), |
||
33 | 'jetpack.testAPIUserCode' => array( $this, 'test_api_user_code' ), |
||
34 | 'jetpack.featuresAvailable' => array( $this, 'features_available' ), |
||
35 | 'jetpack.featuresEnabled' => array( $this, 'features_enabled' ), |
||
36 | 'jetpack.disconnectBlog' => array( $this, 'disconnect_blog' ), |
||
37 | 'jetpack.unlinkUser' => array( $this, 'unlink_user' ), |
||
38 | 'jetpack.syncObject' => array( $this, 'sync_object' ), |
||
39 | 'jetpack.idcUrlValidation' => array( $this, 'validate_urls_for_idc_mitigation' ), |
||
40 | ) ); |
||
41 | |||
42 | if ( isset( $core_methods['metaWeblog.editPost'] ) ) { |
||
43 | $jetpack_methods['metaWeblog.newMediaObject'] = $core_methods['metaWeblog.newMediaObject']; |
||
44 | $jetpack_methods['jetpack.updateAttachmentParent'] = array( $this, 'update_attachment_parent' ); |
||
45 | } |
||
46 | |||
47 | /** |
||
48 | * Filters the XML-RPC methods available to Jetpack for authenticated users. |
||
49 | * |
||
50 | * @since 1.1.0 |
||
51 | * |
||
52 | * @param array $jetpack_methods XML-RPC methods available to the Jetpack Server. |
||
53 | * @param array $core_methods Available core XML-RPC methods. |
||
54 | * @param WP_User $user Information about a given WordPress user. |
||
55 | */ |
||
56 | $jetpack_methods = apply_filters( 'jetpack_xmlrpc_methods', $jetpack_methods, $core_methods, $this->user ); |
||
57 | } |
||
58 | |||
59 | /** |
||
60 | * Filters the XML-RPC methods available to Jetpack for unauthenticated users. |
||
61 | * |
||
62 | * @since 3.0.0 |
||
63 | * |
||
64 | * @param array $jetpack_methods XML-RPC methods available to the Jetpack Server. |
||
65 | * @param array $core_methods Available core XML-RPC methods. |
||
66 | */ |
||
67 | return apply_filters( 'jetpack_xmlrpc_unauthenticated_methods', $jetpack_methods, $core_methods ); |
||
68 | } |
||
69 | |||
70 | /** |
||
71 | * Whitelist of the bootstrap XML-RPC methods |
||
72 | */ |
||
73 | function bootstrap_xmlrpc_methods() { |
||
74 | return array( |
||
75 | 'jetpack.verifyRegistration' => array( $this, 'verify_registration' ), |
||
76 | 'jetpack.remoteAuthorize' => array( $this, 'remote_authorize' ), |
||
77 | ); |
||
78 | } |
||
79 | |||
80 | function authorize_xmlrpc_methods() { |
||
81 | return array( |
||
82 | 'jetpack.remoteAuthorize' => array( $this, 'remote_authorize' ), |
||
83 | 'jetpack.activateManage' => array( $this, 'activate_manage' ), |
||
84 | ); |
||
85 | } |
||
86 | |||
87 | function activate_manage( $request ) { |
||
88 | View Code Duplication | foreach( array( 'secret', 'state' ) as $required ) { |
|
89 | if ( ! isset( $request[ $required ] ) || empty( $request[ $required ] ) ) { |
||
90 | return $this->error( new Jetpack_Error( 'missing_parameter', 'One or more parameters is missing from the request.', 400 ) ); |
||
91 | } |
||
92 | } |
||
93 | $verified = $this->verify_action( array( 'activate_manage', $request['secret'], $request['state'] ) ); |
||
94 | if ( is_a( $verified, 'IXR_Error' ) ) { |
||
95 | return $verified; |
||
96 | } |
||
97 | $activated = Jetpack::activate_module( 'manage', false, false ); |
||
98 | if ( false === $activated || ! Jetpack::is_module_active( 'manage' ) ) { |
||
99 | return $this->error( new Jetpack_Error( 'activation_error', 'There was an error while activating the module.', 500 ) ); |
||
100 | } |
||
101 | return 'active'; |
||
102 | } |
||
103 | |||
104 | function remote_authorize( $request ) { |
||
105 | View Code Duplication | foreach( array( 'secret', 'state', 'redirect_uri', 'code' ) as $required ) { |
|
106 | if ( ! isset( $request[ $required ] ) || empty( $request[ $required ] ) ) { |
||
107 | return $this->error( new Jetpack_Error( 'missing_parameter', 'One or more parameters is missing from the request.', 400 ) ); |
||
108 | } |
||
109 | } |
||
110 | |||
111 | if ( ! get_user_by( 'id', $request['state'] ) ) { |
||
112 | return $this->error( new Jetpack_Error( 'user_unknown', 'User not found.', 404 ) ); |
||
113 | } |
||
114 | |||
115 | if ( Jetpack::is_active() && Jetpack::is_user_connected( $request['state'] ) ) { |
||
116 | return $this->error( new Jetpack_Error( 'already_connected', 'User already connected.', 400 ) ); |
||
117 | } |
||
118 | |||
119 | $verified = $this->verify_action( array( 'authorize', $request['secret'], $request['state'] ) ); |
||
120 | |||
121 | if ( is_a( $verified, 'IXR_Error' ) ) { |
||
122 | return $verified; |
||
123 | } |
||
124 | |||
125 | wp_set_current_user( $request['state'] ); |
||
126 | |||
127 | $client_server = new Jetpack_Client_Server; |
||
128 | $result = $client_server->authorize( $request ); |
||
129 | |||
130 | if ( is_wp_error( $result ) ) { |
||
131 | return $this->error( $result ); |
||
132 | } |
||
133 | // Creates a new secret, allowing someone to activate the manage module for up to 1 day after authorization. |
||
134 | $secrets = Jetpack::init()->generate_secrets( 'activate_manage', DAY_IN_SECONDS ); |
||
135 | @list( $secret ) = explode( ':', $secrets ); |
||
0 ignored issues
–
show
|
|||
136 | $response = array( |
||
137 | 'result' => $result, |
||
138 | 'activate_manage' => $secret, |
||
139 | ); |
||
140 | return $response; |
||
141 | } |
||
142 | |||
143 | /** |
||
144 | * Verifies that Jetpack.WordPress.com received a registration request from this site |
||
145 | */ |
||
146 | function verify_registration( $data ) { |
||
147 | return $this->verify_action( array( 'register', $data[0], $data[1] ) ); |
||
148 | } |
||
149 | |||
150 | /** |
||
151 | * @return WP_Error|string secret_2 on success, WP_Error( error_code => error_code, error_message => error description, error_data => status code ) on failure |
||
152 | * |
||
153 | * Possible error_codes: |
||
154 | * |
||
155 | * verify_secret_1_missing |
||
156 | * verify_secret_1_malformed |
||
157 | * verify_secrets_missing: verification secrets are not found in database |
||
158 | * verify_secrets_incomplete: verification secrets are only partially found in database |
||
159 | * verify_secrets_expired: verification secrets have expired |
||
160 | * verify_secrets_mismatch: stored secret_1 does not match secret_1 sent by Jetpack.WordPress.com |
||
161 | * state_missing: required parameter of state not found |
||
162 | * state_malformed: state is not a digit |
||
163 | * invalid_state: state in request does not match the stored state |
||
164 | * |
||
165 | * The 'authorize' and 'register' actions have additional error codes |
||
166 | * |
||
167 | * state_missing: a state ( user id ) was not supplied |
||
168 | * state_malformed: state is not the correct data type |
||
169 | * invalid_state: supplied state does not match the stored state |
||
170 | */ |
||
171 | function verify_action( $params ) { |
||
172 | $action = $params[0]; |
||
173 | $verify_secret = $params[1]; |
||
174 | $state = isset( $params[2] ) ? $params[2] : ''; |
||
175 | |||
176 | if ( empty( $verify_secret ) ) { |
||
177 | return $this->error( new Jetpack_Error( 'verify_secret_1_missing', sprintf( 'The required "%s" parameter is missing.', 'secret_1' ), 400 ) ); |
||
178 | } else if ( ! is_string( $verify_secret ) ) { |
||
179 | return $this->error( new Jetpack_Error( 'verify_secret_1_malformed', sprintf( 'The required "%s" parameter is malformed.', 'secret_1' ), 400 ) ); |
||
180 | } |
||
181 | |||
182 | $secrets = Jetpack_Options::get_option( $action ); |
||
183 | if ( ! $secrets || is_wp_error( $secrets ) ) { |
||
184 | Jetpack_Options::delete_option( $action ); |
||
185 | return $this->error( new Jetpack_Error( 'verify_secrets_missing', 'Verification secrets not found', 400 ) ); |
||
186 | } |
||
187 | |||
188 | @list( $secret_1, $secret_2, $secret_eol, $user_id ) = explode( ':', $secrets ); |
||
0 ignored issues
–
show
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.
If you suppress an error, we recommend checking for the error condition explicitly: // For example instead of
@mkdir($dir);
// Better use
if (@mkdir($dir) === false) {
throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
![]() |
|||
189 | |||
190 | View Code Duplication | if ( empty( $secret_1 ) || empty( $secret_2 ) || empty( $secret_eol ) ) { |
|
191 | Jetpack_Options::delete_option( $action ); |
||
192 | return $this->error( new Jetpack_Error( 'verify_secrets_incomplete', 'Verification secrets are incomplete', 400 ) ); |
||
193 | } |
||
194 | |||
195 | if ( $secret_eol < time() ) { |
||
196 | Jetpack_Options::delete_option( $action ); |
||
197 | return $this->error( new Jetpack_Error( 'verify_secrets_expired', 'Verification took too long', 400 ) ); |
||
198 | } |
||
199 | |||
200 | if ( ! hash_equals( $verify_secret, $secret_1 ) ) { |
||
201 | Jetpack_Options::delete_option( $action ); |
||
202 | return $this->error( new Jetpack_Error( 'verify_secrets_mismatch', 'Secret mismatch', 400 ) ); |
||
203 | } |
||
204 | |||
205 | if ( in_array( $action, array( 'authorize', 'register' ) ) ) { |
||
206 | // 'authorize' and 'register' actions require further testing |
||
207 | if ( empty( $state ) ) { |
||
208 | return $this->error( new Jetpack_Error( 'state_missing', sprintf( 'The required "%s" parameter is missing.', 'state' ), 400 ) ); |
||
209 | } else if ( ! ctype_digit( $state ) ) { |
||
210 | return $this->error( new Jetpack_Error( 'state_malformed', sprintf( 'The required "%s" parameter is malformed.', 'state' ), 400 ) ); |
||
211 | } |
||
212 | View Code Duplication | if ( empty( $user_id ) || $user_id !== $state ) { |
|
213 | Jetpack_Options::delete_option( $action ); |
||
214 | return $this->error( new Jetpack_Error( 'invalid_state', 'State is invalid', 400 ) ); |
||
215 | } |
||
216 | } |
||
217 | |||
218 | Jetpack_Options::delete_option( $action ); |
||
219 | |||
220 | return $secret_2; |
||
221 | } |
||
222 | |||
223 | /** |
||
224 | * Wrapper for wp_authenticate( $username, $password ); |
||
225 | * |
||
226 | * @return WP_User|bool |
||
227 | */ |
||
228 | function login() { |
||
229 | Jetpack::init()->require_jetpack_authentication(); |
||
230 | $user = wp_authenticate( 'username', 'password' ); |
||
231 | if ( is_wp_error( $user ) ) { |
||
232 | if ( 'authentication_failed' == $user->get_error_code() ) { // Generic error could mean most anything. |
||
233 | $this->error = new Jetpack_Error( 'invalid_request', 'Invalid Request', 403 ); |
||
234 | } else { |
||
235 | $this->error = $user; |
||
236 | } |
||
237 | return false; |
||
238 | } else if ( !$user ) { // Shouldn't happen. |
||
239 | $this->error = new Jetpack_Error( 'invalid_request', 'Invalid Request', 403 ); |
||
240 | return false; |
||
241 | } |
||
242 | |||
243 | return $user; |
||
244 | } |
||
245 | |||
246 | /** |
||
247 | * Returns the current error as an IXR_Error |
||
248 | * |
||
249 | * @return bool|IXR_Error |
||
250 | */ |
||
251 | function error( $error = null ) { |
||
252 | if ( !is_null( $error ) ) { |
||
253 | $this->error = $error; |
||
254 | } |
||
255 | |||
256 | if ( is_wp_error( $this->error ) ) { |
||
257 | $code = $this->error->get_error_data(); |
||
258 | if ( !$code ) { |
||
259 | $code = -10520; |
||
260 | } |
||
261 | $message = sprintf( 'Jetpack: [%s] %s', $this->error->get_error_code(), $this->error->get_error_message() ); |
||
262 | return new IXR_Error( $code, $message ); |
||
263 | } else if ( is_a( $this->error, 'IXR_Error' ) ) { |
||
264 | return $this->error; |
||
265 | } |
||
266 | |||
267 | return false; |
||
268 | } |
||
269 | |||
270 | /* API Methods */ |
||
271 | |||
272 | /** |
||
273 | * Just authenticates with the given Jetpack credentials. |
||
274 | * |
||
275 | * @return string The current Jetpack version number |
||
276 | */ |
||
277 | function test_connection() { |
||
278 | return JETPACK__VERSION; |
||
279 | } |
||
280 | |||
281 | function test_api_user_code( $args ) { |
||
282 | $client_id = (int) $args[0]; |
||
283 | $user_id = (int) $args[1]; |
||
284 | $nonce = (string) $args[2]; |
||
285 | $verify = (string) $args[3]; |
||
286 | |||
287 | if ( !$client_id || !$user_id || !strlen( $nonce ) || 32 !== strlen( $verify ) ) { |
||
288 | return false; |
||
289 | } |
||
290 | |||
291 | $user = get_user_by( 'id', $user_id ); |
||
292 | if ( !$user || is_wp_error( $user ) ) { |
||
293 | return false; |
||
294 | } |
||
295 | |||
296 | /* debugging |
||
297 | error_log( "CLIENT: $client_id" ); |
||
298 | error_log( "USER: $user_id" ); |
||
299 | error_log( "NONCE: $nonce" ); |
||
300 | error_log( "VERIFY: $verify" ); |
||
301 | */ |
||
302 | |||
303 | $jetpack_token = Jetpack_Data::get_access_token( $user_id ); |
||
304 | |||
305 | $api_user_code = get_user_meta( $user_id, "jetpack_json_api_$client_id", true ); |
||
306 | if ( !$api_user_code ) { |
||
307 | return false; |
||
308 | } |
||
309 | |||
310 | $hmac = hash_hmac( 'md5', json_encode( (object) array( |
||
311 | 'client_id' => (int) $client_id, |
||
312 | 'user_id' => (int) $user_id, |
||
313 | 'nonce' => (string) $nonce, |
||
314 | 'code' => (string) $api_user_code, |
||
315 | ) ), $jetpack_token->secret ); |
||
316 | |||
317 | if ( ! hash_equals( $hmac, $verify ) ) { |
||
318 | return false; |
||
319 | } |
||
320 | |||
321 | return $user_id; |
||
322 | } |
||
323 | |||
324 | /** |
||
325 | * Disconnect this blog from the connected wordpress.com account |
||
326 | * @return boolean |
||
327 | */ |
||
328 | function disconnect_blog() { |
||
329 | |||
330 | // For tracking |
||
331 | if ( ! empty( $this->user->ID ) ) { |
||
332 | wp_set_current_user( $this->user->ID ); |
||
333 | } |
||
334 | |||
335 | Jetpack::log( 'disconnect' ); |
||
336 | Jetpack::disconnect(); |
||
337 | |||
338 | return true; |
||
339 | } |
||
340 | |||
341 | /** |
||
342 | * Unlink a user from WordPress.com |
||
343 | * |
||
344 | * This will fail if called by the Master User. |
||
345 | */ |
||
346 | function unlink_user() { |
||
347 | Jetpack::log( 'unlink' ); |
||
348 | return Jetpack::unlink_user(); |
||
349 | } |
||
350 | |||
351 | /** |
||
352 | * Returns any object that is able to be synced |
||
353 | */ |
||
354 | function sync_object( $args ) { |
||
355 | // e.g. posts, post, 5 |
||
356 | list( $module_name, $object_type, $id ) = $args; |
||
357 | require_once dirname( __FILE__ ) . '/sync/class.jetpack-sync-modules.php'; |
||
358 | require_once dirname( __FILE__ ) . '/sync/class.jetpack-sync-sender.php'; |
||
359 | |||
360 | $sync_module = Jetpack_Sync_Modules::get_module( $module_name ); |
||
361 | $codec = Jetpack_Sync_Sender::get_instance()->get_codec(); |
||
362 | |||
363 | return $codec->encode( $sync_module->get_object_by_id( $object_type, $id ) ); |
||
364 | } |
||
365 | |||
366 | /** |
||
367 | * Returns the home URL and site URL for the current site which can be used on the WPCOM side for |
||
368 | * IDC mitigation to decide whether sync should be allowed if the home and siteurl values differ between WPCOM |
||
369 | * and the remote Jetpack site. |
||
370 | * |
||
371 | * @return array |
||
372 | */ |
||
373 | function validate_urls_for_idc_mitigation() { |
||
374 | return array( |
||
375 | 'home' => get_home_url(), |
||
376 | 'siteurl' => get_site_url(), |
||
377 | ); |
||
378 | } |
||
379 | |||
380 | /** |
||
381 | * Returns what features are available. Uses the slug of the module files. |
||
382 | * |
||
383 | * @return array |
||
384 | */ |
||
385 | View Code Duplication | function features_available() { |
|
386 | $raw_modules = Jetpack::get_available_modules(); |
||
387 | $modules = array(); |
||
388 | foreach ( $raw_modules as $module ) { |
||
389 | $modules[] = Jetpack::get_module_slug( $module ); |
||
390 | } |
||
391 | |||
392 | return $modules; |
||
393 | } |
||
394 | |||
395 | /** |
||
396 | * Returns what features are enabled. Uses the slug of the modules files. |
||
397 | * |
||
398 | * @return array |
||
399 | */ |
||
400 | View Code Duplication | function features_enabled() { |
|
401 | $raw_modules = Jetpack::get_active_modules(); |
||
402 | $modules = array(); |
||
403 | foreach ( $raw_modules as $module ) { |
||
404 | $modules[] = Jetpack::get_module_slug( $module ); |
||
405 | } |
||
406 | |||
407 | return $modules; |
||
408 | } |
||
409 | |||
410 | function update_attachment_parent( $args ) { |
||
411 | $attachment_id = (int) $args[0]; |
||
412 | $parent_id = (int) $args[1]; |
||
413 | |||
414 | return wp_update_post( array( |
||
415 | 'ID' => $attachment_id, |
||
416 | 'post_parent' => $parent_id, |
||
417 | ) ); |
||
418 | } |
||
419 | |||
420 | function json_api( $args = array() ) { |
||
421 | $json_api_args = $args[0]; |
||
422 | $verify_api_user_args = $args[1]; |
||
423 | |||
424 | $method = (string) $json_api_args[0]; |
||
425 | $url = (string) $json_api_args[1]; |
||
426 | $post_body = is_null( $json_api_args[2] ) ? null : (string) $json_api_args[2]; |
||
427 | $user_details = (array) $json_api_args[4]; |
||
428 | $locale = (string) $json_api_args[5]; |
||
429 | |||
430 | if ( !$verify_api_user_args ) { |
||
431 | $user_id = 0; |
||
432 | } elseif ( 'internal' === $verify_api_user_args[0] ) { |
||
433 | $user_id = (int) $verify_api_user_args[1]; |
||
434 | if ( $user_id ) { |
||
435 | $user = get_user_by( 'id', $user_id ); |
||
436 | if ( !$user || is_wp_error( $user ) ) { |
||
437 | return false; |
||
438 | } |
||
439 | } |
||
440 | } else { |
||
441 | $user_id = call_user_func( array( $this, 'test_api_user_code' ), $verify_api_user_args ); |
||
442 | if ( !$user_id ) { |
||
443 | return false; |
||
444 | } |
||
445 | } |
||
446 | |||
447 | /* debugging |
||
448 | error_log( "-- begin json api via jetpack debugging -- " ); |
||
449 | error_log( "METHOD: $method" ); |
||
450 | error_log( "URL: $url" ); |
||
451 | error_log( "POST BODY: $post_body" ); |
||
452 | error_log( "VERIFY_ARGS: " . print_r( $verify_api_user_args, 1 ) ); |
||
453 | error_log( "VERIFIED USER_ID: " . (int) $user_id ); |
||
454 | error_log( "-- end json api via jetpack debugging -- " ); |
||
455 | */ |
||
456 | |||
457 | if ( 'en' !== $locale ) { |
||
458 | // .org mo files are named slightly different from .com, and all we have is this the locale -- try to guess them. |
||
459 | $new_locale = $locale; |
||
460 | if ( strpos( $locale, '-' ) !== false ) { |
||
461 | $locale_pieces = explode( '-', $locale ); |
||
462 | $new_locale = $locale_pieces[0]; |
||
463 | $new_locale .= ( ! empty( $locale_pieces[1] ) ) ? '_' . strtoupper( $locale_pieces[1] ) : ''; |
||
464 | } else { |
||
465 | // .com might pass 'fr' because thats what our language files are named as, where core seems |
||
466 | // to do fr_FR - so try that if we don't think we can load the file. |
||
467 | if ( ! file_exists( WP_LANG_DIR . '/' . $locale . '.mo' ) ) { |
||
468 | $new_locale = $locale . '_' . strtoupper( $locale ); |
||
469 | } |
||
470 | } |
||
471 | |||
472 | if ( file_exists( WP_LANG_DIR . '/' . $new_locale . '.mo' ) ) { |
||
473 | unload_textdomain( 'default' ); |
||
474 | load_textdomain( 'default', WP_LANG_DIR . '/' . $new_locale . '.mo' ); |
||
475 | } |
||
476 | } |
||
477 | |||
478 | $old_user = wp_get_current_user(); |
||
479 | wp_set_current_user( $user_id ); |
||
480 | |||
481 | $token = Jetpack_Data::get_access_token( get_current_user_id() ); |
||
482 | if ( !$token || is_wp_error( $token ) ) { |
||
483 | return false; |
||
484 | } |
||
485 | |||
486 | define( 'REST_API_REQUEST', true ); |
||
487 | define( 'WPCOM_JSON_API__BASE', 'public-api.wordpress.com/rest/v1' ); |
||
488 | |||
489 | // needed? |
||
490 | require_once ABSPATH . 'wp-admin/includes/admin.php'; |
||
491 | |||
492 | require_once JETPACK__PLUGIN_DIR . 'class.json-api.php'; |
||
493 | $api = WPCOM_JSON_API::init( $method, $url, $post_body ); |
||
494 | $api->token_details['user'] = $user_details; |
||
495 | require_once JETPACK__PLUGIN_DIR . 'class.json-api-endpoints.php'; |
||
496 | |||
497 | $display_errors = ini_set( 'display_errors', 0 ); |
||
498 | ob_start(); |
||
499 | $content_type = $api->serve( false ); |
||
500 | $output = ob_get_clean(); |
||
501 | ini_set( 'display_errors', $display_errors ); |
||
502 | |||
503 | $nonce = wp_generate_password( 10, false ); |
||
504 | $hmac = hash_hmac( 'md5', $nonce . $output, $token->secret ); |
||
505 | |||
506 | wp_set_current_user( isset( $old_user->ID ) ? $old_user->ID : 0 ); |
||
507 | |||
508 | return array( |
||
509 | (string) $output, |
||
510 | (string) $nonce, |
||
511 | (string) $hmac, |
||
512 | ); |
||
513 | } |
||
514 | } |
||
515 |
If you suppress an error, we recommend checking for the error condition explicitly: