1
|
|
|
<?php |
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 { |
20
|
|
|
|
21
|
|
|
/** |
22
|
|
|
* The original post object. |
23
|
|
|
* |
24
|
|
|
* @since 1.5.0 |
25
|
|
|
* |
26
|
|
|
* @var WP_Post |
27
|
|
|
*/ |
28
|
|
|
public $post; |
29
|
|
|
|
30
|
|
|
/** |
31
|
|
|
* The original post ID. |
32
|
|
|
* |
33
|
|
|
* @since 1.5.0 |
34
|
|
|
* |
35
|
|
|
* @var int |
36
|
|
|
*/ |
37
|
|
|
public $ID; |
38
|
|
|
|
39
|
|
|
/** |
40
|
|
|
* If this post should be shared on diaspora*. |
41
|
|
|
* |
42
|
|
|
* @since 1.5.0 |
43
|
|
|
* |
44
|
|
|
* @var bool |
45
|
|
|
*/ |
46
|
|
|
public $post_to_diaspora; |
47
|
|
|
|
48
|
|
|
/** |
49
|
|
|
* If a link back to the original post should be added. |
50
|
|
|
* |
51
|
|
|
* @since 1.5.0 |
52
|
|
|
* |
53
|
|
|
* @var bool |
54
|
|
|
*/ |
55
|
|
|
public $fullentrylink; |
56
|
|
|
|
57
|
|
|
/** |
58
|
|
|
* What content gets posted. |
59
|
|
|
* |
60
|
|
|
* @since 1.5.0 |
61
|
|
|
* |
62
|
|
|
* @var string |
63
|
|
|
*/ |
64
|
|
|
public $display; |
65
|
|
|
|
66
|
|
|
/** |
67
|
|
|
* The types of tags to post. (global,custom,post) |
68
|
|
|
* |
69
|
|
|
* @since 1.5.0 |
70
|
|
|
* |
71
|
|
|
* @var array |
72
|
|
|
*/ |
73
|
|
|
public $tags_to_post; |
74
|
|
|
|
75
|
|
|
/** |
76
|
|
|
* The post's custom tags. |
77
|
|
|
* |
78
|
|
|
* @since 1.5.0 |
79
|
|
|
* |
80
|
|
|
* @var array |
81
|
|
|
*/ |
82
|
|
|
public $custom_tags; |
83
|
|
|
|
84
|
|
|
/** |
85
|
|
|
* Aspects this post gets posted to. |
86
|
|
|
* |
87
|
|
|
* @since 1.5.0 |
88
|
|
|
* |
89
|
|
|
* @var array |
90
|
|
|
*/ |
91
|
|
|
public $aspects; |
92
|
|
|
|
93
|
|
|
/** |
94
|
|
|
* Services this post gets posted to. |
95
|
|
|
* |
96
|
|
|
* @since 1.5.0 |
97
|
|
|
* |
98
|
|
|
* @var array |
99
|
|
|
*/ |
100
|
|
|
public $services; |
101
|
|
|
|
102
|
|
|
/** |
103
|
|
|
* The post's history of diaspora* posts. |
104
|
|
|
* |
105
|
|
|
* @since 1.5.0 |
106
|
|
|
* |
107
|
|
|
* @var array |
108
|
|
|
*/ |
109
|
|
|
public $post_history; |
110
|
|
|
|
111
|
|
|
/** |
112
|
|
|
* If the post actions have all been set up already. |
113
|
|
|
* |
114
|
|
|
* @since 1.5.0 |
115
|
|
|
* |
116
|
|
|
* @var boolean |
117
|
|
|
*/ |
118
|
|
|
private static $is_set_up = false; |
119
|
|
|
|
120
|
|
|
/** |
121
|
|
|
* Setup all the necessary WP callbacks. |
122
|
|
|
* |
123
|
|
|
* @since 1.5.0 |
124
|
|
|
*/ |
125
|
|
|
public static function setup() { |
126
|
|
|
if ( self::$is_set_up ) { |
127
|
|
|
return; |
128
|
|
|
} |
129
|
|
|
|
130
|
|
|
$instance = new WP2D_Post( null ); |
131
|
|
|
|
132
|
|
|
// Notices when a post has been shared or if it has failed. |
133
|
|
|
add_action( 'admin_notices', [ $instance, 'admin_notices' ] ); |
134
|
|
|
add_action( 'admin_init', [ $instance, 'ignore_post_error' ] ); |
135
|
|
|
|
136
|
|
|
// Handle diaspora* posting when saving the post. |
137
|
|
|
add_action( 'save_post', [ $instance, 'post' ], 20, 2 ); |
138
|
|
|
add_action( 'save_post', [ $instance, 'save_meta_box_data' ], 10 ); |
139
|
|
|
|
140
|
|
|
// Add meta boxes. |
141
|
|
|
add_action( 'add_meta_boxes', [ $instance, 'add_meta_boxes' ] ); |
142
|
|
|
|
143
|
|
|
// AJAX callback for diaspora* post history. |
144
|
|
|
add_action( 'wp_ajax_wp_to_diaspora_get_post_history', [ $instance, 'get_post_history_callback' ] ); |
145
|
|
|
|
146
|
|
|
self::$is_set_up = true; |
147
|
|
|
} |
148
|
|
|
|
149
|
|
|
/** |
150
|
|
|
* Constructor. |
151
|
|
|
* |
152
|
|
|
* @since 1.5.0 |
153
|
|
|
* |
154
|
|
|
* @param int|WP_Post $post Post ID or the post itself. |
155
|
|
|
*/ |
156
|
|
|
public function __construct( $post ) { |
157
|
|
|
$this->assign_wp_post( $post ); |
158
|
|
|
} |
159
|
|
|
|
160
|
|
|
/** |
161
|
|
|
* Assign the original WP_Post object and all the custom meta data. |
162
|
|
|
* |
163
|
|
|
* @since 1.5.0 |
164
|
|
|
* |
165
|
|
|
* @param int|WP_Post $post Post ID or the post itself. |
166
|
|
|
*/ |
167
|
|
|
private function assign_wp_post( $post ) { |
168
|
|
|
if ( $this->post = get_post( $post ) ) { |
169
|
|
|
$this->ID = $this->post->ID; |
170
|
|
|
|
171
|
|
|
$options = WP2D_Options::instance(); |
172
|
|
|
|
173
|
|
|
// Assign all meta values, expanding non-existent ones with the defaults. |
174
|
|
|
$meta_current = get_post_meta( $this->ID, '_wp_to_diaspora', true ); |
175
|
|
|
$meta = wp_parse_args( |
176
|
|
|
$meta_current, |
177
|
|
|
$options->get_options() |
178
|
|
|
); |
179
|
|
|
if ( $meta ) { |
180
|
|
|
foreach ( $meta as $key => $value ) { |
181
|
|
|
$this->$key = $value; |
182
|
|
|
} |
183
|
|
|
} |
184
|
|
|
|
185
|
|
|
// If no WP2D meta data has been saved yet, this post shouldn't be published. |
186
|
|
|
// This can happen if existing posts (before WP2D) get updated externally, not through the post edit screen. |
187
|
|
|
// Check DiasPHPora/wp-to-diaspora#91 for reference. |
188
|
|
|
// Also, when we have a post scheduled for publishing, don't touch it. |
189
|
|
|
// This is important when modifying scheduled posts using Quick Edit. |
190
|
|
|
if ( ! $meta_current && ! in_array( $this->post->post_status, [ 'auto-draft', 'future' ], true ) ) { |
191
|
|
|
$this->post_to_diaspora = false; |
192
|
|
|
} |
193
|
|
|
|
194
|
|
|
$this->post_history = get_post_meta( $this->ID, '_wp_to_diaspora_post_history', true ); |
195
|
|
|
} |
196
|
|
|
} |
197
|
|
|
|
198
|
|
|
/** |
199
|
|
|
* Post to diaspora* when saving a post. |
200
|
|
|
* |
201
|
|
|
* @since 1.5.0 |
202
|
|
|
* |
203
|
|
|
* @todo Maybe somebody wants to share a password protected post to a closed aspect. |
204
|
|
|
* |
205
|
|
|
* @param integer $post_id ID of the post being saved. |
206
|
|
|
* @param WP_Post $post Post object being saved. |
207
|
|
|
* |
208
|
|
|
* @return bool If the post was posted successfully. |
209
|
|
|
*/ |
210
|
|
|
public function post( $post_id, $post ) { |
211
|
|
|
// Ignore any revisions and auto-saves. |
212
|
|
|
if ( wp_is_post_revision( $post_id ) || wp_is_post_autosave( $post_id ) ) { |
213
|
|
|
return false; |
214
|
|
|
} |
215
|
|
|
|
216
|
|
|
$this->assign_wp_post( $post ); |
217
|
|
|
|
218
|
|
|
$options = WP2D_Options::instance(); |
219
|
|
|
|
220
|
|
|
// Is this post type enabled for posting? |
221
|
|
|
if ( ! in_array( $post->post_type, $options->get_option( 'enabled_post_types' ), true ) ) { |
222
|
|
|
return false; |
223
|
|
|
} |
224
|
|
|
|
225
|
|
|
// Make sure we're posting to diaspora* and the post isn't password protected. |
226
|
|
|
if ( ! ( $this->post_to_diaspora && 'publish' === $post->post_status && '' === $post->post_password ) ) { |
227
|
|
|
return false; |
228
|
|
|
} |
229
|
|
|
|
230
|
|
|
// Unset post_to_diaspora meta field to prevent mistakenly republishing to diaspora*. |
231
|
|
|
$meta = get_post_meta( $post_id, '_wp_to_diaspora', true ); |
232
|
|
|
$meta['post_to_diaspora'] = false; |
233
|
|
|
update_post_meta( $post_id, '_wp_to_diaspora', $meta ); |
234
|
|
|
|
235
|
|
|
$status_message = $this->get_title_link(); |
236
|
|
|
|
237
|
|
|
// Post the full post text, just the excerpt, or nothing at all? |
238
|
|
|
if ( 'full' === $this->display ) { |
239
|
|
|
$status_message .= $this->get_full_content(); |
240
|
|
|
} elseif ( 'excerpt' === $this->display ) { |
241
|
|
|
$status_message .= $this->get_excerpt_content(); |
242
|
|
|
} |
243
|
|
|
|
244
|
|
|
// Add the tags assigned to the post. |
245
|
|
|
$status_message .= $this->get_tags_to_add(); |
246
|
|
|
|
247
|
|
|
// Add the original entry link to the post? |
248
|
|
|
$status_message .= $this->get_posted_at_link(); |
249
|
|
|
|
250
|
|
|
$status_converter = new HtmlConverter( [ 'strip_tags' => true ] ); |
251
|
|
|
$status_message = $status_converter->convert( $status_message ); |
252
|
|
|
|
253
|
|
|
// Set up the connection to diaspora*. |
254
|
|
|
$api = WP2D_Helpers::api_quick_connect(); |
255
|
|
|
if ( empty( $status_message ) ) { |
256
|
|
|
return false; |
257
|
|
|
} |
258
|
|
|
|
259
|
|
|
if ( $api->has_last_error() ) { |
260
|
|
|
// Save the post error as post meta data, so we can display it to the user. |
261
|
|
|
update_post_meta( $post_id, '_wp_to_diaspora_post_error', $api->get_last_error() ); |
262
|
|
|
|
263
|
|
|
return false; |
264
|
|
|
} |
265
|
|
|
|
266
|
|
|
// Add services to share to via diaspora*. |
267
|
|
|
$extra_data = [ |
268
|
|
|
'services' => $this->services, |
269
|
|
|
]; |
270
|
|
|
|
271
|
|
|
// Try to post to diaspora*. |
272
|
|
|
$response = $api->post( $status_message, $this->aspects, $extra_data ); |
273
|
|
|
if ( ! $response ) { |
274
|
|
|
return false; |
275
|
|
|
} |
276
|
|
|
|
277
|
|
|
// Save certain diaspora* post data as meta data for future reference. |
278
|
|
|
$this->save_to_history( (object) $response ); |
279
|
|
|
|
280
|
|
|
// If there is still a previous post error around, remove it. |
281
|
|
|
delete_post_meta( $post_id, '_wp_to_diaspora_post_error' ); |
282
|
|
|
|
283
|
|
|
// Prevent any duplicate hook firing. |
284
|
|
|
remove_action( 'save_post', [ $this, 'post' ], 20, 2 ); |
285
|
|
|
|
286
|
|
|
return true; |
287
|
|
|
} |
288
|
|
|
|
289
|
|
|
/** |
290
|
|
|
* Get the title of the post linking to the post itself. |
291
|
|
|
* |
292
|
|
|
* @since 1.5.0 |
293
|
|
|
* |
294
|
|
|
* @return string Post title as a link. |
295
|
|
|
*/ |
296
|
|
|
private function get_title_link() { |
297
|
|
|
$title = esc_html( $this->post->post_title ); |
298
|
|
|
$permalink = get_permalink( $this->ID ); |
299
|
|
|
$title_link = sprintf( '<strong><a href="%2$s" title="%2$s">%1$s</a></strong>', $title, $permalink ); |
300
|
|
|
|
301
|
|
|
/** |
302
|
|
|
* Filter the title link at the top of the post. |
303
|
|
|
* |
304
|
|
|
* @since 1.5.4.1 |
305
|
|
|
* |
306
|
|
|
* @param string $default The whole HTML of the title link to be outputted. |
307
|
|
|
* @param WP2D_Post $wp2d_post This object, to allow total customisation of the title. |
308
|
|
|
*/ |
309
|
|
|
return apply_filters( 'wp2d_title_filter', "<p>{$title_link}</p>", $this ); |
310
|
|
|
} |
311
|
|
|
|
312
|
|
|
/** |
313
|
|
|
* Get the full post content with only default filters applied. |
314
|
|
|
* |
315
|
|
|
* @since 1.5.0 |
316
|
|
|
* |
317
|
|
|
* @return string The full post content. |
318
|
|
|
*/ |
319
|
|
|
private function get_full_content() { |
320
|
|
|
// Only allow certain shortcodes. |
321
|
|
|
global $shortcode_tags; |
322
|
|
|
$shortcode_tags_bkp = []; |
323
|
|
|
|
324
|
|
|
foreach ( $shortcode_tags as $shortcode_tag => $shortcode_function ) { |
325
|
|
|
if ( ! in_array( $shortcode_tag, apply_filters( 'wp2d_shortcodes_filter', [ 'wp_caption', 'caption', 'gallery' ] ), true ) ) { |
326
|
|
|
$shortcode_tags_bkp[ $shortcode_tag ] = $shortcode_function; |
327
|
|
|
unset( $shortcode_tags[ $shortcode_tag ] ); |
328
|
|
|
} |
329
|
|
|
} |
330
|
|
|
|
331
|
|
|
// Disable all filters and then enable only defaults. This prevents additional filters from being posted to diaspora*. |
332
|
|
|
remove_all_filters( 'the_content' ); |
333
|
|
|
|
334
|
|
|
/** @var array $content_filters List of filters to apply to the content. */ |
335
|
|
|
$content_filters = apply_filters( 'wp2d_content_filters_filter', [ 'do_shortcode', 'wptexturize', 'convert_smilies', 'convert_chars', 'wpautop', 'shortcode_unautop', 'prepend_attachment', [ $this, 'embed_remove' ] ] ); |
336
|
|
|
foreach ( $content_filters as $filter ) { |
337
|
|
|
add_filter( 'the_content', $filter ); |
338
|
|
|
} |
339
|
|
|
|
340
|
|
|
// Extract URLs from [embed] shortcodes. |
341
|
|
|
add_filter( 'embed_oembed_html', [ $this, 'embed_url' ], 10, 2 ); |
342
|
|
|
|
343
|
|
|
// Add the pretty caption after the images. |
344
|
|
|
add_filter( 'img_caption_shortcode', [ $this, 'custom_img_caption' ], 10, 3 ); |
345
|
|
|
|
346
|
|
|
// Overwrite the native shortcode handler to add pretty captions. |
347
|
|
|
// http://wordpress.stackexchange.com/a/74675/54456 for explanation. |
348
|
|
|
add_shortcode( 'gallery', [ $this, 'custom_gallery_shortcode' ] ); |
349
|
|
|
|
350
|
|
|
$post_content = apply_filters( 'the_content', $this->post->post_content ); |
351
|
|
|
|
352
|
|
|
// Put the removed shortcode tags back again. |
353
|
|
|
$shortcode_tags += $shortcode_tags_bkp; // phpcs:ignore |
354
|
|
|
|
355
|
|
|
/** |
356
|
|
|
* Filter the full content of the post. |
357
|
|
|
* |
358
|
|
|
* @since 2.1.0 |
359
|
|
|
* |
360
|
|
|
* @param string $default The whole HTML of the post to be outputted. |
361
|
|
|
* @param WP2D_Post $wp2d_post This object, to allow total customisation of the post. |
362
|
|
|
*/ |
363
|
|
|
return apply_filters( 'wp2d_post_filter', $post_content, $this ); |
364
|
|
|
} |
365
|
|
|
|
366
|
|
|
/** |
367
|
|
|
* Get the post's excerpt in a nice format. |
368
|
|
|
* |
369
|
|
|
* @since 1.5.0 |
370
|
|
|
* |
371
|
|
|
* @return string Post's excerpt. |
372
|
|
|
*/ |
373
|
|
|
private function get_excerpt_content() { |
374
|
|
|
// Look for the excerpt in the following order: |
375
|
|
|
// 1. Custom post excerpt. |
376
|
|
|
// 2. Text up to the <!--more--> tag. |
377
|
|
|
// 3. Manually trimmed content. |
378
|
|
|
$content = $this->post->post_content; |
379
|
|
|
$excerpt = $this->post->post_excerpt; |
380
|
|
|
if ( '' === $excerpt ) { |
381
|
|
|
if ( $more_pos = strpos( $content, '<!--more' ) ) { |
382
|
|
|
$excerpt = substr( $content, 0, $more_pos ); |
383
|
|
|
} else { |
384
|
|
|
$excerpt = wp_trim_words( $content, 42, '[...]' ); |
385
|
|
|
} |
386
|
|
|
} |
387
|
|
|
|
388
|
|
|
/** |
389
|
|
|
* Filter the excerpt of the post. |
390
|
|
|
* |
391
|
|
|
* @since 2.1.0 |
392
|
|
|
* |
393
|
|
|
* @param string $default The whole HTML of the excerpt to be outputted. |
394
|
|
|
* @param WP2D_Post $wp2d_post This object, to allow total customisation of the excerpt. |
395
|
|
|
*/ |
396
|
|
|
return apply_filters( 'wp2d_excerpt_filter', "<p>{$excerpt}</p>", $this ); |
397
|
|
|
} |
398
|
|
|
|
399
|
|
|
/** |
400
|
|
|
* Get a string of tags that have been added to the post. |
401
|
|
|
* |
402
|
|
|
* @since 1.5.0 |
403
|
|
|
* |
404
|
|
|
* @return string Tags added to the post. |
405
|
|
|
*/ |
406
|
|
|
private function get_tags_to_add() { |
407
|
|
|
$options = WP2D_Options::instance(); |
408
|
|
|
$tags_to_post = $this->tags_to_post; |
409
|
|
|
$tags_to_add = ''; |
410
|
|
|
$diaspora_tags = []; |
411
|
|
|
|
412
|
|
|
// Add any diaspora* tags? |
413
|
|
|
if ( ! empty( $tags_to_post ) ) { |
414
|
|
|
// The diaspora* tags to add to the post. |
415
|
|
|
$diaspora_tags_tmp = []; |
416
|
|
|
|
417
|
|
|
// Add global tags? |
418
|
|
|
$global_tags = $options->get_option( 'global_tags' ); |
419
|
|
|
if ( is_array( $global_tags ) && in_array( 'global', $tags_to_post, true ) ) { |
420
|
|
|
$diaspora_tags_tmp += array_flip( $global_tags ); |
421
|
|
|
} |
422
|
|
|
|
423
|
|
|
// Add custom tags? |
424
|
|
|
if ( is_array( $this->custom_tags ) && in_array( 'custom', $tags_to_post, true ) ) { |
425
|
|
|
$diaspora_tags_tmp += array_flip( $this->custom_tags ); |
426
|
|
|
} |
427
|
|
|
|
428
|
|
|
// Add post tags? |
429
|
|
|
$post_tags = wp_get_post_tags( $this->ID, [ 'fields' => 'slugs' ] ); |
430
|
|
|
if ( is_array( $post_tags ) && in_array( 'post', $tags_to_post, true ) ) { |
431
|
|
|
$diaspora_tags_tmp += array_flip( $post_tags ); |
432
|
|
|
} |
433
|
|
|
|
434
|
|
|
// Get an array of cleaned up tags. |
435
|
|
|
// NOTE: Validate method needs a variable, as it's passed by reference! |
436
|
|
|
$diaspora_tags_tmp = array_keys( $diaspora_tags_tmp ); |
437
|
|
|
$options->validate_tags( $diaspora_tags_tmp ); |
438
|
|
|
|
439
|
|
|
// Get all the tags and list them all nicely in a row. |
440
|
|
|
foreach ( $diaspora_tags_tmp as $tag ) { |
|
|
|
|
441
|
|
|
$diaspora_tags[] = '#' . $tag; |
442
|
|
|
} |
443
|
|
|
|
444
|
|
|
// Add all the found tags. |
445
|
|
|
if ( ! empty( $diaspora_tags ) ) { |
446
|
|
|
$tags_to_add = implode( ' ', $diaspora_tags ) . '<br/>'; |
447
|
|
|
} |
448
|
|
|
} |
449
|
|
|
|
450
|
|
|
/** |
451
|
|
|
* Filter the tags of the post. |
452
|
|
|
* |
453
|
|
|
* @since 2.1.0 |
454
|
|
|
* |
455
|
|
|
* @param string $default The whole string of tags to be outputted. |
456
|
|
|
* @param array $tags All tags that are assigned to this post. |
457
|
|
|
* @param WP2D_Post $wp2d_post This object, to allow total customisation of the tags output. |
458
|
|
|
*/ |
459
|
|
|
return apply_filters( 'wp2d_tags_filter', $tags_to_add, $diaspora_tags, $this ); |
460
|
|
|
} |
461
|
|
|
|
462
|
|
|
/** |
463
|
|
|
* Get the link to the original post. |
464
|
|
|
* |
465
|
|
|
* @since 1.5.0 |
466
|
|
|
* |
467
|
|
|
* @return string Original post link. |
468
|
|
|
*/ |
469
|
|
|
private function get_posted_at_link() { |
470
|
|
|
if ( $this->fullentrylink ) { |
471
|
|
|
$prefix = esc_html__( 'Originally posted at:', 'wp-to-diaspora' ); |
472
|
|
|
$permalink = get_permalink( $this->ID ); |
473
|
|
|
$title = esc_html__( 'Permalink', 'wp-to-diaspora' ); |
474
|
|
|
$posted_at_link = sprintf( '%1$s <a href="%2$s" title="%3$s">%2$s</a>', $prefix, $permalink, $title ); |
475
|
|
|
|
476
|
|
|
/** |
477
|
|
|
* Filter the "Originally posted at" link at the bottom of the post. |
478
|
|
|
* |
479
|
|
|
* @since 1.5.4.1 |
480
|
|
|
* |
481
|
|
|
* @param string $default The whole HTML of the text and link to be outputted. |
482
|
|
|
* @param WP2D_Post $wp2d_post This object, to allow total customisation of the title. |
483
|
|
|
* @param string $prefix The "Originally posted at:" prefix before the link. |
484
|
|
|
*/ |
485
|
|
|
return apply_filters( 'wp2d_posted_at_link_filter', "<p>{$posted_at_link}</p>", $this, $prefix ); |
486
|
|
|
} |
487
|
|
|
|
488
|
|
|
return ''; |
489
|
|
|
} |
490
|
|
|
|
491
|
|
|
/** |
492
|
|
|
* Save the details of the new diaspora* post to this post's history. |
493
|
|
|
* |
494
|
|
|
* @since 1.5.0 |
495
|
|
|
* |
496
|
|
|
* @param object $response Response from the API containing the diaspora* post details. |
497
|
|
|
*/ |
498
|
|
|
private function save_to_history( $response ) { |
499
|
|
|
// Make sure the post history is an array. |
500
|
|
|
if ( empty( $this->post_history ) ) { |
501
|
|
|
$this->post_history = []; |
502
|
|
|
} |
503
|
|
|
|
504
|
|
|
// Add a new entry to the history. |
505
|
|
|
$this->post_history[] = [ |
506
|
|
|
'id' => $response->id, |
507
|
|
|
'guid' => $response->guid, |
508
|
|
|
'created_at' => $this->post->post_modified, |
509
|
|
|
'aspects' => $this->aspects, |
510
|
|
|
'nsfw' => $response->nsfw, |
511
|
|
|
'post_url' => $response->permalink, |
512
|
|
|
]; |
513
|
|
|
|
514
|
|
|
update_post_meta( $this->ID, '_wp_to_diaspora_post_history', $this->post_history ); |
515
|
|
|
} |
516
|
|
|
|
517
|
|
|
/** |
518
|
|
|
* Return URL from [embed] shortcode instead of generated iframe. |
519
|
|
|
* |
520
|
|
|
* @since 1.5.0 |
521
|
|
|
* @see WP_Embed::shortcode() |
522
|
|
|
* |
523
|
|
|
* @param mixed $html The cached HTML result, stored in post meta. |
524
|
|
|
* @param string $url The attempted embed URL. |
525
|
|
|
* |
526
|
|
|
* @return string URL of the embed. |
527
|
|
|
*/ |
528
|
|
|
public function embed_url( $html, $url ) { |
529
|
|
|
return $url; |
530
|
|
|
} |
531
|
|
|
|
532
|
|
|
/** |
533
|
|
|
* Removes '[embed]' and '[/embed]' left by embed_url. |
534
|
|
|
* |
535
|
|
|
* @since 1.5.0 |
536
|
|
|
* |
537
|
|
|
* @todo It would be great to fix it using only one filter. |
538
|
|
|
* It's happening because embed filter is being removed by remove_all_filters('the_content') on WP2D_Post::post(). |
539
|
|
|
* |
540
|
|
|
* @param string $content Content of the post. |
541
|
|
|
* |
542
|
|
|
* @return string The content with the embed tags removed. |
543
|
|
|
*/ |
544
|
|
|
public function embed_remove( $content ) { |
545
|
|
|
return str_replace( [ '[embed]', '[/embed]' ], [ '<p>', '</p>' ], $content ); |
546
|
|
|
} |
547
|
|
|
|
548
|
|
|
/** |
549
|
|
|
* Prettify the image caption. |
550
|
|
|
* |
551
|
|
|
* @since 1.5.3 |
552
|
|
|
* |
553
|
|
|
* @param string $caption Caption to be prettified. |
554
|
|
|
* |
555
|
|
|
* @return string Prettified image caption. |
556
|
|
|
*/ |
557
|
|
|
public function get_img_caption( $caption ) { |
558
|
|
|
$caption = trim( $caption ); |
559
|
|
|
if ( '' === $caption ) { |
560
|
|
|
return ''; |
561
|
|
|
} |
562
|
|
|
|
563
|
|
|
/** |
564
|
|
|
* Filter the image caption to be displayed after images with captions. |
565
|
|
|
* |
566
|
|
|
* @since 1.5.3 |
567
|
|
|
* |
568
|
|
|
* @param string $default The whole HTML of the caption. |
569
|
|
|
* @param string $caption The caption text. |
570
|
|
|
*/ |
571
|
|
|
return apply_filters( 'wp2d_image_caption', "<blockquote>{$caption}</blockquote>", $caption ); |
572
|
|
|
} |
573
|
|
|
|
574
|
|
|
/** |
575
|
|
|
* Filter the default caption shortcode output. |
576
|
|
|
* |
577
|
|
|
* @since 1.5.3 |
578
|
|
|
* |
579
|
|
|
* @see img_caption_shortcode() |
580
|
|
|
* |
581
|
|
|
* @param string $empty The caption output. Default empty. |
582
|
|
|
* @param array $attr Attributes of the caption shortcode. |
583
|
|
|
* @param string $content The image element, possibly wrapped in a hyperlink. |
584
|
|
|
* |
585
|
|
|
* @return string The caption shortcode output. |
586
|
|
|
*/ |
587
|
|
|
public function custom_img_caption( $empty, $attr, $content ) { |
588
|
|
|
$content = do_shortcode( $content ); |
589
|
|
|
|
590
|
|
|
// If a caption attribute is defined, we'll add it after the image. |
591
|
|
|
if ( isset( $attr['caption'] ) && '' !== $attr['caption'] ) { |
592
|
|
|
$content .= "\n" . $this->get_img_caption( $attr['caption'] ); |
593
|
|
|
} |
594
|
|
|
|
595
|
|
|
return $content; |
596
|
|
|
} |
597
|
|
|
|
598
|
|
|
/** |
599
|
|
|
* Create a custom gallery caption output. |
600
|
|
|
* |
601
|
|
|
* @since 1.5.3 |
602
|
|
|
* |
603
|
|
|
* @param array $attr Gallery attributes. |
604
|
|
|
* |
605
|
|
|
* @return string |
606
|
|
|
*/ |
607
|
|
|
public function custom_gallery_shortcode( $attr ) { |
608
|
|
|
// Try user value and fall back to default value in WordPress. |
609
|
|
|
$captiontag = $attr['captiontag'] ?? ( current_theme_supports( 'html5', 'gallery' ) ? 'figcaption' : 'dd' ); |
610
|
|
|
|
611
|
|
|
// Let WordPress create the regular gallery. |
612
|
|
|
$gallery = gallery_shortcode( $attr ); |
613
|
|
|
|
614
|
|
|
// Change the content of the captions. |
615
|
|
|
$gallery = preg_replace_callback( |
616
|
|
|
'~(<' . $captiontag . '.*>)(.*)(</' . $captiontag . '>)~mUus', |
617
|
|
|
[ $this, 'custom_gallery_regex_callback' ], |
618
|
|
|
$gallery |
619
|
|
|
); |
620
|
|
|
|
621
|
|
|
return $gallery; |
622
|
|
|
} |
623
|
|
|
|
624
|
|
|
/** |
625
|
|
|
* Change the result of the regex match from custom_gallery_shortcode. |
626
|
|
|
* |
627
|
|
|
* @param array $m Regex matches. |
628
|
|
|
* |
629
|
|
|
* @return string Prettified gallery image caption. |
630
|
|
|
*/ |
631
|
|
|
public function custom_gallery_regex_callback( $m ) { |
632
|
|
|
return $this->get_img_caption( $m[2] ); |
633
|
|
|
} |
634
|
|
|
|
635
|
|
|
/* |
636
|
|
|
* META BOX |
637
|
|
|
*/ |
638
|
|
|
|
639
|
|
|
/** |
640
|
|
|
* Adds a meta box to the main column on the enabled Post Types' edit screens. |
641
|
|
|
* |
642
|
|
|
* @since 1.5.0 |
643
|
|
|
*/ |
644
|
|
|
public function add_meta_boxes() { |
645
|
|
|
$options = WP2D_Options::instance(); |
646
|
|
|
foreach ( $options->get_option( 'enabled_post_types' ) as $post_type ) { |
647
|
|
|
add_meta_box( |
648
|
|
|
'wp_to_diaspora_meta_box', |
649
|
|
|
'WP to diaspora*', |
650
|
|
|
[ $this, 'meta_box_render' ], |
651
|
|
|
$post_type, |
652
|
|
|
'side', |
653
|
|
|
'high' |
654
|
|
|
); |
655
|
|
|
} |
656
|
|
|
} |
657
|
|
|
|
658
|
|
|
/** |
659
|
|
|
* Prints the meta box content. |
660
|
|
|
* |
661
|
|
|
* @since 1.5.0 |
662
|
|
|
* |
663
|
|
|
* @param WP_Post $post The object for the current post. |
664
|
|
|
*/ |
665
|
|
|
public function meta_box_render( $post ) { |
666
|
|
|
$this->assign_wp_post( $post ); |
667
|
|
|
|
668
|
|
|
// Add an nonce field so we can check for it later. |
669
|
|
|
wp_nonce_field( 'wp_to_diaspora_meta_box', 'wp_to_diaspora_meta_box_nonce' ); |
670
|
|
|
|
671
|
|
|
// Get the default values to use, but give priority to the meta data already set. |
672
|
|
|
$options = WP2D_Options::instance(); |
673
|
|
|
|
674
|
|
|
// Make sure we have some value for post meta fields. |
675
|
|
|
$this->custom_tags = $this->custom_tags ?: []; |
676
|
|
|
|
677
|
|
|
// If this post is already published, don't post again to diaspora* by default. |
678
|
|
|
$this->post_to_diaspora = ( $this->post_to_diaspora && 'publish' !== get_post_status( $this->ID ) ); |
679
|
|
|
$this->aspects = $this->aspects ?: []; |
680
|
|
|
$this->services = $this->services ?: []; |
681
|
|
|
|
682
|
|
|
// Have we already posted on diaspora*? |
683
|
|
|
$diaspora_post_url = '#'; |
684
|
|
|
if ( is_array( $this->post_history ) ) { |
685
|
|
|
$latest_post = end( $this->post_history ); |
686
|
|
|
$diaspora_post_url = $latest_post['post_url']; |
687
|
|
|
} |
688
|
|
|
?> |
689
|
|
|
<p<?php echo '#' === $diaspora_post_url ? ' style="display: none;"' : ''; ?>><a id="diaspora-post-url" href="<?php echo esc_attr( $diaspora_post_url ); ?>" target="_blank"><?php esc_html_e( 'Already posted to diaspora*.', 'wp-to-diaspora' ); ?></a></p> |
690
|
|
|
|
691
|
|
|
<p><?php $options->post_to_diaspora_render( $this->post_to_diaspora ); ?></p> |
692
|
|
|
<p><?php $options->fullentrylink_render( $this->fullentrylink ); ?></p> |
693
|
|
|
<p><?php $options->display_render( $this->display ); ?></p> |
694
|
|
|
<p><?php $options->tags_to_post_render( $this->tags_to_post ); ?></p> |
695
|
|
|
<p><?php $options->custom_tags_render( $this->custom_tags ); ?></p> |
696
|
|
|
<p><?php $options->aspects_services_render( [ 'aspects', $this->aspects ] ); ?></p> |
697
|
|
|
<p><?php $options->aspects_services_render( [ 'services', $this->services ] ); ?></p> |
698
|
|
|
|
699
|
|
|
<?php |
700
|
|
|
} |
701
|
|
|
|
702
|
|
|
/** |
703
|
|
|
* When the post is saved, save our meta data. |
704
|
|
|
* |
705
|
|
|
* @since 1.5.0 |
706
|
|
|
* |
707
|
|
|
* @param integer $post_id The ID of the post being saved. |
708
|
|
|
*/ |
709
|
|
|
public function save_meta_box_data( $post_id ) { |
710
|
|
|
/* |
711
|
|
|
* We need to verify this came from our screen and with proper authorization, |
712
|
|
|
* because the save_post action can be triggered at other times. |
713
|
|
|
*/ |
714
|
|
|
if ( ! $this->is_safe_to_save() ) { |
715
|
|
|
return; |
716
|
|
|
} |
717
|
|
|
|
718
|
|
|
/* OK, it's safe for us to save the data now. */ |
719
|
|
|
|
720
|
|
|
// Meta data to save. |
721
|
|
|
$meta_to_save = $_POST['wp_to_diaspora_settings']; // phpcs:ignore |
722
|
|
|
$options = WP2D_Options::instance(); |
723
|
|
|
|
724
|
|
|
// Checkboxes. |
725
|
|
|
$options->validate_checkboxes( [ 'post_to_diaspora', 'fullentrylink' ], $meta_to_save ); |
726
|
|
|
|
727
|
|
|
// Single Selects. |
728
|
|
|
$options->validate_single_selects( 'display', $meta_to_save ); |
729
|
|
|
|
730
|
|
|
// Multiple Selects. |
731
|
|
|
$options->validate_multi_selects( 'tags_to_post', $meta_to_save ); |
732
|
|
|
|
733
|
|
|
// Save custom tags as array. |
734
|
|
|
$options->validate_tags( $meta_to_save['custom_tags'] ); |
735
|
|
|
|
736
|
|
|
// Clean up the list of aspects. If the list is empty, only use the 'Public' aspect. |
737
|
|
|
$options->validate_aspects_services( $meta_to_save['aspects'], [ 'public' ] ); |
738
|
|
|
|
739
|
|
|
// Clean up the list of services. |
740
|
|
|
$options->validate_aspects_services( $meta_to_save['services'] ); |
741
|
|
|
|
742
|
|
|
// Update the meta data for this post. |
743
|
|
|
update_post_meta( $post_id, '_wp_to_diaspora', $meta_to_save ); |
744
|
|
|
} |
745
|
|
|
|
746
|
|
|
/** |
747
|
|
|
* Perform all checks to see if we are allowed to save the meta data. |
748
|
|
|
* |
749
|
|
|
* @since 1.5.0 |
750
|
|
|
* |
751
|
|
|
* @return bool If the verification checks have passed. |
752
|
|
|
*/ |
753
|
|
|
private function is_safe_to_save() { |
754
|
|
|
// Verify that our nonce is set and valid. |
755
|
|
|
if ( ! ( isset( $_POST['wp_to_diaspora_meta_box_nonce'] ) && wp_verify_nonce( sanitize_key( $_POST['wp_to_diaspora_meta_box_nonce'] ), 'wp_to_diaspora_meta_box' ) ) ) { |
756
|
|
|
return false; |
757
|
|
|
} |
758
|
|
|
|
759
|
|
|
// If this is an autosave, our form has not been submitted, so we don't want to do anything. |
760
|
|
|
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) { |
761
|
|
|
return false; |
762
|
|
|
} |
763
|
|
|
|
764
|
|
|
// Check the user's permissions. |
765
|
|
|
$permission = ( isset( $_POST['post_type'] ) && 'page' === $_POST['post_type'] ) ? 'edit_pages' : 'edit_posts'; |
766
|
|
|
if ( ! current_user_can( $permission, $this->ID ) ) { |
767
|
|
|
return false; |
768
|
|
|
} |
769
|
|
|
|
770
|
|
|
// Make real sure that we have some meta data to save. |
771
|
|
|
if ( ! isset( $_POST['wp_to_diaspora_settings'] ) ) { |
772
|
|
|
return false; |
773
|
|
|
} |
774
|
|
|
|
775
|
|
|
return true; |
776
|
|
|
} |
777
|
|
|
|
778
|
|
|
/** |
779
|
|
|
* Add admin notices when a post gets displayed. |
780
|
|
|
* |
781
|
|
|
* @since 1.5.0 |
782
|
|
|
* |
783
|
|
|
* @todo Ignore post error with AJAX. |
784
|
|
|
*/ |
785
|
|
|
public function admin_notices() { |
786
|
|
|
global $post, $pagenow; |
787
|
|
|
if ( ! $post || 'post.php' !== $pagenow ) { |
788
|
|
|
return; |
789
|
|
|
} |
790
|
|
|
|
791
|
|
|
if ( ( $error = get_post_meta( $post->ID, '_wp_to_diaspora_post_error', true ) ) && is_wp_error( $error ) ) { |
792
|
|
|
// Are we adding a help tab link to this notice? |
793
|
|
|
$help_link = WP2D_Contextual_Help::get_help_tab_quick_link( $error ); |
794
|
|
|
|
795
|
|
|
// This notice will only be shown if posting to diaspora* has failed. |
796
|
|
|
printf( |
797
|
|
|
'<div class="error notice is-dismissible"><p>%1$s %2$s %3$s <a href="%4$s">%5$s</a></p></div>', |
798
|
|
|
esc_html__( 'Failed to post to diaspora*.', 'wp-to-diaspora' ), |
799
|
|
|
esc_html( $error->get_error_message() ), |
800
|
|
|
$help_link, // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped |
801
|
|
|
esc_url( add_query_arg( 'wp2d_ignore_post_error', '' ) ), |
802
|
|
|
esc_html__( 'Ignore', 'wp-to-diaspora' ) |
803
|
|
|
); |
804
|
|
|
} elseif ( ( $diaspora_post_history = get_post_meta( $post->ID, '_wp_to_diaspora_post_history', true ) ) && is_array( $diaspora_post_history ) ) { |
805
|
|
|
// Get the latest post from the history. |
806
|
|
|
$latest_post = end( $diaspora_post_history ); |
807
|
|
|
|
808
|
|
|
// Only show if this post is showing a message and the post is a fresh share. |
809
|
|
|
if ( isset( $_GET['message'] ) && $post->post_modified === $latest_post['created_at'] ) { // phpcs:ignore |
810
|
|
|
printf( |
811
|
|
|
'<div class="updated notice is-dismissible"><p>%1$s <a href="%2$s" target="_blank">%3$s</a></p></div>', |
812
|
|
|
esc_html__( 'Successfully posted to diaspora*.', 'wp-to-diaspora' ), |
813
|
|
|
esc_url( $latest_post['post_url'] ), |
814
|
|
|
esc_html__( 'View Post', 'wp-to-diaspora' ) |
815
|
|
|
); |
816
|
|
|
} |
817
|
|
|
} |
818
|
|
|
} |
819
|
|
|
|
820
|
|
|
/** |
821
|
|
|
* Delete the error post meta data if it gets ignored. |
822
|
|
|
* |
823
|
|
|
* @since 1.5.0 |
824
|
|
|
*/ |
825
|
|
|
public function ignore_post_error() { |
826
|
|
|
// If "Ignore" link has been clicked, delete the post error meta data. |
827
|
|
|
if ( isset( $_GET['wp2d_ignore_post_error'], $_GET['post'] ) ) { // phpcs:ignore |
828
|
|
|
delete_post_meta( absint( $_GET['post'] ), '_wp_to_diaspora_post_error' ); // phpcs:ignore |
829
|
|
|
} |
830
|
|
|
} |
831
|
|
|
|
832
|
|
|
/** |
833
|
|
|
* Get latest diaspora* share of this post. |
834
|
|
|
* |
835
|
|
|
* @since 3.0.0 |
836
|
|
|
*/ |
837
|
|
|
public function get_post_history_callback() { |
838
|
|
View Code Duplication |
if ( ! check_ajax_referer( 'wp2d', 'nonce', false ) ) { |
|
|
|
|
839
|
|
|
wp_send_json_error( [ |
840
|
|
|
'message' => 'WP2D: ' . __( 'AJAX Nonce failure.', 'wp-to-diaspora' ), |
841
|
|
|
] ); |
842
|
|
|
} |
843
|
|
|
|
844
|
|
|
$post_id = sanitize_key( $_REQUEST['post_id'] ?? '' ); |
845
|
|
|
if ( ! is_numeric( $post_id ) ) { |
846
|
|
|
return; |
847
|
|
|
} |
848
|
|
|
|
849
|
|
|
if ( $error = get_post_meta( $post_id, '_wp_to_diaspora_post_error', true ) ) { |
850
|
|
|
// This notice will only be shown if posting to diaspora* has failed. |
851
|
|
|
wp_send_json_error( [ |
852
|
|
|
'message' => esc_html__( 'Failed to post to diaspora*.', 'wp-to-diaspora' ) . ' - ' . esc_html( $error ), |
853
|
|
|
] ); |
854
|
|
|
} |
855
|
|
|
|
856
|
|
|
if ( ( $diaspora_post_history = get_post_meta( $post_id, '_wp_to_diaspora_post_history', true ) ) && is_array( $diaspora_post_history ) ) { |
857
|
|
|
// Get the latest post from the history. |
858
|
|
|
$latest_post = end( $diaspora_post_history ); |
859
|
|
|
|
860
|
|
|
// Only show if this post is a fresh share. |
861
|
|
|
if ( get_post( $post_id )->post_modified === $latest_post['created_at'] ) { // phpcs:ignore |
862
|
|
|
wp_send_json_success( [ |
863
|
|
|
'message' => esc_html__( 'Successfully posted to diaspora*.', 'wp-to-diaspora' ), |
864
|
|
|
'action' => [ |
865
|
|
|
'label' => esc_html__( 'View Post', 'wp-to-diaspora' ), |
866
|
|
|
'url' => esc_url( $latest_post['post_url'] ), |
867
|
|
|
], |
868
|
|
|
] ); |
869
|
|
|
} |
870
|
|
|
} |
871
|
|
|
} |
872
|
|
|
} |
873
|
|
|
|
There are different options of fixing this problem.
If you want to be on the safe side, you can add an additional type-check:
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:
Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.