WP2D_Post::embed_url()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 3
rs 10
cc 1
eloc 2
nc 1
nop 2
1
<?php
0 ignored issues
show
Coding Style Compatibility introduced by
For compatibility and reusability of your code, PSR1 recommends that a file should introduce either new symbols (like classes, functions, etc.) or have side-effects (like outputting something, or including other files), but not both at the same time. The first symbol is defined on line 19 and the first side effect is on line 10.

The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.

The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.

To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.

Loading history...
2
/**
3
 * A diaspora* flavoured WP Post class.
4
 *
5
 * @package WP_To_Diaspora\Post
6
 * @since 1.5.0
7
 */
8
9
// Exit if accessed directly.
10
defined( 'ABSPATH' ) || exit;
11
12
use League\HTMLToMarkdown\HtmlConverter;
13
14
/**
15
 * Custom diaspora* post class to manage all post related things.
16
 *
17
 * @since 1.5.0
18
 */
19
class WP2D_Post {
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
20
21
	/**
22
	 * The original post object.
23
	 *
24
	 * @var WP_Posts
25
	 * @since 1.5.0
26
	 */
27
	public $post = null;
28
29
	/**
30
	 * The original post ID.
31
	 *
32
	 * @var int
33
	 * @since 1.5.0
34
	 */
35
	public $ID = null;
36
37
	/**
38
	 * If this post should be shared on diaspora*.
39
	 *
40
	 * @var bool
41
	 * @since 1.5.0
42
	 */
43
	public $post_to_diaspora = null;
44
45
	/**
46
	 * If a link back to the original post should be added.
47
	 *
48
	 * @var bool
49
	 * @since 1.5.0
50
	 */
51
	public $fullentrylink = null;
52
53
	/**
54
	 * What content gets posted.
55
	 *
56
	 * @var string
57
	 * @since 1.5.0
58
	 */
59
	public $display = null;
60
61
	/**
62
	 * The types of tags to post. (global,custom,post)
63
	 *
64
	 * @var array
65
	 * @since 1.5.0
66
	 */
67
	public $tags_to_post = null;
68
69
	/**
70
	 * The post's custom tags.
71
	 *
72
	 * @var array
73
	 * @since 1.5.0
74
	 */
75
	public $custom_tags = null;
76
77
	/**
78
	 * Aspects this post gets posted to.
79
	 *
80
	 * @var array
81
	 * @since 1.5.0
82
	 */
83
	public $aspects = null;
84
85
	/**
86
	 * Services this post gets posted to.
87
	 *
88
	 * @var array
89
	 * @since 1.5.0
90
	 */
91
	public $services = null;
92
93
94
	/**
95
	 * The post's history of diaspora* posts.
96
	 *
97
	 * @var array
98
	 * @since 1.5.0
99
	 */
100
	public $post_history = null;
101
102
	/**
103
	 * If the post actions have all been set up already.
104
	 *
105
	 * @var boolean
106
	 * @since 1.5.0
107
	 */
108
	private static $_is_set_up = false;
109
110
	/**
111
	 * Setup all the necessary WP callbacks.
112
	 *
113
	 * @since 1.5.0
114
	 */
115
	public static function setup() {
116
		if ( self::$_is_set_up ) {
117
			return;
118
		}
119
120
		$instance = new WP2D_Post( null );
121
122
		// Notices when a post has been shared or if it has failed.
123
		add_action( 'admin_notices', array( $instance, 'admin_notices' ) );
124
		add_action( 'admin_init', array( $instance, 'ignore_post_error' ) );
125
126
		// Handle diaspora* posting when saving the post.
127
		add_action( 'save_post', array( $instance, 'post' ), 11, 2 );
128
		add_action( 'save_post', array( $instance, 'save_meta_box_data' ), 10 );
129
130
		// Add meta boxes.
131
		add_action( 'add_meta_boxes', array( $instance, 'add_meta_boxes' ) );
132
133
		self::$_is_set_up = true;
134
	}
135
136
	/**
137
	 * Constructor.
138
	 *
139
	 * @since 1.5.0
140
	 *
141
	 * @param int|WP_Post $post Post ID or the post itself.
142
	 */
143
	public function __construct( $post ) {
144
		$this->_assign_wp_post( $post );
145
	}
146
147
	/**
148
	 * Assign the original WP_Post object and all the custom meta data.
149
	 *
150
	 * @since 1.5.0
151
	 *
152
	 * @param int|WP_Post $post Post ID or the post itself.
153
	 */
154
	private function _assign_wp_post( $post ) {
155
		if ( $this->post = get_post( $post ) ) {
156
			$this->ID = $this->post->ID;
157
158
			$options = WP2D_Options::instance();
159
160
			// Assign all meta values, expanding non-existent ones with the defaults.
161
			$meta_current = get_post_meta( $this->ID, '_wp_to_diaspora', true );
162
			$meta = wp_parse_args(
163
				$meta_current,
164
				$options->get_options()
165
			);
166
			if ( $meta ) {
167
				foreach ( $meta as $key => $value ) {
168
					$this->$key = $value;
169
				}
170
			}
171
172
			// If no WP2D meta data has been saved yet, this post shouldn't be published.
173
			// This can happen if existing posts (before WP2D) get updated externally, not through the post edit screen.
174
			// Check gutobenn/wp-to-diaspora#91 for reference.
175
			// Also, when we have a post scheduled for publishing, don't touch it.
176
			// This is important when modifying scheduled posts using Quick Edit.
177
			if ( ! in_array( $this->post->post_status, array( 'auto-draft', 'future' ) ) && ! $meta_current ) {
178
				$this->post_to_diaspora = false;
179
			}
180
181
			$this->post_history = get_post_meta( $this->ID, '_wp_to_diaspora_post_history', true );
182
		}
183
	}
184
185
	/**
186
	 * Post to diaspora* when saving a post.
187
	 *
188
	 * @since 1.5.0
189
	 *
190
	 * @todo Maybe somebody wants to share a password protected post to a closed aspect.
191
	 *
192
	 * @param integer $post_id ID of the post being saved.
193
	 * @param WP_Post $post    Post object being saved.
194
	 * @return boolean If the post was posted successfully.
195
	 */
196
	public function post( $post_id, $post ) {
197
		$this->_assign_wp_post( $post );
198
199
		$options = WP2D_Options::instance();
200
201
		// Is this post type enabled for posting?
202
		if ( ! in_array( $post->post_type, $options->get_option( 'enabled_post_types' ) ) ) {
203
			return false;
204
		}
205
206
		// Make sure we're posting to diaspora* and the post isn't password protected.
207
		if ( ! ( $this->post_to_diaspora && 'publish' === $post->post_status && '' === $post->post_password ) ) {
208
			return false;
209
		}
210
211
		$status_message = $this->_get_title_link();
212
213
		// Post the full post text or just the excerpt?
214
		if ( 'full' === $this->display ) {
215
			$status_message .= $this->_get_full_content();
216
		} else {
217
			$status_message .= $this->_get_excerpt_content();
218
		}
219
220
		// Add the tags assigned to the post.
221
		$status_message .= $this->_get_tags_to_add();
222
223
		// Add the original entry link to the post?
224
		$status_message .= $this->_get_posted_at_link();
225
226
		$status_converter = new HtmlConverter( array( 'strip_tags' => true ) );
227
		$status_message  = $status_converter->convert( $status_message );
228
229
		// Set up the connection to diaspora*.
230
		$api = WP2D_Helpers::api_quick_connect();
231
		if ( ! empty( $status_message ) ) {
232
			if ( $api->has_last_error() ) {
233
				// Save the post error as post meta data, so we can display it to the user.
234
				update_post_meta( $post_id, '_wp_to_diaspora_post_error', $api->get_last_error() );
235
				return false;
236
			}
237
238
			// Add services to share to via diaspora*.
239
			$extra_data = array(
240
				'services' => $this->services,
241
			);
242
243
			// Try to post to diaspora*.
244
			if ( $response = $api->post( $status_message, $this->aspects, $extra_data ) ) {
245
				// Save certain diaspora* post data as meta data for future reference.
246
				$this->_save_to_history( (object) $response );
247
248
				// If there is still a previous post error around, remove it.
249
				delete_post_meta( $post_id, '_wp_to_diaspora_post_error' );
250
251
				// Unset post_to_diaspora meta field to prevent mistakenly republishing to diaspora*.
252
				$meta = get_post_meta( $post_id, '_wp_to_diaspora', true );
253
				$meta['post_to_diaspora'] = false;
254
				update_post_meta( $post_id, '_wp_to_diaspora', $meta );
255
			}
256
		} else {
257
			return false;
258
		}
259
	}
260
261
	/**
262
	 * Get the title of the post linking to the post itself.
263
	 *
264
	 * @since 1.5.0
265
	 *
266
	 * @return string Post title as a link.
267
	 */
268
	private function _get_title_link() {
269
		$title = esc_html( $this->post->post_title );
270
		$permalink = get_permalink( $this->ID );
271
		$default = sprintf( '<strong><a href="%2$s" title="%2$s">%1$s</a></strong>', $title, $permalink );
272
273
		/**
274
		 * Filter the title link at the top of the post.
275
		 *
276
		 * @since 1.5.4.1
277
		 *
278
		 * @param string $default   The whole HTML of the title link to be outputted.
279
		 * @param string $title     The title of the original post.
280
		 * @param string $permalink The permalink of the original post.
281
		 */
282
		$link = apply_filters( 'wp2d_title_filter', $default, $title, $permalink );
283
284
		return '<p>' . $link . '</p>';
285
	}
286
287
	/**
288
	 * Get the full post content with only default filters applied.
289
	 *
290
	 * @since 1.5.0
291
	 *
292
	 * @return string The full post content.
293
	 */
294
	private function _get_full_content() {
295
		// Only allow certain shortcodes.
296
		global $shortcode_tags;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
297
		$shortcode_tags_bkp = array();
298
299
		foreach ( $shortcode_tags as $shortcode_tag => $shortcode_function ) {
300
			if ( ! in_array( $shortcode_tag, apply_filters( 'wp2d_shortcodes_filter', array( 'wp_caption', 'caption', 'gallery' ) ) ) ) {
301
				$shortcode_tags_bkp[ $shortcode_tag ] = $shortcode_function;
302
				unset( $shortcode_tags[ $shortcode_tag ] );
303
			}
304
		}
305
306
		// Disable all filters and then enable only defaults. This prevents additional filters from being posted to diaspora*.
307
		remove_all_filters( 'the_content' );
308
		foreach ( apply_filters( 'wp2d_content_filters_filter', array( 'do_shortcode', 'wptexturize', 'convert_smilies', 'convert_chars', 'wpautop', 'shortcode_unautop', 'prepend_attachment', array( $this, 'embed_remove' ) ) ) as $filter ) {
309
			add_filter( 'the_content', $filter );
310
		}
311
312
		// Extract URLs from [embed] shortcodes.
313
		add_filter( 'embed_oembed_html', array( $this, 'embed_url' ), 10, 2 );
314
315
		// Add the pretty caption after the images.
316
		add_filter( 'img_caption_shortcode', array( $this, 'custom_img_caption' ), 10, 3 );
317
318
		// Overwrite the native shortcode handler to add pretty captions.
319
		// http://wordpress.stackexchange.com/a/74675/54456 for explanation.
320
		add_shortcode( 'gallery', array( $this, 'custom_gallery_shortcode' ) );
321
322
		$full_content = apply_filters( 'the_content', $this->post->post_content );
323
324
		// Put the removed shortcode tags back again.
325
		$shortcode_tags += $shortcode_tags_bkp;
326
327
		return $full_content;
328
	}
329
330
	/**
331
	 * Get the post's excerpt in a nice format.
332
	 *
333
	 * @since 1.5.0
334
	 *
335
	 * @return string Post's excerpt.
336
	 */
337
	private function _get_excerpt_content() {
338
		// Look for the excerpt in the following order:
339
		// 1. Custom post excerpt.
340
		// 2. Text up to the <!--more--> tag.
341
		// 3. Manually trimmed content.
342
		$content = $this->post->post_content;
343
		$excerpt = $this->post->post_excerpt;
344
		if ( '' === $excerpt ) {
345
			if ( $more_pos = strpos( $content, '<!--more' ) ) {
346
				$excerpt = substr( $content, 0, $more_pos );
347
			} else {
348
				$excerpt = wp_trim_words( $content, 42, '[...]' );
349
			}
350
		}
351
		return '<p>' . $excerpt . '</p>';
352
	}
353
354
	/**
355
	 * Get a string of tags that have been added to the post.
356
	 *
357
	 * @since 1.5.0
358
	 *
359
	 * @return string Tags added to the post.
360
	 */
361
	private function _get_tags_to_add() {
362
		$options = WP2D_Options::instance();
363
		$tags_to_post = $this->tags_to_post;
364
		$tags_to_add  = '';
365
366
		// Add any diaspora* tags?
367
		if ( ! empty( $tags_to_post ) ) {
368
			// The diaspora* tags to add to the post.
369
			$diaspora_tags = array();
370
371
			// Add global tags?
372
			$global_tags = $options->get_option( 'global_tags' );
373
			if ( in_array( 'global', $tags_to_post ) && is_array( $global_tags ) ) {
374
				$diaspora_tags += array_flip( $global_tags );
375
			}
376
377
			// Add custom tags?
378
			if ( in_array( 'custom', $tags_to_post ) && is_array( $this->custom_tags ) ) {
379
				$diaspora_tags += array_flip( $this->custom_tags );
380
			}
381
382
			// Add post tags?
383
			$post_tags = wp_get_post_tags( $this->ID, array( 'fields' => 'slugs' ) );
384
			if ( in_array( 'post', $tags_to_post ) && is_array( $post_tags ) ) {
385
				$diaspora_tags += array_flip( $post_tags );
386
			}
387
388
			// Get an array of cleaned up tags.
389
			// NOTE: Validate method needs a variable, as it's passed by reference!
390
			$diaspora_tags = array_keys( $diaspora_tags );
391
			$options->validate_tags( $diaspora_tags );
392
393
			// Get all the tags and list them all nicely in a row.
394
			$diaspora_tags_clean = array();
395
			foreach ( $diaspora_tags as $tag ) {
0 ignored issues
show
Bug introduced by
The expression $diaspora_tags of type array|string is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
396
				$diaspora_tags_clean[] = '#' . $tag;
397
			}
398
399
			// Add all the found tags.
400
			if ( ! empty( $diaspora_tags_clean ) ) {
401
				$tags_to_add = implode( ' ', $diaspora_tags_clean ) . '<br />';
402
			}
403
		}
404
405
		return $tags_to_add;
406
	}
407
408
	/**
409
	 * Get the link to the original post.
410
	 *
411
	 * @since 1.5.0
412
	 *
413
	 * @return string Original post link.
414
	 */
415
	private function _get_posted_at_link() {
416
		$link = '';
417
		if ( $this->fullentrylink ) {
418
419
			$text = esc_html( 'Originally posted at:', 'wp-to-diaspora' );
420
			$permalink = get_permalink( $this->ID );
421
			$title = esc_html( 'Permalink', 'wp-to-diaspora' );
422
			$default = sprintf( '%1$s <a href="%2$s" title="%3$s">%2$s</a>', $text, $permalink, $title );
423
424
			/**
425
			 * Filter the "Originally posted at" link at the bottom of the post.
426
			 *
427
			 * @since 1.5.4.1
428
			 *
429
			 * @param string $default   The whole HTML of the text and link to be outputted.
430
			 * @param string $text      The "Originally posted at:" text before the link.
431
			 * @param string $permalink The permalink of the original post.
432
			 * @param string $title     The "Permalink" title of the link.
433
			 */
434
			$link = apply_filters( 'wp2d_posted_at_link_filter', $default, $text, $permalink, $title );
435
436
			$link = '<p>' . $link . '</p>';
437
		}
438
439
		return $link;
440
	}
441
442
	/**
443
	 * Save the details of the new diaspora* post to this post's history.
444
	 *
445
	 * @since 1.5.0
446
	 *
447
	 * @param object $response Response from the API containing the diaspora* post details.
448
	 */
449
	private function _save_to_history( $response ) {
450
		// Make sure the post history is an array.
451
		if ( empty( $this->post_history ) ) {
452
			$this->post_history = array();
453
		}
454
455
		// Add a new entry to the history.
456
		$this->post_history[] = array(
457
			'id'         => $response->id,
458
			'guid'       => $response->guid,
459
			'created_at' => $this->post->post_modified,
460
			'aspects'    => $this->aspects,
461
			'nsfw'       => $response->nsfw,
462
			'post_url'   => $response->permalink,
463
		);
464
465
		update_post_meta( $this->ID, '_wp_to_diaspora_post_history', $this->post_history );
466
	}
467
468
	/**
469
	 * Return URL from [embed] shortcode instead of generated iframe.
470
	 *
471
	 * @since 1.5.0
472
	 * @see WP_Embed::shortcode()
473
	 *
474
	 * @param mixed  $html The cached HTML result, stored in post meta.
475
	 * @param string $url  The attempted embed URL.
476
	 * @return string URL of the embed.
477
	 */
478
	public function embed_url( $html, $url ) {
479
		return $url;
480
	}
481
482
	/**
483
	 * Removes '[embed]' and '[/embed]' left by embed_url.
484
	 *
485
	 * @since 1.5.0
486
	 * @todo It would be great to fix it using only one filter.
487
	 *       It's happening because embed filter is being removed by remove_all_filters('the_content') on WP2D_Post::post().
488
	 *
489
	 * @param string $content Content of the post.
490
	 * @return string The content with the embed tags removed.
491
	 */
492
	public function embed_remove( $content ) {
493
		return str_replace( array( '[embed]', '[/embed]' ), array( '<p>', '</p>' ), $content );
494
	}
495
496
	/**
497
	 * Prettify the image caption.
498
	 *
499
	 * @since 1.5.3
500
	 *
501
	 * @param string $caption Caption to be prettified.
502
	 * @return string Prettified image caption.
503
	 */
504
	public function get_img_caption( $caption ) {
505
		$caption = trim( $caption );
506
		if ( '' === $caption ) {
507
			return '';
508
		}
509
510
		$default = sprintf( '<blockquote>%s</blockquote>',  $caption );
511
512
		/**
513
		 * Filter the image caption to be displayed after images with captions.
514
		 *
515
		 * @since 1.5.3
516
		 *
517
		 * @param string $default The whole HTML of the caption.
518
		 * @param string $caption The caption text.
519
		 */
520
		return apply_filters( 'wp2d_image_caption', $default, $caption );
521
	}
522
523
	/**
524
	 * Filter the default caption shortcode output.
525
	 *
526
	 * @since 1.5.3
527
	 * @see img_caption_shortcode()
528
	 *
529
	 * @param string $empty   The caption output. Default empty.
530
	 * @param array  $attr    Attributes of the caption shortcode.
531
	 * @param string $content The image element, possibly wrapped in a hyperlink.
532
	 * @return string The caption shortcode output.
533
	 */
534
	public function custom_img_caption( $empty, $attr, $content ) {
535
		$content = do_shortcode( $content );
536
537
		// If a caption attribute is defined, we'll add it after the image.
538
		if ( isset( $attr['caption'] ) && '' !== $attr['caption'] ) {
539
			$content .= "\n" . $this->get_img_caption( $attr['caption'] );
540
		}
541
542
		return $content;
543
	}
544
545
	/**
546
	 * Create a custom gallery caption output.
547
	 *
548
	 * @since 1.5.3
549
	 *
550
	 * @param   array $attr Gallery attributes.
551
	 * @return  string
552
	 */
553
	public function custom_gallery_shortcode( $attr ) {
554
		// Default value in WordPress.
555
		$captiontag = ( current_theme_supports( 'html5', 'gallery' ) ) ? 'figcaption' : 'dd';
556
557
		// User value.
558
		if ( isset( $attr['captiontag'] ) ) {
559
			$captiontag = $attr['captiontag'];
560
		}
561
562
		// Let WordPress create the regular gallery.
563
		$gallery = gallery_shortcode( $attr );
564
565
		// Change the content of the captions.
566
		$gallery = preg_replace_callback(
567
			'~(<' . $captiontag . '.*>)(.*)(</' . $captiontag . '>)~mUus',
568
			array( $this, 'custom_gallery_regex_callback' ),
569
			$gallery
570
		);
571
572
		return $gallery;
573
	}
574
575
	/**
576
	 * Change the result of the regex match from custom_gallery_shortcode.
577
	 *
578
	 * @param array $m Regex matches.
579
	 * @return string Prettified gallery image caption.
580
	 */
581
	public function custom_gallery_regex_callback( $m ) {
582
		return $this->get_img_caption( $m[2] );
583
	}
584
585
	/*
586
	 * META BOX
587
	 */
588
589
	/**
590
	 * Adds a meta box to the main column on the enabled Post Types' edit screens.
591
	 *
592
	 * @since 1.5.0
593
	 */
594
	public function add_meta_boxes() {
595
		$options = WP2D_Options::instance();
596
		foreach ( $options->get_option( 'enabled_post_types' ) as $post_type ) {
0 ignored issues
show
Bug introduced by
The expression $options->get_option('enabled_post_types') of type array|string is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
597
			add_meta_box(
598
				'wp_to_diaspora_meta_box',
599
				'WP to diaspora*',
600
				array( $this, 'meta_box_render' ),
601
				$post_type,
602
				'side',
603
				'high'
604
			);
605
		}
606
	}
607
608
	/**
609
	 * Prints the meta box content.
610
	 *
611
	 * @since 1.5.0
612
	 *
613
	 * @param WP_Post $post The object for the current post.
614
	 */
615
	public function meta_box_render( $post ) {
616
		$this->_assign_wp_post( $post );
617
618
		// Add an nonce field so we can check for it later.
619
		wp_nonce_field( 'wp_to_diaspora_meta_box', 'wp_to_diaspora_meta_box_nonce' );
620
621
		// Get the default values to use, but give priority to the meta data already set.
622
		$options = WP2D_Options::instance();
623
624
		// Make sure we have some value for post meta fields.
625
		$this->custom_tags = $this->custom_tags ?: array();
626
627
		// If this post is already published, don't post again to diaspora* by default.
628
		$this->post_to_diaspora = ( $this->post_to_diaspora && 'publish' !== get_post_status( $this->ID ) );
629
		$this->aspects          = $this->aspects  ?: array();
630
		$this->services         = $this->services ?: array();
631
632
		// Have we already posted on diaspora*?
633
		if ( is_array( $this->post_history ) ) {
634
			$latest_post = end( $this->post_history );
635
			?>
636
			<p><a href="<?php echo esc_attr( $latest_post['post_url'] ); ?>" target="_blank"><?php esc_html_e( 'Already posted to diaspora*.', 'wp-to-diaspora' ); ?></a></p>
637
			<?php
638
		}
639
		?>
640
641
		<p><?php $options->post_to_diaspora_render( $this->post_to_diaspora ); ?></p>
642
		<p><?php $options->fullentrylink_render( $this->fullentrylink ); ?></p>
643
		<p><?php $options->display_render( $this->display ); ?></p>
644
		<p><?php $options->tags_to_post_render( $this->tags_to_post ); ?></p>
645
		<p><?php $options->custom_tags_render( $this->custom_tags ); ?></p>
646
		<p><?php $options->aspects_services_render( array( 'aspects', $this->aspects ) ); ?></p>
647
		<p><?php $options->aspects_services_render( array( 'services', $this->services ) ); ?></p>
648
649
		<?php
650
	}
651
652
	/**
653
	 * When the post is saved, save our meta data.
654
	 *
655
	 * @since 1.5.0
656
	 *
657
	 * @param integer $post_id The ID of the post being saved.
658
	 */
659
	public function save_meta_box_data( $post_id ) {
0 ignored issues
show
Coding Style introduced by
save_meta_box_data uses the super-global variable $_POST which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
660
		/*
661
		 * We need to verify this came from our screen and with proper authorization,
662
		 * because the save_post action can be triggered at other times.
663
		 */
664
		if ( ! $this->_is_safe_to_save() ) {
665
			return;
666
		}
667
668
		/* OK, it's safe for us to save the data now. */
669
670
		// Meta data to save.
671
		$meta_to_save = $_POST['wp_to_diaspora_settings'];
672
		$options = WP2D_Options::instance();
673
674
		// Checkboxes.
675
		$options->validate_checkboxes( array( 'post_to_diaspora', 'fullentrylink' ), $meta_to_save );
676
677
		// Single Selects.
678
		$options->validate_single_selects( 'display', $meta_to_save );
679
680
		// Multiple Selects.
681
		$options->validate_multi_selects( 'tags_to_post', $meta_to_save );
682
683
		// Save custom tags as array.
684
		$options->validate_tags( $meta_to_save['custom_tags'] );
685
686
		// Clean up the list of aspects. If the list is empty, only use the 'Public' aspect.
687
		$options->validate_aspects_services( $meta_to_save['aspects'], array( 'public' ) );
688
689
		// Clean up the list of services.
690
		$options->validate_aspects_services( $meta_to_save['services'] );
691
692
		// Update the meta data for this post.
693
		update_post_meta( $post_id, '_wp_to_diaspora', $meta_to_save );
694
	}
695
696
	/**
697
	 * Perform all checks to see if we are allowed to save the meta data.
698
	 *
699
	 * @since 1.5.0
700
	 *
701
	 * @return boolean If the verification checks have passed.
702
	 */
703
	private function _is_safe_to_save() {
0 ignored issues
show
Coding Style introduced by
_is_safe_to_save uses the super-global variable $_POST which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
704
		// Verify that our nonce is set and  valid.
705
		if ( ! ( isset( $_POST['wp_to_diaspora_meta_box_nonce'] ) && wp_verify_nonce( $_POST['wp_to_diaspora_meta_box_nonce'], 'wp_to_diaspora_meta_box' ) ) ) {
706
			return false;
707
		}
708
709
		// If this is an autosave, our form has not been submitted, so we don't want to do anything.
710
		if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
711
			return false;
712
		}
713
714
		// Check the user's permissions.
715
		$permission = ( isset( $_POST['post_type'] ) && 'page' === $_POST['post_type'] ) ? 'edit_pages' : 'edit_posts';
716
		if ( ! current_user_can( $permission, $this->ID ) ) {
717
			return false;
718
		}
719
720
		// Make real sure that we have some meta data to save.
721
		if ( ! isset( $_POST['wp_to_diaspora_settings'] ) ) {
722
			return false;
723
		}
724
725
		return true;
726
	}
