WP RSS Aggregator - Version 4.17.2

Version Description

(2019-12-19) = Added - The error handler now includes the file and line where the error occurred.

Changed - The obsolete "Link Source" option is now only shown when the Excerpts & Thumbnails add-on is active.

Fixed - The new "feeds" shortcode parameter only showed feed items for the first 10 feed sources.

Download this release

Release Info

Developer Mekku
Plugin Icon 128x128 WP RSS Aggregator
Version 4.17.2
Comparing to
See all releases

Code changes from version 4.17.1 to 4.17.2

CHANGELOG.md CHANGED
@@ -4,6 +4,16 @@ All notable changes to this project will be documented in this file.
4
  The format is based on [Keep a Changelog](http://keepachangelog.com/)
5
  and this project adheres to [Semantic Versioning](http://semver.org/).
6
 
 
 
 
 
 
 
 
 
 
 
7
  ## [4.17.1] - 2019-12-12
8
  ### Fixed
9
  * The new slug option was appearing on the edit pages for posts of all types.
4
  The format is based on [Keep a Changelog](http://keepachangelog.com/)
5
  and this project adheres to [Semantic Versioning](http://semver.org/).
6
 
7
+ ## [4.17.2] - 2019-12-19
8
+ ### Added
9
+ * The error handler now includes the file and line where the error occurred.
10
+
11
+ ### Changed
12
+ * The obsolete "Link Source" option is now only shown when the Excerpts & Thumbnails add-on is active.
13
+
14
+ ### Fixed
15
+ * The new "feeds" shortcode parameter only showed feed items for the first 10 feed sources.
16
+
17
  ## [4.17.1] - 2019-12-12
18
  ### Fixed
19
  * The new slug option was appearing on the edit pages for posts of all types.
README.md DELETED
@@ -1,24 +0,0 @@
1
- ![](https://repository-images.githubusercontent.com/15269888/73ca9400-669f-11e9-9e18-5662f7b5bd68)
2
-
3
- ## Requirements
4
-
5
- **Recommended**
6
- * PHP 7+
7
- * PHP `curl` extension
8
- * PHP `simplexml` extension
9
- * PHP `mbstring` extension
10
- * PHP `gd` extension
11
- * WordPress 5.0+
12
-
13
- **Minimum**
14
- * PHP 5.4+
15
- * PHP `curl` extension
16
- * PHP `simplexml` extension
17
- * WordPress 4.8+
18
-
19
- ## Links
20
-
21
- * [Website](https://wprssaggregator.com)
22
- * [Premium Addons](https://wprssaggregator.com/pricing)
23
- * [Knowledge Base](https://kb.wprssaggregator.com)
24
- * [WordPress.org Page](https://wordpress.org/plugins/wp-rss-aggregator)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/admin-metaboxes.php CHANGED
@@ -115,11 +115,13 @@
115
  'type' => 'checkbox'
116
  );
117
 
118
- $wprss_meta_fields[ 'source_link' ] = array(
119
- 'label' => __( 'Link source', WPRSS_TEXT_DOMAIN ),
120
- 'id' => $prefix . 'source_link',
121
- 'type' => 'boolean_fallback'
122
- );
 
 
123
 
124
  $wprss_meta_fields[ 'import_source' ] = array(
125
  'label' => __( 'Use source info', WPRSS_TEXT_DOMAIN ),
@@ -536,6 +538,7 @@
536
  $activate = get_post_meta( $post->ID, 'wprss_activate_feed', TRUE );
537
  $pause = get_post_meta( $post->ID, 'wprss_pause_feed', TRUE );
538
  $update_interval = get_post_meta( $post->ID, 'wprss_update_interval', TRUE );
 
539
 
540
  $age_limit = get_post_meta( $post->ID, 'wprss_age_limit', true );
541
  $age_unit = get_post_meta( $post->ID, 'wprss_age_unit', true );
@@ -634,6 +637,9 @@
634
  <option value="<?php echo $value; ?>" <?php selected( $update_interval, $value ); ?> ><?php echo $text; ?></option>
635
  <?php endforeach; ?>
636
  </select>
 
 
 
637
  </div>
638
  </div>
639
 
115
  'type' => 'checkbox'
116
  );
117
 
118
+ if (wprss_is_et_active()) {
119
+ $wprss_meta_fields[ 'source_link' ] = array(
120
+ 'label' => __( 'Link source', WPRSS_TEXT_DOMAIN ),
121
+ 'id' => $prefix . 'source_link',
122
+ 'type' => 'boolean_fallback'
123
+ );
124
+ }
125
 
126
  $wprss_meta_fields[ 'import_source' ] = array(
127
  'label' => __( 'Use source info', WPRSS_TEXT_DOMAIN ),
538
  $activate = get_post_meta( $post->ID, 'wprss_activate_feed', TRUE );
539
  $pause = get_post_meta( $post->ID, 'wprss_pause_feed', TRUE );
540
  $update_interval = get_post_meta( $post->ID, 'wprss_update_interval', TRUE );
541
+ $update_time = get_post_meta( $post->ID, 'wprss_update_time', TRUE );
542
 
543
  $age_limit = get_post_meta( $post->ID, 'wprss_age_limit', true );
544
  $age_unit = get_post_meta( $post->ID, 'wprss_age_unit', true );
637
  <option value="<?php echo $value; ?>" <?php selected( $update_interval, $value ); ?> ><?php echo $text; ?></option>
638
  <?php endforeach; ?>
639
  </select>
640
+ <label>
641
+ <input type="time" name="wpra_feed[update_time]" value="<?php echo esc_attr($update_time); ?>">
642
+ </label>
643
  </div>
644
  </div>
645
 
includes/cron-jobs.php CHANGED
@@ -67,6 +67,24 @@ function wprss_schedule_fetch_all_feeds_cron()
67
  wp_schedule_event(time(), $interval, WPRA_FETCH_ALL_FEEDS_HOOK);
68
  }
69
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
70
  /**
71
  * Creates the cron to truncate wprss_feed_item posts daily
72
  *
67
  wp_schedule_event(time(), $interval, WPRA_FETCH_ALL_FEEDS_HOOK);
68
  }
69
 
70
+ /**
71
+ * Gets the time of the global fetch cron.
72
+ *
73
+ * @since [*next-version*]
74
+ *
75
+ * @return false|string A time string in the form `H:i`
76
+ */
77
+ function wprss_get_global_update_time()
78
+ {
79
+ // If the global fetch cron is not scheduled, schedule it
80
+ wprss_schedule_fetch_all_feeds_cron();
81
+
82
+ // Get the timestamp for the next run
83
+ $next = wp_next_scheduled(WPRA_FETCH_ALL_FEEDS_HOOK);
84
+
85
+ return date('H:i', $next);
86
+ }
87
+
88
  /**
89
  * Creates the cron to truncate wprss_feed_item posts daily
90
  *
includes/scripts.php CHANGED
@@ -77,10 +77,21 @@
77
 
78
  wp_register_script( 'wprss-gallery-js', WPRSS_JS . 'gallery.js', array('jquery'), $version, true );
79
 
80
- wp_register_script('wpra-tools', WPRSS_JS . 'tools.js', ['jquery'], $version, true);
81
- wp_register_script('wpra-logs-tool', WPRSS_JS . 'logs-tool.js', ['jquery'], $version, true);
82
- wp_register_script('wpra-blacklist-tool', WPRSS_JS . 'blacklist-tool.js', ['jquery'], $version, true);
83
- wp_register_script('wpra-reset-tool', WPRSS_JS . 'reset-tool.js', ['jquery'], $version, true);
 
 
 
 
 
 
 
 
 
 
 
84
  wp_localize_script('wpra-reset-tool', 'WpraResetTool', [
85
  'message' => __('Are you sure you want to do this? This operation cannot be undone.', 'wprss')
86
  ]);
@@ -174,6 +185,7 @@
174
  wp_enqueue_script('wpra-tools');
175
  wp_enqueue_script('wpra-logs-tool');
176
  wp_enqueue_script('wpra-blacklist-tool');
 
177
  wp_enqueue_script('wpra-reset-tool');
178
  }
179
 
77
 
78
  wp_register_script( 'wprss-gallery-js', WPRSS_JS . 'gallery.js', array('jquery'), $version, true );
79
 
80
+ wp_register_script('wpra-tools', WPRSS_JS . 'admin/tools/main.js', ['jquery'], $version, true);
81
+ wp_register_script('wpra-logs-tool', WPRSS_JS . 'admin/tools/logs.js', ['jquery'], $version, true);
82
+ wp_register_script('wpra-blacklist-tool', WPRSS_JS . 'admin/tools/blacklist.js', ['jquery'], $version, true);
83
+
84
+ wp_register_script('wpra-crons-tool', WPRSS_JS . 'admin/tools/crons.js', ['jquery'], $version, true);
85
+ wp_localize_script('wpra-crons-tool', 'WpraCronsTool', [
86
+ 'restApiNonce' => wp_create_nonce('wp_rest'),
87
+ 'schedules' => wp_get_schedules(),
88
+ 'globalInterval' => wprss_get_general_setting('cron_interval'),
89
+ 'globalTime' => wprss_get_global_update_time(),
90
+ 'globalWord' => __('Global', 'wprss'),
91
+ 'perPage' => 25
92
+ ]);
93
+
94
+ wp_register_script('wpra-reset-tool', WPRSS_JS . 'admin/tools/reset.js', ['jquery'], $version, true);
95
  wp_localize_script('wpra-reset-tool', 'WpraResetTool', [
96
  'message' => __('Are you sure you want to do this? This operation cannot be undone.', 'wprss')
97
  ]);
185
  wp_enqueue_script('wpra-tools');
186
  wp_enqueue_script('wpra-logs-tool');
187
  wp_enqueue_script('wpra-blacklist-tool');
188
+ wp_enqueue_script('wpra-crons-tool');
189
  wp_enqueue_script('wpra-reset-tool');
190
  }
191
 
js/{blacklist-tool.js → admin/tools/blacklist.js} RENAMED
File without changes
js/admin/tools/crons.js ADDED
@@ -0,0 +1,533 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ (function ($, Config) {
2
+
3
+ // Update the table only when the tool is shown
4
+ $(document).on('wpra/tools/on_loaded', function (event, tool) {
5
+ if (tool === 'crons') {
6
+ if (Store.isLoaded) {
7
+ init();
8
+ } else {
9
+ $(document).ready(init);
10
+ }
11
+ }
12
+
13
+ $(document).on('wpra/tools/on_switched_to_crons', init);
14
+ });
15
+
16
+ /**
17
+ * Initializes the crons tool.
18
+ */
19
+ function init() {
20
+ Pagination.init();
21
+ Table.init();
22
+ Timeline.init();
23
+ Info.init();
24
+ }
25
+
26
+ /**
27
+ * The data store.
28
+ */
29
+ var Store = {
30
+ feeds: null,
31
+ count: 0,
32
+ isLoaded: false,
33
+ page: 1,
34
+
35
+ fetchSources: function (callback) {
36
+ Pagination.showLoading();
37
+
38
+ $.ajax({
39
+ url: 'http://dev.wpra/wp-json/wpra/v1/sources',
40
+ method: 'GET',
41
+ data: {
42
+ num: Config.perPage,
43
+ page: Store.page
44
+ },
45
+ beforeSend: function (request) {
46
+ request.setRequestHeader("X-WP-NONCE", Config.restApiNonce);
47
+ },
48
+ success: function (response) {
49
+ if (response && response.items) {
50
+ Store.count = response.count;
51
+ Store.feeds = response.items.sort(function (a, b) {
52
+ return Util.compareTimeObjs(Feed.getUpdateTime(a), Feed.getUpdateTime(b));
53
+ });
54
+ }
55
+
56
+ Pagination.update();
57
+ Table.update();
58
+ Timeline.update();
59
+ Info.update();
60
+
61
+ if (callback) {
62
+ callback();
63
+ }
64
+ },
65
+ error: function (response) {
66
+ console.error(response);
67
+ },
68
+ complete: function () {
69
+ Pagination.hideLoading();
70
+ }
71
+ });
72
+ },
73
+
74
+ getIntervalName: function (interval) {
75
+ return Config.schedules[interval]
76
+ ? Config.schedules[interval]['display']
77
+ : interval;
78
+ },
79
+
80
+ getGroupedFeeds: function () {
81
+ var grouped = {};
82
+
83
+ for (var i in Store.feeds) {
84
+ var feed = Store.feeds[i];
85
+ var time = Feed.getUpdateTime(feed),
86
+ timeStr = Util.formatTimeObj(time);
87
+
88
+ if (!grouped[timeStr]) {
89
+ grouped[timeStr] = [];
90
+ }
91
+
92
+ grouped[timeStr].push(feed);
93
+ }
94
+
95
+ var collapsed = {};
96
+ for (var timeStr in grouped) {
97
+ // Get the time object and string for the previous minute
98
+ var group = grouped[timeStr],
99
+ time = Util.parseTimeStr(timeStr),
100
+ prevTime = Util.addTime(time, {hours: 0, minutes: -1}),
101
+ prevTimeStr = Util.formatTimeObj(prevTime);
102
+
103
+ // The key to use - either this group's time string or a time string for 1 minute less
104
+ var key = grouped.hasOwnProperty(prevTimeStr)
105
+ ? prevTimeStr
106
+ : timeStr;
107
+
108
+ // Create the array for the key if needed
109
+ if (!Array.isArray(collapsed[key])) {
110
+ collapsed[key] = [];
111
+ }
112
+
113
+ // Add the group to the array for the key
114
+ collapsed[key] = collapsed[key].concat(group);
115
+ }
116
+
117
+ return Object.keys(collapsed).sort().reduce((acc, key) => (acc[key] = collapsed[key], acc), {});
118
+ },
119
+ };
120
+
121
+ /**
122
+ * Functions related to feed sources and their data.
123
+ */
124
+ var Feed = {
125
+ getState: function (feed) {
126
+ return feed.active ? 'active' : 'paused';
127
+ },
128
+ getUpdateInterval: function (feed) {
129
+ return (feed.update_interval === 'global')
130
+ ? Config.globalWord
131
+ : feed.update_interval;
132
+ },
133
+ getUpdateTime: function (feed) {
134
+ return (feed.update_time)
135
+ ? Util.parseTimeStr(feed.update_time)
136
+ : Util.parseTimeStr(Config.globalTime);
137
+ },
138
+ };
139
+
140
+ /**
141
+ * The feed sources table.
142
+ */
143
+ var Table = {
144
+ element: null,
145
+ body: null,
146
+ hovered: null,
147
+ init: function () {
148
+ if (Table.element === null) {
149
+ Table.element = $('#wpra-crons-tool-table');
150
+ Table.body = Table.element.find('tbody');
151
+ }
152
+ if (Store.feeds === null) {
153
+ Store.fetchSources();
154
+ }
155
+ },
156
+ createRow: function (feed) {
157
+ var id = feed.id,
158
+ state = Feed.getState(feed),
159
+ name = feed.name,
160
+ interval = Util.getIntervalName(Feed.getUpdateInterval(feed)),
161
+ timeStr = Util.formatTimeObj(Feed.getUpdateTime(feed));
162
+
163
+ var elRow = $('<tr></tr>').addClass('wpra-crons-feed-' + Feed.getState(feed));
164
+
165
+ $('<td></td>').appendTo(elRow).addClass('wpra-crons-feed-id-col').text('#' + id);
166
+ $('<td></td>').appendTo(elRow).addClass('wpra-crons-feed-name-col').text(name);
167
+ $('<td></td>').appendTo(elRow).addClass('wpra-crons-interval-col').text(interval);
168
+ $('<td></td>').appendTo(elRow).addClass('wpra-crons-time-col').text(timeStr ? timeStr : '');
169
+
170
+ elRow.on('click', function (e) {
171
+ Table.body.find('.wpra-crons-highlighted-feed').removeClass('wpra-crons-highlighted-feed');
172
+
173
+ if (Table.hovered === id) {
174
+ Table.hovered = null;
175
+ } else {
176
+ $(this).addClass('wpra-crons-highlighted-feed');
177
+ Table.hovered = id;
178
+ }
179
+
180
+ Timeline.update();
181
+ });
182
+
183
+ return elRow;
184
+ },
185
+ update: function () {
186
+ Table.body.empty();
187
+
188
+ for (var i in Store.feeds) {
189
+ Table.body.append(Table.createRow(Store.feeds[i]));
190
+ }
191
+ },
192
+ };
193
+
194
+ /**
195
+ * The pagination component.
196
+ */
197
+ var Pagination = {
198
+ nextBtn: null,
199
+ prevBtn: null,
200
+ numFeeds: null,
201
+ loadingText: null,
202
+ // Initializes the pagination
203
+ init: function () {
204
+ Pagination.nextBtn = $('#wpra-crons-next-page');
205
+ Pagination.prevBtn = $('#wpra-crons-prev-page');
206
+ Pagination.numFeeds = $('.wpra-crons-num-feeds');
207
+ Pagination.loadingText = $('#wpra-crons-loading');
208
+
209
+ // Hide the feed counter until the component updates
210
+ Pagination.numFeeds.parent().hide();
211
+
212
+ Pagination.nextBtn.click(Pagination.nextPage);
213
+ Pagination.prevBtn.click(Pagination.prevPage);
214
+ },
215
+ // Updates the pagination component
216
+ update: function () {
217
+ Pagination.nextBtn.prop('disabled', Store.page >= Pagination.getNumPages());
218
+ Pagination.prevBtn.prop('disabled', Store.page <= 1);
219
+
220
+ Pagination.numFeeds.text(Store.count);
221
+ Pagination.numFeeds.parent().toggle(Store.count > 0);
222
+ },
223
+ // Calculates the number of pages
224
+ getNumPages: function () {
225
+ return Math.ceil(Store.count / Config.perPage);
226
+ },
227
+ // Switches to the next page
228
+ nextPage: function () {
229
+ Pagination.changePage(Math.min(Store.page + 1, Pagination.getNumPages()));
230
+ },
231
+ // Switches to the previous page
232
+ prevPage: function () {
233
+ Pagination.changePage(Math.max(Store.page - 1, 1));
234
+ },
235
+ // Switches to a specific page
236
+ changePage: function (page) {
237
+ Store.page = page;
238
+ Store.fetchSources();
239
+ },
240
+ // Shows the loading text
241
+ showLoading: function () {
242
+ Pagination.loadingText.show();
243
+ },
244
+ // Hides the loading text
245
+ hideLoading: function () {
246
+ Pagination.loadingText.hide();
247
+ },
248
+ };
249
+
250
+ /**
251
+ * The info component.
252
+ */
253
+ var Info = {
254
+ elGlobalInterval: null,
255
+ elGlobalTime: null,
256
+ elDownloadTimeline: null,
257
+ init: function () {
258
+ Info.elGlobalInterval = $('.wpra-crons-global-interval');
259
+ Info.elGlobalTime = $('.wpra-crons-global-time');
260
+ Info.elDownloadTimeline = $('.wpra-crons-download-timeline');
261
+
262
+ Info.elDownloadTimeline.click(function () {
263
+ var imageUrl = Timeline.canvas.toDataURL();
264
+ window.open(imageUrl, '_wpraTimelineDL');
265
+ window.focus();
266
+ });
267
+ },
268
+ update: function () {
269
+ Info.elGlobalInterval.text(Util.getIntervalName(Config.globalInterval));
270
+ Info.elGlobalTime.text(Config.globalTime);
271
+ }
272
+ };
273
+
274
+ /*
275
+ * The timeline diagram.
276
+ */
277
+ var Timeline = {
278
+ element: null,
279
+ canvas: null,
280
+ minWidth: 1280,
281
+
282
+ init: function () {
283
+ Timeline.element = document.getElementById('wpra-crons-timeline');
284
+ Timeline.canvas = document.getElementById('wpra-crons-timeline-canvas');
285
+
286
+ Timeline.update();
287
+ window.addEventListener('resize', Timeline.update, false);
288
+ },
289
+
290
+ update: function () {
291
+ // Update the width of the canvas to match its parent (-2 for the border of the parent)
292
+ Timeline.canvas.width = Math.max(Timeline.minWidth, Timeline.element.offsetWidth - 2);
293
+
294
+ // Get canvas properties
295
+ var canvas = Timeline.canvas,
296
+ rWidth = canvas.width,
297
+ rHeight = canvas.height,
298
+ hPadding = 10,
299
+ vPadding = 10,
300
+ width = rWidth - (hPadding * 2),
301
+ height = rHeight - (vPadding * 2),
302
+ ctx = canvas.getContext("2d"),
303
+ axisOffset = 10,
304
+ textHeight = 30,
305
+ textSpacing = 20,
306
+ lineY = height - textSpacing - textHeight,
307
+ lineColor = "#555",
308
+ hourGuideColor = "#888",
309
+ minsGuideColor = "#aaa",
310
+ lineWidth = 2,
311
+ evenTextColor = "#444",
312
+ oddTextColor = "#888",
313
+ bubbleColor = "#658c6f",
314
+ bubbleWarningColor = "#b18e76",
315
+ bubbleSeriousColor = "#915759",
316
+ bubbleHighlightColor = "#1a83de",
317
+ bubbleRadius = 12,
318
+ bubbleTopOffset = 5,
319
+ bubbleTop = (bubbleRadius * 2) + bubbleTopOffset;
320
+
321
+ // Clear the canvas
322
+ ctx.clearRect(0, 0, width, height);
323
+ ctx.translate(hPadding, vPadding);
324
+
325
+ // Draw the bottom line
326
+ {
327
+ ctx.save();
328
+ ctx.beginPath();
329
+ ctx.moveTo(0, lineY);
330
+ ctx.lineTo(width, lineY);
331
+ ctx.lineWidth = lineWidth;
332
+ ctx.strokeStyle = lineColor;
333
+ ctx.stroke();
334
+ ctx.restore();
335
+ }
336
+
337
+ // Pad along the x-axis so that the numbers are not exactly at the edges
338
+ ctx.translate(axisOffset, 0);
339
+
340
+ // Draw the numbers and dotted lines
341
+ {
342
+ var hourWidth = width / 24,
343
+ minFontSize = 12,
344
+ maxFontSize = 18,
345
+ fontSizeRatio = 0.011,
346
+ fontSize = Math.max(Math.min(width * fontSizeRatio, maxFontSize), minFontSize);
347
+
348
+ ctx.font = fontSize + "px sans-serif";
349
+ ctx.textBaseline = "hanging";
350
+ for (var hour = 0; hour < 24; ++hour) {
351
+ var hourStr = (hour < 10) ? "0" + hour : hour,
352
+ text = hourStr + ":00",
353
+ even = (hour % 2 === 0),
354
+ x = hour * hourWidth,
355
+ y = height - textHeight - (textSpacing / 2),
356
+ tx = x,
357
+ ty = y + 3,
358
+ color = (even) ? evenTextColor : oddTextColor;
359
+
360
+ ctx.save();
361
+
362
+ ctx.translate(tx, ty);
363
+ ctx.rotate(Math.PI / 5);
364
+ ctx.fillStyle = color;
365
+ ctx.textAlign = "left";
366
+ ctx.fillText(text, 0, 0);
367
+
368
+ ctx.restore();
369
+
370
+ // The hour guide lines
371
+ ctx.save();
372
+ ctx.beginPath();
373
+ ctx.moveTo(x, y);
374
+ ctx.lineTo(x, 0);
375
+ ctx.setLineDash([4, 4]);
376
+ ctx.lineWidth = 1;
377
+ ctx.strokeStyle = hourGuideColor;
378
+ ctx.stroke();
379
+ ctx.moveTo(0, 0);
380
+ ctx.restore();
381
+
382
+ // The half-hour guide lines
383
+ ctx.save();
384
+ ctx.beginPath();
385
+ ctx.moveTo(x + (hourWidth / 2), y);
386
+ ctx.lineTo(x + (hourWidth / 2), 0);
387
+ ctx.setLineDash([2, 2]);
388
+ ctx.lineWidth = 1;
389
+ ctx.strokeStyle = minsGuideColor;
390
+ ctx.stroke();
391
+ ctx.moveTo(0, 0);
392
+ ctx.restore();
393
+ }
394
+ }
395
+
396
+ // Draw the indicators
397
+ {
398
+ if (Store.feeds && Store.feeds.length) {
399
+ var minuteWidth = width / (24 * 60),
400
+ fetchDuration = 5, // in minutes
401
+ fetchWidth = fetchDuration * minuteWidth;
402
+
403
+ var groups = Store.getGroupedFeeds();
404
+ var drawLater = {};
405
+
406
+ var drawFn = function (group, timeStr, highlighted) {
407
+ var time = Util.parseTimeStr(timeStr),
408
+ groupX = (time.hours * hourWidth) + (time.minutes / 60 * hourWidth),
409
+ count = group.length,
410
+ color = bubbleColor,
411
+ bgColor = "#fff",
412
+ textColor = color;
413
+
414
+ if (highlighted) {
415
+ color = bubbleHighlightColor;
416
+ bgColor = color;
417
+ textColor = "#fff";
418
+ } else if (count > 10) {
419
+ color = bubbleSeriousColor;
420
+ } else if (count > 5) {
421
+ color = bubbleWarningColor;
422
+ }
423
+
424
+ // Draw the indicator line
425
+ ctx.save();
426
+ ctx.beginPath();
427
+ ctx.moveTo(groupX, lineY);
428
+ ctx.lineTo(groupX, bubbleTop);
429
+ ctx.lineCap = "square";
430
+ ctx.lineWidth = 2;
431
+ ctx.strokeStyle = color;
432
+ ctx.stroke();
433
+ ctx.restore();
434
+
435
+ // Draw the bubble
436
+ ctx.save();
437
+ ctx.beginPath();
438
+ ctx.arc(groupX, bubbleRadius + bubbleTopOffset, bubbleRadius, 0, 2 * Math.PI);
439
+ ctx.fillStyle = bgColor;
440
+ ctx.fill();
441
+ ctx.lineWidth = 2;
442
+ ctx.strokeStyle = color;
443
+ ctx.stroke();
444
+ ctx.restore();
445
+
446
+ // Draw the feed count
447
+ ctx.save();
448
+ ctx.font = "12px sans-serif";
449
+ ctx.textAlign = "center";
450
+ ctx.textBaseline = "middle";
451
+ ctx.fillStyle = textColor;
452
+ ctx.fillText(count, groupX, bubbleRadius + bubbleTopOffset + 1);
453
+ ctx.restore();
454
+ };
455
+
456
+ for (var timeStr in groups) {
457
+ var group = groups[timeStr];
458
+
459
+ var hasHighlightedFeed = Table.hovered !== null && group.find(function (feed) {
460
+ return feed.id === Table.hovered;
461
+ });
462
+
463
+ if (hasHighlightedFeed) {
464
+ drawLater[timeStr] = group;
465
+ }
466
+
467
+ drawFn(group, timeStr);
468
+ }
469
+
470
+ for (var timeStr in drawLater) {
471
+ drawFn(drawLater[timeStr], timeStr, true);
472
+ }
473
+ }
474
+ }
475
+
476
+ ctx.translate(0, 0);
477
+ },
478
+
479
+ drawLollipop: function () {
480
+
481
+ },
482
+ };
483
+
484
+ /**
485
+ * Utility functions.
486
+ */
487
+ var Util = {
488
+ getIntervalName: function (interval) {
489
+ return Config.schedules[interval]
490
+ ? Config.schedules[interval]['display']
491
+ : interval;
492
+ },
493
+ formatTimeObj: function (obj) {
494
+ if (!obj) {
495
+ return "";
496
+ }
497
+
498
+ var hours = obj.hours < 10 ? "0" + obj.hours : obj.hours;
499
+ var minutes = obj.minutes < 10 ? "0" + obj.minutes : obj.minutes;
500
+
501
+ return hours + ":" + minutes;
502
+ },
503
+ parseTimeStr: function (timeStr) {
504
+ var parts = timeStr.split(':');
505
+ var hours = parseInt(parts[0]);
506
+ var mins = parseInt(parts[1]);
507
+
508
+ return {hours: hours, minutes: mins};
509
+ },
510
+ addTime: function (obj1, obj2) {
511
+ var newObj = {
512
+ hours: obj1.hours + obj2.hours,
513
+ minutes: obj1.minutes + obj2.minutes
514
+ };
515
+
516
+ newObj.hours = (newObj.hours + Math.floor(newObj.minutes / 60)) % 23;
517
+ newObj.minutes = newObj.minutes % 60;
518
+
519
+ return newObj;
520
+ },
521
+ compareTimeObjs(a, b) {
522
+ var an = (a.hours * 60) + a.minutes;
523
+ var bn = (b.hours * 60) + b.minutes;
524
+
525
+ if (an === bn) {
526
+ return 0;
527
+ }
528
+
529
+ return (an < bn) ? -1 : 1;
530
+ }
531
+ };
532
+
533
+ })(jQuery, WpraCronsTool);
js/{logs-tool.js → admin/tools/logs.js} RENAMED
File without changes
js/{tools.js → admin/tools/main.js} RENAMED
@@ -45,6 +45,8 @@
45
  });
46
  }
47
  });
 
 
48
  });
