WP RSS Aggregator - Version 4.2

Version Description

(2014-07-17) = * New Feature: Can now view each feed source's imported feed items separate from other feed sources' feed items. * Enhanced: Major visual update to the Feed Sources page with new live updates. * Enhanced: The custom feed now includes the feed source. * Fixed bug: Google News feeds were importing duplicate items on every update. * Fixed bug: Multiple minor bug fixes with old filters.

Download this release

Release Info

Developer jeangalea
Plugin Icon 128x128 WP RSS Aggregator
Version 4.2
Comparing to
See all releases

Code changes from version 4.1.6 to 4.2

changelog.txt CHANGED
@@ -1,3 +1,10 @@
 
 
 
 
 
 
 
1
  4.1.6 (2014-06-28)
2
  Fixed bug: Results returned by wprss_get_feed_items_for_source() will no longer be affected by filters.
3
  Fixed bug: Charset issue in titles
1
+ 4.2 (2014-07-17)
2
+ New Feature: Can now view each feed source's imported feed items separate from other feed sources' feed items.
3
+ Enhanced: Major visual update to the Feed Sources page with new live updates.
4
+ Enhanced: The custom feed now includes the feed source.
5
+ Fixed bug: Google News feeds were importing duplicate items on every update.
6
+ Fixed bug: Multiple minor bug fixes with old filters.
7
+
8
  4.1.6 (2014-06-28)
9
  Fixed bug: Results returned by wprss_get_feed_items_for_source() will no longer be affected by filters.
10
  Fixed bug: Charset issue in titles
css/admin-3.8.css CHANGED
@@ -1,3 +1,36 @@
1
  #menu-posts-wprss_feed .menu-icon-post div.wp-menu-image:before {
2
- content: "\f303";
3
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  #menu-posts-wprss_feed .menu-icon-post div.wp-menu-image:before {
2
+ content: "\f303" !important;
3
+ }
4
+ .welcome-page-tile {
5
+ display: inline-block;
6
+ padding: 15px 0;
7
+ margin: 15px 0;
8
+ width: 30%;
9
+ text-align: left;
10
+ vertical-align: top;
11
+ box-sizing: border-box;
12
+ -moz-box-sizing: border-box;
13
+ }
14
+ .welcome-page-tile:first-child {
15
+ margin-left: 0;
16
+ }
17
+ .welcome-page-tile:last-child {
18
+ margin-right: 0;
19
+ }
20
+ .welcome-page-tile > h4 {
21
+ margin: 1.4em 0 .6em;
22
+ font-size: 1.2em;
23
+ }
24
+ .welcome-page-tile > p {
25
+ margin: 0;
26
+ }
27
+ .wprss-about-text {
28
+ color: #777;
29
+ line-height: 1.6em;
30
+ margin: 15px 0;
31
+ font-size: 1.2em;
32
+ }
33
+
34
+ #check-out-addons {
35
+ margin-top: 15px;
36
+ }
css/admin-styles.css CHANGED
@@ -304,19 +304,22 @@ body.post-type-wprss_feed.edit-php table.wp-list-table.posts thead th {
304
  }
305
  /* ERRORS */
306
  body.post-type-wprss_feed.edit-php table.wp-list-table.posts thead th#errors {
307
- width: 20px !important;
308
  }
309
  /* ID */
310
  body.post-type-wprss_feed.edit-php table.wp-list-table.posts thead th#id {
311
  width: 50px !important;
312
  }
313
  /* NEXT UPDATE */
314
- body.post-type-wprss_feed.edit-php table.wp-list-table.posts thead th#next-update {
315
- width: 120px !important;
 
 
 
316
  }
317
  /* STATE */
318
  body.post-type-wprss_feed.edit-php table.wp-list-table.posts thead th#state {
319
- width: 100px !important;
320
  }
321
  /* FEED COUNT */
322
  body.post-type-wprss_feed.edit-php table.wp-list-table.posts thead th#feed-count {
@@ -328,6 +331,23 @@ body.post-type-wprss_feed.edit-php table.wp-list-table.posts thead th#category {
328
  }
329
 
330
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
331
  /* Log textarea styles */
332
  #wprss-log-textarea {
333
  width: 800px;
@@ -342,13 +362,6 @@ body.post-type-wprss_feed.edit-php table.wp-list-table.posts thead th#category {
342
 
343
 
344
 
345
- .wprss-feed-error-symbol {
346
- font-size: 1.2em;
347
- vertical-align: middle;
348
- color: rgb(200,0,0);
349
- }
350
-
351
-
352
  /*--------------------------------------------------------------------------
353
  *
354
  * Add-Ons
304
  }
305
  /* ERRORS */
306
  body.post-type-wprss_feed.edit-php table.wp-list-table.posts thead th#errors {
307
+ width: 15px !important;
308
  }
309
  /* ID */
310
  body.post-type-wprss_feed.edit-php table.wp-list-table.posts thead th#id {
311
  width: 50px !important;
312
  }
313
  /* NEXT UPDATE */
314
+ body.post-type-wprss_feed.edit-php table.wp-list-table.posts thead th#updates {
315
+ width: 200px !important;
316
+ }
317
+ body.post-type-wprss_feed.edit-php table.wp-list-table.posts td.column-updates p {
318
+ margin-bottom: 0 !important;
319
  }
320
  /* STATE */
321
  body.post-type-wprss_feed.edit-php table.wp-list-table.posts thead th#state {
322
+ width: 80px !important;
323
  }
324
  /* FEED COUNT */
325
  body.post-type-wprss_feed.edit-php table.wp-list-table.posts thead th#feed-count {
331
  }
332
 
333
 
334
+ i.wprss-feed-error-symbol {
335
+ display: none;
336
+ font-size: 1.2em;
337
+ vertical-align: middle;
338
+ color: rgb(200,0,0);
339
+ }
340
+
341
+ i.wprss-updating-feed-icon {
342
+ margin-left: 8px;
343
+ display: none;
344
+ }
345
+
346
+ i.wprss-feed-error-symbol.wprss-show,
347
+ i.wprss-updating-feed-icon.wprss-show {
348
+ display: inline-block;
349
+ }
350
+
351
  /* Log textarea styles */
352
  #wprss-log-textarea {
353
  width: 800px;
362
 
363
 
