Completed
Push — master ( 24c2f4...f0df34 )
by Augusto
04:34
created
lib/class-api.php 1 patch
Indentation   +685 added lines, -685 removed lines patch added patch discarded remove patch
@@ -1,22 +1,22 @@  discard block
 block discarded – undo
1 1
 <?php
2 2
 /**
3
- * API-like class to deal with HTTP(S) requests to diaspora* using WP_HTTP API.
4
- *
5
- * Basic functionality includes:
6
- * - Logging in to diaspora*
7
- * - Fetching a user's aspects and connected services
8
- * - Posting to diaspora*
9
- *
10
- * Ideas in this class are based on classes from:
11
- * https://github.com/Faldrian/WP-diaspora-postwidget/blob/master/wp-diaspora-postwidget/diasphp.php -- Thanks, Faldrian!
12
- * https://github.com/meitar/diasposter/blob/master/lib/Diaspora_Connection.php -- Thanks, Meitar
13
- *
14
- * Which in turn are based on:
15
- * https://github.com/cocreature/diaspy/blob/master/client.py -- Thanks, Moritz
16
- *
17
- * @package WP_To_Diaspora\API
18
- * @since 1.2.7
19
- */
3
+   * API-like class to deal with HTTP(S) requests to diaspora* using WP_HTTP API.
4
+   *
5
+   * Basic functionality includes:
6
+   * - Logging in to diaspora*
7
+   * - Fetching a user's aspects and connected services
8
+   * - Posting to diaspora*
9
+   *
10
+   * Ideas in this class are based on classes from:
11
+   * https://github.com/Faldrian/WP-diaspora-postwidget/blob/master/wp-diaspora-postwidget/diasphp.php -- Thanks, Faldrian!
12
+   * https://github.com/meitar/diasposter/blob/master/lib/Diaspora_Connection.php -- Thanks, Meitar
13
+   *
14
+   * Which in turn are based on:
15
+   * https://github.com/cocreature/diaspy/blob/master/client.py -- Thanks, Moritz
16
+   *
17
+   * @package WP_To_Diaspora\API
18
+   * @since 1.2.7
19
+   */
20 20
 
21 21
 // Exit if accessed directly.
22 22
 defined( 'ABSPATH' ) || exit;
@@ -26,672 +26,672 @@  discard block
 block discarded – undo
26 26
  */