49
 
50
  // Get the tab for a given tool key
@@ -84,7 +86,13 @@
84
  // Set the current tool and updates the DOM
85
  function setCurrentTool(tool)
86
  {
 
 
 
87
  showTool(currTool = tool);
 
 
 
88
  }
89
 
90
  // Updates the DOM to show a particular tool
45
  });
46
  }
47
  });
48
+
49
+ $(document).trigger('wpra/tools/on_loaded', [currTool]);
50
  });
51
 
52
  // Get the tab for a given tool key
86
  // Set the current tool and updates the DOM
87
  function setCurrentTool(tool)
88
  {
89
+ $(document).trigger('wpra/tools/on_leaving_tool', [currTool]);
90
+ $(document).trigger('wpra/tools/on_leaving_from_' + currTool);
91
+
92
  showTool(currTool = tool);
93
+
94
+ $(document).trigger('wpra/tools/on_switched_to_' + currTool);
95
+ $(document).trigger('wpra/tools/on_switched_tool', [currTool]);
96
  }
97
 
98
  // Updates the DOM to show a particular tool
js/{reset-tool.js → admin/tools/reset.js} RENAMED
File without changes
readme.txt CHANGED
@@ -5,7 +5,7 @@ Tags: RSS import, RSS aggregator, feed import, content curation, feed to post
5
  Requires at least: 4.0 or higher