364
 
 
 
 
 
 
 
 
365
  /*--------------------------------------------------------------------------
366
  *
367
  * Add-Ons
images/welcome-page/spinning-icon.gif ADDED
Binary file
images/welcome-page/updates.png ADDED
Binary file
images/welcome-page/view-items.png ADDED
Binary file
includes/admin-display.php CHANGED
@@ -28,7 +28,7 @@
28
  // Columns to add when feed is not trashed
29
  if ( !isset( $_GET['post_status'] ) || $_GET['post_status'] !== 'trash' ) {
30
  $columns['state'] = __( 'State', 'wprss' );
31
- $columns['next-update'] = __( 'Next Update', 'wprss' );
32
  $columns['feed-count'] = __( apply_filters( 'wprss_feed_items_count_column', 'Imported items' ), 'wprss' );
33
  }
34
 
@@ -47,10 +47,10 @@
47
  switch ( $column ) {
48
  case 'errors':
49
  $errors = get_post_meta( $post_id, 'wprss_error_last_import', true );
50
- if ( $errors === 'true') {
51
- $msg = "This feed source experienced an error during the last feed fetch or validation check. Re-check the feed source URL or check the Error Log in the Debugging page for more details.";
52
- echo '<i title="'.$msg.'" class="wprss-feed-error-symbol fa fa-warning fa-fixed-width"></i>';
53
- }
54
  break;
55
  case 'url':
56
  $url = get_post_meta( $post_id, 'wprss_url', true);
@@ -85,34 +85,55 @@
85
 
86
  break;
87
 
88
- case 'next-update':
89
- $interval = get_post_meta( $post_id, 'wprss_update_interval', TRUE );
90
- $timestamp = wprss_get_next_feed_source_update( $post_id );
91
- // If using the global interval, get the timestamp of the next glboal update
92
- if ( $interval === wprss_get_default_feed_source_update_interval() || $interval === '' ) {
93
- $timestamp = wp_next_scheduled( 'wprss_fetch_all_feeds_hook', array() );
 
 
 
 
 
94
  }
95
  ?>
96
 
97
  <p>
98
- <code>
 
99
  <?php if ( ! wprss_is_feed_source_active( $post_id ) ): ?>
100
  Paused
101
- <?php elseif ( $timestamp === FALSE ) : ?>
102
  None
103
  <?php else: ?>
104
- <?php echo human_time_diff( $timestamp, time() ); ?>
105
  <?php endif; ?>
106
  </code>
107
  </p>
108
 
109
- <?php
 
 
 
 
 
 
 
 
110
 
111
  break;
112
 
113
  case 'feed-count':
114
  $items = wprss_get_feed_items_for_source( $post_id );
115
- echo '<p>' . $items->post_count . '</p>';
 
 
 
 
 
 
 
116
  break;
117
  }
118
  }
@@ -292,12 +313,27 @@
292
  }
293
  elseif ( get_post_type() === 'wprss_feed' ) {
294
  unset( $actions[ 'view'] );
 
295
  if ( get_post_status( get_the_ID() ) !== 'trash' ) {
296
- $actions[ 'fetch' ] = '<a href="javascript:;" class="wprss_ajax_action" pid="'. get_the_ID() .'" purl="'.home_url().'/wp-admin/admin-ajax.php" title="'. esc_attr( __( 'Fetch Feeds', 'wprss' ) ) .'" >' . __( 'Fetch Feeds', 'wprss' ) . '</a>';
297
-
298
- $purge_feeds_row_action_text = apply_filters( 'wprss_purge_feeds_row_action_text ', 'Delete Feed Items' );
299
- $purge_feeds_row_action_title = apply_filters( 'wprss_purge_feeds_row_action_title ', 'Delete feed items imported by this feed source' );
 
 
 
 
 
 
 
 
 
 
 
 
300
  $actions['purge-posts'] = "<a href='".admin_url("edit.php?post_type=wprss_feed&purge-feed-items=" . get_the_ID() ) . "' title='" . __( $purge_feeds_row_action_title, 'wprss' ) . "' >" . __( $purge_feeds_row_action_text, 'wprss' ) . "</a>";
 
 
301
  }
302
  }
303
  return apply_filters( 'wprss_remove_row_actions', $actions );
@@ -318,6 +354,7 @@
318
  wp_schedule_single_event( time(), 'wprss_delete_feed_items_from_source_hook', array( $source_id ) );
319
  // Set a transient
320
  set_transient( 'wprss_delete_posts_by_source_notif', 'true', 30 );
 
321
  // Refresh the page without the GET parameter
322
  header( 'Location: ' . admin_url( 'edit.php?post_type=wprss_feed' ) );
323
  exit();
@@ -376,7 +413,7 @@
376
  * @since 3.5
377
  */
378
  function wprss_notify_about_deleting_source_feed_items() {
379
- $message = __( apply_filters( 'wprss_notify_about_deleting_source_feed_items_message', 'The feeds for this feed source are being deleted in the background.' ), 'wprss' );
380
  echo '<div class="updated"><p>' . $message . '</p></div>';
381
  }
382
 
@@ -442,4 +479,91 @@
442
  return __( 'Publish Feed', 'wprss' );
443
  }
444
  return apply_filters( 'wprss_change_publish_button_text', $translation );
445
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
28
  // Columns to add when feed is not trashed
29
  if ( !isset( $_GET['post_status'] ) || $_GET['post_status'] !== 'trash' ) {
30
  $columns['state'] = __( 'State', 'wprss' );
31
+ $columns['updates'] = __( 'Updates', 'wprss' );
32
  $columns['feed-count'] = __( apply_filters( 'wprss_feed_items_count_column', 'Imported items' ), 'wprss' );
33
  }
34
 
47
  switch ( $column ) {
48
  case 'errors':
49
  $errors = get_post_meta( $post_id, 'wprss_error_last_import', true );
50
+ $showClass = ( $errors === 'true' )? 'wprss-show' : '';
51
+
52
+ $msg = "This feed source experienced an error during the last feed fetch or validation check. Re-check the feed source URL or check the Error Log in the Debugging page for more details.";
53
+ echo "<i title=\"$msg\" class=\"fa fa-warning fa-fw wprss-feed-error-symbol $showClass\"></i>";
54
  break;
55
  case 'url':
56
  $url = get_post_meta( $post_id, 'wprss_url', true);
85
 
86
  break;
87
 
88
+ case 'updates':
89
+ // Get the update interval
90
+ $update_interval = get_post_meta( $post_id, 'wprss_update_interval', TRUE );
91
+ // Get the last updated and next update data
92
+ $last_update = get_post_meta( $post_id, 'wprss_last_update', TRUE );
93
+ $last_update_items = get_post_meta( $post_id, 'wprss_last_update_items', TRUE );
94
+ $next_update = wprss_get_next_feed_source_update( $post_id );
95
+
96
+ // If using the global interval, get the timestamp of the next global update
97
+ if ( $update_interval === wprss_get_default_feed_source_update_interval() || $update_interval === '' ) {
98
+ $next_update = wp_next_scheduled( 'wprss_fetch_all_feeds_hook', array() );
99
  }
100
  ?>
101
 
102
  <p>
103
+ Next update:
104
+ <code class="next-update">
105
  <?php if ( ! wprss_is_feed_source_active( $post_id ) ): ?>
106
  Paused
107
+ <?php elseif ( $next_update === FALSE ) : ?>
108
  None
109
  <?php else: ?>
110
+ <?php echo human_time_diff( $next_update, time() ); ?>
111
  <?php endif; ?>
112
  </code>
113
  </p>
114
 
115
+ <?php if ( $last_update !== '' ): ?>
116
+ <p class="last-update-container">
117
+ Last updated:
118
+ <code class="last-update"><?php echo human_time_diff( $last_update, time() ); ?> <?php _e('ago'); ?></code>
119
+ <?php if ( $last_update_items !== '' ): ?>
120
+ <span class="last-update-imported-container"><br/>Last update imported: <code class="last-update-imported"><?php echo $last_update_items; ?></code> items</span>
121
+ <?php endif; ?>
122
+ </p>
123
+ <?php endif;
124
 
125
  break;
126
 
127
  case 'feed-count':
128
  $items = wprss_get_feed_items_for_source( $post_id );
129
+ $seconds_for_next_update = wprss_get_next_feed_source_update( $post_id ) - time();
130
+ $showClass = ( ( $seconds_for_next_update < 10 && $seconds_for_next_update > 0 ) || wprss_is_feed_source_deleting( $post_id ) )? 'wprss-show' : '';
131
+
132
+ echo '<p>';
133
+ echo "<span class=\"items-imported\">{$items->post_count}</span>";
134
+ echo "<i class=\"fa fa-fw fa-refresh fa-spin wprss-updating-feed-icon $showClass\" title=\"Updating feed source\"></i>";
135
+ echo '</p>';
136
+
137
  break;
138
  }