727
728
	/**
729
	 * Add admin notices when a post gets displayed.
730
	 *
731
	 * @since 1.5.0
732
	 *
733
	 * @todo Ignore post error with AJAX.
734
	 */
735
	public function admin_notices() {
0 ignored issues
show
Coding Style introduced by
admin_notices uses the super-global variable $_GET which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
736
		global $post, $pagenow;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
737
		if ( ! $post || 'post.php' !== $pagenow ) {
738
			return;
739
		}
740
741
		if ( ( $error = get_post_meta( $post->ID, '_wp_to_diaspora_post_error', true ) ) && is_wp_error( $error ) ) {
742
			// Are we adding a help tab link to this notice?
743
			$help_link = WP2D_Contextual_Help::get_help_tab_quick_link( $error );
744
745
			// This notice will only be shown if posting to diaspora* has failed.
746
			printf( '<div class="error notice is-dismissible"><p>%1$s %2$s %3$s <a href="%4$s">%5$s</a></p></div>',
747
				esc_html__( 'Failed to post to diaspora*.', 'wp-to-diaspora' ),
748
				esc_html__( $error->get_error_message() ),
749
				$help_link,
750
				esc_url( add_query_arg( 'wp2d_ignore_post_error', '' ) ),
751
				esc_html__( 'Ignore', 'wp-to-diaspora' )
752
			);
753
		} elseif ( ( $diaspora_post_history = get_post_meta( $post->ID, '_wp_to_diaspora_post_history', true ) ) && is_array( $diaspora_post_history ) ) {
754
			// Get the latest post from the history.
755
			$latest_post = end( $diaspora_post_history );
756
757
			// Only show if this post is showing a message and the post is a fresh share.
758
			if ( isset( $_GET['message'] ) && $post->post_modified === $latest_post['created_at'] ) {
759
				printf( '<div class="updated notice is-dismissible"><p>%1$s <a href="%2$s" target="_blank">%3$s</a></p></div>',
760
					esc_html__( 'Successfully posted to diaspora*.', 'wp-to-diaspora' ),
761
					esc_url( $latest_post['post_url'] ),
762
					esc_html__( 'View Post' )
763
				);
764
			}
765
		}
766
	}
767
768
	/**
769
	 * Delete the error post meta data if it gets ignored.
770
	 *
771
	 * @since 1.5.0
772
	 */
773
	public function ignore_post_error() {
0 ignored issues
show
Coding Style introduced by
ignore_post_error uses the super-global variable $_GET which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
774
		// If "Ignore" link has been clicked, delete the post error meta data.
775
		if ( isset( $_GET['wp2d_ignore_post_error'], $_GET['post'] ) ) {
776
			delete_post_meta( $_GET['post'], '_wp_to_diaspora_post_error' );
777
		}
778
	}
779
}
780