6
  Tested up to: 5.3
7
  Requires PHP: 5.4
8
- Stable tag: 4.17.1
9
  License: GPLv3
10
 
11
  WP RSS Aggregator is the original & most popular WordPress solution for importing RSS feeds, auto-blogging, content curation & aggregation.
@@ -259,6 +259,16 @@ Our complete Knowledge Base with FAQs can be found [here](https://kb.wprssaggreg
259
 
260
  == Changelog ==
261
 
 
 
 
 
 
 
 
 
 
 
262
  = 4.17.1 (2019-12-12) =
263
 
264
  **Fixed**
5
  Requires at least: 4.0 or higher
6
  Tested up to: 5.3
7
  Requires PHP: 5.4
8
+ Stable tag: 4.17.2
9
  License: GPLv3
10
 
11
  WP RSS Aggregator is the original & most popular WordPress solution for importing RSS feeds, auto-blogging, content curation & aggregation.
259
 
260
  == Changelog ==
261
 
262
+ = 4.17.2 (2019-12-19) =
263
+ **Added**
264
+ - The error handler now includes the file and line where the error occurred.
265
+
266
+ **Changed**
267
+ - The obsolete "Link Source" option is now only shown when the Excerpts & Thumbnails add-on is active.
268
+
269
+ **Fixed**
270
+ - The new "feeds" shortcode parameter only showed feed items for the first 10 feed sources.
271
+
272
  = 4.17.1 (2019-12-12) =
273
 
274
  **Fixed**
src/Entities/Collections/FeedItemCollection.php CHANGED
@@ -66,7 +66,8 @@ class FeedItemCollection extends WpEntityCollection
66
  $slugs = $this->_normalizeArray($value);
67
  $posts = get_posts([
68
  'post_name__in' => $slugs,
69
- 'post_type' => 'wprss_feed'
 
70
  ]);
71
  $ids = array_map(function ($post) {
72
  return $post->ID;
66
  $slugs = $this->_normalizeArray($value);
67
  $posts = get_posts([
68
  'post_name__in' => $slugs,
69
+ 'post_type' => 'wprss_feed',
70
+ 'posts_per_page' => -1,
71
  ]);
72
  $ids = array_map(function ($post) {
73
  return $post->ID;
src/Modules/CronsToolModule.php ADDED
@@ -0,0 +1,66 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace RebelCode\Wpra\Core\Modules;
4
+
5
+ use Psr\Container\ContainerInterface;
6
+ use RebelCode\Wpra\Core\Templates\NullTemplate;
7
+
8
+ /**
9
+ * The module that adds the "Crons" tool to WP RSS Aggregator.
10
+ *
11
+ * @since [*next-version*]
12
+ */
13
+ class CronsToolModule implements ModuleInterface
14
+ {
15
+ /**
16
+ * @inheritdoc
17
+ *
18
+ * @since [*next-version*]
19
+ */
20
+ public function getFactories()
21
+ {
22
+ return [
23
+ /*
24
+ * Information about the "Crons" tool.
25
+ *
26
+ * @since [*next-version*]
27
+ */
28
+ 'wpra/admin/tools/crons/info' => function (ContainerInterface $c) {
29
+ return [
30
+ 'name' => __('Crons', 'wprss'),
31
+ 'template' => $c->has('wpra/twig/collection')
32
+ ? $c->get('wpra/twig/collection')['admin/tools/crons.twig']
33
+ : new NullTemplate(),
34
+ ];
35
+ },
36
+ ];
37
+ }
38
+
39
+ /**
40
+ * @inheritdoc
41
+ *
42
+ * @since [*next-version*]
43
+ */
44
+ public function getExtensions()
45
+ {
46
+ return [
47
+ /*
48
+ * Registers the "Crons" tool.
49
+ *
50
+ * @since [*next-version*]
51
+ */
52
+ 'wpra/admin/tools' => function (ContainerInterface $c, $tools) {
53
+ return $tools + ['crons' => $c->get('wpra/admin/tools/crons/info')];
54
+ },
55
+ ];
56
+ }
57
+
58
+ /**
59
+ * @inheritdoc
60
+ *
61
+ * @since [*next-version*]
62
+ */
63
+ public function run(ContainerInterface $c)
64
+ {
65
+ }
66
+ }
src/Modules/FeedSourcesModule.php CHANGED
@@ -16,6 +16,8 @@ use RebelCode\Wpra\Core\Handlers\MultiHandler;
16
  use RebelCode\Wpra\Core\Handlers\NullHandler;
17
  use RebelCode\Wpra\Core\Handlers\RegisterCptHandler;
18
  use RebelCode\Wpra\Core\Handlers\RenderMetaBoxTemplateHandler;
 
 
19
  use RebelCode\Wpra\Core\Templates\NullTemplate;
20
  use RebelCode\Wpra\Core\Util\Sanitizers\BoolSanitizer;
21
  use RebelCode\Wpra\Core\Util\Sanitizers\CallbackSanitizer;
@@ -68,6 +70,9 @@ class FeedSourcesModule implements ModuleInterface
68
  new Property('wprss_unique_titles'),
69
  new BoolSanitizer()
70
  ),
 
 
 
71
  // == Image options ==
72
  'def_ft_image' => new Property('_thumbnail_id'),
73
  'import_ft_images' => new Property('wprss_import_ft_images'),
@@ -350,7 +355,23 @@ class FeedSourcesModule implements ModuleInterface
350
  */
351
  public function getExtensions()
352
  {
353
- return [];
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
354
  }
355
 
356
  /**
16
  use RebelCode\Wpra\Core\Handlers\NullHandler;
17
  use RebelCode\Wpra\Core\Handlers\RegisterCptHandler;
18
  use RebelCode\Wpra\Core\Handlers\RenderMetaBoxTemplateHandler;
19
+ use RebelCode\Wpra\Core\RestApi\EndPoints\EndPoint;
20
+ use RebelCode\Wpra\Core\RestApi\EndPoints\Handlers\GetEntityHandler;
21
  use RebelCode\Wpra\Core\Templates\NullTemplate;
22
  use RebelCode\Wpra\Core\Util\Sanitizers\BoolSanitizer;
23
  use RebelCode\Wpra\Core\Util\Sanitizers\CallbackSanitizer;
70
  new Property('wprss_unique_titles'),
71
  new BoolSanitizer()
72
  ),
73
+ // == Cron options ==
74
+ 'update_interval' => new Property('wprss_update_interval'),
75
+ 'update_time' => new Property('wprss_update_time'),
76
  // == Image options ==
77
  'def_ft_image' => new Property('_thumbnail_id'),
78
  'import_ft_images' => new Property('wprss_import_ft_images'),
355
  */
356
  public function getExtensions()
357
  {
358
+ return [
359
+ /*
360
+ * Extends the list of REST API endpoints to register the feed sources endpoints.
361
+ *
362
+ * @since [*next-version*]
363
+ */
364
+ 'wpra/rest_api/v1/endpoints' => function (ContainerInterface $c, $endpoints) {
365
+ $endpoints['get_sources'] = new EndPoint(
366
+ '/sources(?:/(?P<id>[^/]+))?',
367
+ ['GET'],
368
+ new GetEntityHandler($c->get('wpra/feeds/sources/collection'), 'id', []),
369
+ $c->get('wpra/rest_api/v1/auth/user_is_admin')
370
+ );
371
+
372
+ return $endpoints;
373
+ }
374
+ ];
375
  }
376
 
377
  /**
src/RestApi/EndPoints/Handlers/GetEntityHandler.php ADDED
@@ -0,0 +1,134 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace RebelCode\Wpra\Core\RestApi\EndPoints\Handlers;
4
+
5
+ use Iterator;
6
+ use RebelCode\Wpra\Core\Data\Collections\CollectionInterface;
7
+ use RebelCode\Wpra\Core\RestApi\EndPoints\AbstractRestApiEndPoint;
8
+ use RebelCode\Wpra\Core\Util\PaginatedIterator;
9
+ use WP_REST_Request;
10
+ use WP_REST_Response;
11
+
12
+ /**
13
+ * A generic endpoint handler for entity collections.
14
+ *
15
+ * @since [*next-version*]
16
+ */
17
+ class GetEntityHandler extends AbstractRestApiEndPoint
18
+ {
19
+ /**
20
+ * @since [*next-version*]
21
+ *
22
+ * @var CollectionInterface
23
+ */
24
+ protected $collection;
25
+
26
+ /**
27
+ * @since [*next-version*]
28
+ *
29
+ * @var string
30
+ */
31
+ protected $idKey;
32
+
33
+ /**
34
+ * @since [*next-version*]
35
+ *
36
+ * @var callable[]
37
+ */
38
+ protected $filters;
39
+
40
+ /**
41
+ * @since [*next-version*]
42
+ *
43
+ * @var int
44
+ */
45
+ protected $defPerPage;
46
+
47
+ /**
48
+ * Constructor.
49
+ *
50
+ * @since [*next-version*]
51
+ *
52
+ * @param CollectionInterface $collection The entity collection.
53
+ * @param string $idKey The key in requests for IDs, for responding with single entities.
54
+ * @param callable[] $params The available request params, as functions. Each function is given the
55
+ * current accumulated list of collection filters and the request as
56
+ * arguments and is expected to return the new list of collection filters.
57
+ * @param int $defPerPage The default number of entities to respond with per page.
58
+ */
59
+ public function __construct(CollectionInterface $collection, $idKey, array $params = [], $defPerPage = 20)
60
+ {
61
+ $this->collection = $collection;
62
+ $this->idKey = $idKey;
63
+ $this->filters = $params;
64
+ $this->defPerPage = $defPerPage;
65
+ }
66
+
67
+ /**
68
+ * @inheritDoc
69
+ *
70
+ * @since [*next-version*]
71
+ */
72
+ protected function handle(WP_REST_Request $request)
73
+ {
74
+ $id = filter_input(INPUT_GET, $this->idKey, FILTER_VALIDATE_INT);
75
+
76
+ if (!empty($id)) {
77
+ return new WP_REST_Response($this->collection[$id]->export());
78
+ }
79
+
80
+ $filteredColl = $this->filterCollection($request, $this->collection);
81
+ $paginatedIter = $this->paginateCollection($request, $filteredColl);
82
+
83
+ return new WP_REST_Response([
84
+ 'items' => $paginatedIter,
85
+ 'count' => $filteredColl->getCount(),
86
+ ]);
87
+ }
88
+
89
+ /**
90
+ * Applies filters to the collection based on the request.
91
+ *
92
+ * @since [*next-version*]
93
+ *
94
+ * @param WP_REST_Request $request The request.
95
+ * @param CollectionInterface $collection The collection to filter.
96
+ *
97
+ * @return CollectionInterface The filtered collection.
98
+ */
99
+ protected function filterCollection(WP_REST_Request $request, CollectionInterface $collection)
100
+ {
101
+ $filters = [];
102
+
103
+ foreach ($this->filters as $key => $paramFn) {
104
+ $filters = call_user_func_array($paramFn, [$filters, $request]);
105
+ }
106
+
107
+ return empty($filters)
108
+ ? $collection
109
+ : $collection->filter($filters);
110
+ }
111
+
112
+ /**
113
+ * Paginates the collection.
114
+ *
115
+ * @since [*next-version*]
116
+ *
117
+ * @param WP_REST_Request $request The request.
118
+ * @param CollectionInterface $collection The collection to paginate.
119
+ *
120
+ * @return Iterator The pagination collection iterator.
121
+ */
122
+ protected function paginateCollection(WP_REST_Request $request, CollectionInterface $collection)
123
+ {
124
+ $collection = $this->filterCollection($request, $collection);
125
+
126
+ $num = filter_var($request['num'], FILTER_VALIDATE_INT);
127
+ $page = filter_var($request['page'], FILTER_VALIDATE_INT);
128
+
129
+ $num = empty($num) ? $this->defPerPage : $num;
130
+ $page = empty($page) ? 1 : $page;
131
+
132
+ return new PaginatedIterator($collection, $page, $num);
133
+ }
134
+ }
templates/admin/tools/crons.twig ADDED
@@ -0,0 +1,194 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <h3>{% trans "Crons" %}</h3>
2
+
3
+ <div id="wpra-crons">
4
+
5
+ {# the timeline diagram #}
6
+ <div id="wpra-crons-timeline">
7
+ <canvas id="wpra-crons-timeline-canvas" height="150"></canvas>
8
+ </div>
9
+
10
+ {# Toolbar #}
11
+ <div id="wpra-crons-toolbar">
12
+ {# Pagination #}
13
+ <div class="wpra-crons-pagination">
14
+ <div class="wpra-crons-pagination-info">
15
+ {{ "{number} feeds"|trans|replace({'{number}': '<span class="wpra-crons-num-feeds"></span>'})|raw }}
16
+ </div>
17
+ <div class="wpra-crons-pagination-buttons">
18
+ <button id="wpra-crons-first-page" class="button" disabled>&laquo;</button>
19
+ <button id="wpra-crons-prev-page" class="button" disabled>&lsaquo;</button>
20
+ <span class="wpra-crons-page-indicator">
21
+ <span class="wpra-crons-curr-page">1</span>
22
+ {% trans "of" %}
23
+ <span class="wpra-crons-num-pages">2</span>
24
+ </span>
25
+ <button id="wpra-crons-next-page" class="button" disabled>&rsaquo;</button>
26
+ <button id="wpra-crons-last-page" class="button" disabled>&raquo;</button>
27
+ </div>
28
+ </div>
29
+
30
+ {# Loading text #}
31
+ <span id="wpra-crons-loading">{% trans "Loading" %}</span>
32
+
33
+ {# Info panel #}
34
+ <div class="wpra-crons-info">
35
+ <span>
36
+ <strong>{% trans "Global Interval:" %}</strong>
37
+ <code class="wpra-crons-global-interval"></code>
38
+ </span>
39
+ <span>
40
+ <strong>{% trans "Global Time:" %}</strong>
41
+ <code class="wpra-crons-global-time"></code>
42
+ </span>
43
+
44
+ <span>
45
+ <a class="button wpra-crons-download-timeline">
46
+ {% trans "Download Timeline Image" %}
47
+ </a>
48
+ </span>
49
+ </div>
50
+ </div>
51
+
52
+ {# The table #}
53
+ <table id="wpra-crons-tool-table" class="widefat fixed striped">
54
+ <thead>
55
+ <tr>
56
+ <th class="wpra-crons-feed-id-col"></th>
57
+ <th class="wpra-crons-feed-name-col">{% trans "Feed" %}</th>
58
+ <th class="wpra-crons-interval-col">{% trans "Interval" %}</th>
59
+ <th class="wpra-crons-time-col">{% trans "Time" %}</th>
60
+ </tr>
61
+ </thead>
62
+ <tbody>
63
+ </tbody>
64
+ </table>
65
+ </div>
66
+
67
+ <style type="text/css">
68
+ #wpra-crons-toolbar {
69
+ display: block;
70
+ position: sticky;
71
+ top: 32px;
72
+ width: 100%;
73
+ padding: 10px 10px 0;
74
+ margin-bottom: 5px;
75
+ line-height: 30px;
76
+ box-sizing: border-box;
77
+ }
78
+
79
+ #wpra-crons-timeline {
80
+ display: block;
81
+ width: 100%;
82
+ overflow-x: auto;
83
+ overflow-y: hidden;
84
+ margin: 30px 0;
85
+ padding: 10px 0;
86
+ background: #fff;
87
+ border: 1px solid #ccd0d4;
88
+ box-shadow: 0 0 5px rgba(0, 0, 0, 0.1);
89
+ box-sizing: border-box;
90
+ }
91
+
92
+ #wpra-crons-timeline-canvas {
93
+ display: block;
94
+ }
95
+
96
+ #wpra-crons-tool-table tbody tr {
97
+ cursor: pointer;
98
+ }
99
+ #wpra-crons-tool-table tbody tr td {
100
+ border-width: 1px 0;
101
+ border-style: solid;
102
+ border-color: transparent;
103
+ box-sizing: border-box;
104
+ }
105
+
106
+ #wpra-crons-tool-table tbody tr td:first-child {
107
+ border-left-width: 1px;
108
+ }
109
+
110
+ #wpra-crons-tool-table tbody tr td:last-child {
111
+ border-right-width: 1px;
112
+ }
113
+
114
+ #wpra-crons-tool-table tbody tr:hover td {
115
+ border-color: #9fb1b4;
116
+ }
117
+
118
+ #wpra-crons-tool-table tbody tr.wpra-crons-highlighted-feed td {
119
+ border-color: #0071a1;
120
+ background-color: #f8fdff;
121
+ }
122
+
123
+ #wpra-crons-sidebar {
124
+ display: inline-block;
125
+ position: sticky;
126
+ top: 32px;
127
+ }
128
+
129
+ div.wpra-crons .wpra-crons-feed-paused .wpra-crons-feed-name-col {
130
+ color: #888;
131
+ font-style: italic;
132
+ }
133
+
134
+ div.wpra-crons .wpra-crons-feed-paused .wpra-crons-feed-name.col .wpra-crons-paused-marker:before {
135
+ content: '-';
136
+ font-style: normal;
137
+ }
138
+
139
+ #wpra-crons-tool-table th.wpra-crons-feed-id-col,
140
+ #wpra-crons-tool-table td.wpra-crons-feed-id-col {
141
+ width: 80px;
142
+ color: #999;
143
+ }
144
+
145
+ .wpra-crons-pagination {
146
+ display: inline-block;
147
+ float: right;
148
+ }
149
+ .wpra-crons-pagination-info,
150
+ .wpra-crons-pagination-buttons {
151
+ display: inline-block;
152
+ }
153
+ .wpra-crons-pagination-buttons {
154
+ margin-left: 5px;
155
+ }
156
+
157
+ .wpra-crons-pagination .wpra-crons-page-indicator {
158
+ margin: 0 5px;
159
+ }
160
+
161
+ .wpra-crons-pagination .button {
162
+ min-width: 30px;
163
+ min-height: 30px;
164
+ font-size: 16px;
165
+ line-height: 1.625;
166
+ text-align: center;
167
+ }
168
+
169
+ .wpra-crons-info > span:not(:last-of-type) {
170
+ margin-right: 15px;
171
+ }
172
+
173
+ #wpra-crons-loading {
174
+ display: none;
175
+ float: right;
176
+ color: #666;
177
+ font-size: 1em;
178
+ font-style: italic;
179
+ margin: 0 10px;
180
+ animation: 0.8s linear infinite wpra-crons-loading-anim;
181
+ }
182
+
183
+ @keyframes wpra-crons-loading-anim {
184
+ 0% {
185
+ opacity: 1;
186
+ }
187
+ 50% {
188
+ opacity: 0.6;
189
+ }
190
+ 100% {
191
+ opacity: 1;
192
+ }
193
+ }
194
+ </style>
test/bootstrap.php ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ global $vendorDir;
4
+ $vendorDir = __DIR__ . '/../vendor/';
5
+
6
+ require_once $vendorDir . 'autoload.php';
7
+
8
+ /**
9
+ * Loads a WordPress file.
10
+ *
11
+ * @since [*next-version*]
12
+ *
13
+ * @param string $relPath The path relative to a WordPress installation's root directory.
14
+ */
15
+ function wpraTestLoadWpFile($relPath)
16
+ {
17
+ global $vendorDir;
18
+
19
+ require_once $vendorDir . 'johnpbloch/wordpress-core/' . $relPath;
20
+ }
21
+
vendor/autoload.php CHANGED
@@ -4,4 +4,4 @@
4
 