139
  }
313
  }
314
  elseif ( get_post_type() === 'wprss_feed' ) {
315
  unset( $actions[ 'view'] );
316
+ unset( $actions[ 'inline hide-if-no-js'] );
317
  if ( get_post_status( get_the_ID() ) !== 'trash' ) {
318
+ $trash = $actions['trash'];
319
+ unset( $actions['trash'] );
320
+
321
+ $view_items_link = apply_filters(
322
+ 'wprss_view_feed_items_row_action_link',
323
+ admin_url( 'edit.php?post_type=wprss_feed_item&wprss_feed=' . get_the_ID() ),
324
+ get_the_ID()
325
+ );
326
+ $view_items_text = apply_filters( 'wprss_view_feed_items_row_action_text', 'View items' );
327
+ $actions['view-items'] = '<a href="' . $view_items_link . '">' . __( $view_items_text, 'wprss' ) . '</a>';
328
+
329
+ $fetch_items_row_action_text = apply_filters( 'wprss_fetch_items_row_action_text', 'Fetch items' );
330
+ $actions[ 'fetch' ] = '<a href="javascript:;" class="wprss_ajax_action" pid="'. get_the_ID() .'" purl="'.home_url().'/wp-admin/admin-ajax.php">' . __( $fetch_items_row_action_text, 'wprss' ) . '</a>';
331
+
332
+ $purge_feeds_row_action_text = apply_filters( 'wprss_purge_feeds_row_action_text', 'Delete items' );
333
+ $purge_feeds_row_action_title = apply_filters( 'wprss_purge_feeds_row_action_title', 'Delete feed items imported by this feed source' );
334
  $actions['purge-posts'] = "<a href='".admin_url("edit.php?post_type=wprss_feed&purge-feed-items=" . get_the_ID() ) . "' title='" . __( $purge_feeds_row_action_title, 'wprss' ) . "' >" . __( $purge_feeds_row_action_text, 'wprss' ) . "</a>";
335
+
336
+ $actions['trash'] = $trash;
337
  }
338
  }
339
  return apply_filters( 'wprss_remove_row_actions', $actions );
354
  wp_schedule_single_event( time(), 'wprss_delete_feed_items_from_source_hook', array( $source_id ) );
355
  // Set a transient
356
  set_transient( 'wprss_delete_posts_by_source_notif', 'true', 30 );
357
+ update_post_meta( $source_id, 'wprss_feed_is_deleting_items', 'true' );
358
  // Refresh the page without the GET parameter
359
  header( 'Location: ' . admin_url( 'edit.php?post_type=wprss_feed' ) );
360
  exit();
413
  * @since 3.5
414
  */
415
  function wprss_notify_about_deleting_source_feed_items() {
416
+ $message = __( apply_filters( 'wprss_notify_about_deleting_source_feed_items_message', 'The feed items for this feed source are being deleted in the background.' ), 'wprss' );
417
  echo '<div class="updated"><p>' . $message . '</p></div>';
418
  }
419
 
479
  return __( 'Publish Feed', 'wprss' );
480
  }
481
  return apply_filters( 'wprss_change_publish_button_text', $translation );
482
+ }
483
+
484
+
485
+
486
+ add_action( 'wp_before_admin_bar_render', 'wprss_modify_admin_bar' );
487
+ /**
488
+ * Removes the old "View Source" menu item from the admin bar and adds a new
489
+ * "View items" menu bar item, that opens a new tab, showing the items imported
490
+ * from that feed source.
491
+ *
492
+ * Only shown on the wprss_feed edit page.
493
+ *
494
+ * @since 4.2
495
+ */
496
+ function wprss_modify_admin_bar() {
497
+ global $wp_admin_bar;
498
+ if ( !is_admin() ) return;
499
+ $screen = get_current_screen();
500
+ // Check if we are in the wprss_feed edit page
501
+ if ( $screen->base == 'post' && $screen->post_type == 'wprss_feed' && !empty( $_GET['action'] ) && $_GET['action'] == 'edit' ) {
502
+ // Remove the old 'View Source' menu item
503
+ $wp_admin_bar->remove_node( 'view' );
504
+
505
+ // Prepare the view items link and text
506
+ $view_items_link = apply_filters(
507
+ 'wprss_view_feed_items_row_action_link',
508
+ admin_url( 'edit.php?post_type=wprss_feed_item&wprss_feed=' . get_the_ID() ),
509
+ get_the_ID()
510
+ );
511
+ $view_items_text = apply_filters( 'wprss_view_feed_items_row_action_text', 'View items' );
512
+
513
+ // Prepare the link target
514
+ $link_target = 'wprss-view-items-' . get_the_ID();
515
+
516
+ // Add the new menu item
517
+ $wp_admin_bar->add_node( array(
518
+ 'href' => $view_items_link,
519
+ 'id' => 'view',
520
+ 'title' => $view_items_text,
521
+ 'meta' => array(
522
+ 'target' => $link_target
523
+ )
524
+ ));
525
+ }
526
+ }
527
+
528
+
529
+
530
+
531
+ if ( is_admin() ){
532
+ add_filter('pre_get_posts', 'wprss_view_feed_items_query');
533
+ /**
534
+ * Alters the main query in the WordPress admin, when the wprss_feed GET parameter is set.
535
+ * The queried items are then filtered down to the items imported by the feed source with
536
+ * the ID given in the wprss_feed GET parameter.
537
+ *
538
+ * @since 4.2
539
+ */
540
+ function wprss_view_feed_items_query( $query ) {
541
+ if ( is_admin() && $query->is_main_query() && !empty($_GET['wprss_feed']) ) {
542
+ // Get the ID from the GET param
543
+ $id = $_GET['wprss_feed'];
544
+ // Get the existing meta query
545
+ $mq = $query->get('meta_query');
546
+ // If the meta query is not yet set
547
+ if ( !is_array($mq) ) {
548
+ // initialize it
549
+ $mq = array(
550
+ 'relation' => 'AND',
551
+ );
552
+ }
553
+ // Add the custom meta query
554
+ $mq[] = apply_filters(
555
+ 'wprss_view_feed_items_meta_query',
556
+ array(
557
+ 'key' => 'wprss_feed_id',
558
+ 'value' => $id,
559
+ 'compare' => '='
560
+ ),
561
+ $id
562
+ );
563
+ // Set the new meta query
564
+ $query->set('meta_query', $mq);
565
+ }
566
+ // Return the query
567
+ return $query;
568
+ }
569
+ }
includes/admin-heartbeat.php ADDED
@@ -0,0 +1,70 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ add_action( 'heartbeat_received', 'wprss_heartbeat_received', 10, 2 );
4
+ /**
5
+ *
6
+ */
7
+ function wprss_heartbeat_received( $response, $data ) {
8
+ if ( empty($data['wprss_heartbeat']) ) return $response;
9
+
10
+ // Get the wprss heartbeat data and extract the data
11
+ $wprss_heartbeat = $data['wprss_heartbeat'];
12
+ extract( $wprss_heartbeat );
13
+
14
+ // Perform the action specified by the heartbeat data
15
+ switch( $action ) {
16
+ /* FEED SOURCE UPDATING STATUS
17
+ * Used to determine whether or not to show the updating icon in the feed source table.
18
+ */
19
+ case 'feed_sources':
20
+ // Prepare array of IDs for feed sources currently updating
21
+ $feed_sources_data = array();
22
+ // Iterate all feed sources
23
+ foreach ( $params as $feed_id ) {
24
+ $feed_sources_data[$feed_id] = array();
25
+ $feed_source_data = &$feed_sources_data[$feed_id];
26
+
27
+ // Check if the feed source is updating
28
+ $seconds_for_next_update = wprss_get_next_feed_source_update( $feed_id ) - time();
29
+ $feed_source_data['updating'] = ( $seconds_for_next_update < 15 && $seconds_for_next_update > 0 ) || wprss_is_feed_source_deleting( $feed_id );
30
+
31
+ // Add the number of imported items
32
+ $items = wprss_get_feed_items_for_source( $feed_id );
33
+ $feed_source_data['items'] = $items->post_count;
34
+
35
+ // Add the next update time
36
+ $next_update = wprss_get_next_feed_source_update( $feed_id );
37
+ $update_interval = get_post_meta( $feed_id, 'wprss_update_interval', TRUE );
38
+ // If using the global interval, get the timestamp of the next global update
39
+ if ( $update_interval === wprss_get_default_feed_source_update_interval() || $update_interval === '' ) {
40
+ $next_update = wp_next_scheduled( 'wprss_fetch_all_feeds_hook', array() );
41
+ }
42
+ // Set the text appropriately
43
+ if ( ! wprss_is_feed_source_active( $feed_id ) ) {
44
+ $feed_source_data['next-update'] = "Paused";
45
+ }
46
+ elseif( $next_update === FALSE ) {
47
+ $feed_source_data['next-update'] = "None";
48
+ }
49
+ else {
50
+ $feed_source_data['next-update'] = human_time_diff( $next_update, time() );
51
+ }
52
+
53
+ // Add the last update information
54
+ $last_update = get_post_meta( $feed_id, 'wprss_last_update', TRUE );
55
+ $last_update_items = get_post_meta( $feed_id, 'wprss_last_update_items', TRUE );
56
+
57
+ $feed_source_data['last-update'] = ( $last_update === '' )? '' : human_time_diff( $last_update, time() );
58
+ $feed_source_data['last-update-imported'] = $last_update_items;
59
+
60
+ // Add any error info
61
+ $errors = get_post_meta( $feed_id, 'wprss_error_last_import', true );
62
+ $feed_source_data['errors'] = $errors === 'true';
63
+ }
64
+ // Send back all the IDs
65
+ $response['wprss_feed_sources_data'] = $feed_sources_data;
66
+ break;
67
+ }
68
+ // Return the response
69
+ return $response;
70
+ }
includes/admin-import-export.php CHANGED
@@ -111,6 +111,7 @@
111
  update_option( $key, $value );