27 27
 class WP2D_API {
28 28
 
29
-	/**
30
-	 * The provider name to display when posting to diaspora*.
31
-	 *
32
-	 * @var string
33
-	 */
34
-	public $provider = 'WP to diaspora*';
35
-
36
-	/**
37
-	 * The last http request error that occurred.
38
-	 *
39
-	 * @var WP_Error
40
-	 */
41
-	private $_last_error;
42
-
43
-	/**
44
-	 * Security token to be used for making requests.
45
-	 *
46
-	 * @var string
47
-	 */
48
-	private $_token;
49
-
50
-	/**
51
-	 * Save the cookies for the requests.
52
-	 *
53
-	 * @var array
54
-	 */
55
-	private $_cookies;
56
-
57
-	/**
58
-	 * The last http request made to diaspora*.
59
-	 * Contains the response and request infos.
60
-	 *
61
-	 * @var object
62
-	 */
63
-	private $_last_request;
64
-
65
-	/**
66
-	 * Is this a secure server, use HTTPS instead of HTTP?
67
-	 *
68
-	 * @var boolean
69
-	 */
70
-	private $_is_secure;
71
-
72
-	/**
73
-	 * The pod domain to make the http requests to.
74
-	 *
75
-	 * @var string
76
-	 */
77
-	private $_pod;
78
-
79
-	/**
80
-	 * Username to use when logging in to diaspora*.
81
-	 *
82
-	 * @var string
83
-	 */
84
-	private $_username;
85
-
86
-	/**
87
-	 * Password to use when logging in to diaspora*.
88
-	 *
89
-	 * @var string
90
-	 */
91
-	private $_password;
92
-
93
-	/**
94
-	 * Remember the current login state.
95
-	 *
96
-	 * @var boolean
97
-	 */
98
-	private $_is_logged_in = false;
99
-
100
-	/**
101
-	 * The list of user's aspects, which get set after ever http request.
102
-	 *
103
-	 * @var array
104
-	 */
105
-	private $_aspects = array();
106
-
107
-	/**
108
-	 * The list of user's connected services, which get set after ever http request.
109
-	 *
110
-	 * @var array
111
-	 */
112
-	private $_services = array();
113
-
114
-	/**
115
-	 * List of regex expressions used to filter out details from http request responses.
116
-	 *
117
-	 * @var array
118
-	 */
119
-	private $_regexes = array(
120
-		'token'    => '/content="(.*?)" name="csrf-token"|name="csrf-token" content="(.*?)"/',
121
-		'aspects'  => '/"aspects"\:(\[.*?\])/',
122
-		'services' => '/"configured_services"\:(\[.*?\])/',
123
-	);
124
-
125
-	/**
126
-	 * The full pod url, with the used protocol.
127
-	 *
128
-	 * @param string $path Path to add to the pod url.
129
-	 * @return string Full pod url.
130
-	 */
131
-	public function get_pod_url( $path = '' ) {
132
-		$path = trim( $path, ' /' );
133
-
134
-		// Add a slash to the beginning?
135
-		if ( '' !== $path ) {
136
-			$path = '/' . $path;
137
-		}
138
-
139
-		return sprintf( 'http%s://%s%s', ( $this->_is_secure ) ? 's' : '', $this->_pod, $path );
140
-	}
141
-
142
-	/**
143
-	 * Constructor to initialise the connection to diaspora*.
144
-	 *
145
-	 * @param string  $pod       The pod domain to connect to.
146
-	 * @param boolean $is_secure Is this a secure server? (Default: true).
147
-	 */
148
-	public function __construct( $pod, $is_secure = true ) {
149
-		// Set class variables.
150
-		$this->_pod       = $pod;
151
-		$this->_is_secure = (bool) $is_secure;
152
-	}
153
-
154
-	/**
155
-	 * Initialise the connection to diaspora*. The pod and protocol can be changed by passing new parameters.
156
-	 * Check if we can connect to the pod to retrieve the token.
157
-	 *
158
-	 * @param string  $pod       Pod domain to connect to, if it should be changed.
159
-	 * @param boolean $is_secure Is this a secure server? (Default: true).
160
-	 * @return boolean True if we could get the token, else false.
161
-	 */
162
-	public function init( $pod = null, $is_secure = true ) {
163
-		// If we are changing pod, we need to fetch a new token.
164
-		$force_new_token = false;
165
-
166
-		// When initialising a connection, clear the last error.
167
-		// This is important when multiple init tries happen.
168
-		$this->_last_error = null;
169
-
170
-		// Change the pod we are connecting to?
171
-		if ( isset( $pod ) && ( $this->_pod !== $pod || $this->_is_secure !== $is_secure ) ) {
172
-			$this->_pod       = $pod;
173
-			$this->_is_secure = (bool) $is_secure;
174
-			$force_new_token  = true;
175
-		}
176
-
177
-		// Get and save the token.
178
-		if ( null === $this->_fetch_token( $force_new_token ) ) {
179
-			$error = ( $this->has_last_error() ) ? ' ' . $this->get_last_error() : '';
180
-			$this->_error( 'wp2d_api_init_failed',
181
-				sprintf(
182
-					_x( 'Failed to initialise connection to pod "%s".', 'Placeholder is the full pod URL.', 'wp-to-diaspora' ),
183
-					$this->get_pod_url()
184
-				) . $error,
185
-				array( 'help_tab' => 'troubleshooting' )
186
-			);
187
-
188
-			return false;
189
-		}
190
-		return true;
191
-	}
192
-
193
-	/**
194
-	 * Check if there is an API error around.
195
-	 *
196
-	 * @return boolean If there is an API error around.
197
-	 */
198
-	public function has_last_error() {
199
-		return is_wp_error( $this->_last_error );
200
-	}
201
-
202
-	/**
203
-	 * Get the last API error object.
204
-	 *
205
-	 * @param boolean $clear If the error should be cleared after returning it.
206
-	 * @return WP_Error|null The last API error object or null.
207
-	 */
208
-	public function get_last_error_object( $clear = true ) {
209
-		$last_error = $this->_last_error;
210
-		$clear && $this->_last_error = null;
211
-		return $last_error;
212
-	}
213
-
214
-	/**
215
-	 * Get the last API error message.
216
-	 *
217
-	 * @param boolean $clear If the error should be cleared after returning it.
218
-	 * @return string The last API error message.
219
-	 */
220
-	public function get_last_error( $clear = false ) {
221
-		$last_error = ( $this->has_last_error() ) ? $this->_last_error->get_error_message() : '';
222
-		$clear && $this->_last_error = null;
223
-		return $last_error;
224
-	}
225
-
226
-	/**
227
-	 * Fetch the secure token from Diaspora and save it for future use.
228
-	 *
229
-	 * @param boolean $force Force to fetch a new token.
230
-	 * @return string The fetched token.
231
-	 */
232
-	private function _fetch_token( $force = false ) {
233
-		if ( ! isset( $this->_token ) || (bool) $force ) {
234
-			// Go directly to the sign in page, as it would redirect to there anyway.
235
-			// Since _request function automatically saves the new token, just call it with no data.
236
-			$this->_request( '/users/sign_in' );
237
-		}
238
-		return $this->_token;
239
-	}
240
-
241
-	/**
242
-	 * Check if the API has been initialised. Otherwise set the last error.
243
-	 *
244
-	 * @return boolean Has the connection been initialised?
245
-	 */
246
-	private function _check_init() {
247
-		if ( is_null( $this->_token ) ) {
248
-			$this->_error( 'wp2d_api_connection_not_initialised', __( 'Connection not initialised.', 'wp-to-diaspora' ) );
249
-			return false;
250
-		}
251
-		return true;
252
-	}
253
-
254
-	/**
255
-	 * Check if we're logged in. Otherwise set the last error.
256
-	 *
257
-	 * @return boolean Are we logged in already?
258
-	 */
259
-	private function _check_login() {
260
-		if ( ! $this->_check_init() ) {
261
-			return false;
262
-		}
263
-		if ( ! $this->is_logged_in() ) {
264
-			$this->_error( 'wp2d_api_not_logged_in', __( 'Not logged in.', 'wp-to-diaspora' ) );
265
-			return false;
266
-		}
267
-		return true;
268
-	}
269
-
270
-	/**
271
-	 * Check if we are logged in.
272
-	 *
273
-	 * @return boolean Are we logged in already?
274
-	 */
275
-	public function is_logged_in() {
276
-		return $this->_is_logged_in;
277
-	}
278
-
279
-	/**
280
-	 * Log in to diaspora*.
281
-	 *
282
-	 * @param string  $username Username used for login.
283
-	 * @param string  $password Password used for login.
284
-	 * @param boolean $force    Force a new login even if we are already logged in.
285
-	 * @return boolean Did the login succeed?
286
-	 */
287
-	public function login( $username, $password, $force = false ) {
288
-		// Has the connection been initialised?
289
-		if ( ! $this->_check_init() ) {
290
-			$this->logout();
291
-			return false;
292
-		}
293
-
294
-		// Username and password both need to be set.
295
-		$username = ( isset( $username ) && '' !== $username ) ? $username : null;
296
-		$password = ( isset( $password ) && '' !== $password ) ? $password : null;
297
-		if ( ! isset( $username, $password ) ) {
298
-			$this->logout();
299
-			return false;
300
-		}
301
-
302
-		// If we are already logged in and not forcing a relogin, return.
303
-		if ( ! $force && $this->is_logged_in() &&
304
-			$username === $this->_username &&
305
-			$password === $this->_password ) {
306
-			return true;
307
-		}
308
-
309
-		// Set the newly passed username and password.
310
-		$this->_username = $username;
311
-		$this->_password = $password;
312
-
313
-		// Set up the login parameters.
314
-		$params = array(
315
-			'user[username]'     => $this->_username,
316
-			'user[password]'     => $this->_password,
317
-			'authenticity_token' => $this->_fetch_token(),
318
-		);
319
-
320
-		$args = array(
321
-			'method' => 'POST',
322
-			'body'   => $params,
323
-		);
324
-
325
-		// Try to sign in.
326
-		$this->_request( '/users/sign_in', $args );
327
-
328
-		// Can we load the bookmarklet to make sure we're logged in?
329
-		$response = $this->_request( '/bookmarklet' );
330
-
331
-		// If the request isn't successful, we are not logged in correctly.
332
-		if ( is_wp_error( $response ) || 200 !== $response->code ) {
333
-			// Login failed.
334
-			$this->_error( 'wp2d_api_login_failed', __( 'Login failed. Check your login details.', 'wp-to-diaspora' ), array( 'help_tab' => 'troubleshooting' ) );
335
-			$this->logout();
336
-			return false;
337
-		}
338
-
339
-		// Login succeeded.
340
-		$this->_is_logged_in = true;
341
-		return true;
342
-	}
343
-
344
-	/**
345
-	 * Perform a logout, resetting all login info.
346
-	 *
347
-	 * @since 1.6.0
348
-	 */
349
-	public function logout() {
350
-		$this->_is_logged_in = false;
351
-		$this->_username = null;
352
-		$this->_password = null;
353
-		$this->_aspects = array();
354
-		$this->_services = array();
355
-	}
356
-
357
-	/**
358
-	 * Perform a deinitialisation, resetting all class variables.
359
-	 *
360
-	 * @since 1.7.0
361
-	 */
362
-	public function deinit() {
363
-		$this->logout();
364
-		$this->_last_error = null;
365
-		$this->_token = null;
366
-		$this->_cookies = array();
367
-		$this->_last_request = null;
368
-	}
369
-
370
-	/**
371
-	 * Post to diaspora*.
372
-	 *
373
-	 * @param string       $text       The text to post.
374
-	 * @param array|string $aspects    The aspects to post to. Array or comma seperated ids.
375
-	 * @param array        $extra_data Any extra data to be added to the post call.
376
-	 * @return boolean|object Return the response data of the new diaspora* post if successfully posted, else false.
377
-	 */
378
-	public function post( $text, $aspects = 'public', $extra_data = array() ) {
379
-		// Are we logged in?
380
-		if ( ! $this->_check_login() ) {
381
-			return false;
382
-		}
383
-
384
-		// Put the aspects into a clean array.
385
-		$aspects = array_filter( WP2D_Helpers::str_to_arr( $aspects ) );
386
-
387
-		// If no aspects have been selected or the public one is also included, choose public only.
388
-		if ( empty( $aspects ) || in_array( 'public', $aspects ) ) {
389
-			$aspects = 'public';
390
-		}
391
-
392
-		// Prepare post data.
393
-		$post_data = array(
394
-			'aspect_ids'     => $aspects,
395
-			'status_message' => array(
396
-				'text' => $text,
397
-				'provider_display_name' => $this->provider,
398
-			),
399
-		);
400
-
401
-		// Add any extra data to the post.
402
-		if ( ! empty( $extra_data ) ) {
403
-				$post_data += $extra_data;
404
-		}
405
-
406
-		// Check if we can use the new wp_json_encode function.
407
-		$post_data = ( function_exists( 'wp_json_encode' ) )
408
-			? wp_json_encode( $post_data )
409
-			: json_encode( $post_data );
410
-
411
-		$args = array(
412
-			'method'  => 'POST',
413
-			'body'    => $post_data,
414
-			'headers' => array(
415
-				'Accept'       => 'application/json',
416
-				'Content-Type' => 'application/json',
417
-				'X-CSRF-Token' => $this->_fetch_token(),
418
-			),
419
-		);
420
-
421
-		// Submit the post.
422
-		$response = $this->_request( '/status_messages', $args );
423
-
424
-		if ( is_wp_error( $response ) ) {
425
-			$this->_error( 'wp2d_api_post_failed', $response->get_error_message() );
426
-			return false;
427
-		}
428
-
429
-		$diaspost = json_decode( $response->body );
430
-		if ( 201 !== $response->code ) {
431
-			$this->_error( 'wp2d_api_post_failed', ( isset( $diaspost->error ) ) ? $diaspost->error : _x( 'Unknown error occurred.', 'When an unknown error occurred in the WP2D_API object.', 'wp-to-diaspora' ) );
432
-			return false;
433
-		}
434
-
435
-		// Add additional info to our diaspora post object.
436
-		$diaspost->permalink = $this->get_pod_url( '/posts/' . $diaspost->guid );
437
-
438
-		return $diaspost;
439
-	}
440
-
441
-	/**
442
-	 * Delete a post or comment from diaspora*.
443
-	 *
444
-	 * @since 1.6.0
445
-	 *
446
-	 * @param string $what What to delete, 'post' or 'comment'.
447
-	 * @param string $id The ID of the post or comment to delete.
448
-	 * @return boolean If the deletion was successful.
449
-	 */
450
-	public function delete( $what, $id ) {
451
-		// Are we logged in?
452
-		if ( ! $this->_check_login() ) {
453
-			return false;
454
-		}
455
-
456
-		// For now, only deleting posts and comments is allowed.
457
-		if ( ! in_array( $what, array( 'post', 'comment' ) ) ) {
458
-			$this->_error( 'wp2d_api_delete_failed', __( 'You can only delete posts and comments.', 'wp-to-diaspora' ) );
459
-			return false;
460
-		}
461
-
462
-		$args = array(
463
-			'method'  => 'DELETE',
464
-			'headers' => array(
465
-				'Accept'       => 'application/json',
466
-				'Content-Type' => 'application/json',
467
-				'X-CSRF-Token' => $this->_fetch_token(),
468
-			),
469
-		);
470
-
471
-		// Try to delete the post or comment.
472
-		$response = $this->_request( '/' . $what . 's/' . $id, $args );
473
-
474
-		$error_message = '';
475
-
476
-		if ( is_wp_error( $response ) ) {
477
-			$error_message = $response->get_error_message();
478
-		} else {
479
-			switch ( $response->code ) {
480
-				case 204:
481
-					return true;
482
-				case 404:
483
-					$error_message = ( 'post' === $what )
484
-						? __( 'The post you tried to delete does not exist.', 'wp-to-diaspora' )
485
-						: __( 'The comment you tried to delete does not exist.', 'wp-to-diaspora' );
486
-					break;
487
-
488
-				// Due to diaspora* returning a proper 403 when trying to delete a foreign comment
489
-				// but returning a 500 when trying to delete a foreign post, this needs some special attention.
490
-				case 403:
491
-					if ( 'comment' === $what ) {
492
-						$error_message = __( 'The comment you tried to delete does not belong to you.', 'wp-to-diaspora' );
493
-						break;
494
-					}
495
-					// Fall through...
496
-				case 500:
497
-					if ( 'post' === $what ) {
498
-						$error_message = __( 'The post you tried to delete does not belong to you.', 'wp-to-diaspora' );
499
-						break;
500
-					}
501
-					// Fall through...
502
-				default:
503
-					$error_message = _x( 'Unknown error occurred.', 'When an unknown error occurred in the WP2D_API object.', 'wp-to-diaspora' );
504
-					break;
505
-			}
506
-		}
507
-
508
-		$this->_error( 'wp2d_api_delete_' . $what . '_failed', $error_message );
509
-		return false;
510
-	}
511
-
512
-	/**
513
-	 * Get the list of aspects.
514
-	 *
515
-	 * @param boolean $force Force to fetch new aspects.
516
-	 * @return array Array of aspect objects.
517
-	 */
518
-	public function get_aspects( $force = false ) {
519
-		$this->_aspects = $this->_get_aspects_services( 'aspects', $this->_aspects, $force );
520
-		return ( is_array( $this->_aspects ) ) ? $this->_aspects : false;
521
-	}
522
-
523
-	/**
524
-	 * Get the list of connected services.
525
-	 *
526
-	 * @param boolean $force Force to fetch new connected services.
527
-	 * @return array Array of service objects.
528
-	 */
529
-	public function get_services( $force = false ) {
530
-		$this->_services = $this->_get_aspects_services( 'services', $this->_services, $force );
531
-		return ( is_array( $this->_services ) ) ? $this->_services : false;
532
-	}
533
-
534
-	/**
535
-	 * Get the list of aspects or connected services.
536
-	 *
537
-	 * @param string  $type  Type of list to get.
538
-	 * @param array   $list  The current list of items.
539
-	 * @param boolean $force Force to fetch new list.
540
-	 * @return boolean Was the list fetched successfully?
541
-	 */
542
-	private function _get_aspects_services( $type, $list, $force ) {
543
-		if ( ! $this->_check_login() ) {
544
-			return false;
545
-		}
546
-
547
-		// Fetch the new list if the current list is empty or a reload is forced.
548
-		if ( empty( $list ) || (bool) $force ) {
549
-			$response = $this->_request( '/bookmarklet' );
550
-
551
-			if ( is_wp_error( $response ) || 200 !== $response->code ) {
552
-				switch ( $type ) {
553
-					case 'aspects':
554
-						$this->_error( 'wp2d_api_getting_aspects_failed', __( 'Error loading aspects.', 'wp-to-diaspora' ) );
555
-						break;
556
-					case 'services':
557
-						$this->_error( 'wp2d_api_getting_services_failed', __( 'Error loading services.', 'wp-to-diaspora' ) );
558
-						break;
559
-					default:
560
-						$this->_error( 'wp2d_api_getting_aspects_services_failed', _x( 'Unknown error occurred.', 'When an unknown error occurred in the WP2D_API object.', 'wp-to-diaspora' ) );
561
-						break;
562
-				}
563
-				return false;
564
-			}
565
-
566
-			// Load the aspects or services.
567
-			if ( is_array( $raw_list = json_decode( $this->_parse_regex( $type, $response->body ) ) ) ) {
568
-				// In case this fetch is forced, empty the list.
569
-				$list = array();
570
-
571
-				switch ( $type ) {
572
-					case 'aspects':
573
-						// Add the 'public' aspect, as it's global and not user specific.
574
-						$list['public'] = __( 'Public', 'wp-to-diaspora' );
575
-
576
-						// Add all user specific aspects.
577
-						foreach ( $raw_list as $aspect ) {
578
-							$list[ $aspect->id ] = $aspect->name;
579
-						}
580
-						break;
581
-					case 'services':
582
-						foreach ( $raw_list as $service ) {
583
-							$list[ $service ] = ucfirst( $service );
584
-						}
585
-						break;
586
-				}
587
-			}
588
-		}
589
-		return $list;
590
-	}
591
-
592
-	/**
593
-	 * Send an http(s) request via WP_HTTP API.
594
-	 *
595
-	 * @see WP_Http::request()
596
-	 *
597
-	 * @param string $url  The URL to request.
598
-	 * @param array  $args Arguments to be posted with the request.
599
-	 * @return object An object containing details about this request.
600
-	 */
601
-	private function _request( $url, $args = array() ) {
602
-		// Prefix the full pod URL if necessary.
603
-		if ( 0 === strpos( $url, '/' ) ) {
604
-			$url = $this->get_pod_url( $url );
605
-		}
606
-
607
-		// Disable redirections so we can verify HTTP response codes.
608
-		$defaults = array(
609
-			'redirection' => 0,
610
-			'sslverify'   => true,
611
-			'timeout'     => 60,
612
-			'method'      => 'GET',
613
-		);
614
-
615
-		// If the certificate bundle has been downloaded manually, use that instead.
616
-		// NOTE: This should actually never be necessary, it's a fallback!
617
-		if ( file_exists( WP2D_DIR . '/cacert.pem' ) ) {
618
-			$defaults['sslcertificates'] = WP2D_DIR . '/cacert.pem';
619
-		}
620
-
621
-		// Set the correct cookie.
622
-		if ( ! empty( $this->_cookies ) ) {
623
-			$defaults['cookies'] = $this->_cookies;
624
-		}
625
-
626
-		$args = wp_parse_args( $args, $defaults );
627
-
628
-		// Get the response from the WP_HTTP request.
629
-		$response = wp_remote_request( $url, $args );
630
-
631
-		if ( is_wp_error( $response ) ) {
632
-			$this->_last_error = $response;
633
-			return $response;
634
-		}
635
-
636
-		// Get the headers and the html response.
637
-		$headers = wp_remote_retrieve_headers( $response );
638
-		$body    = wp_remote_retrieve_body( $response );
639
-
640
-		// Remember this request.
641
-		$this->_last_request = new stdClass();
642
-		$this->_last_request->response = $response;
643
-		$this->_last_request->headers  = $headers;
644
-		$this->_last_request->body     = $body;
645
-		$this->_last_request->message  = wp_remote_retrieve_response_message( $response );
646
-		$this->_last_request->code     = wp_remote_retrieve_response_code( $response );
647
-
648
-		// Save the new token.
649
-		if ( $token = $this->_parse_regex( 'token', $body ) ) {
650
-			$this->_token = $token;
651
-		}
652
-
653
-		// Save the latest cookies.
654
-		if ( isset( $response['cookies'] ) ) {
655
-			$this->_cookies = $response['cookies'];
656
-		}
657
-
658
-		// Return the last request details.
659
-		return $this->_last_request;
660
-	}
661
-
662
-	/**
663
-	 * Helper method to set the last occurred error.
664
-	 *
665
-	 * @see WP_Error::__construct()
666
-	 * @since 1.6.0
667
-	 *
668
-	 * @param  string|int $code    Error code.
669
-	 * @param  string     $message Error message.
670
-	 * @param  mixed      $data    Error data.
671
-	 */
672
-	private function _error( $code, $message, $data = '' ) {
673
-		// Always add the code and message of the last request.
674
-		$data = array_merge( array_filter( (array) $data ), array(
675
-			'code'    => ( isset( $this->_last_request->code ) ) ? $this->_last_request->code : null,
676
-			'message' => ( isset( $this->_last_request->message ) ) ? $this->_last_request->message : null,
677
-		) );
678
-		$this->_last_error = new WP_Error( $code, $message, $data );
679
-	}
680
-
681
-	/**
682
-	 * Parse the regex and return the found string.
683
-	 *
684
-	 * @param string $regex   Shorthand of a saved regex or a custom regex.
685
-	 * @param string $content Text to parse the regex with.
686
-	 * @return string The found string, or an empty string.
687
-	 */
688
-	private function _parse_regex( $regex, $content ) {
689
-		// Use a shorthand regex if available.
690
-		if ( array_key_exists( $regex, $this->_regexes ) ) {
691
-			$regex = $this->_regexes[ $regex ];
692
-		}
693
-
694
-		preg_match( $regex, $content, $matches );
695
-		return trim( array_pop( $matches ) );
696
-	}
29
+  /**
30
+   * The provider name to display when posting to diaspora*.
31
+   *
32
+   * @var string
33
+   */
34
+  public $provider = 'WP to diaspora*';
35
+
36
+  /**
37
+   * The last http request error that occurred.
38
+   *
39
+   * @var WP_Error
40
+   */
41
+  private $_last_error;
42
+
43
+  /**
44
+   * Security token to be used for making requests.
45
+   *
46
+   * @var string
47
+   */
48
+  private $_token;
49
+
50
+  /**
51
+   * Save the cookies for the requests.
52
+   *
53
+   * @var array
54
+   */
55
+  private $_cookies;
56
+
57
+  /**
58
+   * The last http request made to diaspora*.
59
+   * Contains the response and request infos.
60
+   *
61
+   * @var object
62
+   */
63
+  private $_last_request;
64
+
65
+  /**
66
+   * Is this a secure server, use HTTPS instead of HTTP?
67
+   *
68
+   * @var boolean
69
+   */
70
+  private $_is_secure;
71
+
72
+  /**
73
+   * The pod domain to make the http requests to.
74
+   *
75
+   * @var string
76
+   */
77
+  private $_pod;
78
+
79
+  /**
80
+   * Username to use when logging in to diaspora*.
81
+   *
82
+   * @var string
83
+   */
84
+  private $_username;
85
+
86
+  /**
87
+   * Password to use when logging in to diaspora*.
88
+   *
89
+   * @var string
90
+   */
91
+  private $_password;
92
+
93
+  /**
94
+   * Remember the current login state.
95
+   *
96
+   * @var boolean
97
+   */
98
+  private $_is_logged_in = false;
99
+
100
+  /**
101
+   * The list of user's aspects, which get set after ever http request.
102
+   *
103
+   * @var array
104
+   */
105
+  private $_aspects = array();
106
+
107
+  /**
108
+   * The list of user's connected services, which get set after ever http request.
109
+   *
110
+   * @var array
111
+   */
112
+  private $_services = array();
113
+
114
+  /**
115
+   * List of regex expressions used to filter out details from http request responses.
116
+   *
117
+   * @var array
118
+   */
119
+  private $_regexes = array(
120
+    'token'    => '/content="(.*?)" name="csrf-token"|name="csrf-token" content="(.*?)"/',
121
+    'aspects'  => '/"aspects"\:(\[.*?\])/',
122
+    'services' => '/"configured_services"\:(\[.*?\])/',
123
+  );
124
+
125
+  /**
126
+   * The full pod url, with the used protocol.
127
+   *
128
+   * @param string $path Path to add to the pod url.
129
+   * @return string Full pod url.
130
+   */
131
+  public function get_pod_url( $path = '' ) {
132
+    $path = trim( $path, ' /' );
133
+
134
+    // Add a slash to the beginning?
135
+    if ( '' !== $path ) {
136
+      $path = '/' . $path;
137
+    }
138
+
139
+    return sprintf( 'http%s://%s%s', ( $this->_is_secure ) ? 's' : '', $this->_pod, $path );
140
+  }
141
+
142
+  /**
143
+   * Constructor to initialise the connection to diaspora*.
144
+   *
145
+   * @param string  $pod       The pod domain to connect to.
146
+   * @param boolean $is_secure Is this a secure server? (Default: true).
147
+   */
148
+  public function __construct( $pod, $is_secure = true ) {
149
+    // Set class variables.
150
+    $this->_pod       = $pod;
151
+    $this->_is_secure = (bool) $is_secure;
152
+  }
153
+
154
+  /**
155
+   * Initialise the connection to diaspora*. The pod and protocol can be changed by passing new parameters.
156
+   * Check if we can connect to the pod to retrieve the token.
157
+   *
158
+   * @param string  $pod       Pod domain to connect to, if it should be changed.
159
+   * @param boolean $is_secure Is this a secure server? (Default: true).
160
+   * @return boolean True if we could get the token, else false.
161
+   */
162
+  public function init( $pod = null, $is_secure = true ) {
163
+    // If we are changing pod, we need to fetch a new token.
164
+    $force_new_token = false;
165
+
166
+    // When initialising a connection, clear the last error.
167
+    // This is important when multiple init tries happen.
168
+    $this->_last_error = null;
169
+
170
+    // Change the pod we are connecting to?
171
+    if ( isset( $pod ) && ( $this->_pod !== $pod || $this->_is_secure !== $is_secure ) ) {
172
+      $this->_pod       = $pod;
173
+      $this->_is_secure = (bool) $is_secure;
174
+      $force_new_token  = true;
175
+    }
176
+
177
+    // Get and save the token.
178
+    if ( null === $this->_fetch_token( $force_new_token ) ) {
179
+      $error = ( $this->has_last_error() ) ? ' ' . $this->get_last_error() : '';
180
+      $this->_error( 'wp2d_api_init_failed',
181
+        sprintf(
182
+          _x( 'Failed to initialise connection to pod "%s".', 'Placeholder is the full pod URL.', 'wp-to-diaspora' ),
183
+          $this->get_pod_url()
184
+        ) . $error,
185
+        array( 'help_tab' => 'troubleshooting' )
186
+      );
187
+
188
+      return false;
189
+    }
190
+    return true;
191
+  }
192
+
193
+  /**
194
+   * Check if there is an API error around.
195
+   *
196
+   * @return boolean If there is an API error around.
197
+   */
198
+  public function has_last_error() {
199
+    return is_wp_error( $this->_last_error );
200
+  }
201
+
202
+  /**
203
+   * Get the last API error object.
204
+   *
205
+   * @param boolean $clear If the error should be cleared after returning it.
206
+   * @return WP_Error|null The last API error object or null.
207
+   */
208
+  public function get_last_error_object( $clear = true ) {
209
+    $last_error = $this->_last_error;
210
+    $clear && $this->_last_error = null;
211
+    return $last_error;
212
+  }
213
+
214
+  /**
215
+   * Get the last API error message.
216
+   *
217
+   * @param boolean $clear If the error should be cleared after returning it.
218
+   * @return string The last API error message.
219
+   */
220
+  public function get_last_error( $clear = false ) {
221
+    $last_error = ( $this->has_last_error() ) ? $this->_last_error->get_error_message() : '';
222
+    $clear && $this->_last_error = null;
223
+    return $last_error;
224
+  }
225
+
226
+  /**
227
+   * Fetch the secure token from Diaspora and save it for future use.
228
+   *
229
+   * @param boolean $force Force to fetch a new token.
230
+   * @return string The fetched token.
231
+   */
232
+  private function _fetch_token( $force = false ) {
233
+    if ( ! isset( $this->_token ) || (bool) $force ) {
234
+      // Go directly to the sign in page, as it would redirect to there anyway.
235
+      // Since _request function automatically saves the new token, just call it with no data.
236
+      $this->_request( '/users/sign_in' );
237
+    }
238
+    return $this->_token;
239
+  }
240
+
241
+  /**
242
+   * Check if the API has been initialised. Otherwise set the last error.
243
+   *
244
+   * @return boolean Has the connection been initialised?
245
+   */
246
+  private function _check_init() {
247
+    if ( is_null( $this->_token ) ) {
248
+      $this->_error( 'wp2d_api_connection_not_initialised', __( 'Connection not initialised.', 'wp-to-diaspora' ) );
249
+      return false;
250
+    }
251
+    return true;
252
+  }
253
+
254
+  /**
255
+   * Check if we're logged in. Otherwise set the last error.
256
+   *
257
+   * @return boolean Are we logged in already?
258
+   */
259
+  private function _check_login() {
260
+    if ( ! $this->_check_init() ) {
261
+      return false;
262
+    }
263
+    if ( ! $this->is_logged_in() ) {
264
+      $this->_error( 'wp2d_api_not_logged_in', __( 'Not logged in.', 'wp-to-diaspora' ) );
265
+      return false;
266
+    }
267
+    return true;
268
+  }
269
+
270
+  /**
271
+   * Check if we are logged in.
272
+   *
273
+   * @return boolean Are we logged in already?
274
+   */
275
+  public function is_logged_in() {
276
+    return $this->_is_logged_in;
277
+  }
278
+
279
+  /**
280
+   * Log in to diaspora*.
281
+   *
282
+   * @param string  $username Username used for login.
283
+   * @param string  $password Password used for login.
284
+   * @param boolean $force    Force a new login even if we are already logged in.
285
+   * @return boolean Did the login succeed?
286
+   */
287
+  public function login( $username, $password, $force = false ) {
288
+    // Has the connection been initialised?
289
+    if ( ! $this->_check_init() ) {
290
+      $this->logout();
291
+      return false;
292
+    }
293
+
294
+    // Username and password both need to be set.
295
+    $username = ( isset( $username ) && '' !== $username ) ? $username : null;
296
+    $password = ( isset( $password ) && '' !== $password ) ? $password : null;
297
+    if ( ! isset( $username, $password ) ) {
298
+      $this->logout();
299
+      return false;
300
+    }
301
+
302
+    // If we are already logged in and not forcing a relogin, return.
303
+    if ( ! $force && $this->is_logged_in() &&
304
+      $username === $this->_username &&
305
+      $password === $this->_password ) {
306
+      return true;
307
+    }
308
+
309
+    // Set the newly passed username and password.
310
+    $this->_username = $username;
311
+    $this->_password = $password;
312
+
313
+    // Set up the login parameters.
314
+    $params = array(
315
+      'user[username]'     => $this->_username,
316
+      'user[password]'     => $this->_password,
317
+      'authenticity_token' => $this->_fetch_token(),
318
+    );
319
+
320
+    $args = array(
321
+      'method' => 'POST',
322
+      'body'   => $params,
323
+    );
324
+
325
+    // Try to sign in.
326
+    $this->_request( '/users/sign_in', $args );
327
+
328
+    // Can we load the bookmarklet to make sure we're logged in?
329
+    $response = $this->_request( '/bookmarklet' );
330
+
331
+    // If the request isn't successful, we are not logged in correctly.
332
+    if ( is_wp_error( $response ) || 200 !== $response->code ) {
333
+      // Login failed.
334
+      $this->_error( 'wp2d_api_login_failed', __( 'Login failed. Check your login details.', 'wp-to-diaspora' ), array( 'help_tab' => 'troubleshooting' ) );
335
+      $this->logout();
336
+      return false;
337
+    }
338
+
339
+    // Login succeeded.
340
+    $this->_is_logged_in = true;
341
+    return true;
342
+  }
343
+
344
+  /**
345
+   * Perform a logout, resetting all login info.
346
+   *
347
+   * @since 1.6.0
348
+   */
349
+  public function logout() {
350
+    $this->_is_logged_in = false;
351
+    $this->_username = null;
352
+    $this->_password = null;
353
+    $this->_aspects = array();
354
+    $this->_services = array();
355
+  }
356
+
357
+  /**
358
+   * Perform a deinitialisation, resetting all class variables.
359
+   *
360
+   * @since 1.7.0
361
+   */
362
+  public function deinit() {
363
+    $this->logout();
364
+    $this->_last_error = null;
365
+    $this->_token = null;
366
+    $this->_cookies = array();
367
+    $this->_last_request = null;
368
+  }
369
+
370
+  /**
371
+   * Post to diaspora*.
372
+   *
373
+   * @param string       $text       The text to post.
374
+   * @param array|string $aspects    The aspects to post to. Array or comma seperated ids.
375
+   * @param array        $extra_data Any extra data to be added to the post call.
376
+   * @return boolean|object Return the response data of the new diaspora* post if successfully posted, else false.
377
+   */
378
+  public function post( $text, $aspects = 'public', $extra_data = array() ) {
379
+    // Are we logged in?
380
+    if ( ! $this->_check_login() ) {
381
+      return false;
382
+    }
383
+
384
+    // Put the aspects into a clean array.
385
+    $aspects = array_filter( WP2D_Helpers::str_to_arr( $aspects ) );
386
+
387
+    // If no aspects have been selected or the public one is also included, choose public only.
388
+    if ( empty( $aspects ) || in_array( 'public', $aspects ) ) {
389
+      $aspects = 'public';
390
+    }
391
+
392
+    // Prepare post data.
393
+    $post_data = array(
394
+      'aspect_ids'     => $aspects,
395
+      'status_message' => array(
396
+        'text' => $text,
397
+        'provider_display_name' => $this->provider,
398
+      ),
399
+    );
400
+
401
+    // Add any extra data to the post.
402
+    if ( ! empty( $extra_data ) ) {
403
+        $post_data += $extra_data;
404
+    }
405
+
406
+    // Check if we can use the new wp_json_encode function.
407
+    $post_data = ( function_exists( 'wp_json_encode' ) )
408
+      ? wp_json_encode( $post_data )
409
+      : json_encode( $post_data );
410
+
411
+    $args = array(
412
+      'method'  => 'POST',
413
+      'body'    => $post_data,
414
+      'headers' => array(
415
+        'Accept'       => 'application/json',
416
+        'Content-Type' => 'application/json',
417
+        'X-CSRF-Token' => $this->_fetch_token(),
418
+      ),
419
+    );
420
+
421
+    // Submit the post.
422
+    $response = $this->_request( '/status_messages', $args );
423
+
424
+    if ( is_wp_error( $response ) ) {
425
+      $this->_error( 'wp2d_api_post_failed', $response->get_error_message() );
426
+      return false;
427
+    }
428
+
429
+    $diaspost = json_decode( $response->body );
430
+    if ( 201 !== $response->code ) {
431
+      $this->_error( 'wp2d_api_post_failed', ( isset( $diaspost->error ) ) ? $diaspost->error : _x( 'Unknown error occurred.', 'When an unknown error occurred in the WP2D_API object.', 'wp-to-diaspora' ) );
432
+      return false;
433
+    }
434
+
435
+    // Add additional info to our diaspora post object.
436
+    $diaspost->permalink = $this->get_pod_url( '/posts/' . $diaspost->guid );
437
+
438
+    return $diaspost;
439
+  }
440
+
441
+  /**
442
+   * Delete a post or comment from diaspora*.
443
+   *
444
+   * @since 1.6.0
445
+   *
446
+   * @param string $what What to delete, 'post' or 'comment'.
447
+   * @param string $id The ID of the post or comment to delete.
448
+   * @return boolean If the deletion was successful.
449
+   */
450
+  public function delete( $what, $id ) {
451
+    // Are we logged in?
452
+    if ( ! $this->_check_login() ) {
453
+      return false;
454
+    }
455
+
456
+    // For now, only deleting posts and comments is allowed.
457
+    if ( ! in_array( $what, array( 'post', 'comment' ) ) ) {
458
+      $this->_error( 'wp2d_api_delete_failed', __( 'You can only delete posts and comments.', 'wp-to-diaspora' ) );
459
+      return false;
460
+    }
461
+
462
+    $args = array(
463
+      'method'  => 'DELETE',
464
+      'headers' => array(
465
+        'Accept'       => 'application/json',
466
+        'Content-Type' => 'application/json',
467
+        'X-CSRF-Token' => $this->_fetch_token(),
468
+      ),
469
+    );
470
+
471
+    // Try to delete the post or comment.
472
+    $response = $this->_request( '/' . $what . 's/' . $id, $args );
473
+
474
+    $error_message = '';
475
+
476
+    if ( is_wp_error( $response ) ) {
477
+      $error_message = $response->get_error_message();
478
+    } else {
479
+      switch ( $response->code ) {
480
+        case 204:
481
+          return true;
482
+        case 404:
483
+          $error_message = ( 'post' === $what )
484
+            ? __( 'The post you tried to delete does not exist.', 'wp-to-diaspora' )
485
+            : __( 'The comment you tried to delete does not exist.', 'wp-to-diaspora' );
486
+          break;
487
+
488
+        // Due to diaspora* returning a proper 403 when trying to delete a foreign comment
489
+        // but returning a 500 when trying to delete a foreign post, this needs some special attention.
490
+        case 403:
491
+          if ( 'comment' === $what ) {
492
+            $error_message = __( 'The comment you tried to delete does not belong to you.', 'wp-to-diaspora' );
493
+            break;
494
+          }
495
+          // Fall through...
496
+        case 500:
497
+          if ( 'post' === $what ) {
498
+            $error_message = __( 'The post you tried to delete does not belong to you.', 'wp-to-diaspora' );
499
+            break;
500
+          }
501
+          // Fall through...
502
+        default:
503
+          $error_message = _x( 'Unknown error occurred.', 'When an unknown error occurred in the WP2D_API object.', 'wp-to-diaspora' );
504
+          break;
505
+      }
506
+    }
507
+
508
+    $this->_error( 'wp2d_api_delete_' . $what . '_failed', $error_message );
509
+    return false;
510
+  }
511
+
512
+  /**
513
+   * Get the list of aspects.
514
+   *
515
+   * @param boolean $force Force to fetch new aspects.
516
+   * @return array Array of aspect objects.
517
+   */
518
+  public function get_aspects( $force = false ) {
519
+    $this->_aspects = $this->_get_aspects_services( 'aspects', $this->_aspects, $force );
520
+    return ( is_array( $this->_aspects ) ) ? $this->_aspects : false;
521
+  }
522
+
523
+  /**
524
+   * Get the list of connected services.
525
+   *
526
+   * @param boolean $force Force to fetch new connected services.
527
+   * @return array Array of service objects.
528
+   */
529
+  public function get_services( $force = false ) {
530
+    $this->_services = $this->_get_aspects_services( 'services', $this->_services, $force );
531
+    return ( is_array( $this->_services ) ) ? $this->_services : false;
532
+  }
533
+
534
+  /**
535
+   * Get the list of aspects or connected services.
536
+   *
537
+   * @param string  $type  Type of list to get.
538
+   * @param array   $list  The current list of items.
539
+   * @param boolean $force Force to fetch new list.
540
+   * @return boolean Was the list fetched successfully?
541
+   */
542
+  private function _get_aspects_services( $type, $list, $force ) {
543
+    if ( ! $this->_check_login() ) {
544
+      return false;
545
+    }
546
+
547
+    // Fetch the new list if the current list is empty or a reload is forced.
548
+    if ( empty( $list ) || (bool) $force ) {
549
+      $response = $this->_request( '/bookmarklet' );
550
+
551
+      if ( is_wp_error( $response ) || 200 !== $response->code ) {
552
+        switch ( $type ) {
553
+          case 'aspects':
554
+            $this->_error( 'wp2d_api_getting_aspects_failed', __( 'Error loading aspects.', 'wp-to-diaspora' ) );
555
+            break;
556
+          case 'services':
557
+            $this->_error( 'wp2d_api_getting_services_failed', __( 'Error loading services.', 'wp-to-diaspora' ) );
558
+            break;
559
+          default:
560
+            $this->_error( 'wp2d_api_getting_aspects_services_failed', _x( 'Unknown error occurred.', 'When an unknown error occurred in the WP2D_API object.', 'wp-to-diaspora' ) );
561
+            break;
562
+        }
563
+        return false;
564
+      }
565
+
566
+      // Load the aspects or services.
567
+      if ( is_array( $raw_list = json_decode( $this->_parse_regex( $type, $response->body ) ) ) ) {
568
+        // In case this fetch is forced, empty the list.
569
+        $list = array();
570
+
571
+        switch ( $type ) {
572
+          case 'aspects':
573
+            // Add the 'public' aspect, as it's global and not user specific.
574
+            $list['public'] = __( 'Public', 'wp-to-diaspora' );
575
+
576
+            // Add all user specific aspects.
577
+            foreach ( $raw_list as $aspect ) {
578
+              $list[ $aspect->id ] = $aspect->name;
579
+            }
580
+            break;
581
+          case 'services':
582
+            foreach ( $raw_list as $service ) {
583
+              $list[ $service ] = ucfirst( $service );
584
+            }
585
+            break;
586
+        }
587
+      }
588
+    }
589
+    return $list;
590
+  }
591
+
592
+  /**
593
+   * Send an http(s) request via WP_HTTP API.
594
+   *
595
+   * @see WP_Http::request()
596
+   *
597
+   * @param string $url  The URL to request.
598
+   * @param array  $args Arguments to be posted with the request.
599
+   * @return object An object containing details about this request.
600
+   */
601
+  private function _request( $url, $args = array() ) {
602
+    // Prefix the full pod URL if necessary.
603
+    if ( 0 === strpos( $url, '/' ) ) {
604
+      $url = $this->get_pod_url( $url );
605
+    }
606
+
607
+    // Disable redirections so we can verify HTTP response codes.
608
+    $defaults = array(
609
+      'redirection' => 0,
610
+      'sslverify'   => true,
611
+      'timeout'     => 60,
612
+      'method'      => 'GET',
613
+    );
614
+
615
+    // If the certificate bundle has been downloaded manually, use that instead.
616
+    // NOTE: This should actually never be necessary, it's a fallback!
617
+    if ( file_exists( WP2D_DIR . '/cacert.pem' ) ) {
618
+      $defaults['sslcertificates'] = WP2D_DIR . '/cacert.pem';
619
+    }
620
+
621
+    // Set the correct cookie.
622
+    if ( ! empty( $this->_cookies ) ) {
623
+      $defaults['cookies'] = $this->_cookies;
624
+    }
625
+
626
+    $args = wp_parse_args( $args, $defaults );
627
+
628
+    // Get the response from the WP_HTTP request.
629
+    $response = wp_remote_request( $url, $args );
630
+
631
+    if ( is_wp_error( $response ) ) {
632
+      $this->_last_error = $response;
633
+      return $response;
634
+    }
635
+
636
+    // Get the headers and the html response.
637
+    $headers = wp_remote_retrieve_headers( $response );
638
+    $body    = wp_remote_retrieve_body( $response );
639
+
640
+    // Remember this request.
641
+    $this->_last_request = new stdClass();
642
+    $this->_last_request->response = $response;
643
+    $this->_last_request->headers  = $headers;
644
+    $this->_last_request->body     = $body;
645
+    $this->_last_request->message  = wp_remote_retrieve_response_message( $response );
646
+    $this->_last_request->code     = wp_remote_retrieve_response_code( $response );
647
+
648
+    // Save the new token.
649
+    if ( $token = $this->_parse_regex( 'token', $body ) ) {
650
+      $this->_token = $token;
651
+    }
652
+
653
+    // Save the latest cookies.
654
+    if ( isset( $response['cookies'] ) ) {
655
+      $this->_cookies = $response['cookies'];
656
+    }
657
+
658
+    // Return the last request details.
659
+    return $this->_last_request;
660
+  }
661
+
662
+  /**
663
+   * Helper method to set the last occurred error.
664
+   *
665
+   * @see WP_Error::__construct()
666
+   * @since 1.6.0
667
+   *
668
+   * @param  string|int $code    Error code.
669
+   * @param  string     $message Error message.
670
+   * @param  mixed      $data    Error data.
671
+   */
672
+  private function _error( $code, $message, $data = '' ) {
673
+    // Always add the code and message of the last request.
674
+    $data = array_merge( array_filter( (array) $data ), array(
675
+      'code'    => ( isset( $this->_last_request->code ) ) ? $this->_last_request->code : null,
676
+      'message' => ( isset( $this->_last_request->message ) ) ? $this->_last_request->message : null,
677
+    ) );
678
+    $this->_last_error = new WP_Error( $code, $message, $data );
679
+  }
680
+
681
+  /**
682
+   * Parse the regex and return the found string.
683
+   *
684
+   * @param string $regex   Shorthand of a saved regex or a custom regex.
685
+   * @param string $content Text to parse the regex with.
686
+   * @return string The found string, or an empty string.
687
+   */
688
+  private function _parse_regex( $regex, $content ) {
689
+    // Use a shorthand regex if available.
690
+    if ( array_key_exists( $regex, $this->_regexes ) ) {
691
+      $regex = $this->_regexes[ $regex ];
692
+    }
693
+
694
+    preg_match( $regex, $content, $matches );
695
+    return trim( array_pop( $matches ) );
696
+  }
697 697
 }