5
  require_once __DIR__ . '/composer/autoload_real.php';
6
 
7
- return ComposerAutoloaderInit796829dbff036dfa1f01a56da70a551a::getLoader();
4
 
5
  require_once __DIR__ . '/composer/autoload_real.php';
6
 
7
+ return ComposerAutoloaderInit1ed1f237c7c03e77bb8213b884aea306::getLoader();
vendor/composer/autoload_classmap.php CHANGED
@@ -399,6 +399,7 @@ return array(
399
  'RebelCode\\Wpra\\Core\\Modules\\BlacklistToolModule' => $baseDir . '/src/Modules/BlacklistToolModule.php',
400
  'RebelCode\\Wpra\\Core\\Modules\\BulkAddToolModule' => $baseDir . '/src/Modules/BulkAddToolModule.php',
401
  'RebelCode\\Wpra\\Core\\Modules\\CoreModule' => $baseDir . '/src/Modules/CoreModule.php',
 
402
  'RebelCode\\Wpra\\Core\\Modules\\CustomFeedModule' => $baseDir . '/src/Modules/CustomFeedModule.php',
403
  'RebelCode\\Wpra\\Core\\Modules\\FeedBlacklistModule' => $baseDir . '/src/Modules/FeedBlacklistModule.php',
404
  'RebelCode\\Wpra\\Core\\Modules\\FeedDisplayModule' => $baseDir . '/src/Modules/FeedDisplayModule.php',
@@ -441,6 +442,7 @@ return array(
441
  'RebelCode\\Wpra\\Core\\RestApi\\EndPoints\\FeedTemplates\\GetTemplatesEndPoint' => $baseDir . '/src/RestApi/EndPoints/FeedTemplates/GetTemplatesEndPoint.php',
442
  'RebelCode\\Wpra\\Core\\RestApi\\EndPoints\\FeedTemplates\\PatchTemplateEndPoint' => $baseDir . '/src/RestApi/EndPoints/FeedTemplates/PatchTemplateEndPoint.php',
443
  'RebelCode\\Wpra\\Core\\RestApi\\EndPoints\\FeedTemplates\\RenderTemplateEndPoint' => $baseDir . '/src/RestApi/EndPoints/FeedTemplates/RenderTemplateEndPoint.php',
 
444
  'RebelCode\\Wpra\\Core\\RestApi\\Transformers\\RecursiveToArrayTransformer' => $baseDir . '/src/RestApi/Transformers/RecursiveToArrayTransformer.php',
445
  'RebelCode\\Wpra\\Core\\Templates\\Feeds\\FeedTemplateType' => $baseDir . '/src/Templates/Feeds/FeedTemplateType.php',
446
  'RebelCode\\Wpra\\Core\\Templates\\Feeds\\LegacyDisplayTemplate' => $baseDir . '/src/Templates/Feeds/LegacyDisplayTemplate.php',
399
  'RebelCode\\Wpra\\Core\\Modules\\BlacklistToolModule' => $baseDir . '/src/Modules/BlacklistToolModule.php',
400
  'RebelCode\\Wpra\\Core\\Modules\\BulkAddToolModule' => $baseDir . '/src/Modules/BulkAddToolModule.php',
401
  'RebelCode\\Wpra\\Core\\Modules\\CoreModule' => $baseDir . '/src/Modules/CoreModule.php',
402
+ 'RebelCode\\Wpra\\Core\\Modules\\CronsToolModule' => $baseDir . '/src/Modules/CronsToolModule.php',
403
  'RebelCode\\Wpra\\Core\\Modules\\CustomFeedModule' => $baseDir . '/src/Modules/CustomFeedModule.php',
404
  'RebelCode\\Wpra\\Core\\Modules\\FeedBlacklistModule' => $baseDir . '/src/Modules/FeedBlacklistModule.php',
405
  'RebelCode\\Wpra\\Core\\Modules\\FeedDisplayModule' => $baseDir . '/src/Modules/FeedDisplayModule.php',
442
  'RebelCode\\Wpra\\Core\\RestApi\\EndPoints\\FeedTemplates\\GetTemplatesEndPoint' => $baseDir . '/src/RestApi/EndPoints/FeedTemplates/GetTemplatesEndPoint.php',
443
  'RebelCode\\Wpra\\Core\\RestApi\\EndPoints\\FeedTemplates\\PatchTemplateEndPoint' => $baseDir . '/src/RestApi/EndPoints/FeedTemplates/PatchTemplateEndPoint.php',
444
  'RebelCode\\Wpra\\Core\\RestApi\\EndPoints\\FeedTemplates\\RenderTemplateEndPoint' => $baseDir . '/src/RestApi/EndPoints/FeedTemplates/RenderTemplateEndPoint.php',
445
+ 'RebelCode\\Wpra\\Core\\RestApi\\EndPoints\\Handlers\\GetEntityHandler' => $baseDir . '/src/RestApi/EndPoints/Handlers/GetEntityHandler.php',
446
  'RebelCode\\Wpra\\Core\\RestApi\\Transformers\\RecursiveToArrayTransformer' => $baseDir . '/src/RestApi/Transformers/RecursiveToArrayTransformer.php',
447
  'RebelCode\\Wpra\\Core\\Templates\\Feeds\\FeedTemplateType' => $baseDir . '/src/Templates/Feeds/FeedTemplateType.php',
448
  'RebelCode\\Wpra\\Core\\Templates\\Feeds\\LegacyDisplayTemplate' => $baseDir . '/src/Templates/Feeds/LegacyDisplayTemplate.php',
vendor/composer/autoload_real.php CHANGED
@@ -2,7 +2,7 @@
2
 
3
  // autoload_real.php @generated by Composer
4
 
5
- class ComposerAutoloaderInit796829dbff036dfa1f01a56da70a551a
6
  {
7
  private static $loader;
8
 
@@ -19,15 +19,15 @@ class ComposerAutoloaderInit796829dbff036dfa1f01a56da70a551a
19
  return self::$loader;
20
  }
21
 
22
- spl_autoload_register(array('ComposerAutoloaderInit796829dbff036dfa1f01a56da70a551a', 'loadClassLoader'), true, true);
23
  self::$loader = $loader = new \Composer\Autoload\ClassLoader();
24
- spl_autoload_unregister(array('ComposerAutoloaderInit796829dbff036dfa1f01a56da70a551a', 'loadClassLoader'));
25
 
26
  $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
27
  if ($useStaticLoader) {
28
  require_once __DIR__ . '/autoload_static.php';
29
 
30
- call_user_func(\Composer\Autoload\ComposerStaticInit796829dbff036dfa1f01a56da70a551a::getInitializer($loader));
31
  } else {
32
  $map = require __DIR__ . '/autoload_namespaces.php';
33
  foreach ($map as $namespace => $path) {
@@ -48,19 +48,19 @@ class ComposerAutoloaderInit796829dbff036dfa1f01a56da70a551a
48
  $loader->register(true);
49
 
50
  if ($useStaticLoader) {
51
- $includeFiles = Composer\Autoload\ComposerStaticInit796829dbff036dfa1f01a56da70a551a::$files;
52
  } else {
53
  $includeFiles = require __DIR__ . '/autoload_files.php';
54
  }
55
  foreach ($includeFiles as $fileIdentifier => $file) {
56
- composerRequire796829dbff036dfa1f01a56da70a551a($fileIdentifier, $file);
57
  }
58
 
59
  return $loader;
60
  }
61
  }
62
 
63
- function composerRequire796829dbff036dfa1f01a56da70a551a($fileIdentifier, $file)
64
  {
65
  if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
66
  require $file;
2
 
3
  // autoload_real.php @generated by Composer
4
 
5
+ class ComposerAutoloaderInit1ed1f237c7c03e77bb8213b884aea306
6
  {
7
  private static $loader;
8
 
19
  return self::$loader;
20
  }
21
 
22
+ spl_autoload_register(array('ComposerAutoloaderInit1ed1f237c7c03e77bb8213b884aea306', 'loadClassLoader'), true, true);
23
  self::$loader = $loader = new \Composer\Autoload\ClassLoader();
24
+ spl_autoload_unregister(array('ComposerAutoloaderInit1ed1f237c7c03e77bb8213b884aea306', 'loadClassLoader'));
25
 
26
  $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
27
  if ($useStaticLoader) {
28
  require_once __DIR__ . '/autoload_static.php';
29
 
30
+ call_user_func(\Composer\Autoload\ComposerStaticInit1ed1f237c7c03e77bb8213b884aea306::getInitializer($loader));
31
  } else {
32
  $map = require __DIR__ . '/autoload_namespaces.php';
33
  foreach ($map as $namespace => $path) {
48
  $loader->register(true);
49
 
50
  if ($useStaticLoader) {
51
+ $includeFiles = Composer\Autoload\ComposerStaticInit1ed1f237c7c03e77bb8213b884aea306::$files;
52
  } else {
53
  $includeFiles = require __DIR__ . '/autoload_files.php';
54
  }
55
  foreach ($includeFiles as $fileIdentifier => $file) {
56
+ composerRequire1ed1f237c7c03e77bb8213b884aea306($fileIdentifier, $file);
57
  }
58
 
59
  return $loader;
60
  }
61
  }
62
 
63
+ function composerRequire1ed1f237c7c03e77bb8213b884aea306($fileIdentifier, $file)
64
  {
65
  if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
66
  require $file;
vendor/composer/autoload_static.php CHANGED
@@ -4,7 +4,7 @@
4
 
5
  namespace Composer\Autoload;
6
 
7
- class ComposerStaticInit796829dbff036dfa1f01a56da70a551a
8
  {
9
  public static $files = array (
10
  '320cde22f66dd4f5d3fd621d3e88b98f' => __DIR__ . '/..' . '/symfony/polyfill-ctype/bootstrap.php',
@@ -587,6 +587,7 @@ class ComposerStaticInit796829dbff036dfa1f01a56da70a551a
587
  'RebelCode\\Wpra\\Core\\Modules\\BlacklistToolModule' => __DIR__ . '/../..' . '/src/Modules/BlacklistToolModule.php',
588
  'RebelCode\\Wpra\\Core\\Modules\\BulkAddToolModule' => __DIR__ . '/../..' . '/src/Modules/BulkAddToolModule.php',
589
  'RebelCode\\Wpra\\Core\\Modules\\CoreModule' => __DIR__ . '/../..' . '/src/Modules/CoreModule.php',
 
590
  'RebelCode\\Wpra\\Core\\Modules\\CustomFeedModule' => __DIR__ . '/../..' . '/src/Modules/CustomFeedModule.php',
591
  'RebelCode\\Wpra\\Core\\Modules\\FeedBlacklistModule' => __DIR__ . '/../..' . '/src/Modules/FeedBlacklistModule.php',
592
  'RebelCode\\Wpra\\Core\\Modules\\FeedDisplayModule' => __DIR__ . '/../..' . '/src/Modules/FeedDisplayModule.php',
@@ -629,6 +630,7 @@ class ComposerStaticInit796829dbff036dfa1f01a56da70a551a
629
  'RebelCode\\Wpra\\Core\\RestApi\\EndPoints\\FeedTemplates\\GetTemplatesEndPoint' => __DIR__ . '/../..' . '/src/RestApi/EndPoints/FeedTemplates/GetTemplatesEndPoint.php',
630
  'RebelCode\\Wpra\\Core\\RestApi\\EndPoints\\FeedTemplates\\PatchTemplateEndPoint' => __DIR__ . '/../..' . '/src/RestApi/EndPoints/FeedTemplates/PatchTemplateEndPoint.php',
631
  'RebelCode\\Wpra\\Core\\RestApi\\EndPoints\\FeedTemplates\\RenderTemplateEndPoint' => __DIR__ . '/../..' . '/src/RestApi/EndPoints/FeedTemplates/RenderTemplateEndPoint.php',
 
632
  'RebelCode\\Wpra\\Core\\RestApi\\Transformers\\RecursiveToArrayTransformer' => __DIR__ . '/../..' . '/src/RestApi/Transformers/RecursiveToArrayTransformer.php',
633
  'RebelCode\\Wpra\\Core\\Templates\\Feeds\\FeedTemplateType' => __DIR__ . '/../..' . '/src/Templates/Feeds/FeedTemplateType.php',
634
  'RebelCode\\Wpra\\Core\\Templates\\Feeds\\LegacyDisplayTemplate' => __DIR__ . '/../..' . '/src/Templates/Feeds/LegacyDisplayTemplate.php',
@@ -1077,10 +1079,10 @@ class ComposerStaticInit796829dbff036dfa1f01a56da70a551a
1077
  public static function getInitializer(ClassLoader $loader)
1078
  {
1079
  return \Closure::bind(function () use ($loader) {
1080
- $loader->prefixLengthsPsr4 = ComposerStaticInit796829dbff036dfa1f01a56da70a551a::$prefixLengthsPsr4;
1081
- $loader->prefixDirsPsr4 = ComposerStaticInit796829dbff036dfa1f01a56da70a551a::$prefixDirsPsr4;
1082
- $loader->prefixesPsr0 = ComposerStaticInit796829dbff036dfa1f01a56da70a551a::$prefixesPsr0;
1083
- $loader->classMap = ComposerStaticInit796829dbff036dfa1f01a56da70a551a::$classMap;
1084
 
1085
  }, null, ClassLoader::class);
1086
  }
4
 
5
  namespace Composer\Autoload;
6
 
7
+ class ComposerStaticInit1ed1f237c7c03e77bb8213b884aea306
8
  {
9
  public static $files = array (
10
  '320cde22f66dd4f5d3fd621d3e88b98f' => __DIR__ . '/..' . '/symfony/polyfill-ctype/bootstrap.php',
587
  'RebelCode\\Wpra\\Core\\Modules\\BlacklistToolModule' => __DIR__ . '/../..' . '/src/Modules/BlacklistToolModule.php',
588
  'RebelCode\\Wpra\\Core\\Modules\\BulkAddToolModule' => __DIR__ . '/../..' . '/src/Modules/BulkAddToolModule.php',
589
  'RebelCode\\Wpra\\Core\\Modules\\CoreModule' => __DIR__ . '/../..' . '/src/Modules/CoreModule.php',
590
+ 'RebelCode\\Wpra\\Core\\Modules\\CronsToolModule' => __DIR__ . '/../..' . '/src/Modules/CronsToolModule.php',
591
  'RebelCode\\Wpra\\Core\\Modules\\CustomFeedModule' => __DIR__ . '/../..' . '/src/Modules/CustomFeedModule.php',
592
  'RebelCode\\Wpra\\Core\\Modules\\FeedBlacklistModule' => __DIR__ . '/../..' . '/src/Modules/FeedBlacklistModule.php',
593
  'RebelCode\\Wpra\\Core\\Modules\\FeedDisplayModule' => __DIR__ . '/../..' . '/src/Modules/FeedDisplayModule.php',
630
  'RebelCode\\Wpra\\Core\\RestApi\\EndPoints\\FeedTemplates\\GetTemplatesEndPoint' => __DIR__ . '/../..' . '/src/RestApi/EndPoints/FeedTemplates/GetTemplatesEndPoint.php',
631
  'RebelCode\\Wpra\\Core\\RestApi\\EndPoints\\FeedTemplates\\PatchTemplateEndPoint' => __DIR__ . '/../..' . '/src/RestApi/EndPoints/FeedTemplates/PatchTemplateEndPoint.php',
632
  'RebelCode\\Wpra\\Core\\RestApi\\EndPoints\\FeedTemplates\\RenderTemplateEndPoint' => __DIR__ . '/../..' . '/src/RestApi/EndPoints/FeedTemplates/RenderTemplateEndPoint.php',
633
+ 'RebelCode\\Wpra\\Core\\RestApi\\EndPoints\\Handlers\\GetEntityHandler' => __DIR__ . '/../..' . '/src/RestApi/EndPoints/Handlers/GetEntityHandler.php',
634
  'RebelCode\\Wpra\\Core\\RestApi\\Transformers\\RecursiveToArrayTransformer' => __DIR__ . '/../..' . '/src/RestApi/Transformers/RecursiveToArrayTransformer.php',
635
  'RebelCode\\Wpra\\Core\\Templates\\Feeds\\FeedTemplateType' => __DIR__ . '/../..' . '/src/Templates/Feeds/FeedTemplateType.php',
636
  'RebelCode\\Wpra\\Core\\Templates\\Feeds\\LegacyDisplayTemplate' => __DIR__ . '/../..' . '/src/Templates/Feeds/LegacyDisplayTemplate.php',
1079
  public static function getInitializer(ClassLoader $loader)
1080
  {
1081
  return \Closure::bind(function () use ($loader) {
1082
+ $loader->prefixLengthsPsr4 = ComposerStaticInit1ed1f237c7c03e77bb8213b884aea306::$prefixLengthsPsr4;
1083
+ $loader->prefixDirsPsr4 = ComposerStaticInit1ed1f237c7c03e77bb8213b884aea306::$prefixDirsPsr4;
1084
+ $loader->prefixesPsr0 = ComposerStaticInit1ed1f237c7c03e77bb8213b884aea306::$prefixesPsr0;
1085
+ $loader->classMap = ComposerStaticInit1ed1f237c7c03e77bb8213b884aea306::$classMap;
1086
 
1087
  }, null, ClassLoader::class);
1088
  }
wp-rss-aggregator.php CHANGED
@@ -4,7 +4,7 @@
4
  * Plugin Name: WP RSS Aggregator
5
  * Plugin URI: https://www.wprssaggregator.com/#utm_source=wpadmin&utm_medium=plugin&utm_campaign=wpraplugin
6
  * Description: Imports and aggregates multiple RSS Feeds.
7
- * Version: 4.17.1
8
  * Author: RebelCode
9
  * Author URI: https://www.wprssaggregator.com
10
  * Text Domain: wprss
@@ -42,6 +42,7 @@ use RebelCode\Wpra\Core\Modules\AssetsModule;
42
  use RebelCode\Wpra\Core\Modules\BlacklistToolModule;
43
  use RebelCode\Wpra\Core\Modules\BulkAddToolModule;
44
  use RebelCode\Wpra\Core\Modules\CoreModule;
 
45
  use RebelCode\Wpra\Core\Modules\CustomFeedModule;
46
  use RebelCode\Wpra\Core\Modules\FeedBlacklistModule;
47
  use RebelCode\Wpra\Core\Modules\FeedDisplayModule;
@@ -77,7 +78,7 @@ use RebelCode\Wpra\Core\Plugin;
77
 
78
  // Set the version number of the plugin.
79
  if( !defined( 'WPRSS_VERSION' ) )
80
- define( 'WPRSS_VERSION', '4.17.1' );
81
 
82
  if( !defined( 'WPRSS_WP_MIN_VERSION' ) )
83
  define( 'WPRSS_WP_MIN_VERSION', '4.8' );
@@ -399,6 +400,7 @@ function wpra_modules()
399
  'tools/bulk_add' => new BulkAddToolModule(),
400
  'tools/blacklist' => new BlackListToolModule(),
401
  'tools/import_export' => new ImportExportToolsModule(),
 
402
  'tools/logs' => new LogsToolModule(),
403
  'tools/sys_info' => new SysInfoToolModule(),
404
  'tools/reset' => new ResetToolModule(),
@@ -568,6 +570,10 @@ function wpra_display_error($message, $error)
568
  <br/>
569
  <pre><?php echo $error->getMessage(); ?></pre>
570
 
 
 
 
 
571
  <strong><?php _e('Stack trace:', 'wprss'); ?></strong>
572
  <br/>
573
  <pre><?php echo $error->getTraceAsString(); ?></pre>
4
  * Plugin Name: WP RSS Aggregator
5
  * Plugin URI: https://www.wprssaggregator.com/#utm_source=wpadmin&utm_medium=plugin&utm_campaign=wpraplugin
6
  * Description: Imports and aggregates multiple RSS Feeds.
7
+ * Version: 4.17.2
8
  * Author: RebelCode
9
  * Author URI: https://www.wprssaggregator.com
10
  * Text Domain: wprss
42
  use RebelCode\Wpra\Core\Modules\BlacklistToolModule;
43
  use RebelCode\Wpra\Core\Modules\BulkAddToolModule;
44
  use RebelCode\Wpra\Core\Modules\CoreModule;
45
+ use RebelCode\Wpra\Core\Modules\CronsToolModule;
46
  use RebelCode\Wpra\Core\Modules\CustomFeedModule;
47
  use RebelCode\Wpra\Core\Modules\FeedBlacklistModule;
48
  use RebelCode\Wpra\Core\Modules\FeedDisplayModule;
78
 
79
  // Set the version number of the plugin.
80
  if( !defined( 'WPRSS_VERSION' ) )
81
+ define( 'WPRSS_VERSION', '4.17.2' );
82
 
83
  if( !defined( 'WPRSS_WP_MIN_VERSION' ) )
84
  define( 'WPRSS_WP_MIN_VERSION', '4.8' );
400
  'tools/bulk_add' => new BulkAddToolModule(),
401
  'tools/blacklist' => new BlackListToolModule(),
402
  'tools/import_export' => new ImportExportToolsModule(),
403
+ // 'tools/crons' => new CronsToolModule(),
404
  'tools/logs' => new LogsToolModule(),
405
  'tools/sys_info' => new SysInfoToolModule(),
406
  'tools/reset' => new ResetToolModule(),
570
  <br/>
571
  <pre><?php echo $error->getMessage(); ?></pre>
572
 
573
+ <strong><?php _e('Occurred at:', 'wprss'); ?></strong>
574
+ <br/>
575
+ <pre><?php echo $error->getFile(); ?> (<?php echo $error->getLine() ?>)</pre>
576
+
577
  <strong><?php _e('Stack trace:', 'wprss'); ?></strong>
578
  <br/>
579
  <pre><?php echo $error->getTraceAsString(); ?></pre>