112
  }
113
  add_action( 'admin_notices', 'wp_rss_aggregator_import_notice1' );
 
114
  }
115
  else {
116
  add_action( 'admin_notices', 'wp_rss_aggregator_import_notice2' );
@@ -135,6 +136,7 @@
135
  <h3><?php _e( 'Export Settings', 'wprss' ); ?></h3>
136
  <p><?php _e( 'Click the <strong>Export Settings</strong> button to generate a file containing all the settings used by WP RSS Aggregator', 'wprss' ); ?></p>
137
  <p><?php _e( 'After exporting, you can either use the backup file to restore your settings to this site or to another WordPress site.</p>', 'wprss' ); ?></p>
 
138
  <form method="post">
139
  <p class="submit">
140
  <?php wp_nonce_field( 'wprss-settings-export' ); ?>
@@ -145,6 +147,7 @@
145
  <h3><?php _e( 'Import Settings', 'wprss' ); ?></h3>
146
  <p><?php _e( 'Click the <strong>Choose file</strong> button and choose a backup file.', 'wprss' ); ?></p>
147
  <p><?php _e( 'Press the <strong>Import Settings</strong> button, and WordPress will do the rest for you.', 'wprss' ); ?></p>
 
148
  <form method='post' enctype='multipart/form-data'>
149
  <p class="submit">
150
  <?php wp_nonce_field( 'wprss-settings-import' ); ?>
111
  update_option( $key, $value );
112
  }
113
  add_action( 'admin_notices', 'wp_rss_aggregator_import_notice1' );
114
+ do_action( 'wprss_settings_imported' );
115
  }
116
  else {
117
  add_action( 'admin_notices', 'wp_rss_aggregator_import_notice2' );
136
  <h3><?php _e( 'Export Settings', 'wprss' ); ?></h3>
137
  <p><?php _e( 'Click the <strong>Export Settings</strong> button to generate a file containing all the settings used by WP RSS Aggregator', 'wprss' ); ?></p>
138
  <p><?php _e( 'After exporting, you can either use the backup file to restore your settings to this site or to another WordPress site.</p>', 'wprss' ); ?></p>
139
+ <?php do_action( 'wprss_export_section' ); ?>
140
  <form method="post">
141
  <p class="submit">
142
  <?php wp_nonce_field( 'wprss-settings-export' ); ?>
147
  <h3><?php _e( 'Import Settings', 'wprss' ); ?></h3>
148
  <p><?php _e( 'Click the <strong>Choose file</strong> button and choose a backup file.', 'wprss' ); ?></p>
149
  <p><?php _e( 'Press the <strong>Import Settings</strong> button, and WordPress will do the rest for you.', 'wprss' ); ?></p>
150
+ <?php do_action( 'wprss_import_section' ); ?>
151
  <form method='post' enctype='multipart/form-data'>
152
  <p class="submit">
153
  <?php wp_nonce_field( 'wprss-settings-import' ); ?>
includes/admin-metaboxes.php CHANGED
@@ -93,7 +93,7 @@
93
  'label' => __( 'URL', 'wprss' ),
94
  'desc' => __( 'Enter feed URL (including http://)', 'wprss' ),
95
  'id' => $prefix .'url',
96
- 'type' => 'text',
97
  'after' => 'wprss_validate_feed_link',
98
  );
99
 
@@ -152,9 +152,10 @@
152
 
153
  switch( $field['type'] ) {
154
 
155
- // text
 
156
  case 'text':
157
- echo '<input type="text" name="'.$field['id'].'" id="'.$field['id'].'" value="'. esc_attr( $meta ) .'" size="55" />
158
  <br><span class="description">'.$field['desc'].'</span>';
159
  break;
160
 
93
  'label' => __( 'URL', 'wprss' ),
94
  'desc' => __( 'Enter feed URL (including http://)', 'wprss' ),
95
  'id' => $prefix .'url',
96
+ 'type' => 'url',
97
  'after' => 'wprss_validate_feed_link',
98
  );
99
 
152
 
