PluginProbe
Display Remote Posts Block / 1.0.2
Display Remote Posts Block v1.0.2
trunk 1.0.0 1.0.1 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.0.7 1.0.8 1.0.9 1.1.0 1.1.1 1.1.2 1.1.3 1.1.4
display-remote-posts-block / display-remote-posts-block.php

display-remote-posts-block.php in Display Remote Posts Block 1.0.2, at display-remote-posts-block.php

598 lines 18.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /*
3 Plugin Name: Display Remote Posts Block
4 Description: Block to display recent posts from a WordPress or Blogger blog
5 Author: Webd Ltd
6 Version: 1.0.2
7 Author URI: https://webd.uk
8 Text Domain: display-remote-posts-block
9 */
10
11
12
13 if (!defined('ABSPATH')) {
14 exit('This isn\'t the page you\'re looking for. Move along, move along.');
15 }
16
17
18
19 if (!class_exists('display_remote_posts_block_class')) {
20
21 class display_remote_posts_block_class {
22
23 function __construct() {
24
25 add_action('init', array($this, 'init'));
26
27 add_action('display_remote_posts_block_cron', array($this, 'display_remote_posts_block_cron'));
28
29 if (!wp_next_scheduled('display_remote_posts_block_cron')) {
30
31 wp_schedule_event(time(), 'hourly', 'display_remote_posts_block_cron');
32
33 }
34
35 register_deactivation_hook(__FILE__, array($this, 'display_remote_posts_block_deactivate'));
36
37 }
38
39 public function init() {
40
41 if (false === self::check_gutenberg()) {
42
43 return false;
44
45 }
46
47 $asset_file = include( plugin_dir_path( __FILE__ ) . 'build/index.asset.php');
48
49 wp_register_script(
50 'display-remote-posts-block',
51 plugins_url( 'build/index.js', __FILE__ ),
52 $asset_file['dependencies'],
53 $asset_file['version']
54 );
55
56 register_block_type( 'display-remote-posts-block/display-remote-posts', array(
57 'apiVersion' => 2,
58 'editor_script' => 'display-remote-posts-block',
59 'render_callback' => array($this, 'render_display_remote_posts_block'),
60 'attributes' => array(
61 'url' => array(
62 'type' => 'string',
63 'default' => '',
64 ),
65 'title' => array(
66 'type' => 'boolean',
67 'default' => true,
68 ),
69 'posts' => array(
70 'type' => 'number',
71 'default' => 1,
72 ),
73 'featured_images' => array(
74 'type' => 'boolean',
75 'default' => true,
76 ),
77 'excerpts' => array(
78 'type' => 'boolean',
79 'default' => true,
80 ),
81 ),
82 ));
83
84 }
85
86 public function display_remote_posts_block_cron() {
87
88 delete_option('display_remote_posts_block_cache');
89
90 }
91
92 public function display_remote_posts_block_deactivate() {
93
94 $timestamp = wp_next_scheduled('display_remote_posts_block_cron');
95 wp_unschedule_event($timestamp, 'display_remote_posts_block_cron');
96
97 }
98
99 public function render_display_remote_posts_block($attributes, $content) {
100
101 $attributes = shortcode_atts(
102 array(
103 'url' => '',
104 'title' => true,
105 'posts' => 1,
106 'featured_images' => true,
107 'excerpts' => true
108 ), $attributes);
109
110 $content = '<div class="wp-block-display-remote-posts wp-block-display-remote-posts__inner-container">';
111
112 $attributes['url'] = trailingslashit(esc_url($attributes['url']));
113
114 if (filter_var($attributes['url'], FILTER_VALIDATE_URL)) {
115
116 $cached_data = get_option('display_remote_posts_block_cache', array());
117
118 $url_hash = md5($attributes['url']);
119
120 if (isset($cached_data[$url_hash])) {
121
122 $blog_data = $cached_data[$url_hash];
123
124 } else {
125
126 $blog_data = $this->get_wordpress_com_data($attributes['url']);
127
128 if (is_wp_error($blog_data)) {
129
130 $blog_data = $this->get_wordpress_org_data($attributes['url']);
131
132 }
133
134 if (is_wp_error($blog_data)) {
135
136 $blog_data = $this->get_blogger_data($attributes['url']);
137
138 }
139
140 if (!is_wp_error($blog_data)) {
141
142 $cached_data[$url_hash] = $blog_data;
143
144 update_option('display_remote_posts_block_cache', $cached_data);
145
146 }
147
148 }
149
150 if (!is_wp_error($blog_data)) {
151
152 if ($attributes['title'] && isset($blog_data->name) && $blog_data->name) {
153
154 $content .= '<h3>' . esc_html($blog_data->name) . '</h3>' . PHP_EOL;
155
156 }
157
158 $post_counter = 0;
159
160 foreach ($blog_data->posts as $single_post) {
161
162 $post_counter++;
163
164 if ($post_counter > absint($attributes['posts'])) { break; }
165
166 If (isset($single_post->URL) && $single_post->URL) {
167
168 $content .= '<h4><a href="' . $single_post->URL . '" title="' . esc_attr( $single_post->title ) . '">' . esc_html($single_post->title) . '</a></h4>' . PHP_EOL;
169
170 } else {
171
172 $content .= '<h4>' . esc_html($single_post->title) . '</h4>' . PHP_EOL;
173
174 }
175
176 If (isset($single_post->URL) && $single_post->URL && $attributes['featured_images'] && $single_post->featured_image) {
177
178 $content .= '<a title="' . esc_attr( $single_post->title ) . '" href="' . $single_post->URL . '"><img src="' . $single_post->featured_image . '" alt="' . esc_attr($single_post->title ) . '"/></a>' . PHP_EOL;
179
180 } elseif ($attributes['featured_images'] && $single_post->featured_image) {
181
182 $content .= '<img src="' . $single_post->featured_image . '" alt="' . esc_attr($single_post->title ) . '"/>' . PHP_EOL;
183
184 }
185
186 if ($attributes['excerpts'] && $single_post->excerpt) {
187
188 $content .= '<p>' . $single_post->excerpt . '</p>' . PHP_EOL;
189
190 }
191
192 }
193
194 } else {
195
196 if (current_user_can('editor') || current_user_can('administrator')) {
197
198 $content .= '<h3>Display Remote Posts Error</h3>' . PHP_EOL;
199 $content .= '<h4>Error: ' . $blog_data->errors[$this->array_key_first($blog_data->errors)][0] . '</h4>' . PHP_EOL;
200
201 if (isset($blog_data->error_data[$this->array_key_first($blog_data->errors)])) {
202
203 $content .= '<p>' . $blog_data->error_data[$this->array_key_first($blog_data->errors)] . '</p>' . PHP_EOL;
204
205 }
206
207 }
208
209 }
210
211 } elseif ($attributes['url'] && !filter_var($attributes['url'], FILTER_VALIDATE_URL)) {
212
213 if( current_user_can('editor') || current_user_can('administrator') ) {
214
215 $content .= '<h3>Display Remote Posts Error</h3>' . PHP_EOL;
216 $content .= '<h4>You need to enter a valid blog URL!</h4>' . PHP_EOL;
217 $content .= '<p>Edit the block settings and provide a valid web address for the blog.</p>' . PHP_EOL;
218
219 }
220
221 } else {
222
223 if( current_user_can('editor') || current_user_can('administrator') ) {
224
225 $content .= '<h3>Display Remote Posts</h3>' . PHP_EOL;
226 $content .= '<h4>Edit the block settings to get started!</h4>' . PHP_EOL;
227 $content .= '<p>To show posts from another blog, edit the block settings and provide the web address for the blog.</p>' . PHP_EOL;
228
229 }
230
231 }
232
233 $content .= '</div>';
234
235 return $content;
236
237 }
238
239 private function array_key_first($array) {
240
241 if (is_array($array)) {
242
243 if (function_exists('array_key_first')) {
244
245 return array_key_first($array);
246
247 } else {
248
249 foreach ($array as $key => $value) {
250
251 return $key;
252
253 }
254
255 }
256
257 }
258
259 return false;
260
261 }
262
263 private function get_wordpress_com_data($url) {
264
265 $blog_info = $this->remote_get_data('https://public-api.wordpress.com/rest/v1.1/sites/' . urlencode($url) . '?fields=ID,name');
266
267 if (is_wp_error($blog_info)) { return $blog_info; }
268
269 $blog_info = json_decode($blog_info);
270
271 if (!$blog_info) {
272
273 return new WP_Error(
274 'no_body',
275 __('Invalid remote response.', 'display-remote-posts-block'),
276 'Invalid JSON from remote.'
277 );
278
279 }
280
281 if (isset($blog_info->error)) {
282
283 return new WP_Error(
284 'remote_error',
285 __('It looks like the WordPress site URL is incorrectly configured. Please check it in the block settings.', 'display-remote-posts-block'),
286 $blog_posts->error
287 );
288
289 }
290
291 if (!isset($blog_info->ID) && !isset($blog_info->name)) {
292
293 return new WP_Error(
294 'no_data',
295 __('Incorrect data received!', 'display-remote-posts-block'),
296 __('No site ID and / or name returned', 'display-remote-posts-block')
297 );
298
299 }
300
301 $blog_info->ID = absint($blog_info->ID);
302 $blog_info->name = sanitize_text_field((string) $blog_info->name);
303
304 $blog_posts = $this->remote_get_data('https://public-api.wordpress.com/rest/v1.1/sites/' . absint($blog_info->ID) . '/posts/?fields=id,title,excerpt,URL,featured_image&number=10');
305
306 if (is_wp_error($blog_posts)) { return $blog_posts; }
307
308 $blog_posts = json_decode($blog_posts);
309
310 if (!$blog_posts) {
311
312 return new WP_Error(
313 'no_body',
314 __('Invalid remote response.', 'display-remote-posts-block'),
315 'Invalid JSON from remote.'
316 );
317
318 }
319
320 if (isset($blog_posts->error)) {
321
322 return new WP_Error(
323 'remote_error',
324 __('It looks like the WordPress site URL is incorrectly configured. Please check it in the block settings.', 'display-remote-posts-block'),
325 $blog_posts->error
326 );
327
328 }
329
330 if (!isset($blog_posts->posts)) {
331
332 return new WP_Error(
333 'no_data',
334 __('Incorrect data received!', 'display-remote-posts-block'),
335 __('No site ID and / or name returned', 'display-remote-posts-block')
336 );
337
338 }
339
340 $blog_info->posts = $blog_posts->posts;
341
342 foreach ($blog_info->posts as $key => $single_post) {
343
344 if (!(isset($single_post->title) && sanitize_text_field((string) $single_post->title))) { $blog_info->posts[$key]->title = 'Blog Post'; } else { $blog_info->posts[$key]->title = sanitize_text_field((string) $single_post->title); }
345
346 $blog_info->posts[$key]->URL = (isset($single_post->URL) && esc_url($single_post->URL)) ? esc_url($single_post->URL) : false;
347
348 if (!(isset($single_post->excerpt) && $single_post->excerpt)) { $blog_info->posts[$key]->excerpt = false; }
349
350 $blog_info->posts[$key]->excerpt = strip_tags($blog_info->posts[$key]->excerpt);
351
352 if (strpos($blog_info->posts[$key]->excerpt, ' [&hellip;]') === false) {
353
354 $blog_info->posts[$key]->excerpt = trim(substr($blog_info->posts[$key]->excerpt, 0, strpos(strip_tags($blog_info->posts[$key]->excerpt), '&hellip;'))) . ' [&hellip;]';
355
356 }
357
358 $blog_info->posts[$key]->featured_image = (isset($single_post->featured_image) && esc_url($single_post->featured_image)) ? esc_url($single_post->featured_image) : false;
359
360 }
361
362 return $blog_info;
363
364 }
365
366 private function get_wordpress_org_data($url) {
367
368 $blog_data = $this->remote_get_data($url . '/feed/');
369
370 if (is_wp_error($blog_data)) { return $blog_data; }
371
372 libxml_use_internal_errors(true);
373
374 $blog_data = simplexml_load_string($blog_data);
375
376 if (!$blog_data || !isset($blog_data->channel)) {
377
378 return new WP_Error(
379 'no_data',
380 __('No XML data received!', 'display-remote-posts-block'),
381 __('The data returned was not an XML feed', 'display-remote-posts-block')
382 );
383
384 }
385
386 $blog_data = $blog_data->channel;
387
388 $blog_info = new stdClass();
389 $blog_info->ID = false;
390
391 if (isset($blog_data->title) && sanitize_text_field((string) $blog_data->title)) { $blog_info->name = sanitize_text_field((string) $blog_data->title); } else { $blog_info->name = false; }
392
393 $blog_info->posts = array();
394 $post_counter = 0;
395
396 foreach ($blog_data->item as $single_post) {
397
398 $post_counter++;
399
400 if ($post_counter > 10) { break; }
401
402 $blog_post = new stdClass();
403 $blog_post->title = (isset($single_post->title) && sanitize_text_field((string) $single_post->title)) ? sanitize_text_field((string) $single_post->title) : 'Blog Post';
404 $blog_post->URL = (isset($single_post->link) && esc_url($single_post->link)) ? esc_url($single_post->link) : false;
405
406 if ($single_post->children("content", true)) {
407
408 $blog_post->excerpt = $this->get_excerpt($single_post->children("content", true));
409 preg_match_all('/<img.+?src=[\'"]([^\'"]+)[\'"].*?>/i', (string) $single_post->children("content", true), $post_images);
410
411 if (isset($post_images[1][0])) {
412
413 $blog_post->featured_image = esc_url($post_images[1][0]);
414
415 } else {
416
417 $blog_post->featured_image = false;
418
419 }
420
421 } elseif (isset($single_post->description) && $single_post->description) {
422
423 $blog_post->excerpt = $this->get_excerpt($single_post->description);
424 $blog_post->featured_image = false;
425
426 } else {
427
428 $blog_post->excerpt = false;
429 $blog_post->featured_image = false;
430
431 }
432
433 $blog_info->posts[] = $blog_post;
434
435 }
436
437 return $blog_info;
438
439 }
440
441 private function get_blogger_data($url) {
442
443 $blog_data = $this->remote_get_data($url . '/feeds/posts/default');
444
445 if (is_wp_error($blog_data)) { return $blog_data; }
446
447 libxml_use_internal_errors(true);
448
449 $blog_data = simplexml_load_string($blog_data);
450
451 if (!$blog_data || !isset($blog_data->entry)) {
452
453 return new WP_Error(
454 'no_data',
455 __('No XML data received!', 'display-remote-posts-block'),
456 __('The data returned was not an XML feed', 'display-remote-posts-block')
457 );
458
459 }
460
461 $blog_info = new stdClass();
462 $blog_info->ID = false;
463
464 if (isset($blog_data->title) && sanitize_text_field((string) $blog_data->title)) { $blog_info->name = sanitize_text_field((string) $blog_data->title); } else { $blog_info->name = false; }
465
466 $blog_info->posts = array();
467 $post_counter = 0;
468
469 foreach ($blog_data->entry as $single_post) {
470
471 $post_counter++;
472
473 if ($post_counter > 10) { break; }
474
475 $blog_post = new stdClass();
476 $blog_post->title = (isset($single_post->title) && sanitize_text_field((string) $single_post->title)) ? sanitize_text_field((string) $single_post->title) : 'Blog Post';
477
478 foreach ($single_post->link as $link_feed) {
479
480 if ((string) $link_feed['rel'] === 'alternate') {
481
482 $blog_post->URL = esc_url((string) $link_feed['href']);
483
484 break;
485
486 }
487
488 }
489
490 if (!isset($blog_post->URL)) { $blog_post->URL = false; }
491
492 if (isset($single_post->content) && $single_post->content) {
493
494 $blog_post->excerpt = $this->get_excerpt($single_post->content);
495 preg_match_all('/<img.+?src=[\'"]([^\'"]+)[\'"].*?>/i', (string) $single_post->content, $post_images);
496
497 if (isset($post_images[1][0])) {
498
499 $blog_post->featured_image = esc_url($post_images[1][0]);
500
501 } else {
502
503 $blog_post->featured_image = false;
504
505 }
506
507 } else {
508
509 $blog_post->excerpt = false;
510 $blog_post->featured_image = false;
511
512 }
513
514 $blog_info->posts[] = $blog_post;
515
516 }
517
518 return $blog_info;
519
520 }
521
522 private function get_excerpt($text) {
523
524 $text = strip_shortcodes( $text );
525 $text = excerpt_remove_blocks( $text );
526 $text = apply_filters( 'the_content', $text );
527 $text = str_replace( ']]>', ']]&gt;', $text );
528 $excerpt_length = (int) _x( '55', 'excerpt_length' );
529 $excerpt_length = (int) apply_filters( 'excerpt_length', $excerpt_length );
530 $text = ltrim(wp_trim_words( $text, $excerpt_length, ' […]' ), '&nbsp;');
531
532 return $text;
533
534 }
535
536 private function remote_get_data($url) {
537
538 $response = wp_remote_get( $url, array( 'timeout' => 15 ) );
539
540 if (is_wp_error($response)) {
541
542 return $response;
543
544 }
545
546 if (wp_remote_retrieve_response_code($response) !== 200) {
547
548 return new WP_Error(
549 'http_error',
550 __('An error occurred fetching the remote data.', 'display-remote-posts-block'),
551 wp_remote_retrieve_response_message($response)
552 );
553
554 }
555
556 $response_body = wp_remote_retrieve_body($response);
557
558 if (!$response_body) {
559
560 return new WP_Error(
561 'no_body',
562 __('Invalid remote response.', 'display-remote-posts-block' ),
563 'No body in response.'
564 );
565 } else {
566
567 return $response_body;
568
569 }
570
571 }
572
573 static function check_gutenberg() {
574
575 if (false === defined('GUTENBERG_VERSION') && false === version_compare(get_bloginfo('version'), '5.0', '>=')) {
576
577 add_action('admin_notices', array(__CLASS__, 'notice_gutenberg_missing'));
578
579 return false;
580
581 }
582
583 }
584
585 static function notice_gutenberg_missing() {
586
587 echo '<div class="error"><p><b>Map Block</b> plugin requires the Gutenberg plugin to work. It is after all a block for Gutenberg ;)<br>Install the <a href="https://wordpress.org/plugins/gutenberg/" target="_blank">Gutenberg plugin</a> and this notice will go away.</p></div>';
588
589 }
590
591 }
592
593 }
594
595 $display_remote_posts_block_object= new display_remote_posts_block_class();
596
597 ?>
598