Please login to merge, or discard this patch.
wp-to-diaspora.php 1 patch
Spacing   +100 added lines, -100 removed lines patch added patch discarded remove patch
@@ -30,10 +30,10 @@  discard block
 block discarded – undo
30 30
  */
31 31
 
32 32
 // Exit if accessed directly.
33
-defined( 'ABSPATH' ) || exit;
33
+defined('ABSPATH') || exit;
34 34
 
35 35
 // Set the current version.
36
-define( 'WP2D_VERSION', '1.7' );
36
+define('WP2D_VERSION', '1.7');
37 37
 
38 38
 /**
39 39
  * WP to diaspora* main plugin class.
@@ -78,10 +78,10 @@  discard block
 block discarded – undo
78 78
 	 * @return WP_To_Diaspora Instance of this class.
79 79
 	 */
80 80
 	public static function instance() {
81
-		if ( ! isset( self::$_instance ) ) {
81
+		if ( ! isset(self::$_instance)) {
82 82
 			self::$_instance = new self();
83 83
 			self::$_instance->_constants();
84
-			if ( self::$_instance->_version_check() ) {
84
+			if (self::$_instance->_version_check()) {
85 85
 				self::$_instance->_includes();
86 86
 				self::$_instance->_setup();
87 87
 			} else {
@@ -98,13 +98,13 @@  discard block
 block discarded – undo
98 98
 	 */
99 99
 	private function _constants() {
100 100
 		// Are we in debugging mode?
101
-		if ( isset( $_GET['debugging'] ) ) {
102
-			define( 'WP2D_DEBUGGING', true );
101
+		if (isset($_GET['debugging'])) {
102
+			define('WP2D_DEBUGGING', true);
103 103
 		}
104 104
 
105
-		define( 'WP2D_DIR', dirname( __FILE__ ) );
106
-		define( 'WP2D_LIB_DIR', WP2D_DIR . '/lib' );
107
-		define( 'WP2D_VENDOR_DIR', WP2D_DIR . '/vendor' );
105
+		define('WP2D_DIR', dirname(__FILE__));
106
+		define('WP2D_LIB_DIR', WP2D_DIR.'/lib');
107
+		define('WP2D_VENDOR_DIR', WP2D_DIR.'/vendor');
108 108
 	}
109 109
 
110 110
 	/**
@@ -116,9 +116,9 @@  discard block
 block discarded – undo
116 116
 	 */
117 117
 	private function _version_check() {
118 118
 		// Check for version requirements.
119
-		if ( version_compare( $GLOBALS['wp_version'], $this->_min_wp, '<' )
120
-			|| version_compare( PHP_VERSION, $this->_min_php, '<' ) ) {
121
-			add_action( 'admin_notices', array( $this, 'deactivate' ) );
119
+		if (version_compare($GLOBALS['wp_version'], $this->_min_wp, '<')
120
+			|| version_compare(PHP_VERSION, $this->_min_php, '<')) {
121
+			add_action('admin_notices', array($this, 'deactivate'));
122 122
 			return false;
123 123
 		}
124 124
 
@@ -132,15 +132,15 @@  discard block
 block discarded – undo
132 132
 	 */
133 133
 	public function deactivate() {
134 134
 		// First of all, deactivate the plugin.
135
-		deactivate_plugins( plugin_basename( __FILE__ ) );
135
+		deactivate_plugins(plugin_basename(__FILE__));
136 136
 
137 137
 		// Get rid of the "Plugin activated" message.
138
-		unset( $_GET['activate'] );
138
+		unset($_GET['activate']);
139 139
 
140 140
 		// Then display the admin notice.
141 141
 		?>
142 142
 		<div class="error">
143
-			<p><?php echo esc_html( sprintf( 'WP to diaspora* requires at least WordPress %1$s (you have %2$s) and PHP %3$s (you have %4$s)!', $this->_min_wp, $GLOBALS['wp_version'], $this->_min_php, PHP_VERSION ) ); ?></p>
143
+			<p><?php echo esc_html(sprintf('WP to diaspora* requires at least WordPress %1$s (you have %2$s) and PHP %3$s (you have %4$s)!', $this->_min_wp, $GLOBALS['wp_version'], $this->_min_php, PHP_VERSION)); ?></p>
144 144
 		</div>
145 145
 		<?php
146 146
 	}
@@ -151,12 +151,12 @@  discard block
 block discarded – undo
151 151
 	 * @since 1.5.0
152 152
 	 */
153 153
 	private function _includes() {
154
-		require WP2D_VENDOR_DIR . '/autoload.php';
155
-		require_once WP2D_LIB_DIR . '/class-api.php';
156
-		require_once WP2D_LIB_DIR . '/class-contextual-help.php';
157
-		require_once WP2D_LIB_DIR . '/class-helpers.php';
158
-		require_once WP2D_LIB_DIR . '/class-options.php';
159
-		require_once WP2D_LIB_DIR . '/class-post.php';
154
+		require WP2D_VENDOR_DIR.'/autoload.php';
155
+		require_once WP2D_LIB_DIR.'/class-api.php';
156
+		require_once WP2D_LIB_DIR.'/class-contextual-help.php';
157
+		require_once WP2D_LIB_DIR.'/class-helpers.php';
158
+		require_once WP2D_LIB_DIR.'/class-options.php';
159
+		require_once WP2D_LIB_DIR.'/class-post.php';
160 160
 	}
161 161
 
162 162
 	/**
@@ -165,30 +165,30 @@  discard block
 block discarded – undo
165 165
 	private function _setup() {
166 166
 
167 167
 		// Load languages.
168
-		add_action( 'plugins_loaded', array( $this, 'l10n' ) );
168
+		add_action('plugins_loaded', array($this, 'l10n'));
169 169
 
170 170
 		// Add "Settings" link to plugin page.
171
-		add_filter( 'plugin_action_links_' . plugin_basename( __FILE__ ), array( $this, 'settings_link' ) );
171
+		add_filter('plugin_action_links_'.plugin_basename(__FILE__), array($this, 'settings_link'));
172 172
 
173 173
 		// Perform any necessary data upgrades.
174
-		add_action( 'admin_init', array( $this, 'upgrade' ) );
174
+		add_action('admin_init', array($this, 'upgrade'));
175 175
 
176 176
 		// Enqueue CSS and JS scripts.
177
-		add_action( 'admin_enqueue_scripts', array( $this, 'admin_load_scripts' ) );
177
+		add_action('admin_enqueue_scripts', array($this, 'admin_load_scripts'));
178 178
 
179 179
 		// Set up the options.
180
-		add_action( 'init', array( 'WP2D_Options', 'instance' ) );
180
+		add_action('init', array('WP2D_Options', 'instance'));
181 181
 
182 182
 		// WP2D Post.
183
-		add_action( 'init', array( 'WP2D_Post', 'setup' ) );
183
+		add_action('init', array('WP2D_Post', 'setup'));
184 184
 
185 185
 		// AJAX actions for loading pods, aspects and services.
186
-		add_action( 'wp_ajax_wp_to_diaspora_update_pod_list', array( $this, 'update_pod_list_callback' ) );
187
-		add_action( 'wp_ajax_wp_to_diaspora_update_aspects_list', array( $this, 'update_aspects_list_callback' ) );
188
-		add_action( 'wp_ajax_wp_to_diaspora_update_services_list', array( $this, 'update_services_list_callback' ) );
186
+		add_action('wp_ajax_wp_to_diaspora_update_pod_list', array($this, 'update_pod_list_callback'));
187
+		add_action('wp_ajax_wp_to_diaspora_update_aspects_list', array($this, 'update_aspects_list_callback'));
188
+		add_action('wp_ajax_wp_to_diaspora_update_services_list', array($this, 'update_services_list_callback'));
189 189
 
190 190
 		// Check the pod connection status on the options page.
191
-		add_action( 'wp_ajax_wp_to_diaspora_check_pod_connection_status', array( $this, 'check_pod_connection_status_callback' ) );
191
+		add_action('wp_ajax_wp_to_diaspora_check_pod_connection_status', array($this, 'check_pod_connection_status_callback'));
192 192
 	}
193 193
 
194 194
 	/**
@@ -197,7 +197,7 @@  discard block
 block discarded – undo
197 197
 	 * @return WP2D_API|boolean The API object, or false.
198 198
 	 */
199 199
 	private function _load_api() {
200
-		if ( ! isset( $this->_api ) ) {
200
+		if ( ! isset($this->_api)) {
201 201
 			$this->_api = WP2D_Helpers::api_quick_connect();
202 202
 		}
203 203
 		return $this->_api;
@@ -209,40 +209,40 @@  discard block
 block discarded – undo
209 209
 	public function upgrade() {
210 210
 		// Get the current options, or assign defaults.
211 211
 		$options = WP2D_Options::instance();
212
-		$version = $options->get_option( 'version' );
212
+		$version = $options->get_option('version');
213 213
 
214 214
 		// If the versions differ, this is probably an update. Need to save updated options.
215
-		if ( WP2D_VERSION !== $version ) {
215
+		if (WP2D_VERSION !== $version) {
216 216
 
217 217
 			// Password is stored encrypted since version 1.2.7.
218 218
 			// When upgrading to it, the plain text password is encrypted and saved again.
219
-			if ( version_compare( $version, '1.2.7', '<' ) ) {
220
-				$options->set_option( 'password', WP2D_Helpers::encrypt( (string) $options->get_option( 'password' ) ) );
219
+			if (version_compare($version, '1.2.7', '<')) {
220
+				$options->set_option('password', WP2D_Helpers::encrypt((string) $options->get_option('password')));
221 221
 			}
222 222
 
223
-			if ( version_compare( $version, '1.3.0', '<' ) ) {
223
+			if (version_compare($version, '1.3.0', '<')) {
224 224
 				// The 'user' setting is renamed to 'username'.
225
-				$options->set_option( 'username', $options->get_option( 'user' ) );
226
-				$options->set_option( 'user', null );
225
+				$options->set_option('username', $options->get_option('user'));
226
+				$options->set_option('user', null);
227 227
 
228 228
 				// Save tags as arrays instead of comma seperated values.
229
-				$global_tags = $options->get_option( 'global_tags' );
230
-				$options->set_option( 'global_tags', $options->validate_tags( $global_tags ) );
229
+				$global_tags = $options->get_option('global_tags');
230
+				$options->set_option('global_tags', $options->validate_tags($global_tags));
231 231
 			}
232 232
 
233
-			if ( version_compare( $version, '1.4.0', '<' ) ) {
233
+			if (version_compare($version, '1.4.0', '<')) {
234 234
 				// Turn tags_to_post string into an array.
235
-				$tags_to_post_old = $options->get_option( 'tags_to_post' );
236
-				$tags_to_post = array_filter( array(
237
-					( ( false !== strpos( $tags_to_post_old, 'g' ) ) ? 'global' : null ),
238
-					( ( false !== strpos( $tags_to_post_old, 'c' ) ) ? 'custom' : null ),
239
-					( ( false !== strpos( $tags_to_post_old, 'p' ) ) ? 'post'   : null ),
240
-				) );
241
-				$options->set_option( 'tags_to_post', $tags_to_post );
235
+				$tags_to_post_old = $options->get_option('tags_to_post');
236
+				$tags_to_post = array_filter(array(
237
+					((false !== strpos($tags_to_post_old, 'g')) ? 'global' : null),
238
+					((false !== strpos($tags_to_post_old, 'c')) ? 'custom' : null),
239
+					((false !== strpos($tags_to_post_old, 'p')) ? 'post' : null),
240
+				));
241
+				$options->set_option('tags_to_post', $tags_to_post);
242 242
 			}
243 243
 
244 244
 			// Update version.
245
-			$options->set_option( 'version', WP2D_VERSION );
245
+			$options->set_option('version', WP2D_VERSION);
246 246
 			$options->save();
247 247
 		}
248 248
 	}
@@ -251,7 +251,7 @@  discard block
 block discarded – undo
251 251
 	 * Set up i18n.
252 252
 	 */
253 253
 	public function l10n() {
254
-		load_plugin_textdomain( 'wp-to-diaspora', false, 'wp-to-diaspora/languages' );
254
+		load_plugin_textdomain('wp-to-diaspora', false, 'wp-to-diaspora/languages');
255 255
 	}
256 256
 
257 257
 	/**
@@ -259,27 +259,27 @@  discard block
 block discarded – undo
259 259
 	 */
260 260
 	public function admin_load_scripts() {
261 261
 		// Get the enabled post types to load the script for.
262
-		$enabled_post_types = WP2D_Options::instance()->get_option( 'enabled_post_types', array() );
262
+		$enabled_post_types = WP2D_Options::instance()->get_option('enabled_post_types', array());
263 263
 
264 264
 		// Get the screen to find out where we are.
265 265
 		$screen = get_current_screen();
266 266
 
267 267
 		// Only load the styles and scripts on the settings page and the allowed post types.
268
-		if ( 'settings_page_wp_to_diaspora' === $screen->id || ( in_array( $screen->post_type, $enabled_post_types ) && 'post' === $screen->base ) ) {
269
-			wp_enqueue_style( 'tag-it', plugins_url( '/css/jquery.tagit.css', __FILE__ ) );
270
-			wp_enqueue_style( 'chosen', plugins_url( '/css/chosen.min.css', __FILE__ ) );
271
-			wp_enqueue_style( 'wp-to-diaspora-admin', plugins_url( '/css/wp-to-diaspora.css', __FILE__ ) );
272
-			wp_enqueue_script( 'chosen', plugins_url( '/js/chosen.jquery.min.js', __FILE__ ), array( 'jquery' ), false, true );
273
-			wp_enqueue_script( 'tag-it', plugins_url( '/js/tag-it.min.js', __FILE__ ), array( 'jquery', 'jquery-ui-autocomplete' ), false, true );
274
-			wp_enqueue_script( 'wp-to-diaspora-admin', plugins_url( '/js/wp-to-diaspora.js', __FILE__ ), array( 'jquery' ), false, true );
268
+		if ('settings_page_wp_to_diaspora' === $screen->id || (in_array($screen->post_type, $enabled_post_types) && 'post' === $screen->base)) {
269
+			wp_enqueue_style('tag-it', plugins_url('/css/jquery.tagit.css', __FILE__));
270
+			wp_enqueue_style('chosen', plugins_url('/css/chosen.min.css', __FILE__));
271
+			wp_enqueue_style('wp-to-diaspora-admin', plugins_url('/css/wp-to-diaspora.css', __FILE__));
272
+			wp_enqueue_script('chosen', plugins_url('/js/chosen.jquery.min.js', __FILE__), array('jquery'), false, true);
273
+			wp_enqueue_script('tag-it', plugins_url('/js/tag-it.min.js', __FILE__), array('jquery', 'jquery-ui-autocomplete'), false, true);
274
+			wp_enqueue_script('wp-to-diaspora-admin', plugins_url('/js/wp-to-diaspora.js', __FILE__), array('jquery'), false, true);
275 275
 			// Javascript-specific l10n.
276
-			wp_localize_script( 'wp-to-diaspora-admin', 'WP2DL10n', array(
277
-				'no_services_connected' => __( 'No services connected yet.', 'wp-to-diaspora' ),
278
-				'sure_reset_defaults'   => __( 'Are you sure you want to reset to default values?', 'wp-to-diaspora' ),
279
-				'conn_testing'          => __( 'Testing connection...', 'wp-to-diaspora' ),
280
-				'conn_successful'       => __( 'Connection successful.', 'wp-to-diaspora' ),
281
-				'conn_failed'           => __( 'Connection failed.', 'wp-to-diaspora' ),
282
-			) );
276
+			wp_localize_script('wp-to-diaspora-admin', 'WP2DL10n', array(
277
+				'no_services_connected' => __('No services connected yet.', 'wp-to-diaspora'),
278
+				'sure_reset_defaults'   => __('Are you sure you want to reset to default values?', 'wp-to-diaspora'),
279
+				'conn_testing'          => __('Testing connection...', 'wp-to-diaspora'),
280
+				'conn_successful'       => __('Connection successful.', 'wp-to-diaspora'),
281
+				'conn_failed'           => __('Connection failed.', 'wp-to-diaspora'),
282
+			));
283 283
 		}
284 284
 	}
285 285
 
@@ -289,8 +289,8 @@  discard block
 block discarded – undo
289 289
 	 * @param array $links Links to display for plugin on plugins page.
290 290
 	 * @return array Links to display for plugin on plugins page.
291 291
 	 */
292
-	public function settings_link( $links ) {
293
-		$links[] = '<a href="' . admin_url( 'options-general.php?page=wp_to_diaspora' ) . '">' . __( 'Settings' ) . '</a>';
292
+	public function settings_link($links) {
293
+		$links[] = '<a href="'.admin_url('options-general.php?page=wp_to_diaspora').'">'.__('Settings').'</a>';
294 294
 		return $links;
295 295
 	}
296 296
 
@@ -305,14 +305,14 @@  discard block
 block discarded – undo
305 305
 		$pods = array();
306 306
 
307 307
 		// Get the response from the WP_HTTP request.
308
-		$response = wp_safe_remote_get( $pod_list_url );
308
+		$response = wp_safe_remote_get($pod_list_url);
309 309
 
310
-		if ( $json = wp_remote_retrieve_body( $response ) ) {
311
-			$pod_list = json_decode( $json );
310
+		if ($json = wp_remote_retrieve_body($response)) {
311
+			$pod_list = json_decode($json);
312 312
 
313
-			if ( isset( $pod_list->pods ) ) {
314
-				foreach ( $pod_list->pods as $pod ) {
315
-					if ( 'no' === $pod->hidden ) {
313
+			if (isset($pod_list->pods)) {
314
+				foreach ($pod_list->pods as $pod) {
315
+					if ('no' === $pod->hidden) {
316 316
 						$pods[] = array(
317 317
 							'secure' => $pod->secure,
318 318
 							'domain' => $pod->domain,
@@ -321,7 +321,7 @@  discard block
 block discarded – undo
321 321
 				}
322 322
 
323 323
 				$options = WP2D_Options::instance();
324
-				$options->set_option( 'pod_list', $pods );
324
+				$options->set_option('pod_list', $pods);
325 325
 				$options->save();
326 326
 			}
327 327
 		}
@@ -333,7 +333,7 @@  discard block
 block discarded – undo
333 333
 	 * Update the list of pods and return them for use with AJAX.
334 334
 	 */
335 335
 	public function update_pod_list_callback() {
336
-		wp_send_json( $this->_update_pod_list() );
336
+		wp_send_json($this->_update_pod_list());
337 337
 	}
338 338
 
339 339
 	/**
@@ -344,40 +344,40 @@  discard block
 block discarded – undo
344 344
 	 * @param string $type Type of list to update.
345 345
 	 * @return array|boolean The list of aspects or services, false if an illegal parameter is passed.
346 346
 	 */
347
-	private function _update_aspects_services_list( $type ) {
347
+	private function _update_aspects_services_list($type) {
348 348
 		// Check for correct argument value.
349
-		if ( ! in_array( $type, array( 'aspects', 'services' ) ) ) {
349
+		if ( ! in_array($type, array('aspects', 'services'))) {
350 350
 			return false;
351 351
 		}
352 352
 
353 353
 		$options = WP2D_Options::instance();
354
-		$list    = $options->get_option( $type . '_list' );
354
+		$list    = $options->get_option($type.'_list');
355 355
 
356 356
 		// Make sure that we have at least the 'Public' aspect.
357
-		if ( 'aspects' === $type && empty( $list ) ) {
358
-			$list = array( 'public' => __( 'Public' ) );
357
+		if ('aspects' === $type && empty($list)) {
358
+			$list = array('public' => __('Public'));
359 359
 		}
360 360
 
361 361
 		// Set up the connection to diaspora*.
362 362
 		$api = $this->_load_api();
363 363
 
364 364
 		// If there was a problem loading the API, return false.
365
-		if ( $api->has_last_error() ) {
365
+		if ($api->has_last_error()) {
366 366
 			return false;
367 367
 		}
368 368
 
369
-		if ( 'aspects' === $type ) {
370
-			$list_new = $api->get_aspects( true );
371
-		} elseif ( 'services' === $type ) {
372
-			$list_new = $api->get_services( true );
369
+		if ('aspects' === $type) {
370
+			$list_new = $api->get_aspects(true);
371
+		} elseif ('services' === $type) {
372
+			$list_new = $api->get_services(true);
373 373
 		}
374 374
 		// If the new list couldn't be fetched successfully, return false.
375
-		if ( $api->has_last_error() ) {
375
+		if ($api->has_last_error()) {
376 376
 			return false;
377 377
 		}
378 378
 
379 379
 		// We have a new list to save and return!
380
-		$options->set_option( $type . '_list', $list_new );
380
+		$options->set_option($type.'_list', $list_new);
381 381
 		$options->save();
382 382
 
383 383
 		return $list_new;
@@ -387,14 +387,14 @@  discard block
 block discarded – undo
387 387
 	 * Update the list of aspects and return them for use with AJAX.
388 388
 	 */
389 389
 	public function update_aspects_list_callback() {
390
-		wp_send_json( $this->_update_aspects_services_list( 'aspects' ) );
390
+		wp_send_json($this->_update_aspects_services_list('aspects'));
391 391
 	}
392 392
 
393 393
 	/**
394 394
 	 * Update the list of services and return them for use with AJAX.
395 395
 	 */
396 396
 	public function update_services_list_callback() {
397
-		wp_send_json( $this->_update_aspects_services_list( 'services' ) );
397
+		wp_send_json($this->_update_aspects_services_list('services'));
398 398
 	}
399 399
 
400 400
 	/**
@@ -407,7 +407,7 @@  discard block
 block discarded – undo
407 407
 
408 408
 		$status = null;
409 409
 
410
-		if ( $options->is_pod_set_up() ) {
410
+		if ($options->is_pod_set_up()) {
411 411
 			$status = ! $this->_load_api()->has_last_error();
412 412
 		}
413 413
 
@@ -420,22 +420,22 @@  discard block
 block discarded – undo
420 420
 	 * @todo esc_html
421 421
 	 */
422 422
 	public function check_pod_connection_status_callback() {
423
-		if ( isset( $_REQUEST['debugging'] ) && ! defined( 'WP2D_DEBUGGING' ) ) {
424
-			define( 'WP2D_DEBUGGING', true );
423
+		if (isset($_REQUEST['debugging']) && ! defined('WP2D_DEBUGGING')) {
424
+			define('WP2D_DEBUGGING', true);
425 425
 		}
426 426
 
427 427
 		$status = $this->_check_pod_connection_status();
428 428
 
429 429
 		$data = array(
430
-			'debug'   => esc_textarea( WP2D_Helpers::get_debugging() ),
431
-			'message' => __( 'Connection successful.', 'wp-to-diaspora' ),
430
+			'debug'   => esc_textarea(WP2D_Helpers::get_debugging()),
431
+			'message' => __('Connection successful.', 'wp-to-diaspora'),
432 432
 		);
433 433
 
434
-		if ( true === $status ) {
435
-			wp_send_json_success( $data );
436
-		} elseif ( false === $status && $this->_load_api()->has_last_error() ) {
437
-			$data['message'] = $this->_load_api()->get_last_error() . ' ' . WP2D_Contextual_Help::get_help_tab_quick_link( $this->_load_api()->get_last_error_object() );
438
-			wp_send_json_error( $data );
434
+		if (true === $status) {
435
+			wp_send_json_success($data);
436
+		} elseif (false === $status && $this->_load_api()->has_last_error()) {
437
+			$data['message'] = $this->_load_api()->get_last_error().' '.WP2D_Contextual_Help::get_help_tab_quick_link($this->_load_api()->get_last_error_object());
438
+			wp_send_json_error($data);
439 439
 		}
440 440
 		// If $status === null, do nothing.
441 441
 	}
Please login to merge, or discard this patch.