153
  switch( $field['type'] ) {
154
 
155
+ // text/url
156
+ case 'url':
157
  case 'text':
158
+ echo '<input type="'.$field['type'].'" name="'.$field['id'].'" id="'.$field['id'].'" value="'. esc_attr( $meta ) .'" size="55" />
159
  <br><span class="description">'.$field['desc'].'</span>';
160
  break;
161
 
includes/admin-welcome.php CHANGED
@@ -25,7 +25,7 @@
25
 
26
  <div class="wrap about-wrap">
27
  <h1><?php printf( __( 'Welcome to WP RSS Aggregator %s !', 'wprss' ), WPRSS_VERSION ); ?></h1>
28
- <div class="about-text">
29
  Thank you for upgrading to the latest version!
30
  </div>
31
  <!-- <div class="wprss-badge">Version</div>-->
@@ -34,7 +34,7 @@
34
  <h2 class="nav-tab-wrapper">
35
  <a class="nav-tab <?php if ( $tab === null ) echo 'nav-tab-active'; ?>"
36
  href="<?php echo esc_url( admin_url( add_query_arg( array( 'page' => 'wprss-welcome' ), 'index.php' ) ) ); ?>">
37
- Overview
38
  </a>
39
 
40
  <!-- SHOW ALL TABS -->
@@ -56,28 +56,67 @@
56
 
57
  // Default tab. ( when tab = null )
58
  default: ?>
59
-
60
- <p class="about-description">
61
- Check out our add-ons:</p>
62
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
63
  <ul>
64
- <li><strong><a href="http://www.wprssaggregator.com/extension/feed-post/" target="wprss_ftp">Feed to Post</a> <!--<span style="color: green;">*New*</span></strong>--></li>
65
- <li><strong><a href="http://www.wprssaggregator.com/extension/excerpts-thumbnails/" target="wprss_et">Excerpts &amp; Thumbnails</a></strong></li>
66
- <li><strong><a href="http://www.wprssaggregator.com/extension/categories/" target="wprss_cat">Categories</a></strong></li>
67
- <li><strong><a href="http://www.wprssaggregator.com/extension/keyword-filtering/" target="wprss_kf">Keyword Filtering</a></strong></li>
 
68
  </ul>
69
- </p>
70
- <p>Need functionality not already available in core or the add-ons? You <a href="http://www.wprssaggregator.com/feature-requests/">suggest new features</a>!</p>
71
- <p>More information about add-ons can be found on our website <a href="http://www.wprssaggregator.com">www.wprssaggregator.com</a></p>
72
-
73
-
74
-
75
- <h3>Changelog for v<?php echo WPRSS_VERSION; ?></h3>
76
- <ul>
77
- <li><strong>Enhanced:</strong> The Feed Sources table now indicates which feed sources encountered errors during their last import.</li>
78
- <li><strong>Fixed bug:</strong> Feed titles were not being decoded for HTML entities.</li>
79
- </ul>
80
 
 
81
 
82
  <?php
83
  break;
25
 
26
  <div class="wrap about-wrap">
27
  <h1><?php printf( __( 'Welcome to WP RSS Aggregator %s !', 'wprss' ), WPRSS_VERSION ); ?></h1>
28
+ <div class="wprss-about-text">
29
  Thank you for upgrading to the latest version!
30
  </div>
31
  <!-- <div class="wprss-badge">Version</div>-->
34
  <h2 class="nav-tab-wrapper">
35
  <a class="nav-tab <?php if ( $tab === null ) echo 'nav-tab-active'; ?>"
36
  href="<?php echo esc_url( admin_url( add_query_arg( array( 'page' => 'wprss-welcome' ), 'index.php' ) ) ); ?>">
37
+ What's New?
38
  </a>
39
 
40
  <!-- SHOW ALL TABS -->
56
 
57
  // Default tab. ( when tab = null )
58
  default: ?>
59
+ <div class="changelog">
60
+
61
+ <h3>Feed Sources Page Visual Updated!</h3>
62
+
63
+ <div class="feature-section col three-col">
64
+
65
+ <div class="col-1">
66
+ <img src="<?php echo WPRSS_IMG;?>welcome-page/spinning-icon.gif" />
67
+ <h4>Live Updates</h4>
68
+ <p>
69
+ Your feed sources page now shows you new information as soon as it's available.
70
+ With the new live updates, you no longer have to refresh the page to check for updates and changes.
71
+ </p>
72
+ </div>
73
+
74
+ <div class="col-2">
75
+ <img src="<?php echo WPRSS_IMG;?>welcome-page/updates.png" />
76
+ <h4>More Information</h4>
77
+ <p>
78
+ We've renamed the <strong>Next Update</strong> column to <strong>Updates</strong>,
79
+ and added to it <strong>two</strong> new fields, showing you the last time
80
+ your feed source was updated, and how many items it imported.
81
+ </p>
82
+ </div>
83
+
84
+ <div class="col-3 last-feature">
85
+ <img src="<?php echo WPRSS_IMG;?>welcome-page/view-items.png" />
86
+ <h4>View Items</h4>
87
+ <p>
88
+ The new <strong>View items</strong> row action link lets you view the feed items for that feed source
89
+ alone, separate from the rest of your imported feed items. We've also cleaned up the rest of the row actions.
90
+ </p>
91
+ </div>
92
+ </div>
93
+
94
+ <hr/>
95
+
96
+ <h3>Check out our add-ons:</h3>
97
+
98
+ <ul>
99
+ <li><strong><a href="http://www.wprssaggregator.com/extension/feed-post/" target="wprss_ftp">Feed to Post</a></strong></li>
100
+ <li><strong><a href="http://www.wprssaggregator.com/extension/excerpts-thumbnails/" target="wprss_et">Excerpts &amp; Thumbnails</a></strong></li>
101
+ <li><strong><a href="http://www.wprssaggregator.com/extension/categories/" target="wprss_cat">Categories</a></strong></li>
102
+ <li><strong><a href="http://www.wprssaggregator.com/extension/keyword-filtering/" target="wprss_kf">Keyword Filtering</a></strong></li>
103
+ </ul>
104
+ </p>
105
+ <p>More information about add-ons can be found on our website <a href="http://www.wprssaggregator.com">www.wprssaggregator.com</a></p>
106
+
107
+ <hr/>
108
+
109
+ <h3>Changelog for v<?php echo WPRSS_VERSION; ?></h3>
110
  <ul>
111
+ <li><strong>New Feature:</strong> Can now view each feed source's imported feed items separate from other feed sources' feed items.</li>
112
+ <li><strong>Enhanced:</strong> Major visual update to the Feed Sources page with new live updates.</li>
113
+ <li><strong>Enhanced:</strong> The custom feed now includes the feed source.</li>
114
+ <li><strong>Fixed bug:</strong> Google News feeds were importing duplicate items on every update.</li>
115
+ <li><strong>Fixed bug:</strong> Multiple minor bug fixes with old filters.</li>
116
  </ul>
117
+ <p>Need functionality not already available in core or the add-ons? You can <a href="http://www.wprssaggregator.com/feature-requests/">suggest new features</a>!</p>
 
 
 
 
 
 
 
 
 
 
118
 
119
+ </div>
120
 
121
  <?php
122
  break;
includes/custom-feed.php CHANGED
@@ -117,15 +117,16 @@
117
  <?php
118
  // Start the Loop
119
  while ( have_posts() ) : the_post();
 
120
  $permalink = get_post_meta( get_the_ID(), 'wprss_item_permalink', true );
121
  ?>
122
  <entry>
123
  <title><![CDATA[<?php the_title_rss(); ?>]]></title>
124
  <link href="<?php echo $permalink; ?>" />
125
  <?php // Enable below to link to post on our site rather than original source ?>
126
- <!--<link href="<?php the_permalink_rss(); ?>" />-->
127
  <published><?php echo get_post_time( 'Y-m-d\TH:i:s\Z' ); ?></published>
128
  <content type="html"><![CDATA[<?php the_content(); ?>]]></content>
 
129
  <?php do_action( 'wprss_custom_feed_entry', get_the_ID() ); ?>
130
  </entry>
131
  <?php
117
  <?php
118
  // Start the Loop
119
  while ( have_posts() ) : the_post();
120
+ $source = get_post_meta( get_the_ID(), 'wprss_feed_id', TRUE );
121
  $permalink = get_post_meta( get_the_ID(), 'wprss_item_permalink', true );
122
  ?>
123
  <entry>
124
  <title><![CDATA[<?php the_title_rss(); ?>]]></title>
125
  <link href="<?php echo $permalink; ?>" />
126
  <?php // Enable below to link to post on our site rather than original source ?>
 
127
  <published><?php echo get_post_time( 'Y-m-d\TH:i:s\Z' ); ?></published>
128
  <content type="html"><![CDATA[<?php the_content(); ?>]]></content>
129
+ <source url="<?php echo get_post_meta( $source, 'wprss_url', TRUE ); ?>"><?php echo get_the_title( $source ); ?></source>
130
  <?php do_action( 'wprss_custom_feed_entry', get_the_ID() ); ?>
131
  </entry>
132
  <?php
includes/feed-importing.php CHANGED
@@ -56,8 +56,8 @@
56
 
57
  // Generate a list of items fetched, that are not already in the DB
58
  $new_items = array();
59
- foreach( $items as $item ) {
60
- $permalink = $item->get_permalink();
61
  if ( !in_array( trim($permalink), $existing_permalinks ) ) {
62
  $new_items[] = $item;
63
  }
@@ -88,6 +88,8 @@
88
  $items_to_insert = $items;
89
  }
90
 
 
 
91
  // Insert the items into the db
92
  if ( !empty( $items_to_insert ) ) {
93
  wprss_items_insert_post( $items_to_insert, $feed_ID );
@@ -201,6 +203,60 @@
201
 
202
 
203
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
204
 
205
  /**
206
  * Converts YouTube, Vimeo and DailyMotion video urls
@@ -262,10 +318,13 @@
262
  // Gather the permalinks of existing feed item's related to this feed source
263
  $existing_permalinks = get_existing_permalinks( $feed_ID );
264
 
 
 
 
265
  foreach ( $items as $item ) {
266
 
267
- // Convert the url if it is a video url and the conversion is enabled in the settings.
268
- $permalink = wprss_convert_video_permalink( $item->get_permalink() );
269
 
270
  // Save the enclosure URL
271
  $enclosure_url = '';
@@ -323,6 +382,9 @@
323
  }
324
  }
325
 
 
 
 
326
  // Create and insert post meta into the DB
327
  wprss_items_insert_post_meta( $inserted_ID, $item, $feed_ID, $permalink, $enclosure_url );
328
 
@@ -336,6 +398,8 @@
336
  }
337
  }
338
  }
 
 
339
  }
340
 
341
 
56
 
57
  // Generate a list of items fetched, that are not already in the DB
58
  $new_items = array();
59
+ foreach( $items_to_insert as $item ) {
60
+ $permalink = wprss_normalize_permalink( $item->get_permalink() );
61
  if ( !in_array( trim($permalink), $existing_permalinks ) ) {
62
  $new_items[] = $item;
63
  }
88
  $items_to_insert = $items;
89
  }
90
 
91
+ update_post_meta( $feed_ID, 'wprss_last_update', time() );
92
+
93
  // Insert the items into the db
94
  if ( !empty( $items_to_insert ) ) {
95
  wprss_items_insert_post( $items_to_insert, $feed_ID );
203
 
204
 
205
 
206
+ /**
207
+ * Normalizes the given permalink.
208
+ *
209
+ * @param $permalink The permalink to normalize
210
+ * @return string The normalized permalink
211
+ */
212
+ function wprss_normalize_permalink( $permalink ) {
213
+ // Apply normalization functions on the permalink
214
+ $permalink = trim( $permalink );
215
+ $permalink = wprss_google_news_url_fix( $permalink );
216
+ $permalink = wprss_convert_video_permalink( $permalink );
217
+ // Return the normalized permalink
218
+ return $permalink;
219
+ }
220
+
221
+
222
+
223
+ /**
224
+ * Checks if the permalink is a Google News permalink, and if it is,
225
+ * returns the normalized URL of the proper feed item article.
226
+ *
227
+ * Fixes the issue with equivalent Google News items having different URLs,
228
+ * that contain randomly generated GET parameters. Example:
229
+ *
230
+ * http://news.google.com/news/url?sa=t&fd=R&ct2=us&ei=V3e9U6izMMnm1QaB1YHoDA&url=http://abcd...
231
+ * http://news.google.com/news/url?sa=t&fd=R&ct2=us&ei=One9U-HQLsTp1Aal-oDQBQ&url=http://abcd...
232
+ *
233
+ * @param $permalink The permalink URL to check and/or normalize.
234
+ * @return string The normalized URL of the original article, as indicated by the `url`
235
+ * parameter in the URL query string.
236
+ */
237
+ function wprss_google_news_url_fix( $permalink ) {
238
+ // Parse the url
239
+ $parsed = parse_url( urldecode( html_entity_decode( $permalink ) ) );
240
+
241
+ // If parsing failed, return the permalink
242
+ if ( $parsed === FALSE || $parsed === NULL ) return $permalink;
243
+
244
+ // Determine if it's a google news item
245
+ if ( strtolower( $parsed['host'] ) !== 'news.google.com' ) return $permalink;
246
+ // Check if the url GET query string is present
247
+ if ( !isset( $parsed['query'] ) ) return $permalink;
248
+
249
+ // Parse the query string
250
+ $query = array();
251
+ parse_str( $parsed['query'], $query );
252
+
253
+ // Check if the url GET parameter is present in the query string
254
+ if ( !is_array($query) || !isset( $query['url'] ) ) return $permalink;
255
+
256
+ return urldecode( $query['url'] );
257
+ }
258
+
259
+
260
 
261
  /**
262
  * Converts YouTube, Vimeo and DailyMotion video urls
318
  // Gather the permalinks of existing feed item's related to this feed source
319
  $existing_permalinks = get_existing_permalinks( $feed_ID );
320
 
321
+ // Count of items inserted
322
+ $items_inserted = 0;
323
+
324
  foreach ( $items as $item ) {
325
 
326
+ // Normalize the URL
327
+ $permalink = wprss_normalize_permalink( $item->get_permalink() );
328
 
329
  // Save the enclosure URL
330
  $enclosure_url = '';
382
  }
383
  }
384
 
385
+ // Increment the inserted items counter
386
+ $items_inserted++;
387
+
388
  // Create and insert post meta into the DB
389
  wprss_items_insert_post_meta( $inserted_ID, $item, $feed_ID, $permalink, $enclosure_url );
390
 
398
  }
399
  }
400
  }
401
+
402
+ update_post_meta( $feed_ID, 'wprss_last_update_items', $items_inserted );
403
  }
404
 
405
 
includes/feed-processing.php CHANGED
@@ -328,6 +328,32 @@
328
  }
329
 
330
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
331
  /**
332
  * Returns the given parameter as a string. Used in wprss_truncate_posts()
333
  *
328
  }
329
 
330
 
331
+
332
+ /**
333
+ * Returns whether or not the feed source is deleting its feeed items.
334
+ *
335
+ * @param (string|int) The id of the feed source
336
+ * @return (bool) TRUE if the feed source is currently deleting its items, FALSE otherwise.
337
+ *
338
+ */
339
+ function wprss_is_feed_source_deleting( $id ) {
340
+ $is_deleting_meta = get_post_meta( $id, 'wprss_feed_is_deleting_items', TRUE );
341
+
342
+ if ( $is_deleting_meta === '' ) {
343
+ return FALSE;
344
+ }
345
+
346
+ $items = wprss_get_feed_items_for_source( $id );
347
+ if ( $items->post_count == 0 ) {
348
+ delete_post_meta( $id, 'wprss_feed_is_deleting_items' );
349
+ return FALSE;
350
+ }
351
+
352
+ return TRUE;
353
+ }
354
+
355
+
356
+
357
  /**
358
  * Returns the given parameter as a string. Used in wprss_truncate_posts()
359
  *
includes/scripts.php CHANGED
@@ -20,6 +20,10 @@
20
  wp_enqueue_style( 'wprss-styles', WPRSS_CSS . 'admin-styles.css' );
21
  }
22
 
 
 
 
 
23
  $screen = get_current_screen();
24
 
25
  wp_enqueue_script( 'wprss-admin-addon-ajax', WPRSS_JS .'admin-addon-ajax.js', array('jquery') );
@@ -35,6 +39,9 @@
35
  wp_enqueue_script( 'wprss-admin-custom', WPRSS_JS .'admin-custom.js', array('jquery','jquery-ui-datepicker','jquery-ui-slider') );
36
  wp_enqueue_script( 'jquery-ui-timepicker-addon', WPRSS_JS .'jquery-ui-timepicker-addon.js', array('jquery','jquery-ui-datepicker') );
37
  wp_enqueue_style( 'jquery-style', 'http://ajax.googleapis.com/ajax/libs/jqueryui/1.10.4/themes/smoothness/jquery-ui.css' );
 
 
 
38
  if ( 'post' === $screen->base && 'wprss_feed' === $screen->post_type ) {
39
  // Change text on post screen from 'Enter title here' to 'Enter feed name here'
40
  add_filter( 'enter_title_here', 'wprss_change_title_text' );
@@ -45,10 +52,6 @@
45
  wp_enqueue_style( 'wprss-admin-styles', WPRSS_CSS . 'admin-styles.css' );
46
  }
47
 
48
- if ( version_compare( get_bloginfo( 'version' ), '3.8', '>=' ) ) {
49
- wp_enqueue_style( 'wprss-admin-styles', WPRSS_CSS . 'admin-3.8.css' );
50
- }
51
-
52
  do_action( 'wprss_admin_scripts_styles' );
53
  } // end wprss_admin_scripts_styles
54
 
20
  wp_enqueue_style( 'wprss-styles', WPRSS_CSS . 'admin-styles.css' );
21
  }
22
 
23
+ if ( is_admin() ) {
24
+ wp_enqueue_style( 'wprss-admin-3.8-styles', WPRSS_CSS . 'admin-3.8.css' );
25
+ }
26
+
27
  $screen = get_current_screen();
28
 
29
  wp_enqueue_script( 'wprss-admin-addon-ajax', WPRSS_JS .'admin-addon-ajax.js', array('jquery') );
39
  wp_enqueue_script( 'wprss-admin-custom', WPRSS_JS .'admin-custom.js', array('jquery','jquery-ui-datepicker','jquery-ui-slider') );
40
  wp_enqueue_script( 'jquery-ui-timepicker-addon', WPRSS_JS .'jquery-ui-timepicker-addon.js', array('jquery','jquery-ui-datepicker') );
41
  wp_enqueue_style( 'jquery-style', 'http://ajax.googleapis.com/ajax/libs/jqueryui/1.10.4/themes/smoothness/jquery-ui.css' );
42
+ // Load Heartbeat script and set dependancy for Heartbeat to ensure Heartbeat is loaded
43
+ wp_enqueue_script( 'wprss-feed-source-table-heartbeat', WPRSS_JS .'heartbeat.js', array('heartbeat') );
44
+ // Heartbeat script
45
  if ( 'post' === $screen->base && 'wprss_feed' === $screen->post_type ) {
46
  // Change text on post screen from 'Enter title here' to 'Enter feed name here'
47
  add_filter( 'enter_title_here', 'wprss_change_title_text' );
52
  wp_enqueue_style( 'wprss-admin-styles', WPRSS_CSS . 'admin-styles.css' );
53
  }
54
 
 
 
 
 
55
  do_action( 'wprss_admin_scripts_styles' );
56
  } // end wprss_admin_scripts_styles
57
 
js/admin-custom.js CHANGED
@@ -14,7 +14,8 @@ function fetch_items_row_action_callback(){
14
  },
15
  success: function( response, status, jqXHR ){
16
  console.log( jqXHR );
17
- link.text( 'Feed items are being imported!' );
 
18
  setTimeout( function(){
19
  link.text( original_text ).click( fetch_items_row_action_callback );
20
  }, 3500 );
14
  },
15
  success: function( response, status, jqXHR ){
16
  console.log( jqXHR );
17
+ link.text( 'Items are importing!' );
18
+ jQuery('table.wp-list-table tbody tr.post-' + id + ' td.column-feed-count i.fa-spin').addClass('wprss-show');
19
  setTimeout( function(){
20
  link.text( original_text ).click( fetch_items_row_action_callback );
21
  }, 3500 );
js/heartbeat.js ADDED
@@ -0,0 +1,110 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ (function($){
2
+
3
+
4
+ /**
5
+ * Returns the IDs of the feed sources shown on the current page
6
+ */
7
+ var getFeedSourceIDS = function() {
8
+ var ids = [];
9
+ $('table.wp-list-table tbody tr').each( function(){
10
+ ids.push( $(this).attr('id').split('-')[1] );
11
+ });
12
+ return ids;
13
+ }
14
+
15
+
16
+ /**
17
+ * Attach the heartbeat data
18
+ */
19
+ var checkFeedSourcesUpdatingStatus = function(e, data) {
20
+ var ids = getFeedSourceIDS();
21
+ // If no feed sources found, do nothing. Performance boost
22
+ if ( ids.length === 0 ) return;
23
+ // Send the data
24
+ data['wprss_heartbeat'] = {
25
+ action: 'feed_sources',
26
+ params: ids
27
+ };
28
+ };
29
+
30
+
31
+
32
+ /**
33
+ * Updates the feed source table using the heartbeat data.
34
+ */
35
+ var updateFeedSourceTable = function(e, data) {
36
+ if ( !data['wprss_feed_sources_data'] ) return;
37
+
38
+ // Get the feed sources data
39
+ var feed_sources = data['wprss_feed_sources_data'];
40
+ // Iterate all the received feed source data
41
+ for( id in feed_sources ) {
42
+ var feed_source = feed_sources[id];
43
+ var row = $('table.wp-list-table tbody tr.post-' + id);
44
+ var updatesCol = row.find('td.column-updates');
45
+ var itemsCol = row.find('td.column-feed-count');
46
+
47
+ // Update the next update time
48
+ updatesCol.find('code.next-update').text( feed_source['next-update'] );
49
+
50
+ // Update the last update time
51
+ if ( feed_source['last-update'] == '' )
52
+ updatesCol.find('p.last-update-container').hide();
53
+ else
54
+ updatesCol.find('code.last-update').text( feed_source['last-update'] + " ago" );
55
+
56
+ // Update the last update items count
57
+ if ( feed_source['last-update-imported'] == '' )
58
+ updatesCol.find('span.last-update-imported-container').hide();
59
+ else
60
+ updatesCol.find('code.last-update-imported').text( feed_source['last-update-imported'] );
61
+
62
+ // Update the items imported count and the icon
63
+ var icon = itemsCol.find('i.fa-spin');
64
+ var itemCount = itemsCol.find('span.items-imported');
65
+ // Check if the icon is shown, and the current heartbeat data indicates no updating
66
+ var stopUpdating = icon.hasClass('wprss-show') && !feed_source['updating'];
67
+ // Check if the item count changed
68
+ var itemCountChanged = feed_source['items'] != itemCount.text();
69
+
70
+ // Check if we are waiting for the item count to update
71
+ var waiting = itemsCol.hasClass('waiting');
72
+
73
+ // Check if the updating stopped, but the item count remained the same.
74
+ // If we were previously waiting, prevent this which causes the script to "wait" again (forever)
75
+ if ( stopUpdating && !itemCountChanged && !waiting ) {
76
+ // If so, then we must wait for next heartbeat pulse to get the item count and remove the spinning icon
77
+ itemsCol.addClass('waiting');
78
+ }
79
+ // Otherwise,
80
+ else {
81
+ // Update the count and the icon appropriately
82
+ itemCount.text( feed_source['items'] );
83
+ icon.toggleClass( 'wprss-show', feed_source['updating'] );
84
+ }
85
+
86
+ // If we were waiting, we are not anymore. Remove the waiting class
87
+ if ( waiting ) {
88
+ itemsCol.removeClass('waiting');
89
+ }
90
+
91
+
92
+ // Update the error icon
93
+ var errorsCol = row.find('td.column-errors');
94
+ var errorIcon = errorsCol.find('i.fa');
95
+ errorIcon.toggleClass( 'wprss-show', feed_source['errors'] );
96
+ }
97
+
98
+ };
99
+
100
+
101
+
102
+ // Hook into the heartbeat-send
103
+ $(document).on('heartbeat-send', checkFeedSourcesUpdatingStatus);
104
+
105
+ // Listen for heartbeat events
106
+ $(document).on('heartbeat-tick', updateFeedSourceTable);
107
+
108
+
109
+
110
+ })(jQuery);
readme.txt CHANGED
@@ -5,7 +5,7 @@ Plugin URI: http://www.wprssaggregator.com
5
  Tags: rss, feeds, aggregation, rss to post, autoblog aggregator, rss import, feed aggregator, rss aggregator, multiple rss feeds, multi rss feeds, rss multi importer, feed import, feed import, multiple feed import, feed aggregation, rss feader, feed reader, feed to post, multiple feeds, multi feed importer, multi feed import, multi import, autoblogging, autoblogger
6
  Requires at least: 3.3
7
  Tested up to: 3.9.1
8
- Stable tag: 4.1.6
9
  License: GPLv2 or later
10
  Imports and aggregates multiple RSS Feeds using SimplePie. Outputs feeds sorted by date (latest first).
11
 
@@ -163,6 +163,13 @@ The full documentation section can be found on the [WP RSS Aggregator website](w
163
 
164
  == Changelog ==
165
 
 
 
 
 
 
 
 
166
  = 4.1.6 (2014-06-28) =
167
  * Fixed bug: Results returned by wprss_get_feed_items_for_source() will no longer be affected by filters.
168
  * Fixed bug: Charset issue in titles
5
  Tags: rss, feeds, aggregation, rss to post, autoblog aggregator, rss import, feed aggregator, rss aggregator, multiple rss feeds, multi rss feeds, rss multi importer, feed import, feed import, multiple feed import, feed aggregation, rss feader, feed reader, feed to post, multiple feeds, multi feed importer, multi feed import, multi import, autoblogging, autoblogger
6
  Requires at least: 3.3
7
  Tested up to: 3.9.1
8
+ Stable tag: 4.2
9
  License: GPLv2 or later
10
  Imports and aggregates multiple RSS Feeds using SimplePie. Outputs feeds sorted by date (latest first).
11
 
163
 
164
  == Changelog ==
165
 
166
+ = 4.2 (2014-07-17) =
167
+ * New Feature: Can now view each feed source's imported feed items separate from other feed sources' feed items.
168
+ * Enhanced: Major visual update to the Feed Sources page with new live updates.
169
+ * Enhanced: The custom feed now includes the feed source.
170
+ * Fixed bug: Google News feeds were importing duplicate items on every update.
171
+ * Fixed bug: Multiple minor bug fixes with old filters.
172
+
173
  = 4.1.6 (2014-06-28) =
174
  * Fixed bug: Results returned by wprss_get_feed_items_for_source() will no longer be affected by filters.
175
  * Fixed bug: Charset issue in titles
wp-rss-aggregator.php CHANGED
@@ -3,7 +3,7 @@
3
  Plugin Name: WP RSS Aggregator
4
  Plugin URI: http://www.wprssaggregator.com
5
  Description: Imports and aggregates multiple RSS Feeds using SimplePie
6
- Version: 4.1.6
7
  Author: Jean Galea
8
  Author URI: http://www.wprssaggregator.com
9
  License: GPLv2
@@ -29,7 +29,7 @@
29
 
30
  /**
31
  * @package WPRSSAggregator
32
- * @version 4.1.6
33
  * @since 1.0
34
  * @author Jean Galea <info@jeangalea.com>
35
  * @copyright Copyright (c) 2012-2014, Jean Galea
@@ -43,7 +43,7 @@
43
 
44
  // Set the version number of the plugin.
45
  if( !defined( 'WPRSS_VERSION' ) )
46
- define( 'WPRSS_VERSION', '4.1.6', true );
47
 
48
  // Set the database version number of the plugin.
49
  if( !defined( 'WPRSS_DB_VERSION' ) )
@@ -176,6 +176,9 @@
176
  /* Load the admin editor file */
177
  require_once ( WPRSS_INC . 'admin-editor.php' );
178
 
 
 
 
179
  // Load the statistics functions file
180
  require_once ( WPRSS_INC . 'admin-statistics.php' );
181
 
3
  Plugin Name: WP RSS Aggregator
4
  Plugin URI: http://www.wprssaggregator.com
5
  Description: Imports and aggregates multiple RSS Feeds using SimplePie
6
+ Version: 4.2
7
  Author: Jean Galea
8
  Author URI: http://www.wprssaggregator.com
9
  License: GPLv2
29
 
30
  /**
31
  * @package WPRSSAggregator
32
+ * @version 4.2
33
  * @since 1.0
34
  * @author Jean Galea <info@jeangalea.com>
35
  * @copyright Copyright (c) 2012-2014, Jean Galea
43
 
44
  // Set the version number of the plugin.
45
  if( !defined( 'WPRSS_VERSION' ) )
46
+ define( 'WPRSS_VERSION', '4.2', true );
47
 
48
  // Set the database version number of the plugin.
49
  if( !defined( 'WPRSS_DB_VERSION' ) )
176
  /* Load the admin editor file */
177
  require_once ( WPRSS_INC . 'admin-editor.php' );
178
 
179
+ /* Load the admin heartbeat functions */
180
+ require_once ( WPRSS_INC . 'admin-heartbeat.php' );
181
+
182
  // Load the statistics functions file
183
  require_once ( WPRSS_INC . 'admin-statistics.php' );
184